Skip to content

Commit 5fb4edb

Browse files
committed
sign-canonicalize dlr and if frequencies for determinsitic grid selection
1 parent f6bd6ab commit 5fb4edb

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

c++/cppdlr/dlr_build.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "dlr_build.hpp"
1818
#include "utils.hpp"
1919
#include "dlr_kernels.hpp"
20+
#include <algorithm>
2021
#include <numbers>
2122

2223
using namespace std;
@@ -280,6 +281,14 @@ namespace cppdlr {
280281
auto omega = nda::vector<double>(r);
281282
for (int i = 0; i < r; ++i) { omega(i) = om(piv(i)); }
282283

284+
// Sign-canonicalize for deterministic grid selection: orient the grid so that the
285+
// most positive frequency is the one with the largest absolute value.
286+
// This helps with reproducibility across different BLAS backends.
287+
if (std::abs(nda::min_element(omega)) > std::abs(nda::max_element(omega))) {
288+
omega *= -1;
289+
std::ranges::reverse(omega);
290+
}
291+
283292
return omega;
284293
}
285294

c++/cppdlr/dlr_imfreq.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ namespace cppdlr {
3939
// Pivoted Gram-Schmidt to obtain DLR imaginary frequency nodes
4040
auto [q, norms, piv] = (symmetrize ? pivrgs_sym(kmat, niom) : pivrgs(kmat, 1e-100));
4141
std::sort(piv.begin(), piv.end()); // Sort pivots in ascending order
42+
43+
// Sign-canonicalize for deterministic grid selection (see build_dlr_rf): orient the node
44+
// set so its most positive Matsubara frequency has the largest absolute value, flipping
45+
// nu_n -> -nu_n (row p -> max_piv - p) otherwise. No effect on grid quality.
46+
long min_if = nda::min_element(piv) - nmax; // index n of the most negative selected node
47+
long max_if = nda::max_element(piv) - nmax; // index n of the most positive selected node
48+
long nu_off = (statistic == Fermion); // Matsubara frequency is 2n+1 (Fermion) / 2n (Boson)
49+
if (std::abs(2 * max_if + nu_off) < std::abs(2 * min_if + nu_off)) {
50+
int max_piv = static_cast<int>(kmat.extent(0)) - 1; // mirror row of p under nu_n -> -nu_n
51+
for (auto &p : piv) p = max_piv - p; // ascending -> descending,
52+
std::ranges::reverse(piv); // so reverse restores ascending order
53+
}
54+
4255
for (int i = 0; i < niom; ++i) { dlr_if(i) = piv(i) - nmax; }
4356

4457
// Obtain coefficients to imaginary frequency values transformation matrix

0 commit comments

Comments
 (0)