24const double kPi = 3.14159265358979323846;
31void setReason(std::string *reason,
const char *message)
33 if (reason) *reason = message;
40bool finite(
double v)
noexcept
42 return std::isfinite(v);
48 std::vector<const PotentialObject2D *>
objects;
55double stdDev(
const std::vector<double> &values)
57 if (values.empty())
return 0.0;
59 for (
double v : values) mean += v;
60 mean /=
static_cast<double>(values.size());
62 for (
double v : values) {
63 const double d = v - mean;
66 return std::sqrt(var /
static_cast<double>(values.size()));
77 setReason(reason,
"QuantumAnderson2D: initial-state values must be finite");
80 if (!(config.
sigma > 0.0)) {
81 setReason(reason,
"QuantumAnderson2D: sigma must be positive");
85 setReason(reason,
"QuantumAnderson2D: the two lanes are too close for a clean comparison");
96 setReason(reason,
"QuantumAnderson2D: field must not be empty");
101 const double inv4Sigma2 = 1.0 / (4.0 * config.
sigma * config.
sigma);
103 const std::complex<double> disorderPhase(std::cos(phase), std::sin(phase));
105 for (std::size_t y = 0; y < field.
height(); ++y) {
107 for (std::size_t x = 0; x < field.
width(); ++x) {
109 const double dx = px - config.
centerX;
110 const double dyClean = py - config.
cleanLaneY;
112 const double a = std::exp(-(dx * dx + dyClean * dyClean) * inv4Sigma2);
113 const double b = std::exp(-(dx * dx + dyDisorder * dyDisorder) * inv4Sigma2);
114 const std::complex<double> value = std::complex<double>(a, 0.0) + disorderPhase * b;
116 static_cast<float>(value.imag()));
121 setReason(reason,
"QuantumAnderson2D: normalization failed");
132 std::vector<const PotentialObject2D *> gaussians;
134 if (!
object.enabled)
continue;
136 setReason(reason,
"QuantumAnderson2D: guided comparison expects Gaussian lattice sites only");
139 gaussians.push_back(&
object);
141 if (gaussians.size() < 14u || (gaussians.size() % 2u) != 0u) {
142 setReason(reason,
"QuantumAnderson2D: two equal Gaussian rows are required");
148 if (a->centerY != b->centerY) return a->centerY < b->centerY;
149 return a->centerX < b->centerX;
152 const double yLow = gaussians.front()->centerY;
153 const double yHigh = gaussians.back()->centerY;
154 if (std::abs(yHigh - yLow) < 1.0e-6) {
155 setReason(reason,
"QuantumAnderson2D: two distinct lattice rows were not found");
159 Row low; low.y = yLow;
160 Row high; high.y = yHigh;
162 if (std::abs(object->centerY - yLow) < 1.0e-5) low.objects.push_back(
object);
163 else if (std::abs(object->centerY - yHigh) < 1.0e-5) high.objects.push_back(
object);
165 setReason(reason,
"QuantumAnderson2D: more than two Gaussian rows were found");
169 if (low.objects.size() != high.objects.size() || low.objects.size() < 7u) {
170 setReason(reason,
"QuantumAnderson2D: lattice rows must contain the same number of sites");
174 auto sortX = [](Row &row) {
177 return a->centerX < b->centerX;
180 sortX(low); sortX(high);
182 const double spacing = low.objects[1]->centerX - low.objects[0]->centerX;
183 if (!(spacing > 0.0)) {
184 setReason(reason,
"QuantumAnderson2D: invalid lattice spacing");
188 std::vector<double> lowDepths;
189 std::vector<double> highDepths;
190 for (std::size_t i = 0; i < low.objects.size(); ++i) {
194 std::abs((a.
centerX - low.objects[0]->centerX) -
static_cast<double>(i) * spacing) > 2.0e-3 ||
195 std::abs((b.
centerX - high.objects[0]->centerX) -
static_cast<double>(i) * spacing) > 2.0e-3) {
196 setReason(reason,
"QuantumAnderson2D: the two rows do not share one regular lattice");
200 setReason(reason,
"QuantumAnderson2D: Gaussian site widths must be positive");
203 lowDepths.push_back(
static_cast<double>(a.
value));
204 highDepths.push_back(
static_cast<double>(b.
value));
207 const double lowStd = stdDev(lowDepths);
208 const double highStd = stdDev(highDepths);
209 const Row *clean = lowStd <= highStd ? &low : &high;
210 const Row *disorder = lowStd <= highStd ? &high : &low;
211 const std::vector<double> &cleanDepths = lowStd <= highStd ? lowDepths : highDepths;
212 const std::vector<double> &disorderDepths = lowStd <= highStd ? highDepths : lowDepths;
214 double cleanMean = 0.0, disorderMean = 0.0;
215 for (
double v : cleanDepths) cleanMean += v;
216 for (
double v : disorderDepths) disorderMean += v;
217 cleanMean /=
static_cast<double>(cleanDepths.size());
218 disorderMean /=
static_cast<double>(disorderDepths.size());
220 if (stdDev(cleanDepths) > 1.0e-3 || stdDev(disorderDepths) < 1.0e-2) {
221 setReason(reason,
"QuantumAnderson2D: one uniform row and one disordered row are required");
225 lattice.
valid =
true;
229 lattice.
siteSigmaX = clean->objects.front()->sigmaX;
230 lattice.
siteSigmaY = clean->objects.front()->sigmaY;
236 lattice.
siteX.reserve(clean->objects.size());
247 if (field.
empty() || !lattice.
valid || lattice.
siteX.empty())
return out;
251 const double cellArea =
static_cast<double>(field.
dx()) *
static_cast<double>(field.
dy());
256 for (std::size_t y = 0; y < field.
height(); ++y) {
258 const bool above = py >= splitY;
259 if ((cleanLane && above != cleanAbove) || (!cleanLane && above == cleanAbove))
continue;
260 for (std::size_t x = 0; x < field.
width(); ++x) {
262 const double p = (
static_cast<double>(v.real()) * v.real() +
263 static_cast<double>(v.imag()) * v.imag()) * cellArea;
265 out.
marginalX[x] +=
static_cast<float>(p /
static_cast<double>(field.
dx()));
270 double weightedX = 0.0;
271 for (std::size_t x = 0; x < field.
width(); ++x) {
273 weightedX +=
static_cast<double>(out.
marginalX[x]) *
static_cast<double>(field.
dx()) * px;
278 double variance = 0.0;
279 for (std::size_t x = 0; x < field.
width(); ++x) {
281 const double p =
static_cast<double>(out.
marginalX[x]) *
static_cast<double>(field.
dx());
282 const double d = px - out.
meanX;
283 variance += p * d * d;
285 out.
sigmaX = std::sqrt(std::max(0.0, variance));
287 std::vector<double> siteProbabilities(lattice.
siteX.size(), 0.0);
288 const double halfCell = 0.5 * lattice.
spacing;
289 for (std::size_t x = 0; x < field.
width(); ++x) {
291 std::size_t nearest = 0u;
292 double best = std::numeric_limits<double>::max();
293 for (std::size_t i = 0; i < lattice.
siteX.size(); ++i) {
294 const double d = std::abs(px - lattice.
siteX[i]);
295 if (d < best) { best = d; nearest = i; }
297 if (best <= halfCell) {
298 siteProbabilities[nearest] +=
static_cast<double>(out.
marginalX[x]) *
static_cast<double>(field.
dx());
301 double sumSquares = 0.0;
302 for (
double p : siteProbabilities) sumSquares += p * p;
307 double sx = 0.0, sy = 0.0, sxx = 0.0, sxy = 0.0;
309 const double centreX = lattice.
siteX[lattice.
siteX.size() / 2u];
310 for (std::size_t i = 0; i < siteProbabilities.size(); ++i) {
311 const double r = std::abs(lattice.
siteX[i] - centreX);
312 const double p = siteProbabilities[i];
313 if (r < 0.75 * lattice.
spacing || p < 1.0e-5)
continue;
314 const double yy = std::log(p);
315 sx += r; sy += yy; sxx += r * r; sxy += r * yy; ++count;
317 const double denom =
static_cast<double>(count) * sxx - sx * sx;
318 if (count >= 4 && std::abs(denom) > 1.0e-12) {
319 const double slope = (
static_cast<double>(count) * sxy - sx * sy) / denom;
320 if (slope < -1.0e-6) {
330 double mass,
double hbar)
noexcept
332 if (!(sigma0 > 0.0) || !(mass > 0.0) || !(hbar > 0.0) || !finite(time))
return 0.0;
333 const double q = hbar * time / (2.0 * mass * sigma0 * sigma0);
334 return sigma0 * std::sqrt(1.0 + q * q);
338 : maxSamples_(std::max<std::size_t>(2u, maxSamples))
370 sample.norm = sample.clean.probability + sample.disorder.probability;
Owning Cartesian grid of complex scalar samples.
bool empty() const noexcept
Returns whether the field contains no samples.
float dx() const noexcept
Returns the X grid spacing.
std::size_t height() const noexcept
Returns the number of samples along Y.
bool normalize() noexcept
Scales the field to unit discrete probability norm.
std::complex< float > Value
float dy() const noexcept
Returns the Y grid spacing.
std::size_t width() const noexcept
Returns the number of samples along X.
static double yCoordinate(const ComplexField2D &field, std::size_t y) noexcept
Performs y coordinate.
static double xCoordinate(const ComplexField2D &field, std::size_t x) noexcept
Performs x coordinate.
Implements the Potential Scene2D component.
const std::vector< PotentialObject2D > & objects() const noexcept
Performs objects.
static QuantumAndersonLaneSample2D measureLane(const ComplexField2D &field, const QuantumAndersonLattice2D &lattice, bool cleanLane)
Measures lane.
static double freeGaussianSigma(double time, double sigma0, double mass, double hbar) noexcept
Performs free gaussian sigma.
static bool initializeDualLane(ComplexField2D &field, const QuantumAndersonInitialState2DConfig &config, std::string *reason=nullptr)
Initializes dual lane.
static bool identifyLattice(const PotentialScene2D &scene, QuantumAndersonLattice2D &lattice, std::string *reason=nullptr)
Returns identify lattice.
static bool validateConfig(const QuantumAndersonInitialState2DConfig &config, std::string *reason=nullptr)
Validates config.
void append(double time, const ComplexField2D &field)
Performs append.
QuantumAndersonInitialState2DConfig config_
void trim()
Performs trim.
QuantumAndersonLattice2D lattice_
const QuantumAndersonInitialState2DConfig & config() const noexcept
Returns config.
const QuantumAndersonLattice2D & lattice() const noexcept
Performs lattice.
QuantumAndersonHistory2D(std::size_t maxSamples=1200u)
Performs quantum anderson history2 d.
void clear()
Performs clear.
void configure(const QuantumAndersonInitialState2DConfig &config, const QuantumAndersonLattice2D &lattice)
Returns configure.
const std::vector< QuantumAndersonSample2D > & samples() const noexcept
Samples s.
std::vector< QuantumAndersonSample2D > samples_
bool configured() const noexcept
Returns configured.
bool empty() const noexcept
Performs empty.
Declares the gaussianpacket2d physics/numerical component used by QPE experiments.
void setReason(std::string *reason, const char *message)
Sets reason.
double stdDev(const std::vector< double > &values)
Performs std dev.
Declares the quantumanderson2d physics/numerical component used by QPE experiments.
Data structure used by the Potential Object2D component.
Configuration values for Quantum Anderson Initial State2D Config.
double relativePhaseDegrees
Data structure used by the Quantum Anderson Lane Sample2D component.
bool localizationLengthValid
double localizationLength
double centralSiteProbability
std::vector< float > marginalX
Data structure used by the Quantum Anderson Lattice2D component.
std::vector< double > siteX
std::vector< double > disorderDepths
double disorderDepthStdDev
std::vector< double > cleanDepths
Data structure used by the Quantum Anderson Sample2D component.
std::vector< const PotentialObject2D * > objects