-
Notifications
You must be signed in to change notification settings - Fork 33
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
Define isequal
and ==
more widely between Kernel
s
#492
Comments
I think it's fair to say that we've avoided taking this implementation task seriously until now because we've not had a complelling use-case -- about the most that we've been able to say is that it is a nice-to-have, rather than a necessity. Do you have a particular use-case in mind? |
The use case that brought me here was to pass an interface test that would like two fitted objects to be equal when one is updated with unchanged parameters. I was hoping to store the posterior in a fitted object to save recomputing it which I think would require Maybe there's a better way? |
Ahh I see. This definitely does indeed sound like an interesting use-case. Probably the best way forward is to first consider how equality tests would be included in our standard collection of interface tests. Clearly edit: updated phrasing |
Relevant parts of the docstrings: help?> isequal
search: isequal issetequal
isequal(x, y)
Similar to ==, except for the treatment of floating point numbers and of missing values.
[...]
Implementation
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
The default implementation of isequal calls ==, so a type that does not involve
floating-point values generally only needs to define ==.
isequal is the comparison function used by hash tables (Dict). isequal(x,y) must imply
that hash(x) == hash(y).
This typically means that types for which a custom == or isequal method exists must
implement a corresponding hash method (and vice versa). Collections typically implement
isequal by calling isequal recursively on all contents.
Furthermore, isequal is linked with isless, and they work together to define a fixed
total ordering, where exactly one of isequal(x, y), isless(x, y), or isless(y, x) must be
true (and the other two false).
Scalar types generally do not need to implement isequal separate from ==, unless they
represent floating-point numbers amenable to a more efficient implementation than that
provided as a generic fallback (based on isnan, signbit, and ==).
[...]
help?> ==
search: == === !==
==(x, y)
[...]
Implementation
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
New numeric types should implement this function for two arguments of the new type, and
handle comparison to other types via promotion rules where possible.
isequal falls back to ==, so new methods of == will be used by the Dict type to compare
keys. If your type will be used as a dictionary key, it should therefore also implement
hash.
If some type defines ==, isequal, and isless then it should also implement < to ensure
consistency of comparisons. That is, according to my understanding one should implement |
Thanks for the reference! @willtebbutt It's not clear to me that testing inequality at the interface level well is feasible. This must be a standard issue, perhaps typically dealt with by unit tests all the way down? To me a natural, compare something similar, but different test for composite types would require a At the interface level, I'd lean towards having a It could also be suggested that equality is implemented for all types in an automated manner - how would you feel about using AutoHashEquals.jl on all AutoHashEquals.jl seems to define |
Thanks for looking at that @devmotion . I agree with your assessment of what should be implemented.
I think this makes a lot of sense. Checking the precise definition of equality is inherently kernel-specific so I don't think we can do much better than your proposal in general. Checking that
I agree that this feels out-of-scope, and I don't think I'd be keen to add it at this point.
I'm less keen on this, but mainly because I don't like the idea of having to write Okay. I'm happy that we can do a decent job of testing. The question is then what to do about implementation.
I'm really hoping that there aren't too many things in category three. Do you think this model of the cases is accurate @mjp98 , or are there some cases that I've missed? |
Regarding the second point, would making some of those transformed kernels (like the scaled one) completely immutable solve the solution? |
Possibly -- I still don't fully understand why they're not already equal to be honest. I also don't really understand why |
I'm hesitant about
Maybe a specialised kind of equality could be implemented for category 3 later, if needed, and stick to cases 1 and 2 for now? |
I would be happy to leave it for now to be honest. It would be good to try and write down a succinct definition of what it mean for two kernels to be equal under this system. It clearly has something to do with
but I'm not sure whether this is exactly it, or if I've missed something. I just want it to be crystal clear what definition we're picking, and whether any two kernels are equal under it. |
A clear definition is definitely sensible to avoid ending up in a hole. There do seem to be various edge cases, as I don't think points 1. and 2. above would catch a case where a
|
Good catch. Maybe point 1 is better phrased as a necessary condition: k1 and k2 are necessarily unequal if they are instances of different (mutable) structs. If k1 and k2 have the same struct, they may be equal. It will be kernel-specific whether or not they are equal. I think the above excludes the annoying case 3, but leaves it open to the kernel-implementer to decide what it means for two instances of their kernel to be equal. |
Okay, so we could have:
and maybe document some general expectations (the first may be too optimistic if methods dispatch on numeric type)
but otherwise
I think this would be sorted by adding the following methods where needed:
If this seems sensible I'll start working on a PR? |
This seems like an excellent definition. This will clearly only hold approximately for things like Otherwise, I think we're good to go. Looking forward to the PR. |
I have almost got tests passing locally on the addition to
The outstanding failures are due to issues with equality between metrics, e.g.
|
Fantastic. How urgent is this for you? We can implement this in this package now and recurse into Distances when the issue is fixed if you need this soon. |
It would be nice to define
isequal
and/or==
as widely as possible betweenKernel
s andTransform
s. At the moment some basic cases seem to be missing, such asI'm not clear exactly when
isequal
/==
both should be extended (and ifhash
is also needed), but would be happy to work on an PR that starts to improve this if there's a clear way forward.The text was updated successfully, but these errors were encountered: