Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QCSimMPSSimulator.h
Go to the documentation of this file.
1#pragma once
2#if defined(INCLUDED_BY_FACTORY)
3#include "MPSSimulator.h"
5#define _USE_MATH_DEFINES
6#include <math.h>
7
9{
10// matrix_product_state backend. Owns exactly one native QCSim implementation.
11class QCSimMPSSimulator : public QCSimTensorChainSimulator
12{
13 public:
14 QCSimMPSSimulator() : QCSimTensorChainSimulator(false)
15 {
16 configuration.SetConfiguration("method", "matrix_product_state");
17 }
18
19 const char *MethodName() const override
20 {
21 return "matrix_product_state";
22 }
23
24 void Initialize() override
25 {
26 InvalidateBoundedRouting(true);
27 RefreshRoutingSettings();
28 InvalidateDummyHistory();
29 if (nrQubits != 0)
30 {
31 {
32 mpsSimulator = std::make_unique<QC::TensorNetworks::MPSSimulator>(nrQubits);
33 if (!useOptimalMeetingPosition)
34 mpsSimulator->SetUseOptimalMeetingPosition(false);
35 InstallBondSummary(*mpsSimulator, bondDimensionCallback);
36 curMaxBondDim = 1;
37 }
38 SetMultithreading(enableMultithreading);
39 for (const auto &[key, value] : configuration.GetConfigMap())
40 if (key != "method")
41 Configure(key.c_str(), value.c_str());
42 }
43 RefreshRoutingCallback();
44 }
45
46 void InitializeToBasisState(size_t num_qubits, Types::qubit_t basisState) override
47 {
48 if (num_qubits == 0)
49 return;
50 Clear();
51 nrQubits = num_qubits;
52 Initialize();
53 mpsSimulator->setToBasisState(static_cast<size_t>(basisState));
54 }
55
56 void InitializeToBasisState(size_t num_qubits, const std::vector<bool> &basisState) override
57 {
58 if (num_qubits == 0)
59 return;
60 Clear();
61 nrQubits = num_qubits;
62 Initialize();
63 mpsSimulator->setToBasisState(basisState);
64 }
65
66 void Reset() override
67 {
68 if (mpsSimulator)
69 {
70 mpsSimulator->Clear();
71 curMaxBondDim = 1;
72 }
73 upcomingGateIndex = 0;
74 ResetDummySimulator();
75 }
76
77 void SetInitialQubitsMap(const std::vector<long long int> &initialMap) override
78 {
79 if (mpsSimulator)
80 {
81 mpsSimulator->SetInitialQubitsMap(initialMap);
82 EnsureDummySimulator(initialMap.size());
83 dummySim->SetInitialQubitsMap(initialMap);
84 }
85 }
86
87 void SetUseOptimalMeetingPosition(bool enable) override
88 {
89 useOptimalMeetingPosition = enable;
90 RefreshRoutingSettings();
91 if (mpsSimulator)
92 mpsSimulator->SetUseOptimalMeetingPosition(enable);
93 RefreshRoutingCallback();
94 }
95
96 void Configure(const char *key, const char *value) override
97 {
98 if (std::string("method") == key)
99 {
100 ValidateMethod(value);
101 configuration.SetConfiguration(key, value);
102 return;
103 }
104 if (!configuration.WasApplied(key, value))
105 configuration.SetConfiguration(key, value);
106 RefreshRoutingSettings();
107 if (std::string("seed") == key)
108 {
109 const uint64_t seed = std::stoull(value);
110 SeedAuxiliaryRng(seed);
111 nextSeedStream = 0;
112 rng.seed(seed);
113 if (mpsSimulator)
114 SeedBackend(mpsSimulator.get(), seed);
115 return;
116 }
117 if (mpsSimulator)
118 {
119 if (std::string(key) == "matrix_product_state_max_bond_dimension")
120 {
121 const auto limit = configuration.GetConfigurationAsInt(key);
122 mpsSimulator->setLimitBondDimension(limit);
123 if (dummySim)
124 dummySim->SetMaxBondDimension(EffectiveLookaheadMaxBondDimension(dummySim->getNrQubits(), limit));
125 }
126 else if (std::string(key) == "matrix_product_state_truncation_threshold")
127 {
128 const double threshold = configuration.GetConfigurationAsDouble(key);
129 if (threshold >= 0.)
130 mpsSimulator->setLimitEntanglement(threshold);
131 }
132 else if (std::string(key) == "matrix_product_state_truncation_mode")
133 {
134 if (std::string(value) == "relative_max")
135 mpsSimulator->setTruncationMode(QC::TensorNetworks::MPSSimulator::TruncationMode::RelativeToMax);
136 else if (std::string(value) == "discarded_weight")
137 mpsSimulator->setTruncationMode(QC::TensorNetworks::MPSSimulator::TruncationMode::DiscardedWeight);
138 }
139 }
140 if (std::string(key) == "pauli_propagator_workers")
141 {
142 const auto workers = configuration.GetConfigurationAsUnsigned(key);
143 if (workers > 1024)
144 throw std::invalid_argument("pauli_propagator_workers exceeds 1024");
145 }
146 RefreshRoutingCallback();
147 }
148
149 size_t AllocateQubits(size_t num_qubits) override
150 {
151 if (mpsSimulator)
152 return 0;
153 const size_t oldNrQubits = nrQubits;
154 nrQubits += num_qubits;
155 return oldNrQubits;
156 }
157
158 void Clear() override
159 {
160 automaticRoutingDepth = false;
161 InvalidateBoundedRouting(true);
162 mpsSimulator = nullptr;
163 ClearDummySimulator();
164 nrQubits = 0;
165 upcomingGateIndex = 0;
166 upcomingGates.clear();
167 }
168
169 size_t Measure(const Types::qubits_vector &qubits) override
170 {
171 InvalidateDummyHistory();
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"
175 << std::endl;
176 size_t res = 0;
177 size_t mask = 1ULL;
178 DontNotify();
179 {
180 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
181 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
182 for (Types::qubit_t qubit : qubits)
183 {
184 if (measured[qubit])
185 res |= mask;
186 mask <<= 1;
187 }
188 }
189 Notify();
190 NotifyObservers(qubits);
191 return res;
192 }
193
194 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override
195 {
196 InvalidateDummyHistory();
197 std::vector<bool> res(qubits.size(), false);
198 DontNotify();
199 {
200 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
201 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
202 for (size_t q = 0; q < qubits.size(); ++q)
203 if (measured[qubits[q]])
204 res[q] = true;
205 }
206 Notify();
207 NotifyObservers(qubits);
208 return res;
209 }
210
211 void ApplyReset(const Types::qubits_vector &qubits) override
212 {
213 InvalidateDummyHistory();
214 DontNotify();
215 {
216 for (size_t qubit : qubits)
217 if (mpsSimulator->MeasureQubit(static_cast<unsigned int>(qubit)))
218 mpsSimulator->ApplyGate(xgate, static_cast<unsigned int>(qubit));
219 }
220 Notify();
221 NotifyObservers(qubits);
222 }
223
224 void MoveAtBeginningOfChain(const Types::qubits_vector &qubits) override
225 {
226 if (!mpsSimulator)
227 return IState::MoveAtBeginningOfChain(qubits);
228 const auto selected = MPOValidation::Qubits(qubits, nrQubits);
229 const std::set<Eigen::Index> targets(selected.begin(), selected.end());
230 mpsSimulator->MoveAtBeginningOfChain(targets);
231 InvalidateDummyHistory();
232 }
233
234 std::vector<std::complex<double>> GetStateVector() override
235 {
236 if (!mpsSimulator)
237 return IState::GetStateVector();
238 if (!nrQubits)
239 return {};
240 const auto count = TensorQueries::DenseSize(nrQubits);
241 const auto values = mpsSimulator->getRegisterStorage();
242 if (static_cast<size_t>(values.size()) != count)
243 throw std::runtime_error("QCSim statevector query returned an invalid size");
244 return {values.data(), values.data() + values.size()};
245 }
246
247 std::complex<double> ExpectationValueOperators(const Types::qubits_vector &qubits, const std::vector<Eigen::MatrixXcd> &matrices) override
248 {
249 if (!mpsSimulator)
250 return IState::ExpectationValueOperators(qubits, matrices);
251 TensorQueries::Operators(qubits, matrices, nrQubits);
252 std::vector<QC::Gates::AppliedGate<>> gates;
253 gates.reserve(qubits.size());
254 for (size_t i = 0; i < qubits.size(); ++i)
255 gates.emplace_back(matrices[i], qubits[i]);
256 return mpsSimulator->ExpectationValue(gates);
257 }
258
259 void Trim() override
260 {
261 InvalidateDummyHistory();
262 if (mpsSimulator)
263 mpsSimulator->Trim();
264 else
265 throw std::runtime_error("Trim is only available for QCSim MPS and MPO");
266 }
267
268 void ReCanonicalize() override
269 {
270 InvalidateDummyHistory();
271 if (mpsSimulator)
272 mpsSimulator->ReCanonicalize();
273 else
274 throw std::runtime_error("Canonicalization is only available for QCSim MPS and MPO");
275 }
276
277 double Probability(Types::qubit_t outcome) override
278 {
279 return mpsSimulator->getBasisStateProbability(static_cast<unsigned int>(outcome));
280 }
281
282 std::complex<double> Amplitude(Types::qubit_t outcome) override
283 {
284 return mpsSimulator->getBasisStateAmplitude(static_cast<unsigned int>(outcome));
285 }
286
287 std::complex<double> ProjectOnZero() override
288 {
289 return mpsSimulator->ProjectOnZero();
290 }
291
292 std::vector<double> AllProbabilities() override
293 {
294 const Eigen::VectorXcd probs = mpsSimulator->getRegisterStorage().cwiseAbs2();
295 std::vector<double> result(probs.size());
296 for (int i = 0; i < probs.size(); ++i)
297 result[i] = probs[i].real();
298 return result;
299 }
300
301 std::vector<double> Probabilities(const Types::qubits_vector &qubits) override
302 {
303 std::vector<double> result(qubits.size());
304 {
305 for (int i = 0; i < static_cast<int>(qubits.size()); ++i)
306 result[i] = mpsSimulator->getBasisStateProbability(qubits[i]);
307 }
308 return result;
309 }
310
311 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(const Types::qubits_vector &qubits, size_t shots = 1000) override
312 {
313 if (qubits.empty() || shots == 0)
314 return {};
315 if (qubits.size() > sizeof(size_t) * 8)
316 std::cerr << "Warning: The number of qubits to measure is larger than the "
317 "number of bits in the size_t type, the outcome will be undefined"
318 << std::endl;
319 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
320 DontNotify();
321 {
322 bool normal = true;
323 if (!configuration.IsSet("mps_sample_measure_algorithm") || configuration.GetConfiguration("mps_sample_measure_algorithm") == "mps_probabilities")
324 {
325 const std::set<Eigen::Index> qset(qubits.begin(), qubits.end());
326 if (qset.size() == GetNumberOfQubits())
327 {
328 normal = false;
329 for (size_t shot = 0; shot < shots; ++shot)
330 {
331 const size_t measRaw = MeasureNoCollapse();
332 size_t meas = 0;
333 size_t mask = 1ULL;
334 for (auto q : qubits)
335 {
336 const size_t qubitMask = 1ULL << q;
337 if (measRaw & qubitMask)
338 meas |= mask;
339 mask <<= 1ULL;
340 }
341 ++result[meas];
342 }
343 }
344 else if (qset.size() > 1)
345 {
346 mpsSimulator->MoveAtBeginningOfChain(qset);
347 InvalidateDummyHistory();
348 normal = false;
349 for (size_t shot = 0; shot < shots; ++shot)
350 {
351 const auto measRaw = mpsSimulator->MeasureNoCollapse(qset);
352 size_t meas = 0;
353 size_t mask = 1ULL;
354 for (auto q : qubits)
355 {
356 if (measRaw.at(q))
357 meas |= mask;
358 mask <<= 1ULL;
359 }
360 ++result[meas];
361 }
362 }
363 else if (qset.size() == 1)
364 {
365 normal = false;
366 const auto prob0 = mpsSimulator->GetProbability(qubits[0]);
367 for (size_t shot = 0; shot < shots; ++shot)
368 {
369 const size_t meas = uniformZeroOne(rng) < prob0 ? 0ULL : 1ULL;
370 size_t m = meas;
371 for (size_t i = 1; i < qubits.size(); ++i)
372 {
373 m <<= 1ULL;
374 m |= meas;
375 }
376 ++result[m];
377 }
378 }
379 }
380 if (normal)
381 {
382 auto savedState = mpsSimulator->getState();
383 const auto savedHistory = CaptureDummyHistory();
384 for (size_t shot = 0; shot < shots; ++shot)
385 {
386 const size_t meas = Measure(qubits);
387 ++result[meas];
388 mpsSimulator->setState(savedState);
389 }
390 RestoreDummyHistory(savedHistory);
391 }
392 }
393 Notify();
394 NotifyObservers(qubits);
395 return result;
396 }
397
398 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(const Types::qubits_vector &qubits, size_t shots = 1000) override
399 {
400 if (qubits.empty() || shots == 0)
401 return {};
402 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
403 DontNotify();
404 {
405 bool normal = true;
406 if (!configuration.IsSet("mps_sample_measure_algorithm") || configuration.GetConfiguration("mps_sample_measure_algorithm") == "mps_probabilities")
407 {
408 const std::set<Eigen::Index> qset(qubits.begin(), qubits.end());
409 if (qset.size() == GetNumberOfQubits())
410 {
411 normal = false;
412 for (size_t shot = 0; shot < shots; ++shot)
413 {
414 const auto meas = MeasureNoCollapseMany();
415 std::vector<bool> measVec(qubits.size());
416 for (size_t i = 0; i < qubits.size(); ++i)
417 measVec[i] = meas[qubits[i]];
418 ++result[measVec];
419 }
420 }
421 else if (qset.size() > 1)
422 {
423 mpsSimulator->MoveAtBeginningOfChain(qset);
424 InvalidateDummyHistory();
425 normal = false;
426 for (size_t shot = 0; shot < shots; ++shot)
427 {
428 const auto meas = mpsSimulator->MeasureNoCollapse(qset);
429 std::vector<bool> measVec(qubits.size());
430 for (size_t i = 0; i < qubits.size(); ++i)
431 measVec[i] = meas.at(qubits[i]);
432 ++result[measVec];
433 }
434 }
435 else if (qset.size() == 1)
436 {
437 normal = false;
438 const auto prob0 = mpsSimulator->GetProbability(qubits[0]);
439 for (size_t shot = 0; shot < shots; ++shot)
440 {
441 const size_t meas = uniformZeroOne(rng) < prob0 ? 0ULL : 1ULL;
442 const std::vector<bool> m(qubits.size(), meas);
443 ++result[m];
444 }
445 }
446 }
447 if (normal)
448 {
449 auto savedState = mpsSimulator->getState();
450 const auto savedHistory = CaptureDummyHistory();
451 for (size_t shot = 0; shot < shots; ++shot)
452 {
453 const auto meas = MeasureMany(qubits);
454 ++result[meas];
455 mpsSimulator->setState(savedState);
456 }
457 RestoreDummyHistory(savedHistory);
458 }
459 }
460 Notify();
461 NotifyObservers(qubits);
462 return result;
463 }
464
465 std::vector<double> ExpectationValues(const std::vector<std::string> &paulis) override
466 {
467 std::vector<double> result(paulis.size(), 1.);
468 std::vector<std::string> selected;
469 std::vector<size_t> indices;
470 const size_t n = GetNumberOfQubits();
471 for (size_t i = 0; i < paulis.size(); ++i)
472 {
473 if (paulis[i].empty())
474 continue;
475 bool zero = false;
476 for (size_t q = n; q < paulis[i].size(); ++q)
477 {
478 const auto p = toupper(static_cast<unsigned char>(paulis[i][q]));
479 if (p != 'I' && p != 'Z')
480 {
481 zero = true;
482 break;
483 }
484 }
485 if (zero)
486 {
487 result[i] = 0.;
488 continue;
489 }
490 std::string pauli = paulis[i];
491 pauli.resize(n, 'I');
492 for (char &p : pauli)
493 {
494 p = static_cast<char>(toupper(static_cast<unsigned char>(p)));
495 if (p != 'X' && p != 'Y' && p != 'Z')
496 p = 'I';
497 }
498 indices.push_back(i);
499 selected.push_back(std::move(pauli));
500 }
501 if (selected.empty())
502 return result;
503 const auto values = TensorExpectationBatch(*mpsSimulator, selected);
504 for (size_t i = 0; i < indices.size(); ++i)
505 result[indices[i]] = values[i].real();
506 return result;
507 }
508
509 double ExpectationValue(const std::string &pauliStringOrig) override
510 {
511 if (pauliStringOrig.empty())
512 return 1.0;
513 std::string pauliString = pauliStringOrig;
514 if (pauliString.size() > GetNumberOfQubits())
515 {
516 for (size_t i = GetNumberOfQubits(); i < pauliString.size(); ++i)
517 {
518 const auto pauliOp = toupper(pauliString[i]);
519 if (pauliOp != 'I' && pauliOp != 'Z')
520 return 0.0;
521 }
522 pauliString.resize(GetNumberOfQubits());
523 }
524 std::vector<QC::Gates::AppliedGate<Eigen::MatrixXcd>> pauliStringVec;
525 pauliStringVec.reserve(pauliString.size());
526 for (size_t q = 0; q < pauliString.size(); ++q)
527 {
528 switch (toupper(pauliString[q]))
529 {
530 case 'X': {
531 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(xgate.getRawOperatorMatrix(), static_cast<Types::qubit_t>(q));
532 pauliStringVec.emplace_back(std::move(ag));
533 }
534 break;
535 case 'Y': {
536 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(ygate.getRawOperatorMatrix(), static_cast<Types::qubit_t>(q));
537 pauliStringVec.emplace_back(std::move(ag));
538 }
539 break;
540 case 'Z': {
541 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(zgate.getRawOperatorMatrix(), static_cast<Types::qubit_t>(q));
542 pauliStringVec.emplace_back(std::move(ag));
543 }
544 break;
545 case 'I':
546 [[fallthrough]];
547 default:
548 break;
549 }
550 }
551 if (pauliStringVec.empty())
552 return 1.0;
553 return mpsSimulator->ExpectationValue(pauliStringVec).real();
554 }
555
556 SimulationType GetSimulationType() const override
557 {
558 return SimulationType::kMatrixProductState;
559 }
560
561 void SaveState() override
562 {
563 mpsSimulator->SaveState();
564 SaveDummyState();
565 }
566
567 void RestoreState() override
568 {
569 mpsSimulator->RestoreState();
570 RestoreDummyState();
571 }
572
573 void SetMultithreading(bool multithreading = true) override
574 {
575 enableMultithreading = multithreading;
576 if (mpsSimulator)
577 mpsSimulator->SetMultithreading(multithreading);
578 }
579
581 {
582 if (GetNumberOfQubits() > sizeof(Types::qubit_t) * 8)
583 std::cerr << "Warning: The number of qubits to measure is larger than the "
584 "number of bits in the Types::qubit_t type, the outcome will be "
585 "undefined"
586 << std::endl;
587 {
588 const auto measured = mpsSimulator->MeasureNoCollapse();
589 Types::qubit_t result = 0;
590 Types::qubit_t mask = 1;
591 for (Types::qubit_t q = 0; q < measured.size(); ++q)
592 {
593 if (measured.at(q))
594 result |= mask;
595 mask <<= 1;
596 }
597 return result;
598 }
599 }
600
601 std::vector<bool> MeasureNoCollapseMany() override
602 {
603 const auto measured = mpsSimulator->MeasureNoCollapse();
604 std::vector<bool> res(nrQubits);
605 for (size_t i = 0; i < nrQubits; ++i)
606 res[i] = measured.at(i);
607 return res;
608 }
609
610 void ApplyGenericOneQubitGate(Types::qubit_t qubit, const Eigen::Matrix2cd &gate) override
611 {
612 const QC::Gates::AppliedGate<> agate(gate, qubit);
613 mpsSimulator->ApplyGate(agate);
614 NotifyObservers({qubit});
615 }
616
617 void ApplyGenericTwoQubitGate(Types::qubit_t qubit0, Types::qubit_t qubit1, const Eigen::Matrix4cd &gate) override
618 {
619 if (IsExactSwapMatrix(gate))
620 return ApplySwap(qubit0, qubit1);
621 const QC::Gates::AppliedGate<> agate(gate, qubit0, qubit1);
622 mpsSimulator->ApplyGate(agate);
623 RecordExecutedTwoQubitGate(qubit0, qubit1, false, EffectiveSchmidtRank(gate));
624 NotifyObservers({qubit0, qubit1});
625 }
626
627 void ApplyP(Types::qubit_t qubit, double lambda) override
628 {
629 pgate.SetPhaseShift(lambda);
630 mpsSimulator->ApplyGate(pgate, static_cast<unsigned int>(qubit));
631 NotifyObservers({qubit});
632 }
633
634 void ApplyX(Types::qubit_t qubit) override
635 {
636 mpsSimulator->ApplyGate(xgate, static_cast<unsigned int>(qubit));
637 NotifyObservers({qubit});
638 }
639
640 void ApplyY(Types::qubit_t qubit) override
641 {
642 mpsSimulator->ApplyGate(ygate, static_cast<unsigned int>(qubit));
643 NotifyObservers({qubit});
644 }
645
646 void ApplyZ(Types::qubit_t qubit) override
647 {
648 mpsSimulator->ApplyGate(zgate, static_cast<unsigned int>(qubit));
649 NotifyObservers({qubit});
650 }
651
652 void ApplyH(Types::qubit_t qubit) override
653 {
654 mpsSimulator->ApplyGate(h, static_cast<unsigned int>(qubit));
655 NotifyObservers({qubit});
656 }
657
658 void ApplyS(Types::qubit_t qubit) override
659 {
660 mpsSimulator->ApplyGate(sgate, static_cast<unsigned int>(qubit));
661 NotifyObservers({qubit});
662 }
663
664 void ApplySDG(Types::qubit_t qubit) override
665 {
666 mpsSimulator->ApplyGate(sdggate, static_cast<unsigned int>(qubit));
667 NotifyObservers({qubit});
668 }
669
670 void ApplyT(Types::qubit_t qubit) override
671 {
672 mpsSimulator->ApplyGate(tgate, static_cast<unsigned int>(qubit));
673 NotifyObservers({qubit});
674 }
675
676 void ApplyTDG(Types::qubit_t qubit) override
677 {
678 mpsSimulator->ApplyGate(tdggate, static_cast<unsigned int>(qubit));
679 NotifyObservers({qubit});
680 }
681
682 void ApplySx(Types::qubit_t qubit) override
683 {
684 mpsSimulator->ApplyGate(sxgate, static_cast<unsigned int>(qubit));
685 NotifyObservers({qubit});
686 }
687
688 void ApplySxDAG(Types::qubit_t qubit) override
689 {
690 mpsSimulator->ApplyGate(sxdaggate, static_cast<unsigned int>(qubit));
691 NotifyObservers({qubit});
692 }
693
694 void ApplyK(Types::qubit_t qubit) override
695 {
696 mpsSimulator->ApplyGate(k, static_cast<unsigned int>(qubit));
697 NotifyObservers({qubit});
698 }
699
700 void ApplyRx(Types::qubit_t qubit, double theta) override
701 {
702 rxgate.SetTheta(theta);
703 mpsSimulator->ApplyGate(rxgate, static_cast<unsigned int>(qubit));
704 NotifyObservers({qubit});
705 }
706
707 void ApplyRy(Types::qubit_t qubit, double theta) override
708 {
709 rygate.SetTheta(theta);
710 mpsSimulator->ApplyGate(rygate, static_cast<unsigned int>(qubit));
711 NotifyObservers({qubit});
712 }
713
714 void ApplyRz(Types::qubit_t qubit, double theta) override
715 {
716 rzgate.SetTheta(theta);
717 mpsSimulator->ApplyGate(rzgate, static_cast<unsigned int>(qubit));
718 NotifyObservers({qubit});
719 }
720
721 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda, double gamma) override
722 {
723 ugate.SetParams(theta, phi, lambda, gamma);
724 mpsSimulator->ApplyGate(ugate, static_cast<unsigned int>(qubit));
725 NotifyObservers({qubit});
726 }
727
728 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
729 {
730 mpsSimulator->ApplyGate(cxgate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
731 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, 2.);
732 NotifyObservers({tgt_qubit, ctrl_qubit});
733 }
734
735 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
736 {
737 mpsSimulator->ApplyGate(cygate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
738 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, 2.);
739 NotifyObservers({tgt_qubit, ctrl_qubit});
740 }
741
742 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
743 {
744 mpsSimulator->ApplyGate(czgate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
745 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, 2.);
746 NotifyObservers({tgt_qubit, ctrl_qubit});
747 }
748
749 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double lambda) override
750 {
751 cpgate.SetPhaseShift(lambda);
752 mpsSimulator->ApplyGate(cpgate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
753 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, ControlledSchmidtRank(2. * std::abs(std::cos(lambda / 2.))));
754 NotifyObservers({tgt_qubit, ctrl_qubit});
755 }
756
757 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
758 {
759 crxgate.SetTheta(theta);
760 mpsSimulator->ApplyGate(crxgate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
761 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, ControlledSchmidtRank(2. * std::abs(std::cos(theta / 2.))));
762 NotifyObservers({tgt_qubit, ctrl_qubit});
763 }
764
765 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
766 {
767 crygate.SetTheta(theta);
768 mpsSimulator->ApplyGate(crygate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
769 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, ControlledSchmidtRank(2. * std::abs(std::cos(theta / 2.))));
770 NotifyObservers({tgt_qubit, ctrl_qubit});
771 }
772
773 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
774 {
775 crzgate.SetTheta(theta);
776 mpsSimulator->ApplyGate(crzgate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
777 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, ControlledSchmidtRank(2. * std::abs(std::cos(theta / 2.))));
778 NotifyObservers({tgt_qubit, ctrl_qubit});
779 }
780
781 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
782 {
783 mpsSimulator->ApplyGate(ch, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
784 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, 2.);
785 NotifyObservers({tgt_qubit, ctrl_qubit});
786 }
787
788 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
789 {
790 mpsSimulator->ApplyGate(csx, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
791 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, ControlledSchmidtRank(std::sqrt(2.)));
792 NotifyObservers({tgt_qubit, ctrl_qubit});
793 }
794
795 void ApplyCSxDAG(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
796 {
797 mpsSimulator->ApplyGate(csxdag, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
798 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, ControlledSchmidtRank(std::sqrt(2.)));
799 NotifyObservers({tgt_qubit, ctrl_qubit});
800 }
801
802 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override
803 {
804 mpsSimulator->ApplyGate(swapgate, static_cast<unsigned int>(qubit1), static_cast<unsigned int>(qubit0));
805 RecordExecutedTwoQubitGate(qubit0, qubit1, true, 4.);
806 NotifyObservers({qubit1, qubit0});
807 }
808
809 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1, Types::qubit_t qubit2) override
810 {
811 {
812 DecompositionScope scope(*this);
813 const size_t q1 = qubit0;
814 const size_t q2 = qubit1;
815 const size_t q3 = qubit2;
816 mpsSimulator->ApplyGate(csx, static_cast<unsigned int>(q3), static_cast<unsigned int>(q2));
817 RecordExecutedTwoQubitGate(qubit1, qubit2, false, 2.);
818 NotifyObservers({qubit1, qubit2});
819 mpsSimulator->ApplyGate(cxgate, static_cast<unsigned int>(q2), static_cast<unsigned int>(q1));
820 RecordExecutedTwoQubitGate(qubit0, qubit1, false, 2.);
821 NotifyObservers({qubit0, qubit1});
822 mpsSimulator->ApplyGate(csxdag, static_cast<unsigned int>(q3), static_cast<unsigned int>(q2));
823 RecordExecutedTwoQubitGate(qubit1, qubit2, false, 2.);
824 NotifyObservers({qubit1, qubit2});
825 mpsSimulator->ApplyGate(cxgate, static_cast<unsigned int>(q2), static_cast<unsigned int>(q1));
826 RecordExecutedTwoQubitGate(qubit0, qubit1, false, 2.);
827 NotifyObservers({qubit0, qubit1});
828 mpsSimulator->ApplyGate(csx, static_cast<unsigned int>(q3), static_cast<unsigned int>(q1));
829 RecordExecutedTwoQubitGate(qubit0, qubit2, false, 2.);
830 NotifyObservers({qubit0, qubit2});
831 }
832 NotifyObservers({qubit2, qubit1, qubit0});
833 }
834
835 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0, Types::qubit_t qubit1) override
836 {
837 {
838 DecompositionScope scope(*this);
839 const size_t q1 = ctrl_qubit;
840 const size_t q2 = qubit0;
841 const size_t q3 = qubit1;
842 mpsSimulator->ApplyGate(cxgate, static_cast<unsigned int>(q2), static_cast<unsigned int>(q3));
843 RecordExecutedTwoQubitGate(qubit1, qubit0, false, 2.);
844 NotifyObservers({qubit1, qubit0});
845 mpsSimulator->ApplyGate(csx, static_cast<unsigned int>(q3), static_cast<unsigned int>(q2));
846 RecordExecutedTwoQubitGate(qubit0, qubit1, false, 2.);
847 NotifyObservers({qubit0, qubit1});
848 mpsSimulator->ApplyGate(cxgate, static_cast<unsigned int>(q2), static_cast<unsigned int>(q1));
849 RecordExecutedTwoQubitGate(ctrl_qubit, qubit0, false, 2.);
850 NotifyObservers({ctrl_qubit, qubit0});
851 pgate.SetPhaseShift(M_PI);
852 mpsSimulator->ApplyGate(pgate, static_cast<unsigned int>(q3));
853 NotifyObservers({qubit1});
854 pgate.SetPhaseShift(-M_PI_2);
855 mpsSimulator->ApplyGate(pgate, static_cast<unsigned int>(q2));
856 NotifyObservers({qubit0});
857 mpsSimulator->ApplyGate(csx, static_cast<unsigned int>(q3), static_cast<unsigned int>(q2));
858 RecordExecutedTwoQubitGate(qubit0, qubit1, false, 2.);
859 NotifyObservers({qubit0, qubit1});
860 mpsSimulator->ApplyGate(cxgate, static_cast<unsigned int>(q2), static_cast<unsigned int>(q1));
861 RecordExecutedTwoQubitGate(ctrl_qubit, qubit0, false, 2.);
862 NotifyObservers({ctrl_qubit, qubit0});
863 pgate.SetPhaseShift(M_PI);
864 mpsSimulator->ApplyGate(pgate, static_cast<unsigned int>(q3));
865 NotifyObservers({qubit1});
866 mpsSimulator->ApplyGate(csx, static_cast<unsigned int>(q3), static_cast<unsigned int>(q1));
867 RecordExecutedTwoQubitGate(ctrl_qubit, qubit1, false, 2.);
868 NotifyObservers({ctrl_qubit, qubit1});
869 mpsSimulator->ApplyGate(cxgate, static_cast<unsigned int>(q2), static_cast<unsigned int>(q3));
870 RecordExecutedTwoQubitGate(qubit1, qubit0, false, 2.);
871 NotifyObservers({qubit1, qubit0});
872 }
873 NotifyObservers({qubit1, qubit0, ctrl_qubit});
874 }
875
876 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta, double phi, double lambda, double gamma) override
877 {
878 cugate.SetParams(theta, phi, lambda, gamma);
879 mpsSimulator->ApplyGate(cugate, static_cast<unsigned int>(tgt_qubit), static_cast<unsigned int>(ctrl_qubit));
880 RecordExecutedTwoQubitGate(ctrl_qubit, tgt_qubit, false, ControlledSchmidtRank(2. * std::abs(std::cos(theta / 2.) * std::cos((phi + lambda) / 2.))));
881 NotifyObservers({tgt_qubit, ctrl_qubit});
882 }
883
884 std::unique_ptr<ISimulator> Clone() override
885 {
886 auto cloned = std::make_unique<QCSimMPSSimulator>();
887 cloned->nrQubits = nrQubits;
888 cloned->enableMultithreading = enableMultithreading;
889 cloned->lookaheadDepth = lookaheadDepth;
890 cloned->automaticRoutingDepth = automaticRoutingDepth;
891 cloned->lookaheadDepthWithHeuristic = lookaheadDepthWithHeuristic;
892 cloned->useOptimalMeetingPosition = useOptimalMeetingPosition;
893 cloned->upcomingGates = upcomingGates;
894 cloned->upcomingGateIndex = upcomingGateIndex;
895 cloned->boundedRoutingOperations = boundedRoutingOperations;
896 cloned->boundedRoutingOperationsQubits = boundedRoutingOperationsQubits;
897 cloned->growthFactorGate = growthFactorGate;
898 cloned->growthFactorSwap = growthFactorSwap;
899 if (mpsSimulator)
900 {
901 cloned->mpsSimulator = mpsSimulator->Clone();
902 cloned->gateCounterObserver = std::make_shared<GateCounterObserver>(cloned->upcomingGateIndex);
903 cloned->RegisterObserver(cloned->gateCounterObserver);
904 cloned->curMaxBondDim = curMaxBondDim;
905 cloned->mpsSimulator->SetMeetingPositionCallback(cloned->meetingPositionCallback);
906 InstallBondSummary(*cloned->mpsSimulator, cloned->bondDimensionCallback);
907 }
908 for (const auto &[key, value] : configuration.GetConfigMap())
909 cloned->Configure(key.c_str(), value.c_str());
910 cloned->RefreshRoutingSettings();
911 cloned->dummySim = dummySim ? dummySim->Clone() : nullptr;
912 cloned->dummyHistoryValid = dummyHistoryValid;
913 cloned->savedDummyBondDims = savedDummyBondDims;
914 if (configuration.IsSet("seed"))
915 cloned->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration("seed")), nextSeedStream++));
916 cloned->RefreshRoutingCallback();
917 return cloned;
918 }
919
920 protected:
921 std::vector<double> CurrentBondDimensions() const override
922 {
923 if (!mpsSimulator)
924 return {};
925 const auto dims = mpsSimulator->getBondDimensions();
926 return {dims.begin(), dims.end()};
927 }
928
929 std::vector<long long> CurrentRoutingMap() const override
930 {
931 if (mpsSimulator)
932 return ReadRoutingMap(mpsSimulator.get());
933 return {};
934 }
935
936 void RefreshRoutingCallback() override
937 {
938 RefreshBoundedRouting();
939 const bool active = IsRoutingLookaheadEnabled() && !upcomingGates.empty();
940 if (mpsSimulator)
941 mpsSimulator->SetMeetingPositionCallback(active ? meetingPositionCallback : nullptr);
942 }
943
944 std::unique_ptr<QC::TensorNetworks::MPSSimulator> mpsSimulator;
945};
946} // namespace Simulators::Private
947#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)
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)
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)
std::vector< std::complex< double > > TensorExpectationBatch(T &backend, const std::vector< std::string > &paulis)
void InstallBondSummary(T &backend, Callback callback)
std::vector< long long > ReadRoutingMap(const T *simulator)
Definition RoutingMap.h:18
SimulationType
The type of simulation.
Definition State.h:109
double EffectiveSchmidtRank(const Eigen::MatrixXcd &u)
double ControlledSchmidtRank(double traceAbs)
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