dmft/hybridization: apply the MC sign once in measure_Gl - #99
Merged
Conversation
hybmatrix::measure_Gl multiplied the Monte Carlo configuration sign into BOTH factors of every contribution: once into M_ji and once into bubble_sign. Each accumulated term therefore carried sign^2 = 1, so the Legendre estimators Gl/Fl ignored the configuration sign entirely, while measure_G (binned tau) and measure_Gw (Matsubara) apply it exactly once via bubble_sign. In any run with <sign> != 1 the Legendre channel accumulates the unweighted average while the other channels accumulate the sign-weighted numerator: the channels are mutually inconsistent and Gl/Fl are biased. Apply the sign once, through bubble_sign, matching measure_G. The tau-wraparound anticommutator flip on bubble_sign is unchanged. Sign-free runs (the common density-density segment case, where sign = 1 throughout) are bit-identical, which is how this survived: MEASURE_legendre also defaults off. Found by the ALPS modernization fork in a systematic estimator audit and confirmed there with a sign-linearity test: a deterministic two-operator-pair hybridization matrix built through the production insert path must satisfy measure(sign=-1) == -measure(sign=+1) elementwise for all of G/F/Gl/Fl. Before this change Gl/Fl return identical values for sign = +1 and sign = -1 (G/F already pass); after it all four channels are exactly sign-antisymmetric. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
egull
approved these changes
Jul 20, 2026
egull
left a comment
Contributor
There was a problem hiding this comment.
Looks good. Likely hard to test in a 'real world' scenario since the typical cases we use for this code are sign-free.
Ooolab
approved these changes
Jul 22, 2026
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.
Problem
hybmatrix::measure_Glmultiplies the Monte Carlo configuration sign into both factors of every contribution: once intoM_jiand once intobubble_sign:Each accumulated term therefore carries sign² = 1, so the Legendre estimators
Gl/Flignore the configuration sign entirely — whilemeasure_G(binned τ) andmeasure_Gw(Matsubara) apply it exactly once viabubble_sign. In any run with ⟨sign⟩ ≠ 1 the Legendre channel accumulates the unweighted average while the other channels accumulate the sign-weighted numerator: the channels are mutually inconsistent andGl/Flare biased.Fix
One line: drop the sign from
M_ji, so it enters exactly once throughbubble_sign, matchingmeasure_G/measure_Gw. The τ-wraparound anticommutator flip onbubble_signis unchanged.Sign-free runs (the common density-density segment case, where sign = 1 throughout) are bit-identical — which is how this survived;
MEASURE_legendrealso defaults off.How to verify
There is deliberately no runtime reproducer in this PR: exercising the bug end-to-end needs a model with ⟨sign⟩ ≠ 1 and
MEASURE_legendre=1, and there is no signful reference result in-tree to compare against. The bug is instead verifiable by inspection in under a minute at the quoted lines ofmeasure_Gl:M_jicarriessign,bubble_signcarriessignagain, and every accumulated term isM_ji * legendre_p * bubble_sign— so the configuration sign enters squared and cancels identically, whilemeasure_G/measure_Gwin the same file apply it exactly once viabubble_sign. Equivalently: flip the sign ofsignat the call site and observe thatGl/Flare unchanged whileG/Gwnegate.The downstream fork pins the fix with a sign-linearity test: a deterministic two-operator-pair hybridization matrix built through the production insert path must satisfy
measure(sign=−1) == −measure(sign=+1)elementwise for all of G/F/Gl/Fl. Before the change Gl/Fl return identical values for both signs (G/F already pass); after it all four channels are exactly sign-antisymmetric. (That test rig depends on fork-side scaffolding and is not ported here; happy to port it if wanted.) The solver builds cleanly with the change on current master (73b331006).Provenance
Found in a systematic estimator audit in a downstream ALPS modernization fork; the fix is identical there and covered by the sign-linearity lock described above.