2#if defined(INCLUDED_BY_FACTORY)
5#define _USE_MATH_DEFINES
11class QCSimStabilizerSimulator :
public ImmediateQCSimSimulator
14 QCSimStabilizerSimulator()
16 configuration.SetConfiguration(
"method",
"stabilizer");
19 const char *MethodName()
const override
24 void Initialize()
override
28 cliffordSimulator = std::make_unique<QC::Clifford::StabilizerSimulator>(nrQubits);
30 for (
const auto &[key, value] : configuration.GetConfigMap())
32 Configure(key.c_str(), value.c_str());
38 if (cliffordSimulator)
39 cliffordSimulator->Reset();
40 upcomingGateIndex = 0;
43 void Configure(
const char *key,
const char *value)
override
45 if (std::string(
"method") == key)
47 ValidateMethod(value);
48 configuration.SetConfiguration(key, value);
51 if (!configuration.WasApplied(key, value))
52 configuration.SetConfiguration(key, value);
53 if (std::string(
"seed") == key)
55 const uint64_t seed = std::stoull(value);
56 SeedAuxiliaryRng(seed);
59 if (cliffordSimulator)
60 SeedBackend(cliffordSimulator.get(), seed);
63 if (std::string(key) ==
"pauli_propagator_workers")
65 const auto workers = configuration.GetConfigurationAsUnsigned(key);
67 throw std::invalid_argument(
"pauli_propagator_workers exceeds 1024");
73 if (cliffordSimulator)
75 const size_t oldNrQubits = nrQubits;
76 nrQubits += num_qubits;
82 cliffordSimulator =
nullptr;
84 upcomingGateIndex = 0;
85 upcomingGates.clear();
90 if (qubits.size() >
sizeof(
size_t) * 8)
91 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
92 "number of bits in the size_t type, the outcome will be undefined"
98 for (
size_t qubit : qubits)
100 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
106 NotifyObservers(qubits);
112 std::vector<bool> res(qubits.size(),
false);
115 for (
size_t q = 0; q < qubits.size(); ++q)
116 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubits[q])))
120 NotifyObservers(qubits);
128 for (
size_t qubit : qubits)
129 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
130 cliffordSimulator->ApplyX(
static_cast<unsigned int>(qubit));
133 NotifyObservers(qubits);
138 if constexpr (std::numeric_limits<size_t>::digits >= std::numeric_limits<Types::qubit_t>::digits)
140 return cliffordSimulator->getBasisStateProbability(
static_cast<size_t>(outcome));
144 const size_t n = cliffordSimulator->getNrQubits();
145 if (n < std::numeric_limits<Types::qubit_t>::digits && (outcome >> n) != 0)
147 std::vector<bool> bits(n);
148 for (
size_t q = 0; q < n && q < std::numeric_limits<Types::qubit_t>::digits; ++q)
149 bits[q] = ((outcome >> q) & 1) != 0;
150 return cliffordSimulator->getBasisStateProbability(bits);
156 return cliffordSimulator->AllProbabilities();
161 throw std::runtime_error(
"QCSimState::Probabilities: Invalid simulation "
162 "type for obtaining probabilities.");
167 if (qubits.empty() || shots == 0)
170 const auto selected = CliffordSamplingQubits(qubits);
171 const auto counts = cliffordSimulator->SampleCounts(selected, shots);
172 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
173 for (
const auto &item : counts)
174 result.emplace(item.first, item.second);
175 NotifyObservers(qubits);
182 if (qubits.empty() || shots == 0)
185 const auto selected = CliffordSamplingQubits(qubits);
186 const auto counts = cliffordSimulator->SampleCountsMany(selected, shots);
188 for (
const auto &item : counts)
189 result.emplace(item.first, item.second);
190 NotifyObservers(qubits);
195 double ExpectationValue(
const std::string &pauliStringOrig)
override
197 if (pauliStringOrig.empty())
199 std::string pauliString = pauliStringOrig;
204 const auto pauliOp = toupper(pauliString[i]);
205 if (pauliOp !=
'I' && pauliOp !=
'Z')
210 return cliffordSimulator->ExpectationValue(pauliString);
215 return SimulationType::kStabilizer;
220 cliffordSimulator->SaveState();
225 cliffordSimulator->RestoreState();
230 enableMultithreading = multithreading;
231 if (cliffordSimulator)
232 cliffordSimulator->SetMultithreading(multithreading);
238 if (std::abs(lambda - M_PI_2) > 1e-10)
239 throw std::runtime_error(
"QCSimSimulator::ApplyP: Invalid phase shift "
240 "angle for a Clifford gate.");
241 cliffordSimulator->ApplyS(
static_cast<unsigned int>(qubit));
243 NotifyObservers({qubit});
248 cliffordSimulator->ApplyX(
static_cast<unsigned int>(qubit));
249 NotifyObservers({qubit});
254 cliffordSimulator->ApplyY(
static_cast<unsigned int>(qubit));
255 NotifyObservers({qubit});
260 cliffordSimulator->ApplyZ(
static_cast<unsigned int>(qubit));
261 NotifyObservers({qubit});
266 cliffordSimulator->ApplyH(
static_cast<unsigned int>(qubit));
267 NotifyObservers({qubit});
272 cliffordSimulator->ApplyS(
static_cast<unsigned int>(qubit));
273 NotifyObservers({qubit});
278 cliffordSimulator->ApplySdg(
static_cast<unsigned int>(qubit));
279 NotifyObservers({qubit});
284 throw std::runtime_error(
"QCSimSimulator::ApplyT: The stabilizer simulator does not support "
285 "non-clifford gates.");
290 throw std::runtime_error(
"QCSimSimulator::ApplyTDG: The stabilizer simulator does not support "
291 "non-clifford gates.");
296 cliffordSimulator->ApplySx(
static_cast<unsigned int>(qubit));
297 NotifyObservers({qubit});
302 cliffordSimulator->ApplySxDag(
static_cast<unsigned int>(qubit));
303 NotifyObservers({qubit});
308 cliffordSimulator->ApplyK(
static_cast<unsigned int>(qubit));
309 NotifyObservers({qubit});
314 throw std::runtime_error(
"QCSimSimulator::ApplyRx: The stabilizer "
315 "simulator does not support the Rx gate.");
320 throw std::runtime_error(
"QCSimSimulator::ApplyRy: The stabilizer "
321 "simulator does not support the Ry gate.");
326 throw std::runtime_error(
"QCSimSimulator::ApplyRz: The stabilizer "
327 "simulator does not support the Rz gate.");
330 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
332 throw std::runtime_error(
"QCSimSimulator::ApplyU: The stabilizer "
333 "simulator does not support the U gate.");
338 cliffordSimulator->ApplyCX(
static_cast<unsigned int>(tgt_qubit),
static_cast<unsigned int>(ctrl_qubit));
339 NotifyObservers({tgt_qubit, ctrl_qubit});
344 cliffordSimulator->ApplyCY(
static_cast<unsigned int>(tgt_qubit),
static_cast<unsigned int>(ctrl_qubit));
345 NotifyObservers({tgt_qubit, ctrl_qubit});
350 cliffordSimulator->ApplyCZ(
static_cast<unsigned int>(tgt_qubit),
static_cast<unsigned int>(ctrl_qubit));
351 NotifyObservers({tgt_qubit, ctrl_qubit});
356 throw std::runtime_error(
"QCSimSimulator::ApplyCP: The stabilizer "
357 "simulator does not support the CP gate.");
362 throw std::runtime_error(
"QCSimSimulator::ApplyCRx: The stabilizer "
363 "simulator does not support the CRx gate.");
368 throw std::runtime_error(
"QCSimSimulator::ApplyCRy: The stabilizer "
369 "simulator does not support the CRy gate.");
374 throw std::runtime_error(
"QCSimSimulator::ApplyCRz: The stabilizer "
375 "simulator does not support the CRz gate.");
380 throw std::runtime_error(
"QCSimSimulator::ApplyCH: The stabilizer "
381 "simulator does not support the CH gate.");
386 throw std::runtime_error(
"QCSimSimulator::ApplyCSx: The stabilizer "
387 "simulator does not support the CSx gate.");
392 throw std::runtime_error(
"QCSimSimulator::ApplyCSxDAG: The stabilizer "
393 "simulator does not support the CSxDag gate.");
398 cliffordSimulator->ApplySwap(
static_cast<unsigned int>(qubit1),
static_cast<unsigned int>(qubit0));
399 NotifyObservers({qubit1, qubit0});
404 throw std::runtime_error(
"QCSimSimulator::ApplyCCX: The stabilizer "
405 "simulator does not support the CCX gate.");
410 throw std::runtime_error(
"QCSimSimulator::ApplyCSwap: The stabilizer "
411 "simulator does not support the CSwap gate.");
416 throw std::runtime_error(
"QCSimSimulator::ApplyCU: The stabilizer "
417 "simulator does not support the CU gate.");
420 std::unique_ptr<ISimulator> Clone()
override
422 auto cloned = std::make_unique<QCSimStabilizerSimulator>();
423 cloned->nrQubits = nrQubits;
424 cloned->enableMultithreading = enableMultithreading;
425 cloned->upcomingGates = upcomingGates;
426 cloned->upcomingGateIndex = upcomingGateIndex;
427 if (cliffordSimulator)
428 cloned->cliffordSimulator = cliffordSimulator->Clone();
429 for (
const auto &[key, value] : configuration.GetConfigMap())
430 cloned->Configure(key.c_str(), value.c_str());
431 if (configuration.IsSet(
"seed"))
432 cloned->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration(
"seed")), nextSeedStream++));
439 std::vector<size_t> selected;
440 selected.reserve(qubits.size());
441 for (
const auto q : qubits)
443 if (q >= cliffordSimulator->getNrQubits())
444 throw std::out_of_range(
"Qubit index out of range");
445 selected.push_back(
static_cast<size_t>(q));
450 std::unique_ptr<QC::Clifford::StabilizerSimulator> cliffordSimulator;
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)
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)
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.