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

Add hash methods for many types with == method #2373

Merged
merged 23 commits into from
Jul 5, 2023

Conversation

lgoettgens
Copy link
Member

@lgoettgens lgoettgens commented May 10, 2023

This addresses parts of #2222 and resolves #1264.

Julia requires that equal elements (w.r.t. ==) hash to the same value to make Sets etc. work.
For many OSCAR types (cf. #2222), there currently is a dedicated ==, but no hash; thus contradicting the requirement.

@lgoettgens lgoettgens force-pushed the lg/hash branch 2 times, most recently from fa49b72 to 0f39d99 Compare May 11, 2023 10:10
@codecov
Copy link

codecov bot commented May 11, 2023

Codecov Report

Merging #2373 (db87017) into master (53ea281) will decrease coverage by 0.13%.
The diff coverage is 23.52%.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2373      +/-   ##
==========================================
- Coverage   72.94%   72.82%   -0.13%     
==========================================
  Files         405      405              
  Lines       53781    53874      +93     
==========================================
+ Hits        39232    39235       +3     
- Misses      14549    14639      +90     
Impacted Files Coverage Δ
...metry/ToricVarieties/ToricDivisors/constructors.jl 60.41% <0.00%> (-7.03%) ⬇️
...ry/ToricVarieties/ToricLineBundles/constructors.jl 48.00% <0.00%> (-5.34%) ⬇️
...etry/ToricVarieties/ToricMorphisms/constructors.jl 60.00% <0.00%> (-6.67%) ⬇️
src/Modules/ModulesGraded.jl 55.13% <0.00%> (-0.26%) ⬇️
src/PolyhedralGeometry/iterators.jl 86.75% <0.00%> (-1.17%) ⬇️
src/Rings/PBWAlgebra.jl 94.20% <0.00%> (-0.52%) ⬇️
src/Rings/mpoly-localizations.jl 64.42% <0.00%> (-0.65%) ⬇️
src/Rings/mpolyquo-localizations.jl 66.70% <0.00%> (-0.60%) ⬇️
src/TropicalGeometry/semiring.jl 23.07% <0.00%> (-0.69%) ⬇️
...try/ToricVarieties/AlgebraicCycles/constructors.jl 53.68% <16.66%> (-2.99%) ⬇️
... and 6 more

... and 3 files with indirect coverage changes

@lgoettgens lgoettgens changed the title Add hash methods for types with == method Add hash methods for many types with == method May 11, 2023
@lgoettgens
Copy link
Member Author

Most implementations are purely based on the things that are compared in the == implementation right above. If x == y does something like issubset(x,y) || issubset(y,x) or iszero(reduce(x.arg - y.arg)) this is not used, and the hash will be the same for all elements with the same parent (or similar).

@lgoettgens lgoettgens marked this pull request as ready for review May 11, 2023 14:31
@lgoettgens lgoettgens force-pushed the lg/hash branch 2 times, most recently from 441a5a9 to 91bcf5d Compare May 11, 2023 14:57
Copy link
Contributor

@fieker fieker left a comment

Choose a reason for hiding this comment

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

The hash functions apprea to be correct, but are very weak in many cases. Can someone from teh geometry crowed maybe have a look?
Fundamentally, I'm not sure if a weak hash function is better than throwing an error. Several hash functinos introduced here shuold never be used.

@lgoettgens lgoettgens force-pushed the lg/hash branch 2 times, most recently from 4bc4e96 to 2fc7c8e Compare May 17, 2023 09:45
Comment on lines 536 to 679
function Base.hash(T::AbsMPolyMultSet, h::UInt)
b = 0x7ce51a28c47ec5e1 % UInt
h = hash(typeof(T), h)
h = hash(ambient_ring(T), h)
return xor(h, b)
end
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for the effort! However, this kind of hashing will not be sufficient. Instead, I propose to throw an error here which requires the user to overwrite the hash function for their concrete type.

Can I do that and push to this PR?

Copy link
Member Author

@lgoettgens lgoettgens May 17, 2023

Choose a reason for hiding this comment

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

Do you mean something similar to this?

error("comparison of multiplicative sets of type $(typeof(T)) and $(typeof(U)) is not implemented")

Yeah, that would be great. Please text me on slack to coordinate, so that we delete nothing by accidentally force pushing anything.

Copy link
Member Author

@lgoettgens lgoettgens May 22, 2023

Choose a reason for hiding this comment

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

I added a warning in 0dfcbe8. Is this fine with you?

Copy link
Member Author

Choose a reason for hiding this comment

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

After looking a bit deeper into the concrete subtypes, I think there cannot be special implementations of hash for each type. There are many different implementations for issubset for different pairs of types, and equality is just defined generically using issubset. Since AbsMPolyMultSets of different concrete types can be equal, their hashes should coincide as well. And I do not see how to do that with specialized implementations.

src/Rings/mpoly-localizations.jl Show resolved Hide resolved
src/Rings/mpolyquo-localizations.jl Show resolved Hide resolved
@lgoettgens lgoettgens marked this pull request as draft May 17, 2023 10:40
@fingolfin
Copy link
Member

In principle this is fine by me, but there is (a) a conflict and (b) this is marked as a draft, so I won't look closer for now.

@lgoettgens lgoettgens marked this pull request as ready for review May 22, 2023 13:36
@lgoettgens lgoettgens marked this pull request as draft May 22, 2023 13:36
@lgoettgens lgoettgens marked this pull request as ready for review May 22, 2023 13:50
@lgoettgens
Copy link
Member Author

Let's see if the CI runs without any warnings.

fieker
fieker previously requested changes May 23, 2023
Copy link
Contributor

@fieker fieker left a comment

Choose a reason for hiding this comment

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

function Base.hash(a::SubquoModuleElem, h::UInt)

the current hash does not depend on the element, only on the parent. This is julia-correct, but is this what you want? I'd rather throw an error... @HechtiDerLachs ?

Similar: GAPGroupHomomorphism @fingolfin is there a decent hash for f.map or should this be an error?

@fingolfin
Copy link
Member

I don't see a way to define an efficient hash for group morphisms, so I think that should throw an error

@lgoettgens
Copy link
Member Author

I would refrain from throwing errors in these cases to not render these types useless for anyone who needs to use them in some container/setting with hashing (even without knowning). Instead, I would like to have some kind of warning. If possible, this warning should be marking the CI as failed.
Is something like this possible?

@thofma
Copy link
Collaborator

thofma commented May 23, 2023

If the warning is supposed to make CI fail, why not error in the first place?

Or why not define the hash to be 0 % UInt for the types where there is no efficient hashing? Then one can still use them for containers.

@lgoettgens
Copy link
Member Author

If the warning is supposed to make CI fail, why not error in the first place?

Or why not define the hash to be 0 % UInt for the types where there is no efficient hashing? Then one can still use them for containers.

The latter is my proposal in this PR. I use every little bit of information to make at least some hashes different to at least circumvent hash conflicts for objects of completely different types.

@fingolfin
Copy link
Member

Or why not define the hash to be 0 % UInt for the types where there is no efficient hashing? Then one can still use them for containers.

That's one way to put it, as an advantage. But there's also the counterpoint: with a 0-hash, one can use these objects as keys for a container, without noticing at first that this is a terrible idea with worst case performance. Other than for toy examples it won't be useful...

That's why I'd rather have an error in those cases...

Comment on lines 3567 to 3569
b = 0x0361a2f6467e4200 % UInt
h = hash(parent(a), h)
return xor(h, b)
Copy link
Member

Choose a reason for hiding this comment

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

So this is (one of?) the contentious parts: we (@fieker and me) don't think this is really better (in practical applications) than a function returning a constant, and that of course is mostly useless. So we'd favor an error indicating "not implemented".

Actually, to make it stronger: we require this to merge the PR. However, of course if we run into actual problems caused by this, we can revisit the situation.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed in 722eccf.

I still think this is a bad idea and could potentially render Oscar useless for some users that rely on some julia Base functionality that uses hashing. I would prefer to return 0 or some constant and give a warning (that in the best case should make CI fail) instead. Then, some user can still use Oscar types for their use-case, although it may be very inefficient in those cases.

But if this is what you want, let's go with it.

Copy link
Member

@fingolfin fingolfin left a comment

Choose a reason for hiding this comment

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

Let's merge this if tests pass now

@fingolfin fingolfin dismissed fieker’s stale review June 26, 2023 08:13

Talked with Claus it is OK

@fingolfin fingolfin closed this Jun 26, 2023
@fingolfin fingolfin reopened this Jun 26, 2023
@fingolfin fingolfin merged commit 4f262f5 into oscar-system:master Jul 5, 2023
@lgoettgens lgoettgens deleted the lg/hash branch July 5, 2023 10:24
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.

ToricVarieties: Add Base.hash
6 participants