Qrack  9.13
General classical-emulating-quantum development framework
qcircuit.hpp
Go to the documentation of this file.
1 //
3 // (C) Daniel Strano and the Qrack contributors 2017-2023. All rights reserved.
4 //
5 // This is a multithreaded, universal quantum register simulation, allowing
6 // (nonphysical) register cloning and direct measurement of probability and
7 // phase, to leverage what advantages classical emulation of qubits can have.
8 //
9 // Licensed under the GNU Lesser General Public License V3.
10 // See LICENSE.md in the project root or https://www.gnu.org/licenses/lgpl-3.0.en.html
11 // for details.
12 
13 #pragma once
14 
15 #include "qinterface.hpp"
16 
17 #include <algorithm>
18 #include <iostream>
19 #include <iterator>
20 #include <list>
21 
22 #define amp_leq_0(x) (norm(x) <= FP_NORM_EPSILON)
23 #define __IS_REAL_1(r) (abs(ONE_R1 - r) <= FP_NORM_EPSILON)
24 #define __IS_SAME(a, b) (norm((a) - (b)) <= FP_NORM_EPSILON)
25 #define __IS_CTRLED_CLIFFORD(top, bottom) \
26  ((__IS_REAL_1(std::real(top)) || __IS_REAL_1(std::imag(bottom))) && \
27  (__IS_SAME(top, bottom) || __IS_SAME(top, -bottom)))
28 #define __IS_CLIFFORD_PHASE_INVERT(top, bottom) \
29  (__IS_SAME(top, bottom) || __IS_SAME(top, -bottom) || __IS_SAME(top, I_CMPLX * bottom) || \
30  __IS_SAME(top, -I_CMPLX * bottom))
31 #define __IS_CLIFFORD(mtrx) \
32  ((__IS_PHASE(mtrx) && __IS_CLIFFORD_PHASE_INVERT(mtrx[0], mtrx[3])) || \
33  (__IS_INVERT(mtrx) && __IS_CLIFFORD_PHASE_INVERT(mtrx[1], mtrx[2])) || \
34  ((__IS_SAME(mtrx[0U], mtrx[1U]) || __IS_SAME(mtrx[0U], -mtrx[1U]) || \
35  __IS_SAME(mtrx[0U], I_CMPLX * mtrx[1U]) || __IS_SAME(mtrx[0U], -I_CMPLX * mtrx[1U])) && \
36  (__IS_SAME(mtrx[0U], mtrx[2U]) || __IS_SAME(mtrx[0U], -mtrx[2U]) || \
37  __IS_SAME(mtrx[0U], I_CMPLX * mtrx[2U]) || __IS_SAME(mtrx[0U], -I_CMPLX * mtrx[2U])) && \
38  (__IS_SAME(mtrx[0U], mtrx[3U]) || __IS_SAME(mtrx[0U], -mtrx[3U]) || \
39  __IS_SAME(mtrx[0U], I_CMPLX * mtrx[3U]) || IS_SAME(mtrx[0U], -I_CMPLX * mtrx[3U]))))
40 #define __IS_PHASE(mtrx) (IS_NORM_0(mtrx[1U]) && IS_NORM_0(mtrx[2U]))
41 #define __IS_INVERT(mtrx) (IS_NORM_0(mtrx[0U]) && IS_NORM_0(mtrx[3U]))
42 
43 namespace Qrack {
44 
48 struct QCircuitGate;
49 typedef std::shared_ptr<QCircuitGate> QCircuitGatePtr;
50 
51 struct QCircuitGate {
53  std::map<bitCapInt, std::shared_ptr<complex>> payloads;
54  std::set<bitLenInt> controls;
55 
60  : target(0U)
61  , payloads()
62  , controls()
63 
64  {
65  Clear();
66  }
67 
72  : target(q1)
73  , payloads()
74  , controls({ q2 })
75 
76  {
77  // Swap gate constructor.
78  }
79 
83  QCircuitGate(bitLenInt trgt, const complex matrix[])
84  : target(trgt)
85  {
86  payloads[ZERO_BCI] = std::shared_ptr<complex>(new complex[4U], std::default_delete<complex[]>());
87  std::copy(matrix, matrix + 4U, payloads[ZERO_BCI].get());
88  }
89 
93  QCircuitGate(bitLenInt trgt, const complex matrix[], const std::set<bitLenInt>& ctrls, const bitCapInt& perm)
94  : target(trgt)
95  , controls(ctrls)
96  {
97  const std::shared_ptr<complex>& p = payloads[perm] =
98  std::shared_ptr<complex>(new complex[4U], std::default_delete<complex[]>());
99  std::copy(matrix, matrix + 4U, p.get());
100  }
101 
106  bitLenInt trgt, const std::map<bitCapInt, std::shared_ptr<complex>>& pylds, const std::set<bitLenInt>& ctrls)
107  : target(trgt)
108  , controls(ctrls)
109  {
110  for (const auto& payload : pylds) {
111  payloads[payload.first] = std::shared_ptr<complex>(new complex[4U], std::default_delete<complex[]>());
112  std::copy(payload.second.get(), payload.second.get() + 4U, payloads[payload.first].get());
113  }
114  }
115 
116  QCircuitGatePtr Clone() { return std::make_shared<QCircuitGate>(target, payloads, controls); }
117 
121  bool CanCombine(QCircuitGatePtr other, bool clifford = false)
122  {
123  if (target != other->target) {
124  return false;
125  }
126 
127  if (clifford) {
128  if (controls.empty() && other->controls.empty()) {
129  return true;
130  }
131 
132  const bool mc = IsClifford();
133  const bool oc = other->IsClifford();
134 
135  if (mc != oc) {
136  return false;
137  }
138 
139  if (mc) {
140  return controls.empty() || other->controls.empty() ||
141  (*(controls.begin()) == *(other->controls.begin()));
142  }
143  }
144 
145  if (controls.empty() || other->controls.empty()) {
146  return true;
147  }
148 
149  return std::includes(other->controls.begin(), other->controls.end(), controls.begin(), controls.end()) ||
150  std::includes(controls.begin(), controls.end(), other->controls.begin(), other->controls.end());
151  }
152 
156  void Clear()
157  {
158  controls.clear();
159  payloads.clear();
160 
161  payloads[ZERO_BCI] = std::shared_ptr<complex>(new complex[4U], std::default_delete<complex[]>());
162  complex* p = payloads[ZERO_BCI].get();
163  p[0U] = ONE_CMPLX;
164  p[1U] = ZERO_CMPLX;
165  p[2U] = ZERO_CMPLX;
166  p[3U] = ONE_CMPLX;
167  }
168 
173  {
174  if (controls.find(c) != controls.end()) {
175  return;
176  }
177 
178  controls.insert(c);
179 
180  const size_t cpos = std::distance(controls.begin(), controls.find(c));
181  const bitCapInt midPow = pow2(cpos);
182  bitCapInt lowMask = midPow;
183  bi_decrement(&lowMask, 1U);
184  const bitCapInt highMask = ~lowMask;
185 
186  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
187  for (const auto& payload : payloads) {
188  bitCapInt nKey = (payload.first & lowMask) | ((payload.first & highMask) << 1U);
189 
190  nPayloads.emplace(nKey, payload.second);
191 
192  std::shared_ptr<complex> np = std::shared_ptr<complex>(new complex[4U], std::default_delete<complex[]>());
193  std::copy(payload.second.get(), payload.second.get() + 4U, np.get());
194  bi_or_ip(&nKey, midPow);
195  nPayloads.emplace(nKey, np);
196  }
197 
198  payloads = nPayloads;
199  }
200 
205  {
206  const size_t cpos = std::distance(controls.begin(), controls.find(c));
207  const bitCapInt midPow = pow2(cpos);
208 
209  for (const auto& payload : payloads) {
210  bitCapInt nKey = ~midPow & payload.first;
211 
212  if (bi_compare(nKey, payload.first) == 0) {
213  if (payloads.find(nKey | midPow) == payloads.end()) {
214  return false;
215  }
216  } else {
217  if (payloads.find(nKey) == payloads.end()) {
218  return false;
219  }
220  }
221 
222  const complex* l = payloads[nKey].get();
223  bi_or_ip(&nKey, midPow);
224  const complex* h = payloads[nKey].get();
225  if (amp_leq_0(l[0U] - h[0U]) && amp_leq_0(l[1U] - h[1U]) && amp_leq_0(l[2U] - h[2U]) &&
226  amp_leq_0(l[3U] - h[3U])) {
227  continue;
228  }
229 
230  return false;
231  }
232 
233  return true;
234  }
235 
240  {
241  const size_t cpos = std::distance(controls.begin(), controls.find(c));
242  const bitCapInt midPow = pow2(cpos);
243  bitCapInt lowMask = midPow;
244  bi_decrement(&lowMask, 1U);
245  const bitCapInt highMask = ~(lowMask | midPow);
246 
247  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
248  for (const auto& payload : payloads) {
249  nPayloads.emplace((payload.first & lowMask) | ((payload.first & highMask) >> 1U), payload.second);
250  }
251 
252  payloads = nPayloads;
253  controls.erase(c);
254  }
255 
260  {
261  if (!CanRemoveControl(c)) {
262  return false;
263  }
264  RemoveControl(c);
265 
266  return true;
267  }
268 
273  {
274  std::set<bitLenInt> ctrlsToTest;
275  std::set_intersection(controls.begin(), controls.end(), other->controls.begin(), other->controls.end(),
276  std::inserter(ctrlsToTest, ctrlsToTest.begin()));
277 
278  if (controls.size() < other->controls.size()) {
279  for (const bitLenInt& oc : other->controls) {
280  AddControl(oc);
281  }
282  } else if (controls.size() > other->controls.size()) {
283  for (const bitLenInt& c : controls) {
284  other->AddControl(c);
285  }
286  }
287 
288  for (const auto& payload : other->payloads) {
289  const auto& pit = payloads.find(payload.first);
290  if (pit == payloads.end()) {
291  const std::shared_ptr<complex>& p = payloads[payload.first] =
292  std::shared_ptr<complex>(new complex[4U], std::default_delete<complex[]>());
293  std::copy(payload.second.get(), payload.second.get() + 4U, p.get());
294 
295  continue;
296  }
297 
298  complex* p = pit->second.get();
299  complex out[4];
300  mul2x2(payload.second.get(), p, out);
301 
302  if (amp_leq_0(out[1U]) && amp_leq_0(out[2U]) && amp_leq_0(ONE_CMPLX - out[0U]) &&
303  amp_leq_0(ONE_CMPLX - out[3U])) {
304  payloads.erase(pit);
305 
306  continue;
307  }
308 
309  std::copy(out, out + 4U, p);
310  }
311 
312  if (payloads.empty()) {
313  Clear();
314  return;
315  }
316 
317  for (const bitLenInt& c : ctrlsToTest) {
318  TryRemoveControl(c);
319  }
320  }
321 
325  bool TryCombine(QCircuitGatePtr other, bool clifford = false)
326  {
327  if (!CanCombine(other, clifford)) {
328  return false;
329  }
330  Combine(other);
331 
332  return true;
333  }
334 
338  bool IsIdentity()
339  {
340  const bitCapInt controlPow = pow2(controls.size());
341  if (payloads.size() == controlPow) {
342  const complex* refP = payloads.begin()->second.get();
343  if (norm(refP[0U] - refP[3U]) > FP_NORM_EPSILON) {
344  return false;
345  }
346  const complex phaseFac = refP[0U];
347  for (const auto& payload : payloads) {
348  complex* p = payload.second.get();
349  if ((norm(p[1U]) > FP_NORM_EPSILON) || (norm(p[2U]) > FP_NORM_EPSILON) ||
350  (norm(phaseFac - p[0U]) > FP_NORM_EPSILON) || (norm(phaseFac - p[3U]) > FP_NORM_EPSILON)) {
351  return false;
352  }
353  }
354  return true;
355  }
356 
357  for (const auto& payload : payloads) {
358  complex* p = payload.second.get();
359  if ((norm(p[1U]) > FP_NORM_EPSILON) || (norm(p[2U]) > FP_NORM_EPSILON) ||
360  (norm(ONE_CMPLX - p[0U]) > FP_NORM_EPSILON) || (norm(ONE_CMPLX - p[3U]) > FP_NORM_EPSILON)) {
361  return false;
362  }
363  }
364 
365  return true;
366  }
367 
371  bool IsPhase()
372  {
373  for (const auto& payload : payloads) {
374  complex* p = payload.second.get();
375  if ((norm(p[1U]) > FP_NORM_EPSILON) || (norm(p[2U]) > FP_NORM_EPSILON)) {
376  return false;
377  }
378  }
379 
380  return true;
381  }
382 
386  bool IsInvert()
387  {
388  for (const auto& payload : payloads) {
389  complex* p = payload.second.get();
390  if ((norm(p[0U]) > FP_NORM_EPSILON) || (norm(p[3U]) > FP_NORM_EPSILON)) {
391  return false;
392  }
393  }
394 
395  return true;
396  }
397 
402  {
403  for (const auto& payload : payloads) {
404  complex* p = payload.second.get();
405  if (((norm(p[0]) > FP_NORM_EPSILON) || (norm(p[3]) > FP_NORM_EPSILON)) &&
406  ((norm(p[1]) > FP_NORM_EPSILON) || (norm(p[2]) > FP_NORM_EPSILON))) {
407  return false;
408  }
409  }
410 
411  return true;
412  }
413 
417  bool IsCnot()
418  {
419  if ((controls.size() != 1U) || (payloads.size() != 1U) || (payloads.find(ONE_BCI) == payloads.end())) {
420  return false;
421  }
422  complex* p = payloads[ONE_BCI].get();
423  if ((norm(p[0]) > FP_NORM_EPSILON) || (norm(p[3]) > FP_NORM_EPSILON) ||
424  (norm(ONE_CMPLX - p[1]) > FP_NORM_EPSILON) || (norm(ONE_CMPLX - p[2]) > FP_NORM_EPSILON)) {
425  return false;
426  }
427 
428  return true;
429  }
430 
434  bool IsAntiCnot()
435  {
436  if ((controls.size() != 1U) || (payloads.size() != 1U) || (payloads.find(ZERO_BCI) == payloads.end())) {
437  return false;
438  }
439  complex* p = payloads[ZERO_BCI].get();
440  if ((norm(p[0]) > FP_NORM_EPSILON) || (norm(p[3]) > FP_NORM_EPSILON) ||
441  (norm(ONE_CMPLX - p[1]) > FP_NORM_EPSILON) || (norm(ONE_CMPLX - p[2]) > FP_NORM_EPSILON)) {
442  return false;
443  }
444 
445  return true;
446  }
447 
451  bool IsClifford()
452  {
453  if (payloads.empty()) {
454  // Swap gate is Clifford
455  return true;
456  }
457 
458  if (controls.size() > 1U) {
459  return false;
460  }
461 
462  if (controls.empty()) {
463  return __IS_CLIFFORD(payloads[ZERO_BCI].get());
464  }
465 
466  for (const auto& kvPair : payloads) {
467  const complex* p = kvPair.second.get();
468  if ((norm(p[1U]) <= FP_NORM_EPSILON) && (norm(p[2U]) <= FP_NORM_EPSILON)) {
469  // Phase payload
470  if (!__IS_CLIFFORD_PHASE_INVERT(p[0U], p[3U])) {
471  return false;
472  }
473  } else if ((norm(p[0U]) <= FP_NORM_EPSILON) && (norm(p[3U]) <= FP_NORM_EPSILON)) {
474  // Negation payload
475  if (!__IS_CLIFFORD_PHASE_INVERT(p[1U], p[2U])) {
476  return false;
477  }
478  } else {
479  return false;
480  }
481  }
482 
483  return true;
484  }
485 
490  {
491  const std::set<bitLenInt>::iterator c = other->controls.find(target);
492  if (c == other->controls.end()) {
493  if (controls.find(other->target) != controls.end()) {
494  return other->IsPhase();
495  }
496 
497  return (target != other->target) || (IsPhase() && other->IsPhase());
498  }
499 
500  if (controls.find(other->target) != controls.end()) {
501  return IsPhase() && other->IsPhase();
502  }
503  if (IsPhase()) {
504  return true;
505  }
506  if (!IsPhaseInvert() ||
507  !std::includes(other->controls.begin(), other->controls.end(), controls.begin(), controls.end())) {
508  return false;
509  }
510 
511  std::vector<bitCapInt> opfPows;
512  opfPows.reserve(controls.size());
513  for (const bitLenInt& ctrl : controls) {
514  opfPows.emplace_back(pow2(std::distance(other->controls.begin(), other->controls.find(ctrl))));
515  }
516  const bitCapInt p = pow2(std::distance(other->controls.begin(), c));
517  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
518  for (const auto& payload : other->payloads) {
519  bitCapInt pf = ZERO_BCI;
520  for (size_t i = 0U; i < opfPows.size(); ++i) {
521  if (bi_compare_0(payload.first & opfPows[i]) != 0) {
522  bi_or_ip(&pf, pow2(i));
523  }
524  }
525  const auto& poi = payloads.find(pf);
526  if ((poi == payloads.end()) || (norm(poi->second.get()[0U]) > FP_NORM_EPSILON)) {
527  nPayloads[payload.first] = payload.second;
528  } else {
529  nPayloads[payload.first ^ p] = payload.second;
530  }
531  }
532  other->payloads = nPayloads;
533 
534  return true;
535  }
536 
540  std::unique_ptr<complex[]> MakeUniformlyControlledPayload()
541  {
542  const bitCapIntOcl maxQPower = pow2Ocl(controls.size());
543  std::unique_ptr<complex[]> toRet(new complex[maxQPower << 2U]);
545  for (bitCapIntOcl i = 0U; i < maxQPower; ++i) {
546  complex* mtrx = toRet.get() + (i << 2U);
547  const auto& p = payloads.find(i);
548  if (p == payloads.end()) {
549  std::copy(identity, identity + 4U, mtrx);
550  continue;
551  }
552 
553  const complex* oMtrx = p->second.get();
554  std::copy(oMtrx, oMtrx + 4U, mtrx);
555  }
556 
557  return toRet;
558  }
559 
563  std::vector<bitLenInt> GetControlsVector() { return std::vector<bitLenInt>(controls.begin(), controls.end()); }
564 
568  void PostSelectControl(bitLenInt c, bool eigen)
569  {
570  const auto controlIt = controls.find(c);
571  if (controlIt == controls.end()) {
572  return;
573  }
574 
575  const size_t cpos = std::distance(controls.begin(), controlIt);
576  const bitCapInt midPow = pow2(cpos);
577  bitCapInt lowMask = midPow;
578  bi_decrement(&lowMask, 1U);
579  const bitCapInt highMask = ~(lowMask | midPow);
580  const bitCapInt qubitPow = pow2(cpos);
581  const bitCapInt eigenPow = eigen ? qubitPow : ZERO_BCI;
582 
583  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
584  for (const auto& payload : payloads) {
585  if (bi_compare(payload.first & qubitPow, eigenPow) != 0) {
586  continue;
587  }
588  nPayloads.emplace((payload.first & lowMask) | ((payload.first & highMask) >> 1U), payload.second);
589  }
590 
591  payloads = nPayloads;
592  controls.erase(c);
593  }
594 };
595 
596 std::ostream& operator<<(std::ostream& os, const QCircuitGatePtr g);
597 std::istream& operator>>(std::istream& os, QCircuitGatePtr& g);
598 
602 class QCircuit;
603 typedef std::shared_ptr<QCircuit> QCircuitPtr;
604 
605 class QCircuit {
606 protected:
610  std::list<QCircuitGatePtr> gates;
611 
612 public:
616  QCircuit(bool collapse = true, bool clifford = false)
617  : isCollapsed(collapse)
618  , isNearClifford(clifford)
619  , qubitCount(0U)
620  , gates()
621  {
622  // Intentionally left blank
623  }
624 
628  QCircuit(bitLenInt qbCount, const std::list<QCircuitGatePtr>& g, bool collapse = true, bool clifford = false)
629  : isCollapsed(collapse)
630  , isNearClifford(clifford)
631  , qubitCount(qbCount)
632  {
633  for (const QCircuitGatePtr& gate : g) {
634  gates.push_back(gate->Clone());
635  }
636  }
637 
638  QCircuitPtr Clone() { return std::make_shared<QCircuit>(qubitCount, gates, isCollapsed, isNearClifford); }
639 
641  {
642  QCircuitPtr clone = Clone();
643  for (QCircuitGatePtr& gate : clone->gates) {
644  for (auto& p : gate->payloads) {
645  const complex* m = p.second.get();
646  complex inv[4U]{ conj(m[0U]), conj(m[2U]), conj(m[1U]), conj(m[3U]) };
647  std::copy(inv, inv + 4U, p.second.get());
648  }
649  }
650  clone->gates.reverse();
651 
652  return clone;
653  }
654 
659 
664 
668  std::list<QCircuitGatePtr> GetGateList() { return gates; }
669 
673  void SetGateList(std::list<QCircuitGatePtr> gl) { gates = gl; }
674 
678  void Swap(bitLenInt q1, bitLenInt q2)
679  {
680  if (q1 == q2) {
681  return;
682  }
683 
684  // If all swap gates are constructed in the same order, between high and low qubits, then the chances of
685  // combining them might be higher.
686  if (q1 > q2) {
687  std::swap(q1, q2);
688  }
689 
691  const std::set<bitLenInt> s1 = { q1 };
692  const std::set<bitLenInt> s2 = { q2 };
693  AppendGate(std::make_shared<QCircuitGate>(q1, m, s2, ONE_BCI));
694  AppendGate(std::make_shared<QCircuitGate>(q2, m, s1, ONE_BCI));
695  AppendGate(std::make_shared<QCircuitGate>(q1, m, s2, ONE_BCI));
696  }
697 
701  void Append(QCircuitPtr circuit)
702  {
703  if (circuit->qubitCount > qubitCount) {
704  qubitCount = circuit->qubitCount;
705  }
706  gates.insert(gates.end(), circuit->gates.begin(), circuit->gates.end());
707  }
708 
713  void Combine(QCircuitPtr circuit)
714  {
715  if (circuit->qubitCount > qubitCount) {
716  qubitCount = circuit->qubitCount;
717  }
718  for (const QCircuitGatePtr& g : circuit->gates) {
719  AppendGate(g);
720  }
721  }
722 
726  bool AppendGate(QCircuitGatePtr nGate);
730  void Run(QInterfacePtr qsim);
731 
736  {
737  for (const QCircuitGatePtr& gate : gates) {
738  if ((gate->target == qubit) && !(gate->IsPhase())) {
739  return true;
740  }
741  }
742 
743  return false;
744  }
745 
749  void DeletePhaseTarget(bitLenInt qubit, bool eigen)
750  {
751  std::list<QCircuitGatePtr> nGates;
752  gates.reverse();
753  for (const QCircuitGatePtr& gate : gates) {
754  if (gate->target == qubit) {
755  continue;
756  }
757  QCircuitGatePtr nGate = gate->Clone();
758  nGate->PostSelectControl(qubit, eigen);
759  nGates.insert(nGates.begin(), nGate);
760  }
761  gates = nGates;
762  }
763 
767  QCircuitPtr PastLightCone(std::set<bitLenInt>& qubits)
768  {
769  // We're working from latest gate to earliest gate.
770  gates.reverse();
771 
772  std::list<QCircuitGatePtr> nGates;
773  for (const QCircuitGatePtr& gate : gates) {
774  // Is the target qubit on the light cone?
775  if (qubits.find(gate->target) == qubits.end()) {
776  // The target isn't on the light cone, but the controls might be.
777  bool isNonCausal = true;
778  for (const bitLenInt& c : gate->controls) {
779  if (qubits.find(c) != qubits.end()) {
780  isNonCausal = false;
781  break;
782  }
783  }
784  if (isNonCausal) {
785  // This gate is not on the past light cone.
786  continue;
787  }
788  }
789 
790  // This gate is on the past light cone.
791  nGates.insert(nGates.begin(), gate->Clone());
792 
793  // Every qubit involved in this gate is now considered to be part of the past light cone.
794  qubits.insert(gate->target);
795  qubits.insert(gate->controls.begin(), gate->controls.end());
796  }
797 
798  // Restore the original order of this QCircuit's gates.
799  gates.reverse();
800 
801  return std::make_shared<QCircuit>(qubitCount, nGates, isCollapsed);
802  }
803 
804 #if ENABLE_ALU
806  void INC(const bitCapInt& toAdd, bitLenInt start, bitLenInt length);
807 #endif
808 };
809 
810 std::ostream& operator<<(std::ostream& os, const QCircuitPtr g);
811 std::istream& operator>>(std::istream& os, QCircuitPtr& g);
812 } // namespace Qrack
void bi_or_ip(BigInteger *left, const BigInteger &right)
Definition: big_integer.hpp:429
void bi_decrement(BigInteger *pBigInt, const BIG_INTEGER_WORD &value)
Definition: big_integer.hpp:229
int bi_compare_0(const BigInteger &left)
Definition: big_integer.hpp:134
int bi_compare(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:120
Definition: qcircuit.hpp:605
void DeletePhaseTarget(bitLenInt qubit, bool eigen)
(If the qubit is not a target of a non-phase gate...) Delete this qubits' controls and phase targets.
Definition: qcircuit.hpp:749
std::list< QCircuitGatePtr > GetGateList()
Return the raw list of gates.
Definition: qcircuit.hpp:668
bool isNearClifford
Definition: qcircuit.hpp:608
bitLenInt GetQubitCount()
Get the (automatically calculated) count of qubits in this circuit, so far.
Definition: qcircuit.hpp:658
void SetGateList(std::list< QCircuitGatePtr > gl)
Set the raw list of gates.
Definition: qcircuit.hpp:673
bitLenInt qubitCount
Definition: qcircuit.hpp:609
void Append(QCircuitPtr circuit)
Append circuit (with identical qubit index mappings) at the end of this circuit.
Definition: qcircuit.hpp:701
void INC(const bitCapInt &toAdd, bitLenInt start, bitLenInt length)
Add integer (without sign)
Definition: arithmetic_qcircuit.cpp:23
QCircuit(bitLenInt qbCount, const std::list< QCircuitGatePtr > &g, bool collapse=true, bool clifford=false)
Manual constructor.
Definition: qcircuit.hpp:628
QCircuitPtr Inverse()
Definition: qcircuit.hpp:640
void Combine(QCircuitPtr circuit)
Combine circuit (with identical qubit index mappings) at the end of this circuit, by acting all addit...
Definition: qcircuit.hpp:713
QCircuitPtr PastLightCone(std::set< bitLenInt > &qubits)
Return (as a new QCircuit) just the gates on the past light cone of a set of qubit indices.
Definition: qcircuit.hpp:767
QCircuit(bool collapse=true, bool clifford=false)
Default constructor.
Definition: qcircuit.hpp:616
bool AppendGate(QCircuitGatePtr nGate)
Add a gate to the gate sequence.
Definition: qcircuit.cpp:101
QCircuitPtr Clone()
Definition: qcircuit.hpp:638
void SetQubitCount(bitLenInt n)
Set the count of qubits in this circuit, so far.
Definition: qcircuit.hpp:663
void Run(QInterfacePtr qsim)
Run this circuit.
Definition: qcircuit.cpp:168
void Swap(bitLenInt q1, bitLenInt q2)
Add a Swap gate to the gate sequence.
Definition: qcircuit.hpp:678
bool IsNonPhaseTarget(bitLenInt qubit)
Check if an index is any target qubit of this circuit.
Definition: qcircuit.hpp:735
std::list< QCircuitGatePtr > gates
Definition: qcircuit.hpp:610
bool isCollapsed
Definition: qcircuit.hpp:607
GLOSSARY: bitLenInt - "bit-length integer" - unsigned integer ID of qubit position in register bitCap...
Definition: complex16x2simd.hpp:25
std::shared_ptr< QInterface > QInterfacePtr
Definition: qinterface.hpp:29
void mul2x2(const complex *left, const complex *right, complex *out)
Definition: functions.cpp:111
void U(quid sid, bitLenInt q, real1_f theta, real1_f phi, real1_f lambda)
(External API) 3-parameter unitary gate
Definition: wasm_api.cpp:1143
std::istream & operator>>(std::istream &os, QCircuitGatePtr &g)
Definition: qcircuit.cpp:38
std::complex< real1 > complex
Definition: qrack_types.hpp:128
QRACK_CONST real1 FP_NORM_EPSILON
Definition: qrack_types.hpp:258
bitCapInt pow2(const bitLenInt &p)
Definition: qrack_functions.hpp:136
double norm(const complex2 &c)
Definition: complex16x2simd.hpp:101
QRACK_CONST complex ONE_CMPLX
Definition: qrack_types.hpp:252
std::shared_ptr< QCircuitGate > QCircuitGatePtr
Definition: qcircuit.hpp:48
std::shared_ptr< QCircuit > QCircuitPtr
Definition: qcircuit.hpp:602
std::ostream & operator<<(std::ostream &os, const QCircuitGatePtr g)
Definition: qcircuit.cpp:17
QRACK_CONST complex ZERO_CMPLX
Definition: qrack_types.hpp:253
const bitCapInt ONE_BCI
Definition: qrack_types.hpp:129
const bitCapInt ZERO_BCI
Definition: qrack_types.hpp:130
bitCapIntOcl pow2Ocl(const bitLenInt &p)
Definition: qrack_functions.hpp:137
#define amp_leq_0(x)
Definition: qcircuit.hpp:22
#define __IS_CLIFFORD_PHASE_INVERT(top, bottom)
Definition: qcircuit.hpp:28
#define __IS_CLIFFORD(mtrx)
Definition: qcircuit.hpp:31
#define QRACK_CONST
Definition: qrack_types.hpp:174
#define bitLenInt
Definition: qrack_types.hpp:38
#define bitCapInt
Definition: qrack_types.hpp:62
#define bitCapIntOcl
Definition: qrack_types.hpp:50
Definition: qcircuit.hpp:51
std::unique_ptr< complex[]> MakeUniformlyControlledPayload()
To run as a uniformly controlled gate, generate my payload array.
Definition: qcircuit.hpp:540
std::set< bitLenInt > controls
Definition: qcircuit.hpp:54
QCircuitGate(bitLenInt trgt, const complex matrix[], const std::set< bitLenInt > &ctrls, const bitCapInt &perm)
Controlled gate constructor.
Definition: qcircuit.hpp:93
QCircuitGate(bitLenInt trgt, const std::map< bitCapInt, std::shared_ptr< complex >> &pylds, const std::set< bitLenInt > &ctrls)
Uniformly controlled gate constructor (that only accepts control qubits is ascending order)
Definition: qcircuit.hpp:105
bool TryRemoveControl(bitLenInt c)
Check if I can remove control, and do so, if possible.
Definition: qcircuit.hpp:259
std::map< bitCapInt, std::shared_ptr< complex > > payloads
Definition: qcircuit.hpp:53
bool CanCombine(QCircuitGatePtr other, bool clifford=false)
Can I combine myself with gate other?
Definition: qcircuit.hpp:121
bool IsCnot()
Am I a CNOT gate?
Definition: qcircuit.hpp:417
bool TryCombine(QCircuitGatePtr other, bool clifford=false)
Check if I can combine with gate other, and do so, if possible.
Definition: qcircuit.hpp:325
QCircuitGate()
Identity gate constructor.
Definition: qcircuit.hpp:59
std::vector< bitLenInt > GetControlsVector()
Convert my set of qubit indices to a vector.
Definition: qcircuit.hpp:563
void Clear()
Set this gate to the identity operator.
Definition: qcircuit.hpp:156
void RemoveControl(bitLenInt c)
Remove control qubit.
Definition: qcircuit.hpp:239
bool CanPass(QCircuitGatePtr other)
Do I commute with gate other?
Definition: qcircuit.hpp:489
QCircuitGate(bitLenInt trgt, const complex matrix[])
Single-qubit gate constructor.
Definition: qcircuit.hpp:83
void Combine(QCircuitGatePtr other)
Combine myself with gate other
Definition: qcircuit.hpp:272
QCircuitGatePtr Clone()
Definition: qcircuit.hpp:116
bool IsAntiCnot()
Am I a CNOT gate?
Definition: qcircuit.hpp:434
bool IsPhaseInvert()
Am I a combination of "phase" and "invert" payloads?
Definition: qcircuit.hpp:401
void AddControl(bitLenInt c)
Add control qubit.
Definition: qcircuit.hpp:172
bool CanRemoveControl(bitLenInt c)
Check if a control qubit can be removed.
Definition: qcircuit.hpp:204
bool IsClifford()
Am I a Clifford gate?
Definition: qcircuit.hpp:451
bitLenInt target
Definition: qcircuit.hpp:52
bool IsPhase()
Am I a phase gate?
Definition: qcircuit.hpp:371
bool IsIdentity()
Am I an identity gate?
Definition: qcircuit.hpp:338
bool IsInvert()
Am I a Pauli X plus a phase gate?
Definition: qcircuit.hpp:386
QCircuitGate(bitLenInt q1, bitLenInt q2)
Swap gate constructor
Definition: qcircuit.hpp:71
void PostSelectControl(bitLenInt c, bool eigen)
Erase a control index, if it exists, (via post selection).
Definition: qcircuit.hpp:568