Skip to content

Symmetrization: recover symmetries for same-site orbital swap case - #374

Open
tylersax wants to merge 7 commits into
CompFUSE:masterfrom
tylersax:symm-derive-p
Open

Symmetrization: recover symmetries for same-site orbital swap case#374
tylersax wants to merge 7 commits into
CompFUSE:masterfrom
tylersax:symm-derive-p

Conversation

@tylersax

@tylersax tylersax commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Important

Stacked on #369. This PR will shrink to 1 commit / 171 lines once #369 merges. The only commit to review here is 663769f8

Background: I was running FeAs against the derived-symmetry report we just landed in #369, and it came back with 4 ops vs the expected 8. The solver was rejecting C4, C4^3 and the two diagonal mirrors.

Problem: FeAs's two orbitals (d_xz, d_yz) both sit at a_vec = 0. set_symmetry_matrices builds the band image by transforming r + a_b and looking for an orbital at the image position carrying the same flavor.
Two orbitals on one site make the position test uninformative -- it matches every band equally. The "flavor" breaks the tie, and that pins each band to itself. The band image comes out the identity for every op, unconditionally. solveSignsForOp took the image on faith and solved only the signs. Signs can flip an entry, but they cannot move it to another band. So the solver falsely rejected real symmetries.

The (small) fix: treat the geometric image as a candidate rather than an oracle. solveSignsForOp splits into tryPermutation (same function we had before, returning false where it used to throw) and deriveOrbitalOpForOp, which checks the geometric candidate first and otherwise walks the remaining permutations. Throw only when none of them works.

Result 1: FeAs goes from 4 derived ops to 8, and is added as a characterization fixture to pin the number.

Result 2: A Kagome win falls out of the same change. Kagome labels its three symmetry-equivalent sublattices with distinct flavors, so its matching finds no admissible image at all and records the -1 that #369 added a guard for. Deriving P from H0 does more than dodge the out-of-bounds read -- it recovers the ops geometry could not place, and Kagome goes from 2 derived ops to 12.

tylersax added 7 commits July 15, 2026 08:41
Replace the per-geometry declared point-group files
(2d_square/hexagonal/oblique/rectangular) with a single holohedries_2d.hpp
defining the two 2D holohedries D4 and D6 and the candidate pool they generate.
By the crystallographic restriction every 2D point group is a subgroup of one of
these, so the lower-symmetry groups (rectangular D2, oblique C2, ...) are derived
by the geometry filter rather than declared per model.

- Correct D6 at the source: add the identity and use mirror denominator 12 so all
  six mirror lines survive (the legacy list omitted the identity and used
  denominator 6, collapsing to only three distinct mirrors).
- Delete the now-unused subgroup structs and repoint all D4 consumers to
  holohedries_2d.hpp.
- Migrate the triangular lattice test from C6 to D6 (its actual holohedry) and
  drop C6
- Add a completeness oracle (holohedries_2d_test) asserting that filtering the
  pool by each 2D lattice reproduces its full holohedry (8/12/4/2).
…rgence

deriveAndComparePointGroup installs the 2D holohedry pool as the live
group of a cluster family, gates the geometrically realized ops on H0
invariance, then restores (and verifies) the declared symmetry state.
update_domains runs the check after each family's declared initializer
and prints a rank-0 report only when the derived and declared groups
differ; production symmetrization is unchanged.

3D models and legacy lattices without initializeH0 skip derivation.
Add point_group_symmetry_element::describe(): a short human-readable
label decoded from the op matrix -- Schoenflies name (Cn^k, sigma)
plus geometry (rotation angle, mirror-line angle).

The derive-and-compare report now lists the labeled ops in both
divergence directions (under-declared and unverified) instead of bare
counts, so a report line like "sigma (mirror @ 45 deg)" pinpoints which
symmetry a model's declaration is missing or overclaiming.

Some minor comment cleanup as well
Hats off to Claude for catching this. Since set_symmetry_matrices records (-1, -1) when no
band image is found (i.e. no symmetry gets accepted), there is a possibility that H0 gets
indexed with -1 leading to an out-of-bounds read. (Identified statically, confirmed with
AddressSanitizer). The fix is one more rejection branch on solveSignsForOp. Kagome is the
model that reliably produces this state, so it gets added as a fixture.
Background: I was running FeAs against the derived-symmetry report we
just landed in CompFUSE#369, and it came back with 4 ops vs the expected 8.
The solver was rejecting C4, C4^3 and the two diagonal mirrors.

Problem: FeAs's two orbitals (d_xz, d_yz) both sit at a_vec = 0.
set_symmetry_matrices builds the band image by transforming r + a_b and
looking for an orbital at the image position carrying the same flavor.
Two orbitals on one site make the position test uninformative -- it
matches every band equally. The "flavor" breaks the tie, and that pins
each band to itself. The band image comes out the identity for every op,
unconditionally. solveSignsForOp took the image on faith and solved only
the signs. Signs can flip an entry, but they cannot move it to another
band. So the solver falsely rejected real symmetries.

The (small) fix: treat the geometric image as a candidate rather than an
oracle. solveSignsForOp splits into tryPermutation (same function we had
before, returning false where it used to throw) and
deriveOrbitalOpForOp, which checks the geometric candidate first and
otherwise walks the remaining permutations. Throw only when none of them
works.

Result 1: FeAs goes from 4 derived ops to 8, and is added as a
characterization fixture to pin the number.

Result 2: A Kagome win falls out of the same change. Kagome labels its
three symmetry-equivalent sublattices with distinct flavors, so its
matching finds no admissible image at all and records the -1 that
c401448 added a guard for. Deriving P from H0 does more than dodge the
out-of-bounds read -- it recovers the ops geometry could not place, and
Kagome goes from 2 derived ops to 12.
@tylersax
tylersax marked this pull request as ready for review July 21, 2026 15:37
@PDoakORNL

PDoakORNL commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

I read over your indicated significant commit, looks good to me but lets get this cleaned up so @maierta can also take a look. By which I mean lets get #369 merged so this PR gets reduced to something easy to look at.

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.

2 participants