#pragma once // Copyright (c) 2024-2026 Tarik Moussa. // SPDX-License-Identifier: MIT // Ported from de.varylab.discreteconformal.util.DiscreteEllipticUtility (Java). // Only the pure-math subset (no HDS required). #include #include namespace conformallab { // Move tau into the fundamental domain of the modular group SL(2,Z): // |Re(tau)| <= 0.5, Im(tau) >= 0, Re(tau) >= 0, |tau| >= 1 // // Algorithm: iteratively apply // 1. T-shift: Re > 0.5 or Re < 0 → Re -= sign(Re) // 2. Im-flip: Im < 0 → Im = -Im // 3. Re-flip: Re < 0 → Re = -Re // 4. S-invert: |tau| < 1 → tau = 1/tau // /// Normalise a complex modulus `τ` into the standard fundamental /// domain of an elliptic curve (`|τ| ≥ 1`, `0 ≤ Re τ ≤ ½`, `Im τ ≥ 0`). /// Same as Java `DiscreteEllipticUtility.normalizeModulus(Complex)`. inline std::complex normalizeModulus(std::complex tau) { int maxIter = 100; while (--maxIter > 0) { double re = tau.real(); double im = tau.imag(); // exit when all conditions satisfied if (std::abs(re) <= 0.5 && im >= 0.0 && re >= 0.0 && std::abs(tau) >= 1.0) break; if (std::abs(re) > 0.5) re -= (re > 0.0 ? 1.0 : -1.0); // signum shift if (im < 0.0) im = -im; if (re < 0.0) re = -re; tau = std::complex(re, im); if (std::abs(tau) < 1.0) tau = 1.0 / tau; // S-transformation: invert } return tau; } } // namespace conformallab