2#if defined(INCLUDED_BY_FACTORY)
5#define _USE_MATH_DEFINES
11class QCSimPauliPropagatorSimulator :
public ImmediateQCSimSimulator
14 QCSimPauliPropagatorSimulator()
16 configuration.SetConfiguration(
"method",
"pauli_propagator");
19 const char *MethodName()
const override
21 return "pauli_propagator";
24 void Initialize()
override
29 pp = std::make_unique<Simulators::QcsimPauliPropagator>();
30 pp->SetNrQubits(
static_cast<int>(nrQubits));
33 for (
const auto &[key, value] : configuration.GetConfigMap())
35 Configure(key.c_str(), value.c_str());
42 pp->ClearOperations();
43 upcomingGateIndex = 0;
46 void Configure(
const char *key,
const char *value)
override
48 if (std::string(
"method") == key)
50 ValidateMethod(value);
51 configuration.SetConfiguration(key, value);
54 if (!configuration.WasApplied(key, value))
55 configuration.SetConfiguration(key, value);
56 if (std::string(
"seed") == key)
58 const uint64_t seed = std::stoull(value);
59 SeedAuxiliaryRng(seed);
63 SeedBackend(pp.get(), seed);
66 if (std::string(key) ==
"pauli_propagator_workers")
68 const auto workers = configuration.GetConfigurationAsUnsigned(key);
70 throw std::invalid_argument(
"pauli_propagator_workers exceeds 1024");
71 pauliWorkerCount =
static_cast<size_t>(workers);
72 if (pp && enableMultithreading)
73 pp->EnableParallel(pauliWorkerCount);
77 if (std::string(key) ==
"pauli_propagator_sampling_cache_nodes")
79 pp->SetSamplingCacheMaxNodes(configuration.GetConfigurationAsUnsigned(key));
81 else if (std::string(key) ==
"pauli_propagator_coefficient_threshold")
83 pp->SetCoefficientThreshold(configuration.GetConfigurationAsDouble(key));
85 else if (std::string(key) ==
"pauli_propagator_pauli_weight_threshold")
87 pp->SetPauliWeightThreshold(configuration.GetConfigurationAsUnsigned(key));
89 else if (std::string(key) ==
"pauli_propagator_steps_between_trims")
91 pp->SetStepsBetweenTrims(configuration.GetConfigurationAsInt(key));
93 else if (std::string(key) ==
"pauli_propagator_num_gates_between_deduplications")
95 pp->SetStepsBetweenDeduplication(configuration.GetConfigurationAsInt(key));
102 const size_t oldNrQubits = nrQubits;
103 nrQubits += num_qubits;
105 pp->SetNrQubits(
static_cast<int>(nrQubits));
109 void Clear()
override
113 upcomingGateIndex = 0;
114 upcomingGates.clear();
119 if (qubits.size() >
sizeof(
size_t) * 8)
120 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
121 "number of bits in the size_t type, the outcome will be undefined"
126 std::vector<int> qubitsInt;
127 qubitsInt.reserve(qubits.size());
128 for (
const auto q : qubits)
129 qubitsInt.push_back(
static_cast<int>(q));
130 const auto res = pp->Measure(qubitsInt);
132 for (
size_t i = 0; i < res.size(); ++i)
144 std::vector<bool> res(qubits.size(),
false);
147 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
148 res = pp->Measure(qubitsInt);
151 NotifyObservers(qubits);
159 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
160 const auto res = pp->Measure(qubitsInt);
161 for (
size_t i = 0; i < res.size(); ++i)
164 pp->ApplyX(qubitsInt[i]);
168 NotifyObservers(qubits);
173 return pp->Probability(outcome);
179 std::vector<double> result(nrBasisStates);
180 for (
size_t i = 0; i < nrBasisStates; ++i)
181 result[i] = pp->Probability(i);
187 std::vector<double> result(qubits.size());
189 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
190 result[i] = pp->Probability(qubits[i]);
197 if (qubits.empty() || shots == 0)
199 if (qubits.size() >
sizeof(
size_t) * 8)
200 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
201 "number of bits in the size_t type, the outcome will be undefined"
203 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
206 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
207 if (qubits.size() > 64)
208 throw std::invalid_argument(
"Use SampleCountsMany for more than 64 measured qubits");
209 const auto counts = pp->SampleCounts(qubitsInt, shots);
210 for (
const auto &[bits, count] : counts)
213 for (
size_t i = 0; i < bits.size(); ++i)
216 result[meas] += count;
220 NotifyObservers(qubits);
226 if (qubits.empty() || shots == 0)
231 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
232 const auto counts = pp->SampleCounts(qubitsInt, shots);
233 for (
const auto &[bits, count] : counts)
234 result[bits] += count;
237 NotifyObservers(qubits);
241 double ExpectationValue(
const std::string &pauliStringOrig)
override
243 if (pauliStringOrig.empty())
245 std::string pauliString = pauliStringOrig;
250 const auto pauliOp = toupper(pauliString[i]);
251 if (pauliOp !=
'I' && pauliOp !=
'Z')
256 return pp->ExpectationValue(pauliString);
261 return SimulationType::kPauliPropagator;
276 enableMultithreading = multithreading;
280 pp->EnableParallel(pauliWorkerCount);
282 pp->DisableParallel();
289 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
290 "number of bits in the Types::qubit_t type, the outcome will be "
295 std::iota(qubitsInt.begin(), qubitsInt.end(), 0);
296 const auto res = pp->Sample(qubitsInt);
298 for (
size_t i = 0; i < res.size(); ++i)
301 result |= (1ULL << i);
307 std::vector<bool> MeasureNoCollapseMany()
override
310 std::iota(qubitsInt.begin(), qubitsInt.end(), 0);
311 return pp->Sample(qubitsInt);
316 pp->ApplyP(
static_cast<unsigned int>(qubit), lambda);
317 NotifyObservers({qubit});
322 pp->ApplyX(
static_cast<unsigned int>(qubit));
323 NotifyObservers({qubit});
328 pp->ApplyY(
static_cast<unsigned int>(qubit));
329 NotifyObservers({qubit});
334 pp->ApplyZ(
static_cast<unsigned int>(qubit));
335 NotifyObservers({qubit});
340 pp->ApplyH(
static_cast<unsigned int>(qubit));
341 NotifyObservers({qubit});
346 pp->ApplyS(
static_cast<unsigned int>(qubit));
347 NotifyObservers({qubit});
352 pp->ApplySDG(
static_cast<unsigned int>(qubit));
353 NotifyObservers({qubit});
358 pp->ApplyT(
static_cast<unsigned int>(qubit));
359 NotifyObservers({qubit});
364 pp->ApplyTDG(
static_cast<unsigned int>(qubit));
365 NotifyObservers({qubit});
370 pp->ApplySX(
static_cast<unsigned int>(qubit));
371 NotifyObservers({qubit});
376 pp->ApplySXDG(
static_cast<unsigned int>(qubit));
377 NotifyObservers({qubit});
382 pp->ApplyK(
static_cast<unsigned int>(qubit));
383 NotifyObservers({qubit});
388 pp->ApplyRX(
static_cast<unsigned int>(qubit), theta);
389 NotifyObservers({qubit});
394 pp->ApplyRY(
static_cast<unsigned int>(qubit), theta);
395 NotifyObservers({qubit});
400 pp->ApplyRZ(
static_cast<unsigned int>(qubit), theta);
401 NotifyObservers({qubit});
404 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
406 pp->ApplyU(
static_cast<unsigned int>(qubit), theta, phi, lambda, gamma);
407 NotifyObservers({qubit});
412 pp->ApplyCX(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit));
413 NotifyObservers({tgt_qubit, ctrl_qubit});
418 pp->ApplyCY(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit));
419 NotifyObservers({tgt_qubit, ctrl_qubit});
424 pp->ApplyCZ(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit));
425 NotifyObservers({tgt_qubit, ctrl_qubit});
430 pp->ApplyCP(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit), lambda);
431 NotifyObservers({tgt_qubit, ctrl_qubit});
436 pp->ApplyCRX(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit), theta);
437 NotifyObservers({tgt_qubit, ctrl_qubit});
442 pp->ApplyCRY(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit), theta);
443 NotifyObservers({tgt_qubit, ctrl_qubit});
448 pp->ApplyCRZ(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit), theta);
449 NotifyObservers({tgt_qubit, ctrl_qubit});
454 pp->ApplyCH(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit));
455 NotifyObservers({tgt_qubit, ctrl_qubit});
460 pp->ApplyCSX(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit));
461 NotifyObservers({tgt_qubit, ctrl_qubit});
466 pp->ApplyCSXDAG(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit));
467 NotifyObservers({tgt_qubit, ctrl_qubit});
472 pp->ApplySWAP(
static_cast<unsigned int>(qubit0),
static_cast<unsigned int>(qubit1));
473 NotifyObservers({qubit1, qubit0});
478 pp->ApplyCCX(
static_cast<unsigned int>(qubit0),
static_cast<unsigned int>(qubit1),
static_cast<unsigned int>(qubit2));
479 NotifyObservers({qubit2, qubit1, qubit0});
484 pp->ApplyCSwap(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(qubit0),
static_cast<unsigned int>(qubit1));
485 NotifyObservers({qubit1, qubit0, ctrl_qubit});
490 pp->ApplyCU(
static_cast<unsigned int>(ctrl_qubit),
static_cast<unsigned int>(tgt_qubit), theta, phi, lambda, gamma);
491 NotifyObservers({tgt_qubit, ctrl_qubit});
494 std::unique_ptr<ISimulator> Clone()
override
496 auto cloned = std::make_unique<QCSimPauliPropagatorSimulator>();
497 cloned->nrQubits = nrQubits;
498 cloned->enableMultithreading = enableMultithreading;
499 cloned->pauliWorkerCount = pauliWorkerCount;
500 cloned->upcomingGates = upcomingGates;
501 cloned->upcomingGateIndex = upcomingGateIndex;
503 cloned->pp = pp->Clone();
504 for (
const auto &[key, value] : configuration.GetConfigMap())
505 cloned->Configure(key.c_str(), value.c_str());
506 if (configuration.IsSet(
"seed"))
507 cloned->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration(
"seed")), nextSeedStream++));
512 std::unique_ptr<QcsimPauliPropagator> pp;
514 size_t pauliWorkerCount = 0;
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)
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.