Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QCSimTensorNetworkSimulator.h
Go to the documentation of this file.
1#pragma once
2#if defined(INCLUDED_BY_FACTORY)
6#define _USE_MATH_DEFINES
7#include <math.h>
8
10{
11// tensor_network backend. Owns exactly one native QCSim implementation.
12class QCSimTensorNetworkSimulator : public QCSimGateSimulator
13{
14 public:
15 QCSimTensorNetworkSimulator()
16 {
17 configuration.SetConfiguration("method", "tensor_network");
18 }
19
20 const char *MethodName() const override
21 {
22 return "tensor_network";
23 }
24
25 void Initialize() override
26 {
27 if (nrQubits != 0)
28 {
29 {
30 tensorNetwork = std::make_unique<TensorNetworks::TensorNetwork>(nrQubits);
31 const auto tensorContractor = std::make_shared<TensorNetworks::ForestContractor>();
32 tensorNetwork->SetContractor(tensorContractor);
33 }
34 SetMultithreading(enableMultithreading);
35 for (const auto &[key, value] : configuration.GetConfigMap())
36 if (key != "method")
37 Configure(key.c_str(), value.c_str());
38 }
39 }
40
41 void Reset() override
42 {
43 if (tensorNetwork)
44 tensorNetwork->Clear();
45 upcomingGateIndex = 0;
46 }
47
48 void Configure(const char *key, const char *value) override
49 {
50 if (std::string("method") == key)
51 {
52 ValidateMethod(value);
53 configuration.SetConfiguration(key, value);
54 return;
55 }
56 if (!configuration.WasApplied(key, value))
57 configuration.SetConfiguration(key, value);
58 if (std::string("seed") == key)
59 {
60 const uint64_t seed = std::stoull(value);
61 SeedAuxiliaryRng(seed);
62 nextSeedStream = 0;
63 rng.seed(seed);
64 if (tensorNetwork)
65 tensorNetwork->SetSeed(seed);
66 return;
67 }
68 if (std::string(key) == "pauli_propagator_workers")
69 {
70 const auto workers = configuration.GetConfigurationAsUnsigned(key);
71 if (workers > 1024)
72 throw std::invalid_argument("pauli_propagator_workers exceeds 1024");
73 }
74 }
75
76 size_t AllocateQubits(size_t num_qubits) override
77 {
78 if (tensorNetwork)
79 return 0;
80 const size_t oldNrQubits = nrQubits;
81 nrQubits += num_qubits;
82 return oldNrQubits;
83 }
84
85 void Clear() override
86 {
87 tensorNetwork = nullptr;
88 nrQubits = 0;
89 upcomingGateIndex = 0;
90 upcomingGates.clear();
91 }
92
93 size_t Measure(const Types::qubits_vector &qubits) override
94 {
95 if (qubits.size() > sizeof(size_t) * 8)
96 std::cerr << "Warning: The number of qubits to measure is larger than the "
97 "number of bits in the size_t type, the outcome will be undefined"
98 << std::endl;
99 size_t res = 0;
100 size_t mask = 1ULL;
101 DontNotify();
102 {
103 for (size_t qubit : qubits)
104 {
105 if (tensorNetwork->Measure(static_cast<unsigned int>(qubit)))
106 res |= mask;
107 mask <<= 1;
108 }
109 }
110 Notify();
111 NotifyObservers(qubits);
112 return res;
113 }
114
115 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override
116 {
117 std::vector<bool> res(qubits.size(), false);
118 DontNotify();
119 {
120 for (size_t q = 0; q < qubits.size(); ++q)
121 if (tensorNetwork->Measure(static_cast<unsigned int>(qubits[q])))
122 res[q] = true;
123 }
124 Notify();
125 NotifyObservers(qubits);
126 return res;
127 }
128
129 void ApplyReset(const Types::qubits_vector &qubits) override
130 {
131 DontNotify();
132 {
133 for (size_t qubit : qubits)
134 if (tensorNetwork->Measure(static_cast<unsigned int>(qubit)))
135 tensorNetwork->AddGate(xgate, static_cast<unsigned int>(qubit));
136 }
137 Notify();
138 NotifyObservers(qubits);
139 }
140
141 double Probability(Types::qubit_t outcome) override
142 {
143 return tensorNetwork->getBasisStateProbability(outcome);
144 }
145
146 std::complex<double> Amplitude(Types::qubit_t outcome) override
147 {
148 throw std::runtime_error("QCSimState::Amplitude: Not supported for the "
149 "tensor network simulator.");
150 }
151
152 std::vector<double> AllProbabilities() override
153 {
154 throw std::runtime_error("QCSimState::AllProbabilities: Invalid "
155 "simulation type for obtaining probabilities.");
156 }
157
158 std::vector<double> Probabilities(const Types::qubits_vector &qubits) override
159 {
160 throw std::runtime_error("QCSimState::Probabilities: Not implemented yet "
161 "for the tensor network simulator.");
162 }
163
164 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(const Types::qubits_vector &qubits, size_t shots = 1000) override
165 {
166 if (qubits.empty() || shots == 0)
167 return {};
168 if (qubits.size() > sizeof(size_t) * 8)
169 std::cerr << "Warning: The number of qubits to measure is larger than the "
170 "number of bits in the size_t type, the outcome will be undefined"
171 << std::endl;
172 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
173 DontNotify();
174 {
175 tensorNetwork->SaveState();
176 for (size_t shot = 0; shot < shots; ++shot)
177 {
178 const size_t meas = Measure(qubits);
179 ++result[meas];
180 tensorNetwork->RestoreState();
181 }
182 tensorNetwork->ClearSavedState();
183 }
184 Notify();
185 NotifyObservers(qubits);
186 return result;
187 }
188
189 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(const Types::qubits_vector &qubits, size_t shots = 1000) override
190 {
191 if (qubits.empty() || shots == 0)
192 return {};
193 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
194 DontNotify();
195 {
196 tensorNetwork->SaveState();
197 for (size_t shot = 0; shot < shots; ++shot)
198 {
199 const auto meas = MeasureMany(qubits);
200 ++result[meas];
201 tensorNetwork->RestoreState();
202 }
203 tensorNetwork->ClearSavedState();
204 }
205 Notify();
206 NotifyObservers(qubits);
207 return result;
208 }
209
210 double ExpectationValue(const std::string &pauliStringOrig) override
211 {
212 if (pauliStringOrig.empty())
213 return 1.0;
214 std::string pauliString = pauliStringOrig;
215 if (pauliString.size() > GetNumberOfQubits())
216 {
217 for (size_t i = GetNumberOfQubits(); i < pauliString.size(); ++i)
218 {
219 const auto pauliOp = toupper(pauliString[i]);
220 if (pauliOp != 'I' && pauliOp != 'Z')
221 return 0.0;
222 }
223 pauliString.resize(GetNumberOfQubits());
224 }
225 return tensorNetwork->ExpectationValue(pauliString);
226 }
227
228 SimulationType GetSimulationType() const override
229 {
230 return SimulationType::kTensorNetwork;
231 }
232
233 void SaveState() override
234 {
235 tensorNetwork->SaveState();
236 }
237
238 void RestoreState() override
239 {
240 tensorNetwork->RestoreState();
241 }
242
243 void SetMultithreading(bool multithreading = true) override
244 {
245 enableMultithreading = multithreading;
246 if (tensorNetwork)
247 tensorNetwork->SetMultithreading(multithreading);
248 }
249
250 void ApplyGenericOneQubitGate(Types::qubit_t qubit, const Eigen::Matrix2cd &gate) override
251 {
252 const QC::Gates::AppliedGate<> agate(gate, qubit);
253 tensorNetwork->AddGate(agate, qubit);
254 NotifyObservers({qubit});
255 }
256
257 void ApplyGenericTwoQubitGate(Types::qubit_t qubit0, Types::qubit_t qubit1, const Eigen::Matrix4cd &gate) override
258 {
259 const QC::Gates::AppliedGate<> agate(gate, qubit0, qubit1);
260 tensorNetwork->AddGate(agate, qubit1, qubit0);
261 NotifyObservers({qubit0, qubit1});
262 }
263
264 void ApplyP(Types::qubit_t qubit, double lambda) override
265 {
266 pgate.SetPhaseShift(lambda);
267 tensorNetwork->AddGate(pgate, static_cast<unsigned int>(qubit));
268 NotifyObservers({qubit});
269 }
270
271 void ApplyX(Types::qubit_t qubit) override
272 {
273 tensorNetwork->AddGate(xgate, static_cast<unsigned int>(qubit));
274 NotifyObservers({qubit});
275 }
276
277 void ApplyY(Types::qubit_t qubit) override
278 {
279 tensorNetwork->AddGate(ygate, static_cast<unsigned int>(qubit));
280 NotifyObservers({qubit});
281 }
282
283 void ApplyZ(Types::qubit_t qubit) override
284 {
285 tensorNetwork->AddGate(zgate, static_cast<unsigned int>(qubit));
286 NotifyObservers({qubit});
287 }
288
289 void ApplyH(Types::qubit_t qubit) override
290 {
291 tensorNetwork->AddGate(h, static_cast<unsigned int>(qubit));
292 NotifyObservers({qubit});
293 }
294
295 void ApplyS(Types::qubit_t qubit) override
296 {
297 tensorNetwork->AddGate(sgate, static_cast<unsigned int>(qubit));
298 NotifyObservers({qubit});
299 }
300
301 void ApplySDG(Types::qubit_t qubit) override
302 {
303 tensorNetwork->AddGate(sdggate, static_cast<unsigned int>(qubit));
304 NotifyObservers({qubit});
305 }
306
307 void ApplyT(Types::qubit_t qubit) override
308 {
309 tensorNetwork->AddGate(tgate, static_cast<unsigned int>(qubit));
310 NotifyObservers({qubit});
311 }
312
313 void ApplyTDG(Types::qubit_t qubit) override
314 {
315 tensorNetwork->AddGate(tdggate, static_cast<unsigned int>(qubit));
316 NotifyObservers({qubit});
317 }
318
319 void ApplySx(Types::qubit_t qubit) override
320 {
321 tensorNetwork->AddGate(sxgate, static_cast<unsigned int>(qubit));
322 NotifyObservers({qubit});
323 }
324
325 void ApplySxDAG(Types::qubit_t qubit) override
326 {
327 tensorNetwork->AddGate(sxdaggate, static_cast<unsigned int>(qubit));
328 NotifyObservers({qubit});
329 }
330
331 void ApplyK(Types::qubit_t qubit) override
332 {
333 tensorNetwork->AddGate(k, static_cast<unsigned int>(qubit));
334 NotifyObservers({qubit});
335 }
336
337 void ApplyRx(Types::qubit_t qubit, double theta) override
338 {
339 rxgate.SetTheta(theta);
340 tensorNetwork->AddGate(rxgate, static_cast<unsigned int>(qubit));
341 NotifyObservers({qubit});
342 }
343
344 void ApplyRy(Types::qubit_t qubit, double theta) override
345 {
346 rygate.SetTheta(theta);
347 tensorNetwork->AddGate(rygate, static_cast<unsigned int>(qubit));
348 NotifyObservers({qubit});
349 }
350
351 void ApplyRz(Types::qubit_t qubit, double theta) override
352 {
353 rzgate.SetTheta(theta);
354 tensorNetwork->AddGate(rzgate, static_cast<unsigned int>(qubit));
355 NotifyObservers({qubit});
356 }
357
358 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda, double gamma) override
359 {
360 ugate.SetParams(theta, phi, lambda, gamma);
361 tensorNetwork->AddGate(ugate, static_cast<unsigned int>(qubit));
362 NotifyObservers({qubit});
363 }
364
365 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
366 {
367 tensorNetwork->AddGate(cxgate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
368 NotifyObservers({tgt_qubit, ctrl_qubit});
369 }
370
371 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
372 {
373 tensorNetwork->AddGate(cygate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
374 NotifyObservers({tgt_qubit, ctrl_qubit});
375 }
376
377 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
378 {
379 tensorNetwork->AddGate(czgate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
380 NotifyObservers({tgt_qubit, ctrl_qubit});
381 }
382
383 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double lambda) override
384 {
385 cpgate.SetPhaseShift(lambda);
386 tensorNetwork->AddGate(cpgate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
387 NotifyObservers({tgt_qubit, ctrl_qubit});
388 }
389
390 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
391 {
392 crxgate.SetTheta(theta);
393 tensorNetwork->AddGate(crxgate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
394 NotifyObservers({tgt_qubit, ctrl_qubit});
395 }
396
397 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
398 {
399 crygate.SetTheta(theta);
400 tensorNetwork->AddGate(crygate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
401 NotifyObservers({tgt_qubit, ctrl_qubit});
402 }
403
404 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
405 {
406 crzgate.SetTheta(theta);
407 tensorNetwork->AddGate(crzgate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
408 NotifyObservers({tgt_qubit, ctrl_qubit});
409 }
410
411 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
412 {
413 tensorNetwork->AddGate(ch, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
414 NotifyObservers({tgt_qubit, ctrl_qubit});
415 }
416
417 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
418 {
419 tensorNetwork->AddGate(csx, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
420 NotifyObservers({tgt_qubit, ctrl_qubit});
421 }
422
423 void ApplyCSxDAG(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
424 {
425 tensorNetwork->AddGate(csxdag, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
426 NotifyObservers({tgt_qubit, ctrl_qubit});
427 }
428
429 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override
430 {
431 tensorNetwork->AddGate(swapgate, static_cast<unsigned int>(qubit0), static_cast<unsigned int>(qubit1));
432 NotifyObservers({qubit1, qubit0});
433 }
434
435 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1, Types::qubit_t qubit2) override
436 {
437 const size_t q1 = qubit0;
438 const size_t q2 = qubit1;
439 const size_t q3 = qubit2;
440 tensorNetwork->AddGate(csx, static_cast<unsigned int>(q2), static_cast<unsigned int>(q3));
441 NotifyObservers({qubit1, qubit2});
442 tensorNetwork->AddGate(cxgate, static_cast<unsigned int>(q1), static_cast<unsigned int>(q2));
443 NotifyObservers({qubit0, qubit1});
444 tensorNetwork->AddGate(csxdag, static_cast<unsigned int>(q2), static_cast<unsigned int>(q3));
445 NotifyObservers({qubit1, qubit2});
446 tensorNetwork->AddGate(cxgate, static_cast<unsigned int>(q1), static_cast<unsigned int>(q2));
447 NotifyObservers({qubit0, qubit1});
448 tensorNetwork->AddGate(csx, static_cast<unsigned int>(q1), static_cast<unsigned int>(q3));
449 NotifyObservers({qubit0, qubit2});
450 }
451
452 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0, Types::qubit_t qubit1) override
453 {
454 const size_t q1 = ctrl_qubit;
455 const size_t q2 = qubit0;
456 const size_t q3 = qubit1;
457 tensorNetwork->AddGate(cxgate, static_cast<unsigned int>(q3), static_cast<unsigned int>(q2));
458 NotifyObservers({qubit1, qubit0});
459 tensorNetwork->AddGate(csx, static_cast<unsigned int>(q2), static_cast<unsigned int>(q3));
460 NotifyObservers({qubit0, qubit1});
461 tensorNetwork->AddGate(cxgate, static_cast<unsigned int>(q1), static_cast<unsigned int>(q2));
462 NotifyObservers({ctrl_qubit, qubit0});
463 pgate.SetPhaseShift(M_PI);
464 tensorNetwork->AddGate(pgate, static_cast<unsigned int>(q3));
465 NotifyObservers({qubit1});
466 pgate.SetPhaseShift(-M_PI_2);
467 tensorNetwork->AddGate(pgate, static_cast<unsigned int>(q2));
468 NotifyObservers({qubit0});
469 tensorNetwork->AddGate(csx, static_cast<unsigned int>(q2), static_cast<unsigned int>(q3));
470 NotifyObservers({qubit0, qubit1});
471 tensorNetwork->AddGate(cxgate, static_cast<unsigned int>(q1), static_cast<unsigned int>(q2));
472 NotifyObservers({ctrl_qubit, qubit0});
473 pgate.SetPhaseShift(M_PI);
474 tensorNetwork->AddGate(pgate, static_cast<unsigned int>(q3));
475 NotifyObservers({qubit1});
476 tensorNetwork->AddGate(csx, static_cast<unsigned int>(q1), static_cast<unsigned int>(q3));
477 NotifyObservers({ctrl_qubit, qubit1});
478 tensorNetwork->AddGate(cxgate, static_cast<unsigned int>(q3), static_cast<unsigned int>(q2));
479 NotifyObservers({qubit1, qubit0});
480 }
481
482 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta, double phi, double lambda, double gamma) override
483 {
484 cugate.SetParams(theta, phi, lambda, gamma);
485 tensorNetwork->AddGate(cugate, static_cast<unsigned int>(ctrl_qubit), static_cast<unsigned int>(tgt_qubit));
486 NotifyObservers({tgt_qubit, ctrl_qubit});
487 }
488
489 std::unique_ptr<ISimulator> Clone() override
490 {
491 auto cloned = std::make_unique<QCSimTensorNetworkSimulator>();
492 cloned->nrQubits = nrQubits;
493 cloned->enableMultithreading = enableMultithreading;
494 cloned->upcomingGates = upcomingGates;
495 cloned->upcomingGateIndex = upcomingGateIndex;
496 if (tensorNetwork)
497 cloned->tensorNetwork = tensorNetwork->Clone();
498 for (const auto &[key, value] : configuration.GetConfigMap())
499 cloned->Configure(key.c_str(), value.c_str());
500 if (configuration.IsSet("seed"))
501 cloned->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration("seed")), nextSeedStream++));
502 return cloned;
503 }
504
505 protected:
506 std::unique_ptr<TensorNetworks::TensorNetwork> tensorNetwork;
507};
508} // namespace Simulators::Private
509#endif
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)
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)
int ApplyGenericOneQubitGate(void *sim, unsigned long q0, const double *buffer)
int ApplyGenericTwoQubitGate(void *sim, unsigned long q0, unsigned long q1, const double *buffer)
int SaveState(void *sim)
SimulationType
The type of simulation.
Definition State.h:109
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:24
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:23