2#if defined(INCLUDED_BY_FACTORY)
5#define _USE_MATH_DEFINES
11class QCSimExtendedStabilizerSimulator :
public ImmediateQCSimSimulator
14 QCSimExtendedStabilizerSimulator()
16 configuration.SetConfiguration(
"method",
"extended_stabilizer");
19 const char *MethodName()
const override
21 return "extended_stabilizer";
24 void Initialize()
override
29 extendedStabilizer = std::make_unique<Simulators::QCSimExtendedStabilizer>(nrQubits);
32 for (
const auto &[key, value] : configuration.GetConfigMap())
34 Configure(key.c_str(), value.c_str());
40 if (extendedStabilizer)
41 extendedStabilizer->Reset(nrQubits);
42 upcomingGateIndex = 0;
45 void Configure(
const char *key,
const char *value)
override
47 if (std::string(
"method") == key)
49 ValidateMethod(value);
50 configuration.SetConfiguration(key, value);
53 if (!configuration.WasApplied(key, value))
54 configuration.SetConfiguration(key, value);
55 if (std::string(
"seed") == key)
57 const uint64_t seed = std::stoull(value);
58 SeedAuxiliaryRng(seed);
61 if (extendedStabilizer)
62 SeedBackend(extendedStabilizer.get(), seed);
65 if (std::string(key) ==
"pauli_propagator_workers")
67 const auto workers = configuration.GetConfigurationAsUnsigned(key);
69 throw std::invalid_argument(
"pauli_propagator_workers exceeds 1024");
75 if (extendedStabilizer)
77 const size_t oldNrQubits = nrQubits;
78 nrQubits += num_qubits;
84 extendedStabilizer =
nullptr;
86 upcomingGateIndex = 0;
87 upcomingGates.clear();
92 if (qubits.size() >
sizeof(
size_t) * 8)
93 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
94 "number of bits in the size_t type, the outcome will be undefined"
100 for (
size_t qubit : qubits)
102 if (extendedStabilizer->Measure(qubit))
108 NotifyObservers(qubits);
114 std::vector<bool> res(qubits.size(),
false);
117 for (
size_t q = 0; q < qubits.size(); ++q)
118 if (extendedStabilizer->Measure(qubits[q]))
122 NotifyObservers(qubits);
130 for (
size_t qubit : qubits)
131 if (extendedStabilizer->Measure(qubit))
132 extendedStabilizer->ApplyX(qubit);
135 NotifyObservers(qubits);
140 return ExtendedStabilizerBasisProbability(outcome);
145 throw std::runtime_error(
"QCSimState::Amplitude: Amplitudes are not exposed by the extended "
146 "stabilizer simulator.");
151 const size_t nrBasisStates = CheckedBasisStateCountForQueries();
152 std::vector<double> result(nrBasisStates);
153 for (
size_t i = 0; i < nrBasisStates; ++i)
154 result[i] = ExtendedStabilizerBasisProbability(i);
160 std::vector<double> result(qubits.size());
162 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
163 result[i] = ExtendedStabilizerBasisProbability(qubits[i]);
170 if (qubits.empty() || shots == 0)
172 if (qubits.size() >
sizeof(
size_t) * 8)
173 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
174 "number of bits in the size_t type, the outcome will be undefined"
176 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
179 const std::vector<size_t> selected(qubits.begin(), qubits.end());
180 auto sampler = extendedStabilizer->CloneWithSeed(rng());
181 for (
const auto &item : sampler->SampleCounts(selected, shots))
182 result[item.first] += item.second;
185 NotifyObservers(qubits);
191 if (qubits.empty() || shots == 0)
196 const std::vector<size_t> selected(qubits.begin(), qubits.end());
197 auto sampler = extendedStabilizer->CloneWithSeed(rng());
198 for (
const auto &item : sampler->SampleCountsMany(selected, shots))
199 result[item.first] += item.second;
202 NotifyObservers(qubits);
206 double ExpectationValue(
const std::string &pauliStringOrig)
override
208 if (pauliStringOrig.empty())
210 std::string pauliString = pauliStringOrig;
215 const auto pauliOp = toupper(pauliString[i]);
216 if (pauliOp !=
'I' && pauliOp !=
'Z')
221 return extendedStabilizer->ExpectationValue(pauliString);
226 return SimulationType::kExtendedStabilizer;
231 extendedStabilizer->SaveState();
236 extendedStabilizer->RestoreState();
241 enableMultithreading = multithreading;
242 if (extendedStabilizer)
243 extendedStabilizer->SetMultithreading(multithreading);
249 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
250 "number of bits in the Types::qubit_t type, the outcome will be "
254 auto sampler = extendedStabilizer->CloneWithSeed(rng());
256 for (
size_t qubit = 0; qubit < nrQubits; ++qubit)
257 if (sampler->Measure(qubit))
258 result |= 1ULL << qubit;
263 std::vector<bool> MeasureNoCollapseMany()
override
265 auto sampler = extendedStabilizer->CloneWithSeed(rng());
266 std::vector<bool> res(nrQubits);
267 for (
size_t i = 0; i < nrQubits; ++i)
268 res[i] = sampler->Measure(i);
274 extendedStabilizer->ApplyP(qubit, lambda);
275 NotifyObservers({qubit});
280 extendedStabilizer->ApplyX(qubit);
281 NotifyObservers({qubit});
286 extendedStabilizer->ApplyY(qubit);
287 NotifyObservers({qubit});
292 extendedStabilizer->ApplyZ(qubit);
293 NotifyObservers({qubit});
298 extendedStabilizer->ApplyH(qubit);
299 NotifyObservers({qubit});
304 extendedStabilizer->ApplyS(qubit);
305 NotifyObservers({qubit});
310 extendedStabilizer->ApplySDG(qubit);
311 NotifyObservers({qubit});
316 extendedStabilizer->ApplyT(qubit);
317 NotifyObservers({qubit});
322 extendedStabilizer->ApplyTDG(qubit);
323 NotifyObservers({qubit});
328 extendedStabilizer->ApplySX(qubit);
329 NotifyObservers({qubit});
334 extendedStabilizer->ApplySXDG(qubit);
335 NotifyObservers({qubit});
340 extendedStabilizer->ApplyK(qubit);
341 NotifyObservers({qubit});
346 extendedStabilizer->ApplyRX(qubit, theta);
347 NotifyObservers({qubit});
352 extendedStabilizer->ApplyRY(qubit, theta);
353 NotifyObservers({qubit});
358 extendedStabilizer->ApplyRZ(qubit, theta);
359 NotifyObservers({qubit});
362 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
364 extendedStabilizer->ApplyU(qubit, theta, phi, lambda, gamma);
365 NotifyObservers({qubit});
370 extendedStabilizer->ApplyCX(ctrl_qubit, tgt_qubit);
371 NotifyObservers({tgt_qubit, ctrl_qubit});
376 extendedStabilizer->ApplyCY(ctrl_qubit, tgt_qubit);
377 NotifyObservers({tgt_qubit, ctrl_qubit});
382 extendedStabilizer->ApplyCZ(ctrl_qubit, tgt_qubit);
383 NotifyObservers({tgt_qubit, ctrl_qubit});
388 extendedStabilizer->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
389 NotifyObservers({tgt_qubit, ctrl_qubit});
394 extendedStabilizer->ApplyCRX(ctrl_qubit, tgt_qubit, theta);
395 NotifyObservers({tgt_qubit, ctrl_qubit});
400 extendedStabilizer->ApplyCRY(ctrl_qubit, tgt_qubit, theta);
401 NotifyObservers({tgt_qubit, ctrl_qubit});
406 extendedStabilizer->ApplyCRZ(ctrl_qubit, tgt_qubit, theta);
407 NotifyObservers({tgt_qubit, ctrl_qubit});
412 extendedStabilizer->ApplyCH(ctrl_qubit, tgt_qubit);
413 NotifyObservers({tgt_qubit, ctrl_qubit});
418 extendedStabilizer->ApplyCSX(ctrl_qubit, tgt_qubit);
419 NotifyObservers({tgt_qubit, ctrl_qubit});
424 extendedStabilizer->ApplyCSXDAG(ctrl_qubit, tgt_qubit);
425 NotifyObservers({tgt_qubit, ctrl_qubit});
430 extendedStabilizer->ApplySWAP(qubit0, qubit1);
431 NotifyObservers({qubit1, qubit0});
436 extendedStabilizer->ApplyCCX(qubit0, qubit1, qubit2);
437 NotifyObservers({qubit2, qubit1, qubit0});
442 extendedStabilizer->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
443 NotifyObservers({qubit1, qubit0, ctrl_qubit});
448 extendedStabilizer->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
449 NotifyObservers({tgt_qubit, ctrl_qubit});
452 std::unique_ptr<ISimulator> Clone()
override
454 auto cloned = std::make_unique<QCSimExtendedStabilizerSimulator>();
455 cloned->nrQubits = nrQubits;
456 cloned->enableMultithreading = enableMultithreading;
457 cloned->upcomingGates = upcomingGates;
458 cloned->upcomingGateIndex = upcomingGateIndex;
459 if (extendedStabilizer)
460 cloned->extendedStabilizer = configuration.IsSet(
"seed") ? extendedStabilizer->Clone() : extendedStabilizer->CloneWithSeed(rng());
461 for (
const auto &[key, value] : configuration.GetConfigMap())
462 cloned->Configure(key.c_str(), value.c_str());
463 if (configuration.IsSet(
"seed"))
464 cloned->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration(
"seed")), nextSeedStream++));
469 double ExtendedStabilizerBasisProbability(
Types::qubit_t outcome)
const
471 const size_t nrBasisStates = CheckedBasisStateCountForQueries();
472 if (outcome >= nrBasisStates)
474 double probability = 0.0;
475 std::string pauliString(nrQubits,
'I');
476 for (
size_t mask = 0; mask < nrBasisStates; ++mask)
479 size_t parityBits = mask &
static_cast<size_t>(outcome);
480 while (parityBits != 0)
483 parityBits &= parityBits - 1;
485 for (
size_t qubit = 0; qubit < nrQubits; ++qubit)
486 pauliString[qubit] = ((mask >> qubit) & 1ULL) == 0 ?
'I' :
'Z';
487 probability += sign * extendedStabilizer->ExpectationValue(pauliString);
489 probability /=
static_cast<double>(nrBasisStates);
490 return std::max(0.0, std::min(1.0, probability));
493 std::unique_ptr<Simulators::QCSimExtendedStabilizer> extendedStabilizer;
int ApplyK(void *sim, int qubit)
double Probability(void *sim, unsigned long long int outcome)
int RestoreState(void *sim)
int ApplyRx(void *sim, int qubit, double theta)
int ApplyReset(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyX(void *sim, int qubit)
int ApplyU(void *sim, int qubit, double theta, double phi, double lambda, double gamma)
int ApplyCRy(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyTDG(void *sim, int qubit)
int ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
unsigned long int AllocateQubits(void *sim, unsigned long int nrQubits)
int ApplyCRz(void *sim, int controlQubit, int targetQubit, double theta)
unsigned long int GetNumberOfQubits(void *sim)
double * AllProbabilities(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
int ApplySDG(void *sim, int qubit)
unsigned long long int Measure(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyCSwap(void *sim, int controlQubit, int qubit1, int qubit2)
int ApplyCCX(void *sim, int controlQubit1, int controlQubit2, int targetQubit)
int ApplyY(void *sim, int qubit)
double * Amplitude(void *sim, unsigned long long int outcome)
int ApplyZ(void *sim, int qubit)
int ApplyH(void *sim, int qubit)
int ApplyCY(void *sim, int controlQubit, int targetQubit)
double * Probabilities(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits)
int SetMultithreading(void *sim, int multithreading)
int ApplyCU(void *sim, int controlQubit, int targetQubit, double theta, double phi, double lambda, double gamma)
int ApplySwap(void *sim, int qubit1, int qubit2)
int ApplyRy(void *sim, int qubit, double theta)
int ApplyP(void *sim, int qubit, double theta)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int GetSimulationType(void *sim)
unsigned long long int * SampleCounts(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits, unsigned long int shots)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyRz(void *sim, int qubit, double theta)
int ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
SimulationType
The type of simulation.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.