Skip to content

Conversation

odow
Copy link
Member

@odow odow commented Jul 5, 2021

I took a look through DoubleDicts for the first time in a long time (ever?).

Why are there so many types and implementations? This is very complicated (600 lines!) for something that should be simple.

From what I can tell, the only type in DoubleDicts that is used is

con_map::DoubleDicts.MainIndexDoubleDict

With this constructor
con_map = DoubleDicts.IndexDoubleDict()

And this related type which is used to access the inner dictionaries
map::MOIU.DoubleDicts.IndexWithType{F,S},

called from here
_identity_constraints_map(model, map.con_map[F, S])

Does that mean I can remove anything unused? Are other packages using this somewhere? If so, how?

Closes #1230

@odow odow added the Submodule: Utilities About the Utilities submodule label Jul 5, 2021
@odow odow requested review from joaquimg and blegat July 5, 2021 07:10
@blegat
Copy link
Member

blegat commented Jul 6, 2021

Does that mean I can remove anything unused? Are other packages using this somewhere? If so, how?

No there are plan to us it in more places than the IndexMap, e.g. UniversalFallback, DiffOpt but it hasn't been done yet.
MOI brings a generic and extensible interface but supporting any function and set types should not mean that all the code become unstable. We should educate the user to store things in DoubleDicts, use function barriers taking type-stable versions of the double dicts through the barrier.
The current DoubleDicts cover many possible use cases but I've encountered cases that are not covered, e.g., where what you store depends on F and S but is not exactly Tuple{F,S}

@odow
Copy link
Member Author

odow commented Jul 6, 2021

but it hasn't been done yet

My problem with this is that we have a lot of code in MOI that is sitting there un-used on the off-chance that it might be useful in the future. We should tear it out prior to 1.0. We can always add it back later...

@odow
Copy link
Member Author

odow commented Jul 7, 2021

Okay. This needs a pretty thorough review by @joaquimg and @blegat.

The changes are actually less scary than the diff seems. It may be best to review in side-by-side mode. The interleaved diff isn't very helpful.

  • Removed FunctionSetDoubleDict. If we need this later, it can get added back then.
  • Massively simplify the type signatures of AbstractDoubleDict and AbstractWIthType (now AbstractDoubleDictInner)
  • Rename WithType to DoubleDictInner
  • Rename IndexWithType to IndexDoubleDictInner

@odow odow changed the title WIP: refactor DoubleDicts.jl Refactor DoubleDicts.jl Jul 8, 2021
@odow
Copy link
Member Author

odow commented Jul 11, 2021

Bump @blegat

@joaquimg
Copy link
Member

Will read tomorrow

Copy link
Member

@joaquimg joaquimg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use case for ParametricOptInterface would be ci as keys and arrays of Linear/QuadraricTerms as values.

DiffOpt already uses CIs as keys and functions (SAF) as values.

I am planning to test DDs in xpress in the short term. CleverDicts inside double dicta might be nice to consider.

@odow
Copy link
Member Author

odow commented Jul 12, 2021

These use-cases are all fine for DoubleDict. I don't think anything needs changing.

@joaquimg
Copy link
Member

As long as values have a single type they fall into the simpler version of DoubleDict.

The odd one is DiffOpt, which has two DD's, one for scalar and another for vector. It is not clear to me if they should be merged.

const AD = AbstractDict

const DataTypePair = Tuple{DataType,DataType}
abstract type AbstractDoubleDict{V} <: AbstractDict{MOI.ConstraintIndex,V} end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we end up with this simple implementation...
We should rename this to ConstraintIndexedDict and reserve DoubleDict for future flexible implementation. Or ConstraintIndexDict or something along those lines.

DoubleDictInner could be SingleTypeConstraintIndexedDict.

IndexDoubleDict would become ConstraintIndexMap...

Copy link
Member

@joaquimg joaquimg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can get rid of a few haskey's

@blegat
Copy link
Member

blegat commented Jul 13, 2021

Yes with DiffOpt, I could just split it in two but in general, it would be nice to have any value type parametrized by F, S. For DiffOpt, it would be F. The user could give a function mapping F, S to the value. So for constraint indices, it is (F, S)-> CI{F, S} and for DiffOpt, it is (F, S)-> F.

@odow
Copy link
Member Author

odow commented Jul 13, 2021

For DiffOpt, it would be F

The right way to do this is for DiffOpt to implement this locally as a subtype of AbstractDoubleDict, show it has a performance benefit, debug, and them make a PR to MOI.

I don't think we should add in this PR.

@odow odow force-pushed the od/double-dicts branch from f5b92ef to 788dd51 Compare July 14, 2021 00:10
@odow odow mentioned this pull request Jul 14, 2021
22 tasks
@odow
Copy link
Member Author

odow commented Jul 14, 2021

Okay. I've addressed the haskey issue. But we still have our naming problem. I think it's fine to keep DoubleDict as the name. It's a submodule within the Utilities submodule, so it's obviously not for wider consumption.

It solves the major issue, and provides a decent fallback for other cases. I'm in favor of merging as-is.

struct IndexDoubleDict{DI,DO} <: AbstractDoubleDict{DataTypePair,CI,Int64,DI,DO}
dict::DO
struct IndexDoubleDict <: AbstractDoubleDict{MOI.ConstraintIndex}
dict::Dict{Tuple{DataType,DataType},Dict{Int64,Int64}}
Copy link
Member

@blegat blegat Jul 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use a CleverDict here. With VectorOfConstraints and MatrixOfConstraints, the constraint indices are now 1:n for scalar constraints so using CleverDict here would speed up copy time for large LP's

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that is why it was previously parametrized by dict.
That is for the second Dict....
And.... we might consider LittleDict for the outer Dict.... (it is from OrderedCollections) leave it as comment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so using CleverDict here would speed up copy time for large LP's

Benchmark? I struggle to believe that the time looking up the index translation is significant. I'm against adding complexity, even if it is a minor speed improvement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When doing the benchmarks for MatrixOfConstraints, I noticed creating the IndexMap was taking a significant time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a proper model? Or in a microbenchmark?

struct DoubleDict{V,DI,DO} <: AbstractDoubleDict{DataTypePair,V,Int64,DI,DO}
dict::DO
struct DoubleDict{V} <: AbstractDoubleDict{V}
dict::Dict{Tuple{DataType,DataType},Dict{Int64,V}}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a function _inner_type(F, S) = V and have

Suggested change
dict::Dict{Tuple{DataType,DataType},Dict{Int64,V}}
dict::Dict{Tuple{DataType,DataType},Dict{Int64}}

"""
struct DoubleDict{V,DI,DO} <: AbstractDoubleDict{DataTypePair,V,Int64,DI,DO}
dict::DO
struct DoubleDict{V} <: AbstractDoubleDict{V}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially call it ConstraintIndexDict

@odow
Copy link
Member Author

odow commented Jul 22, 2021

@blegat shall I merge this for now, and we can address any other issues in a follow-up PR?

@odow odow merged commit 9668d19 into master Jul 23, 2021
@odow odow deleted the od/double-dicts branch July 23, 2021 22:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Submodule: Utilities About the Utilities submodule
Development

Successfully merging this pull request may close these issues.

Missing docstring for lazy_get
3 participants