2#if defined(INCLUDED_BY_FACTORY)
20template <
typename T,
typename =
void>
struct HasSetSeed : std::false_type
24template <
typename T>
struct HasSetSeed<T, std::void_t<decltype(std::declval<T &>().SetSeed(std::declval<uint64_t>()))>> : std::true_type
28template <
typename T>
void SeedBackend(T *backend, uint64_t seed)
30 if constexpr (HasSetSeed<T>::value)
31 backend->SetSeed(seed);
40class ImmediateQCSimSimulator :
public ISimulator
43 virtual const char *MethodName()
const = 0;
46 void ValidateMethod(
const char *value)
const
48 if (std::string(value) != MethodName())
49 throw std::invalid_argument(
"A concrete simulator cannot change method; select the backend through SimulatorsFactory");
52 virtual void RefreshRoutingCallback()
56 ImmediateQCSimSimulator() : samplingSeed(Utils::RandomStream::
FreshSeed()), rng(samplingSeed), uniformZeroOne(0, 1)
58 SeedAuxiliaryRng(samplingSeed);
62 void InitializeState(
size_t num_qubits, std::vector<std::complex<double>> &litudes)
override
67 nrQubits = num_qubits;
69 throw std::runtime_error(
"QCSimState::InitializeState: Invalid "
70 "simulation type for initializing the state.");
74 void InitializeState(
size_t num_qubits, AER::Vector<std::complex<double>> &litudes)
override
79 nrQubits = num_qubits;
81 throw std::runtime_error(
"QCSimState::InitializeState: Invalid "
82 "simulation type for initializing the state.");
87 void InitializeState(
size_t num_qubits, Eigen::VectorXcd &litudes)
override
92 nrQubits = num_qubits;
94 throw std::runtime_error(
"QCSimState::InitializeState: Invalid "
95 "simulation type for initializing the state.");
98 void InitializeToBasisState(
size_t num_qubits,
Types::qubit_t basisState)
override
103 nrQubits = num_qubits;
105 for (
size_t q = 0; q < num_qubits; ++q)
106 if ((basisState >> q) & 1ULL)
110 void InitializeToBasisState(
size_t num_qubits,
const std::vector<bool> &basisState)
override
115 nrQubits = num_qubits;
117 for (
size_t q = 0; q < num_qubits && q < basisState.size(); ++q)
122 void InitializeToMixtureOfBasisStates(
size_t num_qubits,
const std::vector<std::pair<Types::qubit_t, double>> &mixture)
override
127 nrQubits = num_qubits;
129 throw std::runtime_error(
"QCSimState::InitializeToMixtureOfBasisStates: Invalid simulation "
130 "type for initializing to a mixture of basis states.");
133 void InitializeToMixtureOfBasisStates(
size_t num_qubits,
const std::vector<std::pair<std::vector<bool>,
double>> &mixture)
override
138 nrQubits = num_qubits;
140 throw std::runtime_error(
"QCSimState::InitializeToMixtureOfBasisStates: Invalid simulation "
141 "type for initializing to a mixture of basis states.");
144 bool SupportsMPSSwapOptimization()
const override
149 void SetUpcomingGates(
const std::vector<std::shared_ptr<Circuits::IOperation<double>>> &gates)
override
151 upcomingGates = gates;
152 upcomingGateIndex = 0;
153 if (!gateCounterObserver)
154 gateCounterObserver = std::make_shared<GateCounterObserver>(upcomingGateIndex);
155 RegisterObserver(gateCounterObserver);
156 RefreshRoutingCallback();
159 long long int GetGatesCounter()
const override
161 return upcomingGateIndex;
164 void SetGatesCounter(
long long int counter)
override
166 upcomingGateIndex = counter;
169 void IncrementGatesCounter()
override
178 const bool adaptiveSampling =
179 std::string(MethodName()) ==
"statevector" || std::string(MethodName()) ==
"density_matrix" || std::string(MethodName()) ==
"path_integral";
180 if (adaptiveSampling && std::string(key) ==
"sampling_seed")
181 return std::to_string(samplingSeed);
182 if (adaptiveSampling && std::string(key) ==
"sampling_policy" && !configuration.IsSet(key))
183 return "reproducible_v1";
184 if (std::string(key) ==
"precision")
186 if (std::string(key) ==
"use_double_precision")
188 if (std::string(
"method") == key)
190 return configuration.GetConfiguration(key);
198 bool SupportsQuantumChannels()
const override
203 void ApplyQuantumChannel(
const Types::qubits_vector &targets,
const QuantumChannel &channel)
override
205 throw std::runtime_error(
"QCSim quantum channels require density_matrix or matrix_product_operator simulation");
208 double ProbabilityBits(
const std::vector<bool> &bits)
override
210 return IState::ProbabilityBits(bits);
213 std::complex<double> DensityMatrixElementBits(
const std::vector<bool> &row,
const std::vector<bool> &col)
const override
215 return IState::DensityMatrixElementBits(row, col);
218 Eigen::MatrixXcd GetDensityMatrix(
bool normalized =
true)
const override
220 return IState::GetDensityMatrix(normalized);
223 std::complex<double> ExpectationValueComplex(
const std::string &pauli,
bool normalized =
true)
const override
225 return IState::ExpectationValueComplex(pauli, normalized);
228 std::vector<std::complex<double>> ExpectationValuesComplex(
const std::vector<std::string> &paulis,
bool normalized =
true)
const override
230 return IState::ExpectationValuesComplex(paulis, normalized);
233 void ApplyOperator(
const Types::qubits_vector &qubits,
const Eigen::MatrixXcd &matrix,
bool normalize =
false)
override
235 return IState::ApplyOperator(qubits, matrix, normalize);
240 return IState::MoveAtBeginningOfChain(qubits);
243 std::vector<std::complex<double>> GetStateVector()
override
245 return IState::GetStateVector();
248 std::complex<double> ExpectationValueOperators(
const Types::qubits_vector &qubits,
const std::vector<Eigen::MatrixXcd> &matrices)
override
250 return IState::ExpectationValueOperators(qubits, matrices);
253 std::complex<double> DensityMatrixTrace()
const override
255 throw std::runtime_error(
"Mixed-state diagnostics require density_matrix or "
256 "matrix_product_operator");
259 std::complex<double> DensityMatrixOverlap(
const IState &other)
const override
261 throw std::invalid_argument(
"Density-matrix overlap requires two density matrices or two MPOs");
264 double DensityMatrixPurity()
const override
266 throw std::runtime_error(
"Mixed-state diagnostics require density_matrix or "
267 "matrix_product_operator");
270 std::complex<double> DensityMatrixTraceOfSquare()
const override
272 throw std::runtime_error(
"Mixed-state diagnostics require density_matrix or "
273 "matrix_product_operator");
276 double DensityMatrixHermiticityResidual()
const override
278 throw std::runtime_error(
"Mixed-state diagnostics require density_matrix or "
279 "matrix_product_operator");
282 bool IsDensityMatrixHermitian(
double eps = 1e-10)
const override
284 throw std::runtime_error(
"Mixed-state diagnostics require density_matrix or "
285 "matrix_product_operator");
290 throw std::runtime_error(
"Partial trace requires density_matrix or matrix_product_operator");
293 double FidelityWithStatevector(
const Eigen::VectorXcd &psi)
const override
295 throw std::runtime_error(
"Mixed-state fidelity requires density_matrix or "
296 "matrix_product_operator");
299 void RestoreDensityMatrixTrace()
override
301 throw std::runtime_error(
"Trace restoration is only available for QCSim MPO");
304 void HermitizeDensityMatrix()
override
306 throw std::runtime_error(
"Hermitization is only available for QCSim MPO");
311 throw std::runtime_error(
"Trim is only available for QCSim MPS and MPO");
314 void ReCanonicalize()
override
316 throw std::runtime_error(
"Canonicalization is only available for QCSim MPS and MPO");
321 throw std::runtime_error(
"QCSimState::Amplitude: Invalid simulation type for obtaining the "
322 "amplitude of the specified outcome.");
325 std::complex<double> ProjectOnZero()
override
330 std::vector<double> ExpectationValues(
const std::vector<std::string> &paulis)
override
332 return ISimulator::ExpectationValues(paulis);
337 return SimulatorType::kQCSim;
340 void Flush()
override
352 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override
359 return enableMultithreading;
370 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
371 "number of bits in the Types::qubit_t type, the outcome will be "
374 throw std::runtime_error(
"QCSimState::MeasureNoCollapse: Invalid simulation type for "
376 "all the qubits without collapsing the state.");
379 std::vector<bool> MeasureNoCollapseMany()
override
381 throw std::runtime_error(
"QCSimState::MeasureNoCollapseMany: Invalid simulation type for "
382 "measuring all the qubits without collapsing the state.");
387 return configuration;
390 const std::unordered_map<std::string, std::string> &GetConfigMap()
const override
392 return configuration.GetConfigMap();
397 throw std::runtime_error(
"QCSimSimulator::ApplyGenericOneQubitGate: Unsupported simulation "
403 throw std::runtime_error(
"QCSimSimulator::ApplyGenericTwoQubitGate: Unsupported simulation "
409 throw std::runtime_error(
"Generic three-qubit gates require a statevector or density matrix");
412 void ApplyNop()
override
417 bool ConfigureSampling(
const char *key,
const char *value)
421 configuration.SetConfiguration(key, value);
425 bool LegacySampling()
const
427 return configuration.GetConfiguration(
"sampling_policy") ==
"legacy";
430 Utils::Sampling::Options SamplingOptions()
const
432 Utils::Sampling::Options options;
434 if (configuration.IsSet(
"sampling_max_memory_mb"))
435 options.
memoryBytes =
static_cast<size_t>(std::stoull(configuration.GetConfiguration(
"sampling_max_memory_mb"))) << 20;
439 void SeedSampling(uint64_t seed)
444 uniformZeroOne.reset();
447 void InitializeSamplingSeed()
451 if (!configuration.IsSet(
"seed"))
454 SeedAuxiliaryRng(samplingSeed);
458 uint64_t NextCloneSeed()
460 if (nextSeedStream == std::numeric_limits<uint64_t>::max())
461 throw std::overflow_error(
"Simulator clone stream ids exhausted");
462 return DeriveSeed(samplingSeed, nextSeedStream++);
465 size_t CheckedBasisStateCountForQueries()
const
467 if (nrQubits >= std::numeric_limits<size_t>::digits)
468 throw std::runtime_error(
"ImmediateQCSimState: Too many qubits for enumerating basis states.");
469 return 1ULL << nrQubits;
474 bool enableMultithreading =
true;
476 std::vector<std::shared_ptr<Circuits::IOperation<>>> upcomingGates;
478 long long int upcomingGateIndex = 0;
480 class GateCounterObserver :
public ISimulatorObserver
483 GateCounterObserver(
long long int &indexRef) : index(indexRef)
493 long long int &index;
496 std::shared_ptr<GateCounterObserver> gateCounterObserver;
498 uint64_t samplingSeed;
501 uint64_t nextSeedStream = 0;
503 std::uniform_real_distribution<double> uniformZeroOne;
505 Configuration configuration;
char * GetConfiguration(void *sim, const char *key)
int ApplyX(void *sim, int qubit)
unsigned long int GetNumberOfQubits(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int GetMultithreading(void *sim)
double * Amplitude(void *sim, unsigned long long int outcome)
int ApplyGenericThreeQubitGate(void *sim, unsigned long q0, unsigned long q1, unsigned long q2, const double *buffer)
int SaveStateToInternalDestructive(void *sim)
int RestoreInternalDestructiveSavedState(void *sim)
int ApplyGenericOneQubitGate(void *sim, unsigned long q0, const double *buffer)
int ApplyGenericTwoQubitGate(void *sim, unsigned long q0, unsigned long q1, const double *buffer)
SimulatorType
The type of simulator.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.
bool ValidateSetting(std::string_view name, std::string_view setting)