Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
ramseyinterferometry2d_tests.cpp
Go to the documentation of this file.
1/**
2 * @file ramseyinterferometry2d_tests.cpp
3 * @brief Implements regression and invariant tests for ramseyinterferometry2d tests.
4 * @ingroup qpe_tests
5 *
6 * Source: @c tests/ramseyinterferometry2d_tests.cpp. This file is part of Quantum Phenomena Explorer (QPE),
7 * maintained by Officina Turini. See LICENSE_IT.txt / LICENSE.txt for the
8 * QPE freeware source-available terms and THIRD_PARTY_NOTICES.txt for
9 * third-party components.
10 */
11
13
17
18#include <algorithm>
19#include <cmath>
20
21namespace qpe {
22namespace tests {
23
24/**
25 * @brief Runs ramsey interferometry2 d tests.
26 * @param errorMessage The error message value used by the operation.
27 */
28bool runRamseyInterferometry2DTests(std::string &errorMessage)
29{
30 errorMessage.clear();
31
32 // A compact synthetic two-state spectrum is enough to test the Ramsey
33 // reference model. The full 2D split-step validation is kept separate.
34 BoundStateSpectrum1D spectrum;
35 spectrum.valid = true;
36 spectrum.dx = 0.1;
37 spectrum.x.resize(81u);
38 for (std::size_t i = 0; i < spectrum.x.size(); ++i) {
39 spectrum.x[i] = (static_cast<double>(i) - 40.0) * spectrum.dx;
40 }
41
42 BoundState1D ground;
43 BoundState1D excited;
44 ground.energy = 0.2;
45 excited.energy = 0.5;
46 ground.amplitude.resize(spectrum.x.size(), 0.0);
47 excited.amplitude.resize(spectrum.x.size(), 0.0);
48 for (std::size_t i = 0; i < spectrum.x.size(); ++i) {
49 const double x = spectrum.x[i];
50 ground.amplitude[i] = std::exp(-0.5 * x * x);
51 excited.amplitude[i] = x * std::exp(-0.5 * x * x);
52 }
53 auto normalize = [&spectrum](std::vector<float> &v) {
54 double n = 0.0;
55 for (float q : v) n += q * q * spectrum.dx;
56 n = std::sqrt(n);
57 for (float &q : v) q = static_cast<float>(static_cast<double>(q) / n);
58 };
59 normalize(ground.amplitude);
60 normalize(excited.amplitude);
61 spectrum.states.push_back(ground);
62 spectrum.states.push_back(excited);
63
65 sequence.enabled = true;
66 sequence.targetObjectId = 1;
68 sequence.meanValue = 0.0;
69 sequence.amplitude = 0.10;
70 sequence.angularFrequency = 0.30;
71 sequence.startTime = 0.0;
72 sequence.pulseDuration = 12.0;
73 sequence.freeEvolutionDuration = 5.0;
74 sequence.firstPulsePhaseDegrees = 0.0;
75 sequence.secondPulsePhaseDegrees = 0.0;
76
77 const RamseyTheory2D theory = RamseyInterferometry2D::analyze(spectrum, sequence, 0, 1, 1.0);
78 if (!theory.valid || std::abs(theory.transitionAngularFrequency - 0.30) > 1.0e-12 ||
79 !(std::abs(theory.couplingMatrixElementX) > 0.1) ||
80 !(theory.idealPiOver2Duration > 0.0) ||
81 std::abs((theory.predictedFinalPopulationA + theory.predictedFinalPopulationB) - 1.0) > 2.0e-4) {
82 errorMessage = "Ramsey theory analysis is inconsistent";
83 return false;
84 }
85
86 const std::vector<RamseyFringeSample2D> fringe =
87 RamseyInterferometry2D::scanFreeEvolution(spectrum, sequence, 0.0, 30.0, 61, 0, 1, 1.0);
88 if (fringe.size() != 61u) {
89 errorMessage = "Ramsey fringe scan has wrong sample count";
90 return false;
91 }
92 double minP2 = 1.0;
93 double maxP2 = 0.0;
94 for (const RamseyFringeSample2D &sample : fringe) {
95 minP2 = std::min(minP2, sample.populationB);
96 maxP2 = std::max(maxP2, sample.populationB);
97 if (sample.populationA < -1.0e-8 || sample.populationB < -1.0e-8 ||
98 sample.populationA > 1.0001 || sample.populationB > 1.0001) {
99 errorMessage = "Ramsey fringe population is out of range";
100 return false;
101 }
102 }
103 if (!(maxP2 - minP2 > 0.20)) {
104 errorMessage = "Ramsey fringe contrast is unexpectedly small";
105 return false;
106 }
107
108 // Step 27: a calibrated central pi pulse should strongly reduce the
109 // sensitivity to free-evolution time in the same two-level reference.
110 RamseyPulseSequence2DConfig echo = sequence;
111 echo.echoEnabled = true;
112 echo.echoPulseDuration = 2.0 * sequence.pulseDuration;
113 echo.echoPulsePhaseDegrees = 90.0;
114 const RamseyTheory2D echoTheory = RamseyInterferometry2D::analyze(spectrum, echo, 0, 1, 1.0);
115 if (!echoTheory.valid || !echoTheory.echoEnabled ||
116 !(echoTheory.echoPulseEnd > echoTheory.echoPulseStart)) {
117 errorMessage = "Hahn-echo theory timing is invalid";
118 return false;
119 }
120 const std::vector<RamseyFringeSample2D> echoFringe =
121 RamseyInterferometry2D::scanFreeEvolution(spectrum, echo, 0.0, 30.0, 61, 0, 1, 1.0);
122 if (echoFringe.size() != 61u) {
123 errorMessage = "Hahn-echo fringe scan has wrong sample count";
124 return false;
125 }
126
127 // Step 28: the static-detuning ensemble is diagnostic only. Its mean
128 // probabilities must remain normalized, and sigma=0 must collapse to the
129 // nominal two-level prediction within the ensemble integration tolerance.
130 RamseyEnsemble2DConfig ensemble;
131 ensemble.enabled = true;
132 ensemble.detuningStdDev = 0.06;
133 ensemble.memberCount = 41;
135 errorMessage = "valid Ramsey ensemble config was rejected";
136 return false;
137 }
138 const RamseyEnsembleResult2D ensembleResult =
140 spectrum, sequence, ensemble, 0, 1, 1.0);
141 if (!ensembleResult.valid || ensembleResult.memberCount != 41 ||
142 std::abs((ensembleResult.meanPopulationA + ensembleResult.meanPopulationB) - 1.0) > 3.0e-4 ||
143 ensembleResult.meanPopulationA < -1.0e-8 || ensembleResult.meanPopulationB < -1.0e-8 ||
144 ensembleResult.meanPopulationA > 1.0001 || ensembleResult.meanPopulationB > 1.0001) {
145 errorMessage = "Ramsey static-detuning ensemble result is inconsistent";
146 return false;
147 }
148 const std::vector<RamseyEnsembleFringeSample2D> ensembleFringe =
150 spectrum, sequence, ensemble, 0.0, 30.0, 61, 0, 1, 1.0);
151 if (ensembleFringe.size() != 61u) {
152 errorMessage = "Ramsey ensemble fringe scan has wrong sample count";
153 return false;
154 }
155 for (const RamseyEnsembleFringeSample2D &sample : ensembleFringe) {
156 if (sample.meanPopulationA < -1.0e-8 || sample.meanPopulationB < -1.0e-8 ||
157 sample.meanPopulationA > 1.0001 || sample.meanPopulationB > 1.0001 ||
158 std::abs((sample.meanPopulationA + sample.meanPopulationB) - 1.0) > 3.0e-4) {
159 errorMessage = "Ramsey ensemble fringe population is inconsistent";
160 return false;
161 }
162 }
163
164 RamseyEnsemble2DConfig zeroWidth = ensemble;
165 zeroWidth.detuningStdDev = 0.0;
166 const RamseyEnsembleResult2D zeroWidthResult =
168 spectrum, sequence, zeroWidth, 0, 1, 1.0);
169 if (!zeroWidthResult.valid || zeroWidthResult.memberCount != 1 ||
170 std::abs(zeroWidthResult.meanPopulationA - theory.predictedFinalPopulationA) > 2.0e-3 ||
171 std::abs(zeroWidthResult.meanPopulationB - theory.predictedFinalPopulationB) > 2.0e-3) {
172 errorMessage = "zero-width Ramsey ensemble does not reduce to the nominal system";
173 return false;
174 }
175
176 RamseyEnsemble2DConfig invalidEnsemble = ensemble;
177 invalidEnsemble.memberCount = 2;
179 errorMessage = "invalid Ramsey ensemble config was accepted";
180 return false;
181 }
182
183 return true;
184}
185
186} // namespace tests
187} // namespace qpe
Declares the boundstates1d physics/numerical component used by QPE experiments.
static bool validateEnsembleConfig(const RamseyEnsemble2DConfig &config) noexcept
Validates ensemble config.
static RamseyTheory2D analyze(const BoundStateSpectrum1D &spectrum, const RamseyPulseSequence2DConfig &sequence, int stateA=0, int stateB=1, double hbar=1.0) noexcept
Performs analyze.
static RamseyEnsembleResult2D analyzeStaticDetuningEnsemble(const BoundStateSpectrum1D &spectrum, const RamseyPulseSequence2DConfig &sequence, const RamseyEnsemble2DConfig &ensemble, int stateA=0, int stateB=1, double hbar=1.0)
Performs analyze static detuning ensemble.
static std::vector< RamseyFringeSample2D > scanFreeEvolution(const BoundStateSpectrum1D &spectrum, const RamseyPulseSequence2DConfig &sequence, double minimumFreeTime, double maximumFreeTime, int sampleCount, int stateA=0, int stateB=1, double hbar=1.0)
Performs scan free evolution.
static std::vector< RamseyEnsembleFringeSample2D > scanFreeEvolutionEnsemble(const BoundStateSpectrum1D &spectrum, const RamseyPulseSequence2DConfig &sequence, const RamseyEnsemble2DConfig &ensemble, double minimumFreeTime, double maximumFreeTime, int sampleCount, int stateA=0, int stateB=1, double hbar=1.0)
Performs scan free evolution ensemble.
bool runRamseyInterferometry2DTests(std::string &errorMessage)
Runs ramsey interferometry2 d tests.
Declares the ramseyinterferometry2d physics/numerical component used by QPE experiments.
Declares regression and invariant tests for ramseyinterferometry2d tests.
Data structure used by the Bound State1D component.
std::vector< float > amplitude
Data structure used by the Bound State Spectrum1D component.
std::vector< double > x
std::vector< BoundState1D > states
Configuration values for Ramsey Ensemble2D Config.
Data structure used by the Ramsey Ensemble Fringe Sample2D component.
Data structure used by the Ramsey Ensemble Result2D component.
Data structure used by the Ramsey Fringe Sample2D component.
Configuration values for Ramsey Pulse Sequence2D Config.
Data structure used by the Ramsey Theory2D component.
Declares the timedependentpotential2d physics/numerical component used by QPE experiments.