Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend flattener to allow multiple sets #1768

Merged
merged 48 commits into from
Jan 27, 2021
Merged

Conversation

Robbybp
Copy link
Contributor

@Robbybp Robbybp commented Jan 3, 2021

Summary/Motivation:

The current pyomo.dae.flatten module has a function flatten_dae_components that partitions indexed components into new (reference) components, indexed only (if at all) by a specified set. This PR extends this functionality by allowing multiple sets to be specified. The returned components may be indexed by any or all of the specified sets. This is useful especially for PDE modeling/analysis, where a unique "variable" is defined as something indexed by e.g. time and space.

Changes proposed in this PR:

  • Overhaul flattener helper functions to allow the more general functionality
  • Add a user-facing function flatten_components_along_sets that implements this partition
  • Rewrite flatten_dae_components as a special case of flatten_components_along_sets

Legal Acknowledgement

By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

@codecov
Copy link

codecov bot commented Jan 19, 2021

Codecov Report

Merging #1768 (7c26253) into master (a05199e) will decrease coverage by 0.17%.
The diff coverage is 97.85%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1768      +/-   ##
==========================================
- Coverage   75.14%   74.96%   -0.18%     
==========================================
  Files         638      638              
  Lines       91863    94318    +2455     
==========================================
+ Hits        69027    70706    +1679     
- Misses      22836    23612     +776     
Impacted Files Coverage Δ
pyomo/dae/flatten.py 97.88% <97.85%> (+7.22%) ⬆️
pyomo/pysp/phsolverserver.py 7.83% <0.00%> (-58.99%) ⬇️
pyomo/opt/parallel/pyro.py 69.48% <0.00%> (-18.71%) ⬇️
pyomo/solvers/plugins/solvers/CPLEX.py 84.60% <0.00%> (-4.19%) ⬇️
pyomo/core/base/global_set.py 90.69% <0.00%> (-2.33%) ⬇️
pyomo/pysp/plugins/wwphextension.py 55.55% <0.00%> (-1.97%) ⬇️
pyomo/pysp/ph.py 68.21% <0.00%> (-1.12%) ⬇️
pyomo/pysp/phutils.py 72.31% <0.00%> (-0.57%) ⬇️
pyomo/pysp/phsolverserverutils.py 68.95% <0.00%> (-0.20%) ⬇️
pyomo/core/kernel/block.py 100.00% <0.00%> (ø)
... and 16 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a05199e...7c26253. Read the comment docs.

Copy link
Member

@blnicho blnicho left a comment

Choose a reason for hiding this comment

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

A few minor comments but otherwise I think this looks fine.

pyomo/dae/flatten.py Outdated Show resolved Hide resolved
pyomo/dae/flatten.py Outdated Show resolved Hide resolved
pyomo/dae/flatten.py Outdated Show resolved Hide resolved
pyomo/dae/flatten.py Show resolved Hide resolved
pyomo/dae/tests/test_flatten.py Outdated Show resolved Hide resolved
Comment on lines +590 to +598
#for sets, comps in zip(sets_list, comps_list):
# if len(sets) == 1 and sets[0] is m.d2:
# ref_data = {
# self._hashRef(Reference(m.v_2n[:,('a',1)])),
# self._hashRef(Reference(m.v_2n[:,('b',2)])),
# }
# # Cannot access the data of ^these references
# for comp in comps:
# self.assertIn(self._hashRef(comp), ref_data)
Copy link
Member

Choose a reason for hiding this comment

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

Can this commented code be removed? At a higher level, is this test complete and doing what you expect? The comments seem to indicate that there may have been some issues debugging it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test is basically not doing what is expected. The line

self.assertNotIn(('a', 1), ref1._index._ref)

confirms this. ('a', 1) should be a valid index. This is a problem with compatibility between slices and normalize_index.flatten == False. Basically a one-dimensional slice does not properly slice a higher-dimension set in this case. I'm not sure there is an easy fix. The commented code is what I would have expected to work.

Probably should just open an issue about this then remove this test?

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the clarification. I think the best thing to do is to open an issue and then add a "TODO" comment in this test that references the issue. I think leaving the commented test for future reference is fine as long as we can follow the context of why it's there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added comment and opened issue

Copy link
Member

@jsiirola jsiirola left a comment

Choose a reason for hiding this comment

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

I think this looks good (up do some questions on naming / documentation).

I do have a side question for you: how challenging do you think it would be it be to add a wrapper object around ReferenceDict to support reordering the indices of a reference? That way you wouldn't have to create separate results for [I, J, I] and [I, I, J]. I suspect we could do that pretty easily (in a separate PR).

pyomo/dae/flatten.py Outdated Show resolved Hide resolved
pyomo/dae/tests/test_flatten.py Outdated Show resolved Hide resolved
pyomo/dae/tests/test_flatten.py Outdated Show resolved Hide resolved
pyomo/dae/tests/test_flatten.py Outdated Show resolved Hide resolved
pyomo/dae/tests/test_flatten.py Outdated Show resolved Hide resolved
@Robbybp
Copy link
Contributor Author

Robbybp commented Jan 26, 2021

This may be a larger can of worms than I should open right now, but I'm not sure I like the name flatten_components_along_sets. "Flatten" seems to imply that we are going from a "higher dimension" object to a "lower dimension" object by multiplying sets into a single index, like we might do for finite elements and collocation points.

This functionality seems closer to a partition of component data objects into containers that preserve indexing by the specified sets. Any thoughts on the name partition_components_by_sets?

@jsiirola
Copy link
Member

This may be a larger can of worms than I should open right now, but I'm not sure I like the name flatten_components_along_sets. "Flatten" seems to imply that we are going from a "higher dimension" object to a "lower dimension" object by multiplying sets into a single index, like we might do for finite elements and collocation points.

I think this does move from a higher dimension down to a lower one, in that all the index sets other than the ones you are flattening along disappear.

@Robbybp
Copy link
Contributor Author

Robbybp commented Jan 26, 2021

I think this does move from a higher dimension down to a lower one, in that all the index sets other than the ones you are flattening along disappear.

I usually think of flattening as going from a single 2d array to a single 1d array. Here we are going from high-dimensional objects to many low-dimensional objects. I suppose it still is flattening but it seems to be closer to some sort of partition. It feels like cheating to say we "flattened" an object when really we broke it up enough that we could call each piece flat.

@Robbybp
Copy link
Contributor Author

Robbybp commented Jan 26, 2021

After a little more thought, I think we are actually doing three things here. First we split components by eliminating any sets we don't care about, second we partition these components according to what sets they're still indexed by, and third we create references that allow the user to access the new components directly.

The first and second steps can be thought of as partitions, the third as flattening. I think the entire procedure can be thought of as viewing components "from the perspective of" the specified sets. Not sure how much this helps naming. Best I can come up with is something like
view_components_from_sets or
view_components_through_sets.

@blnicho
Copy link
Member

blnicho commented Jan 27, 2021

I suggest we keep the current name for now. This is a fairly advanced and specific tool and I think expanding the documentation to include the purpose and intended use of this functionality will be more helpful to "future-us" than trying to find a more precise name at this point.

@blnicho blnicho merged commit 29dc786 into Pyomo:master Jan 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants