Define hash for the remaining spaces - #700
Merged
Merged
Conversation
PR JuliaApproximation#698 fixed PointSpace and DiracSpace, but every other space in this package was in the same position: Space.jl:165 defines == as spacescompatible plus equal domains, while hash fell back to the identity-based default. Equal-valued spaces therefore hashed differently whenever they held a mutable field, or whenever the domains compared equal without being identical objects: julia> u1, u2 = UnionDomain([0..1, 2..3]), UnionDomain([2..3, 0..1]); julia> ConstantSpace(u1) == ConstantSpace(u2) true julia> hash(ConstantSpace(u1)) == hash(ConstantSpace(u2)) false Since == is a conjunction that includes domain(A) == domain(B), hashing the domain always agrees with ==, and this is all that is needed for the spaces that only compare domains: ZeroSpace, ConstantSpace, ContinuousSpace and SplineSpace. The order of a SplineSpace is part of the type, and it is mixed in so that splines of different orders over the same domain don't collide. The remaining spaces additionally hash whatever spacescompatible compares: the components for SumSpace, PiecewiseSpace, ArraySpace and TensorSpace, the space and the indices for SubSpace, and the underlying space for QuotientSpace, whose boundary conditions are not compared by == either. Two direct sums may hold their pieces in different containers and still be equal, so their components are hashed one at a time instead of hashing the container. Base hashes a range through its length, which it can't do for the infinite ranges that SubSpace often uses, so these are hashed through their first index and step instead. PiecewiseSegment overrides == to compare points, so it needs a matching hash as well; ContinuousSpace and SplineSpace hash it as their domain. Spaces that compare their domains do so with domainscompatible, which uses isapprox, so == is not transitive for them and no hash function can respect it exactly. Hashing the domain reproduces == for exactly equal domains, which is the case that matters for a Dict or a Set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ay3nR9CQtrrZj3r5LFu59c
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ay3nR9CQtrrZj3r5LFu59c
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #700 +/- ##
==========================================
- Coverage 75.20% 74.39% -0.81%
==========================================
Files 79 81 +2
Lines 8445 8659 +214
==========================================
+ Hits 6351 6442 +91
- Misses 2094 2217 +123 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #698, which defined
hashforPointSpaceandDiracSpace. Every other space in this package was in the same position:Space.jl:165defines==asspacescompatibleplus equal domains, whilehashfell back to the identity-based default, so equal-valued spaces hashed differently whenever they held a mutable field, or whenever their domains compared equal without being identical objects.Since
==is a conjunction that includesdomain(A) == domain(B), hashing the domain always agrees with==, and this is all that is needed for the spaces that only compare domains:ZeroSpace,ConstantSpace,ContinuousSpaceandSplineSpace(whose order is mixed in, so that splines of different orders over the same domain don't collide). The others additionally hash whateverspacescompatiblecompares:ZeroSpace,ConstantSpace,ContinuousSpace,SplineSpace{λ}λ)SumSpace,PiecewiseSpace,ArraySpace,TensorSpaceSubSpaceQuotientSpace==eitherPiecewiseSegmentTwo direct sums may hold their pieces in different containers and still be equal (#574), so their components are hashed one at a time rather than hashing the container. Base hashes a range through its length, which it can't do for the infinite ranges that
SubSpaceoften uses, so those are hashed through their first index and step instead.PiecewiseSegmentis a domain rather than a space, but it overrides==to compare points and has the same missinghash;ContinuousSpaceandSplineSpacehash it as their domain.Two things deliberately left out:
domainscompatible, which usesisapprox.==is therefore not transitive for them and no hash can respect it exactly. Hashing the domain reproduces==for exactly equal domains, which is the case that matters for aDictor aSet.FunandSegmenthave the same mismatch (Funcompares coefficients and space,Segmentcompares endpoints across types), andProductSpace/PathologicalQuotientSpacedefine nospacescompatibleat all, so==errors for them. These seem worth separate PRs.The version bump is a separate commit, in case you'd rather batch it.
Tests: the full suite passes locally, with a new
hashtestset intest/SpacesTest.jlcovering each type above.🤖 Generated with Claude Code
https://claude.ai/code/session_01Ay3nR9CQtrrZj3r5LFu59c