From 14946ddb5b1752629b4144c565d245679501719f Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Thu, 11 Jun 2026 01:15:47 -0500 Subject: [PATCH 1/2] qmc/sse: default EPSILON to an ergodic value for sign-problematic models The sse4 worker reads EPSILON (default 0) and floors it to 1e-6 regardless of the Hamiltonian. The per-bond diagonal constant is c(type) = epsilon + max_diag_me(type), so the vertex carrying the maximum diagonal matrix element is inserted with weight c - me = epsilon ~= 1e-6. On a sign-problematic (frustrated / non-bipartite) Hamiltonian this makes the diagonal update effectively non-ergodic: the operator-string sampler freezes, the expansion order is undersampled, and the simulation reports a confidently wrong, seed-dependent energy with small error bars. A 3x3 Heisenberg lattice with periodic boundary conditions gives = -3.39 at beta=1 against the exact thermal average -2.6525 (checked with two independent exact diagonalizations). The constructor already warned about exactly this case ("make sure that EPSILON is ergodic") but proceeded with the non-ergodic floor. The SSE energy estimator is invariant to EPSILON (a constant shift of the diagonal vertex weights), so when EPSILON is unset and the model is signed, default it to the largest diagonal matrix element. That gives the maximum-diagonal vertex an O(1) insertion weight and restores ergodicity, auto-scaling with the model. Sign-free models keep the previous 1e-6 floor bit-identically (they are ergodic at EPSILON=0, and a larger shift would only inflate the expansion order), so existing unfrustrated results are unchanged. An explicit EPSILON still overrides everything, as before. The warning is reworded into a note describing the applied default. Root-caused and fixed in the ALPS modernization fork while chasing wrong SSE energies on periodic 2-D lattices; instrumentation first refuted a bond-counting hypothesis and then identified the frozen diagonal update. Verified there against exact diagonalization on a periodic 3x3 Heisenberg lattice (SSE reproduces the exact within error bars after this change, with no EPSILON set) plus unchanged results on chains and open 2-D/3-D lattices. Co-Authored-By: Claude Fable 5 --- applications/qmc/sse4/model.h | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/applications/qmc/sse4/model.h b/applications/qmc/sse4/model.h index 226225fcc..33918984a 100644 --- a/applications/qmc/sse4/model.h +++ b/applications/qmc/sse4/model.h @@ -80,8 +80,9 @@ class Model { { epsilon = params.value_or_default("EPSILON", 0.0); if (epsilon <= 0.0 && model.is_signed()) - std::cout << "Warning: Hamiltonian has a sign problem and EPSILON=0; " - "make sure that EPSILON is ergodic.\n"; + std::cout << "Note: Hamiltonian has a sign problem and EPSILON is unset; " + "defaulting EPSILON to the largest diagonal matrix element so the " + "diagonal update is ergodic (pass EPSILON explicitly to override).\n"; _nbstates.resize(lattice.max_site_type() + 1); for (unsigned i = 0; i < lattice.nsites(); ++i) { @@ -328,9 +329,32 @@ class Model { if (epsilon == 0.0 && !have_diagonal) throw std::runtime_error("Hamiltonian looks purely off-diagonal. " "Parameter EPSILON has to be non zero for SSE to work."); - - if (epsilon <= 0.0) - epsilon = 1e-6; + + if (epsilon <= 0.0) { + if (model.is_signed()) { + // With EPSILON ~= 0 the maximum-diagonal vertex is left with + // diagonal-insertion weight c - me = epsilon ~= 0 (where + // c(type) = epsilon + _max_diag_me[type]). On a + // sign-problematic (frustrated / non-bipartite) Hamiltonian + // that makes the diagonal update NON-ERGODIC: the worker + // freezes, undersamples the expansion order, and reports a + // confidently-wrong, seed-dependent (e.g. periodic 3x3 + // Heisenberg -> -3.39 vs the exact -2.6525 at beta=1). The + // SSE energy is INVARIANT to EPSILON (it is a constant shift + // of the operator string), so default it to the largest + // diagonal matrix element, giving that vertex an O(1) + // weight. Pass EPSILON explicitly to override. Sign-free + // models are ergodic at EPSILON=0, so keep the tiny shift + // there to avoid needlessly inflating the expansion order. + double ergodic = 1e-6; + for (std::vector::const_iterator it = _max_diag_me.begin(); + it != _max_diag_me.end(); ++it) + if (*it > ergodic) ergodic = *it; + epsilon = ergodic; + } else { + epsilon = 1e-6; + } + } std::set::const_iterator sti = site_types.begin(); for (; sti != site_types.end(); ++sti) From f280192b2330f3040dfe84452843474310681694 Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Wed, 22 Jul 2026 17:45:33 -0500 Subject: [PATCH 2/2] qmc/sse: apply signed epsilon default before fallback --- applications/qmc/sse4/model.h | 46 ++++++++++------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/applications/qmc/sse4/model.h b/applications/qmc/sse4/model.h index 85ce5f080..17f8aecc8 100644 --- a/applications/qmc/sse4/model.h +++ b/applications/qmc/sse4/model.h @@ -90,19 +90,6 @@ class Model { _lowering_matrix_elements.resize(lattice.max_site_type() + 1); construct_vertices(); - - if (epsilon <= 0.0 && model.is_signed()) { - epsilon = *std::max_element( - _max_diag_me.begin(), - _max_diag_me.end() - ); - - std::cout - << "Warning: Hamiltonian has a sign problem and EPSILON<=0.\n" - << "Automatically setting EPSILON = " - << epsilon - << " (largest diagonal matrix element).\n"; - } } std::vector const& nbstates() const @@ -289,8 +276,7 @@ class Model { unsigned nneighbors0 = lattice.nneighbors(sites[0]); unsigned nneighbors1 = lattice.nneighbors(sites[1]); - // _max_diag_me[i] = std::numeric_limits::min(); - _max_diag_me[i] = std::numeric_limits::lowest(); + _max_diag_me[i] = std::numeric_limits::lowest(); for (unsigned l = 0; l < nstates[i]; ++l) { vertex_type vertex; @@ -339,28 +325,22 @@ class Model { if (epsilon == 0.0 && !have_diagonal) throw std::runtime_error("Hamiltonian looks purely off-diagonal. " "Parameter EPSILON has to be non zero for SSE to work."); - if (epsilon <= 0.0) { if (model.is_signed()) { - // With EPSILON ~= 0 the maximum-diagonal vertex is left with - // diagonal-insertion weight c - me = epsilon ~= 0 (where - // c(type) = epsilon + _max_diag_me[type]). On a - // sign-problematic (frustrated / non-bipartite) Hamiltonian - // that makes the diagonal update NON-ERGODIC: the worker - // freezes, undersamples the expansion order, and reports a - // confidently-wrong, seed-dependent (e.g. periodic 3x3 - // Heisenberg -> -3.39 vs the exact -2.6525 at beta=1). The - // SSE energy is INVARIANT to EPSILON (it is a constant shift - // of the operator string), so default it to the largest - // diagonal matrix element, giving that vertex an O(1) - // weight. Pass EPSILON explicitly to override. Sign-free - // models are ergodic at EPSILON=0, so keep the tiny shift - // there to avoid needlessly inflating the expansion order. - double ergodic = 1e-6; + // A tiny EPSILON can make the diagonal update effectively + // non-ergodic for signed models. Use the largest positive + // diagonal matrix element once those elements are known. + epsilon = 1e-6; for (std::vector::const_iterator it = _max_diag_me.begin(); it != _max_diag_me.end(); ++it) - if (*it > ergodic) ergodic = *it; - epsilon = ergodic; + if (*it > epsilon) + epsilon = *it; + + std::cout + << "Warning: Hamiltonian has a sign problem and EPSILON<=0.\n" + << "Automatically setting EPSILON = " << epsilon + << " (largest positive diagonal matrix element, with a " + "1e-6 minimum).\n"; } else { epsilon = 1e-6; }