Repository navigation
Cosmo: Parameters, equality, equivalence - #12136
Conversation
e64d637 to
dcc1127
Compare
4c1a293 to
e6dacc2
Compare
mhvk
left a comment
There was a problem hiding this comment.
@nstarman - I like the ideas here very much but have some comments on the implementation (which may help to simplify it).
Also, while it is a different module, we do already have a Parameter class for astropy.models - might it make sense to use a different name?
|
@mhvk, thanks for the detailed comments! |
e6dacc2 to
ca9ffa5
Compare
|
Hello @nstarman 👋! It looks like you've made some changes in your pull request, so I've checked the code again for style. There are no PEP8 style issues with this pull request - thanks! 🎉 Comment last updated at 2021-09-22 18:48:49 UTC |
|
On |
As I have it currently, one of the mandatory arguments to |
c9f8c8e to
fb68914
Compare
|
@mhvk, there are a number of new things since last you reviewed. I think the important ones are Apparently I didn't sort out the strange error in the parallel build. Somehow |
c035b00 to
7f46f5c
Compare
mhvk
left a comment
There was a problem hiding this comment.
Haven't quite finished reviewing the tests, but am running out of steam, so I'll just put this out. Overall, it looks nice. My main suggestion would be to use Parameter.__set__ for one-off setting (i.e., only works if _attr_name_private does not yet exist), which can then include validation. I think the current Parameter.validate sequence is unusual and likely to be forgotten in user subclasses.
| if self._parent is None: | ||
| return super().__repr__() | ||
| out = StringIO() | ||
| print(self.__call__(option="parameters", out=out), file=out) |
There was a problem hiding this comment.
This does the print(..., file=out) twice, once in __call__ and once here!
There was a problem hiding this comment.
Ahh. I'll look at that again. I patterned this off of an example in Table, I think. info for Cosmology was sitting in a different branch I was working on for a while... I forget exactly what everything is meant to do.
There was a problem hiding this comment.
info isn't necessary for this PR, so I moved it to a subsequent PR.
But yes, thanks! I fixed the print problem.
| def __init__(self, name="cosmology with kwargs", meta=None, **kwargs): | ||
| super().__init__(name=name, meta=meta, **kwargs) | ||
|
|
||
| def __equiv__(self, other): |
There was a problem hiding this comment.
This makes me wonder whether it is really useful to make this an abstractmethod. Could the default just call __eq__? (Which is allowed to return NotImplemented as well)
There was a problem hiding this comment.
I actually think the default should be what I implement for FLRW. Cosmology has no parameters, but any subclass will, so that equivalency check will be for 1) the same class and 2) the same parameters.
I refactored __eq__ to use __equiv__ to minimize code duplication. It always uses Cosmology.__equiv__, because self.__equiv__ is overwritten in subclasses, like FlatLambdaCDM
|
|
||
| def test_has_expected_attributes(self, info): | ||
| """Test ``CosmologyInfo`` has all the expected attributes.""" | ||
| assert info._stats == [] |
There was a problem hiding this comment.
I'd generally not test private attributes, but rather (try to) test their effects.
bc5d445 to
fe04cea
Compare
fe04cea to
39ce4ac
Compare
7c5f09a to
2ed5282
Compare
|
Thanks @mhvk for the detailed review. I think I addressed all points and have moved a fair bit of the bells and whistles to future PRs. |
3463550 to
7a46c94
Compare
mhvk
left a comment
There was a problem hiding this comment.
As I'm on the train from London to The Netherlands, my review is a bit less thoughtful than I would've liked, but hopefully something useful. Overall, this looks nice!
| an ABC and subclasses must override some methods. | ||
| """ | ||
|
|
||
| @abc.abstractmethod |
There was a problem hiding this comment.
Maybe because of this. But is it actually used?
There was a problem hiding this comment.
Yeah, that's one reason. FLRWSubclassTest is used here for all the FLRW-subclass tests, like TestLambdaCDM.
And if someone wanted to write their own FLRW subclass and use the test suite, then they too would have to define a setup_class().
There was a problem hiding this comment.
When I start migrating the tests from test_cosmology to the new test suite I'll add
@abc.abstractmethod
def test_w(self, cosmo):
"""`FLRW.w` is abstract and subclasses must provide a test."""86c0cd3 to
b351ef6
Compare
mhvk
left a comment
There was a problem hiding this comment.
Now looks very good. Still a few comments you may want to consider - but nothing to stop merging, so approved!
| # classes, different parameters. (1) & (3) => True, (2) & (4) => False. | ||
|
|
||
| if not isinstance(other, Cosmology): | ||
| return False |
There was a problem hiding this comment.
Should this not still allow other to try? In principle a non-Cosmology other might have everything in place...
Effectively, this would mean that self.__equiv__ should do the instance check (which of course the base class here already does by insisting it is the same class), i.e., this stanza should just be removed.
There was a problem hiding this comment.
SGTM. It would be very cool to allow equivalence checks against 3rd-party cosmologies using to_format(). I made a card for this. https://github.com/astropy/astropy/projects/7#card-69385769
There was a problem hiding this comment.
Essentially if it fails the class check it will try other = Cosmology.from_format(other) and then proceed
| True if all immutable fields are equal, False otherwise. | ||
| True if cosmologies are equivalent, False otherwise. | ||
| """ | ||
| # The options are: 1) same class & parameters; 2) same class, different |
There was a problem hiding this comment.
General thought given the comment below about python: I think generally python for things like self == other will only call other.__eq__(self) if other is a strict subclass of self. In principle, you could do the same here, though I don't know if there is much benefit to it.
There was a problem hiding this comment.
Related note, I should add __req__.
Doesn't exist
There was a problem hiding this comment.
How does Numpy do 1 == array if python only "call[s] other.__eq__(self) if other is a strict subclass of self" ?
There was a problem hiding this comment.
Sorry, I was unclear: if the two are different classes, both get called; but if isinstance(other, type(self)) and type(other) is not type(self), then only other.__eq__(self) is called - since presumably, the subclass knows how to deal with the superclass. See https://docs.python.org/3/reference/datamodel.html#object.__radd__
(Actually, that suggests self.__eq__(other) may still get called, but just second - not completely sure!!)
There was a problem hiding this comment.
Thanks for the explanation! I'll make a card for followup on this. Seems good to have it implemented exactly like python, but lower priority because it already works as expected.
There was a problem hiding this comment.
Signed-off-by: Nathaniel Starkman (@nstarman) <[email protected]>
Signed-off-by: Nathaniel Starkman (@nstarman) <[email protected]>
remove ``_float_or_None`` Signed-off-by: Nathaniel Starkman (@nstarman) <[email protected]>
Parameters store units and equivalencies and have a new method “validate” to make a quantity from the value using the stored unit and equivalencies. This method is safe for non-Parameters. Signed-off-by: Nathaniel Starkman (@nstarman) <[email protected]>
Co-authored-by: Marten van Kerkwijk <[email protected]> Signed-off-by: Nathaniel Starkman (@nstarman) <[email protected]>
Signed-off-by: Nathaniel Starkman (@nstarman) <[email protected]>
Signed-off-by: Nathaniel Starkman (@nstarman) <[email protected]>
b351ef6 to
a6928bb
Compare
|
Thanks @mhvk for the detailed conversation! This PR is definitely the better for it and I think one of the 3 most foundational PRs I've worked on though far as a @astropy/cosmology maintainer. Lots of avenues for expansion. |
|
This was a really nice cleanup & improvement! |
Cosmology parameters are now descriptors, defaulting to getting the private attribute (e.g. "_name") but allowing for custom getter methods.
Cosmological equality is refactored to check the class, Parameters, the name.
This closes a potential bug where Cosmologies of different classes but had the same parameters could be considered equal.
A new method,
is_equivalent, is added to check Parameter equivalence, so aFlatLambdaCDMand flatLambdaCDMare equivalent.__repr__is generalized to use Parameter, correcting some bugs. Now onlyCosmologyhas__repr__defined._float_or_Noneis removed.The new descriptormoved to subsequent PR.infois addedTODO:
is_equivalentChecklist for package maintainer(s)
This checklist is meant to remind the package maintainer(s) who will review this pull request of some common things to look for. This list is not exhaustive.
Extra CIlabel.no-changelog-entry-neededlabel. If this is a manual backport, use theskip-changelog-checkslabel unless special changelog handling is necessary.astropy-botcheck might be missing; do not let the green checkmark fool you.backport-X.Y.xlabel(s) before merge.