Skip to content

Make the element hash agree with operator== - #1104

Open
jhale wants to merge 1 commit into
mainfrom
jhale/deterministic-element-hash
Open

jhale wants to merge 1 commit into
mainfrom
jhale/deterministic-element-hash

Conversation

@jhale

@jhale jhale commented Oct 18, 2026

Copy link
Copy Markdown
Member

FFCx stores each element's hash() in the generated ufcx_form, and DOLFINx compares it with the elements it is given at run time (form_factory.h, expression_evaluate.h). Two different elements with the same hash get past that check, and two equal elements with different hashes fail it. hash() had both problems.

Different dof orderings could collide. Only positions where dof_ordering[i] != i were hashed, and only through the offset dof_ordering[i] - i. So [1, 0, 2, 3] and [0, 1, 3, 2] on a quadrilateral both hashed the offsets +1, −1 and collided, although == tells them apart. The ordering is now hashed entry by entry. An identity ordering still hashes like no ordering, as test_hash expects. The duplicated combine_hashes(h, dof_ordering_hash) is gone.

Custom elements: hash and == disagreed. The hash truncated the coefficient matrix to five decimals with int(c * 100000), which is undefined for |c| > ~21474, while == compared coefficients to within 1e-10. Coefficients 1e-11 apart that straddle a 1e-5 boundary were equal but hashed differently. No quantised hash can match a tolerance comparison, so both now use the data that defines a custom element, wcoeffs, x and M, exactly. This is a behaviour change: custom elements built from inputs that differ only by round-off are no longer equal.

discontinuous is now hashed explicitly. It was only covered through the Sobolev space before.

std::hash and combine_hashes are unchanged, so hash values still differ between standard libraries, e.g. MSVC and libstdc++. That's fine, since the hashes that are compared always come from the same platform.

All hash values change, so this belongs in a minor release. Kernels generated with older hashes fail DOLFINx's check with an error rather than giving wrong results, and FEniCS/ffcx#926 makes FFCx regenerate cached kernels when the Basix version changes.

The new tests test_hash_dof_ordering, test_hash_discontinuous and test_hash_custom_element cover these cases. The first and last fail on main and pass here. The full Python suite passes locally: 10056 passed, 338 skipped, 23 xfailed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JudYk8UecTQyirGsLsHUN2

Different dof orderings could share a hash, and custom elements were
hashed on truncated coefficients but compared with a tolerance, so equal
elements could hash differently. Hash every dof ordering entry, the
discontinuous flag, and the exact data defining custom elements, and
compare that data exactly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JudYk8UecTQyirGsLsHUN2
@jhale
jhale requested a review from mscroggs October 18, 2026 16:54

This branch has not been deployed

No deployments
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.

1 participant