Qrack  9.0
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(0)
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[0] = std::shared_ptr<complex>(new complex[4], std::default_delete<complex[]>());
87  std::copy(matrix, matrix + 4, payloads[0].get());
88  }
89 
93  QCircuitGate(bitLenInt trgt, const complex matrix[], const std::set<bitLenInt>& ctrls, 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[4], std::default_delete<complex[]>());
99  std::copy(matrix, matrix + 4, 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[4], std::default_delete<complex[]>());
112  std::copy(payload.second.get(), payload.second.get() + 4, 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 (!controls.size() && !other->controls.size()) {
128  return true;
129  }
130 
131  if (clifford) {
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.size() || !other->controls.size() ||
141  (*(controls.begin()) == *(other->controls.begin()));
142  }
143  }
144 
145  if (std::includes(other->controls.begin(), other->controls.end(), controls.begin(), controls.end()) ||
146  std::includes(controls.begin(), controls.end(), other->controls.begin(), other->controls.end())) {
147  return true;
148  }
149 
150  return false;
151  }
152 
156  void Clear()
157  {
158  controls.clear();
159  payloads.clear();
160 
161  payloads[0] = std::shared_ptr<complex>(new complex[4], std::default_delete<complex[]>());
162  complex* p = payloads[0].get();
163  p[0] = ONE_CMPLX;
164  p[1] = ZERO_CMPLX;
165  p[2] = ZERO_CMPLX;
166  p[3] = 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  const bitCapInt lowMask = midPow - 1U;
183  const bitCapInt highMask = ~lowMask;
184 
185  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
186  for (const auto& payload : payloads) {
187  const bitCapInt nKey = (payload.first & lowMask) | ((payload.first & highMask) << 1U);
188 
189  nPayloads.emplace(nKey, payload.second);
190 
191  std::shared_ptr<complex> np = std::shared_ptr<complex>(new complex[4], std::default_delete<complex[]>());
192  std::copy(payload.second.get(), payload.second.get() + 4U, np.get());
193  nPayloads.emplace(nKey | midPow, np);
194  }
195 
196  payloads = nPayloads;
197  }
198 
203  {
204  const size_t cpos = std::distance(controls.begin(), controls.find(c));
205  const bitCapInt midPow = pow2(cpos);
206 
207  for (const auto& payload : payloads) {
208  const bitCapInt nKey = payload.first & ~midPow;
209 
210  if (nKey == payload.first) {
211  if (payloads.find(nKey | midPow) == payloads.end()) {
212  return false;
213  }
214  } else {
215  if (payloads.find(nKey) == payloads.end()) {
216  return false;
217  }
218  }
219 
220  const complex* l = payloads[nKey].get();
221  const complex* h = payloads[nKey | midPow].get();
222  if (amp_leq_0(l[0] - h[0]) && amp_leq_0(l[1] - h[1]) && amp_leq_0(l[2] - h[2]) && amp_leq_0(l[3] - h[3])) {
223  continue;
224  }
225 
226  return false;
227  }
228 
229  return true;
230  }
231 
236  {
237  const size_t cpos = std::distance(controls.begin(), controls.find(c));
238  const bitCapInt midPow = pow2(cpos);
239  const bitCapInt lowMask = midPow - 1U;
240  const bitCapInt highMask = ~(lowMask | midPow);
241 
242  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
243  for (const auto& payload : payloads) {
244  const bitCapInt nKey = (payload.first & lowMask) | ((payload.first & highMask) >> 1U);
245  nPayloads.emplace(nKey, payload.second);
246  }
247 
248  payloads = nPayloads;
249  controls.erase(c);
250  }
251 
256  {
257  if (!CanRemoveControl(c)) {
258  return false;
259  }
260  RemoveControl(c);
261 
262  return true;
263  }
264 
269  {
270  std::set<bitLenInt> ctrlsToTest;
271  std::set_intersection(controls.begin(), controls.end(), other->controls.begin(), other->controls.end(),
272  std::inserter(ctrlsToTest, ctrlsToTest.begin()));
273 
274  if (controls.size() < other->controls.size()) {
275  for (const bitLenInt& oc : other->controls) {
276  AddControl(oc);
277  }
278  } else if (controls.size() > other->controls.size()) {
279  for (const bitLenInt& c : controls) {
280  other->AddControl(c);
281  }
282  }
283 
284  for (const auto& payload : other->payloads) {
285  const auto& pit = payloads.find(payload.first);
286  if (pit == payloads.end()) {
287  const std::shared_ptr<complex>& p = payloads[payload.first] =
288  std::shared_ptr<complex>(new complex[4], std::default_delete<complex[]>());
289  std::copy(payload.second.get(), payload.second.get() + 4U, p.get());
290 
291  continue;
292  }
293 
294  complex* p = pit->second.get();
295  complex out[4];
296  mul2x2(payload.second.get(), p, out);
297 
298  if (amp_leq_0(out[1]) && amp_leq_0(out[2]) && amp_leq_0(ONE_CMPLX - out[0]) &&
299  amp_leq_0(ONE_CMPLX - out[3])) {
300  payloads.erase(pit);
301 
302  continue;
303  }
304 
305  std::copy(out, out + 4U, p);
306  }
307 
308  if (!payloads.size()) {
309  Clear();
310  return;
311  }
312 
313  for (const bitLenInt& c : ctrlsToTest) {
314  TryRemoveControl(c);
315  }
316  }
317 
321  bool TryCombine(QCircuitGatePtr other, bool clifford = false)
322  {
323  if (!CanCombine(other, clifford)) {
324  return false;
325  }
326  Combine(other);
327 
328  return true;
329  }
330 
334  bool IsIdentity()
335  {
336  if (controls.size()) {
337  return false;
338  }
339 
340  if (payloads.size() != 1U) {
341  return false;
342  }
343 
344  complex* p = payloads.begin()->second.get();
345 
346  if (amp_leq_0(p[1]) && amp_leq_0(p[2]) && amp_leq_0(ONE_CMPLX - p[0]) && amp_leq_0(ONE_CMPLX - p[3])) {
347  return true;
348  }
349 
350  return false;
351  }
352 
356  bool IsPhase()
357  {
358  for (const auto& payload : payloads) {
359  complex* p = payload.second.get();
360  if ((norm(p[1]) > FP_NORM_EPSILON) || (norm(p[2]) > FP_NORM_EPSILON)) {
361  return false;
362  }
363  }
364 
365  return true;
366  }
367 
371  bool IsInvert()
372  {
373  for (const auto& payload : payloads) {
374  complex* p = payload.second.get();
375  if ((norm(p[0]) > FP_NORM_EPSILON) || (norm(p[3]) > FP_NORM_EPSILON)) {
376  return false;
377  }
378  }
379 
380  return true;
381  }
382 
387  {
388  for (const auto& payload : payloads) {
389  complex* p = payload.second.get();
390  if (((norm(p[0]) > FP_NORM_EPSILON) || (norm(p[3]) > FP_NORM_EPSILON)) &&
391  ((norm(p[1]) > FP_NORM_EPSILON) || (norm(p[2]) > FP_NORM_EPSILON))) {
392  return false;
393  }
394  }
395 
396  return true;
397  }
398 
402  bool IsCnot()
403  {
404  if ((controls.size() != 1U) || (payloads.size() != 1U) || (payloads.find(1U) == payloads.end())) {
405  return false;
406  }
407  complex* p = payloads[1U].get();
408  if ((norm(p[0]) > FP_NORM_EPSILON) || (norm(p[3]) > FP_NORM_EPSILON) ||
409  (norm(ONE_CMPLX - p[1]) > FP_NORM_EPSILON) || (norm(ONE_CMPLX - p[2]) > FP_NORM_EPSILON)) {
410  return false;
411  }
412 
413  return true;
414  }
415 
419  bool IsClifford()
420  {
421  if (!payloads.size()) {
422  // Swap gate is Clifford
423  return true;
424  }
425 
426  if (controls.size() > 1U) {
427  return false;
428  }
429 
430  if (!controls.size()) {
431  return __IS_CLIFFORD(payloads[0U].get());
432  }
433 
434  for (const auto& kvPair : payloads) {
435  const complex* p = kvPair.second.get();
436  if ((norm(p[1U]) <= FP_NORM_EPSILON) && (norm(p[2U]) <= FP_NORM_EPSILON)) {
437  // Phase payload
438  if (!__IS_CLIFFORD_PHASE_INVERT(p[0U], p[3U])) {
439  return false;
440  }
441  } else if ((norm(p[0U]) <= FP_NORM_EPSILON) && (norm(p[3U]) <= FP_NORM_EPSILON)) {
442  // Negation payload
443  if (!__IS_CLIFFORD_PHASE_INVERT(p[1U], p[2U])) {
444  return false;
445  }
446  } else {
447  return false;
448  }
449  }
450 
451  return true;
452  }
453 
458  {
459  std::set<bitLenInt>::iterator c = other->controls.find(target);
460  if (c != other->controls.end()) {
461  if (controls.find(other->target) != controls.end()) {
462  return IsPhase() && other->IsPhase();
463  }
464  if (IsPhase()) {
465  return true;
466  }
467  if (!IsPhaseInvert() ||
468  !std::includes(other->controls.begin(), other->controls.end(), controls.begin(), controls.end())) {
469  return false;
470  }
471 
472  std::vector<bitCapInt> opfPows;
473  opfPows.reserve(controls.size());
474  for (const bitLenInt& ctrl : controls) {
475  opfPows.emplace_back(pow2(std::distance(other->controls.begin(), other->controls.find(ctrl))));
476  }
477  const bitCapInt p = pow2(std::distance(other->controls.begin(), c));
478  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
479  for (const auto& payload : other->payloads) {
480  bitCapInt pf = 0U;
481  for (size_t i = 0U; i < opfPows.size(); ++i) {
482  if (payload.first & opfPows[i]) {
483  pf |= pow2(i);
484  }
485  }
486  const auto& poi = payloads.find(pf);
487  if ((poi == payloads.end()) || (norm(poi->second.get()[0]) > FP_NORM_EPSILON)) {
488  nPayloads[payload.first] = payload.second;
489  } else {
490  nPayloads[payload.first ^ p] = payload.second;
491  }
492  }
493  other->payloads = nPayloads;
494 
495  return true;
496  }
497 
498  if (controls.find(other->target) != controls.end()) {
499  return other->IsPhase();
500  }
501 
502  return (target != other->target) || (IsPhase() && other->IsPhase());
503  }
504 
508  std::unique_ptr<complex[]> MakeUniformlyControlledPayload()
509  {
510  const bitCapIntOcl maxQPower = pow2Ocl(controls.size());
511  std::unique_ptr<complex[]> toRet(new complex[maxQPower << 2U]);
513  for (bitCapIntOcl i = 0U; i < maxQPower; ++i) {
514  complex* mtrx = toRet.get() + (i << 2U);
515  const auto& p = payloads.find(i);
516  if (p == payloads.end()) {
517  std::copy(identity, identity + 4, mtrx);
518  continue;
519  }
520 
521  const complex* oMtrx = p->second.get();
522  std::copy(oMtrx, oMtrx + 4U, mtrx);
523  }
524 
525  return toRet;
526  }
527 
531  std::vector<bitLenInt> GetControlsVector() { return std::vector<bitLenInt>(controls.begin(), controls.end()); }
532 
536  void PostSelectControl(bitLenInt c, bool eigen)
537  {
538  const auto controlIt = controls.find(c);
539  if (controlIt == controls.end()) {
540  return;
541  }
542 
543  const size_t cpos = std::distance(controls.begin(), controlIt);
544  const bitCapInt midPow = pow2(cpos);
545  const bitCapInt lowMask = midPow - 1U;
546  const bitCapInt highMask = ~(lowMask | midPow);
547  const bitCapInt qubitPow = pow2(cpos);
548  const bitCapInt eigenPow = eigen ? qubitPow : 0U;
549 
550  std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
551  for (const auto& payload : payloads) {
552  if ((payload.first & qubitPow) != eigenPow) {
553  continue;
554  }
555  const bitCapInt nKey = (payload.first & lowMask) | ((payload.first & highMask) >> 1U);
556  nPayloads.emplace(nKey, payload.second);
557  }
558 
559  payloads = nPayloads;
560  controls.erase(c);
561  }
562 };
563 
564 std::ostream& operator<<(std::ostream& os, const QCircuitGatePtr g);
565 std::istream& operator>>(std::istream& os, QCircuitGatePtr& g);
566 
570 class QCircuit;
571 typedef std::shared_ptr<QCircuit> QCircuitPtr;
572 
573 class QCircuit {
574 protected:
578  std::list<QCircuitGatePtr> gates;
579 
580 public:
584  QCircuit(bool collapse = true, bool clifford = false)
585  : isCollapsed(collapse)
586  , isNearClifford(clifford)
587  , qubitCount(0)
588  , gates()
589  {
590  // Intentionally left blank
591  }
592 
596  QCircuit(bitLenInt qbCount, const std::list<QCircuitGatePtr>& g, bool collapse = true, bool clifford = false)
597  : isCollapsed(collapse)
598  , isNearClifford(clifford)
599  , qubitCount(qbCount)
600  {
601  for (const QCircuitGatePtr& gate : g) {
602  gates.push_back(gate->Clone());
603  }
604  }
605 
606  QCircuitPtr Clone() { return std::make_shared<QCircuit>(qubitCount, gates, isCollapsed, isNearClifford); }
607 
609  {
610  QCircuitPtr clone = Clone();
611  for (QCircuitGatePtr& gate : clone->gates) {
612  for (auto& p : gate->payloads) {
613  const complex* m = p.second.get();
614  complex inv[4U]{ conj(m[0U]), conj(m[2U]), conj(m[1U]), conj(m[3U]) };
615  std::copy(inv, inv + 4U, p.second.get());
616  }
617  }
618  clone->gates.reverse();
619 
620  return clone;
621  }
622 
627 
632 
636  std::list<QCircuitGatePtr> GetGateList() { return gates; }
637 
641  void SetGateList(std::list<QCircuitGatePtr> gl) { gates = gl; }
642 
646  void Swap(bitLenInt q1, bitLenInt q2)
647  {
648  if (q1 == q2) {
649  return;
650  }
651 
652  // If all swap gates are constructed in the same order, between high and low qubits, then the chances of
653  // combining them might be higher.
654  if (q1 > q2) {
655  std::swap(q1, q2);
656  }
657 
659  const std::set<bitLenInt> s1 = { q1 };
660  const std::set<bitLenInt> s2 = { q2 };
661  AppendGate(std::make_shared<QCircuitGate>(q1, m, s2, 1U));
662  AppendGate(std::make_shared<QCircuitGate>(q2, m, s1, 1U));
663  AppendGate(std::make_shared<QCircuitGate>(q1, m, s2, 1U));
664  }
665 
669  void Append(QCircuitPtr circuit)
670  {
671  if (circuit->qubitCount > qubitCount) {
672  qubitCount = circuit->qubitCount;
673  }
674  gates.insert(gates.end(), circuit->gates.begin(), circuit->gates.end());
675  }
676 
681  void Combine(QCircuitPtr circuit)
682  {
683  if (circuit->qubitCount > qubitCount) {
684  qubitCount = circuit->qubitCount;
685  }
686  for (const QCircuitGatePtr& g : circuit->gates) {
687  AppendGate(g);
688  }
689  }
690 
694  void AppendGate(QCircuitGatePtr nGate);
698  void Run(QInterfacePtr qsim);
699 
704  {
705  for (const QCircuitGatePtr& gate : gates) {
706  if ((gate->target == qubit) && !(gate->IsPhase())) {
707  return true;
708  }
709  }
710 
711  return false;
712  }
713 
717  void DeletePhaseTarget(bitLenInt qubit, bool eigen)
718  {
719  std::list<QCircuitGatePtr> nGates;
720  gates.reverse();
721  for (const QCircuitGatePtr& gate : gates) {
722  if (gate->target == qubit) {
723  continue;
724  }
725  QCircuitGatePtr nGate = gate->Clone();
726  nGate->PostSelectControl(qubit, eigen);
727  nGates.insert(nGates.begin(), nGate);
728  }
729  gates = nGates;
730  }
731 
735  QCircuitPtr PastLightCone(std::set<bitLenInt>& qubits)
736  {
737  // We're working from latest gate to earliest gate.
738  gates.reverse();
739 
740  std::list<QCircuitGatePtr> nGates;
741  for (const QCircuitGatePtr& gate : gates) {
742  // Is the target qubit on the light cone?
743  if (qubits.find(gate->target) == qubits.end()) {
744  // The target isn't on the light cone, but the controls might be.
745  bool isNonCausal = true;
746  for (const bitLenInt& c : gate->controls) {
747  if (qubits.find(c) != qubits.end()) {
748  isNonCausal = false;
749  break;
750  }
751  }
752  if (isNonCausal) {
753  // This gate is not on the past light cone.
754  continue;
755  }
756  }
757 
758  // This gate is on the past light cone.
759  nGates.insert(nGates.begin(), gate->Clone());
760 
761  // Every qubit involved in this gate is now considered to be part of the past light cone.
762  qubits.insert(gate->target);
763  qubits.insert(gate->controls.begin(), gate->controls.end());
764  }
765 
766  // Restore the original order of this QCircuit's gates.
767  gates.reverse();
768 
769  return std::make_shared<QCircuit>(qubitCount, nGates, isCollapsed);
770  }
771 
772 #if ENABLE_ALU
774  void INC(bitCapInt toAdd, bitLenInt start, bitLenInt length);
775 #endif
776 };
777 
778 std::ostream& operator<<(std::ostream& os, const QCircuitPtr g);
779 std::istream& operator>>(std::istream& os, QCircuitPtr& g);
780 } // namespace Qrack
Definition: qcircuit.hpp:573
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:717
std::list< QCircuitGatePtr > GetGateList()
Return the raw list of gates.
Definition: qcircuit.hpp:636
bool isNearClifford
Definition: qcircuit.hpp:576
bitLenInt GetQubitCount()
Get the (automatically calculated) count of qubits in this circuit, so far.
Definition: qcircuit.hpp:626
void SetGateList(std::list< QCircuitGatePtr > gl)
Set the raw list of gates.
Definition: qcircuit.hpp:641
bitLenInt qubitCount
Definition: qcircuit.hpp:577
void AppendGate(QCircuitGatePtr nGate)
Add a gate to the gate sequence.
Definition: qcircuit.cpp:107
void Append(QCircuitPtr circuit)
Append circuit (with identical qubit index mappings) at the end of this circuit.
Definition: qcircuit.hpp:669
QCircuit(bitLenInt qbCount, const std::list< QCircuitGatePtr > &g, bool collapse=true, bool clifford=false)
Manual constructor.
Definition: qcircuit.hpp:596
QCircuitPtr Inverse()
Definition: qcircuit.hpp:608
void Combine(QCircuitPtr circuit)
Combine circuit (with identical qubit index mappings) at the end of this circuit, by acting all addit...
Definition: qcircuit.hpp:681
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:735
QCircuit(bool collapse=true, bool clifford=false)
Default constructor.
Definition: qcircuit.hpp:584
QCircuitPtr Clone()
Definition: qcircuit.hpp:606
void SetQubitCount(bitLenInt n)
Set the count of qubits in this circuit, so far.
Definition: qcircuit.hpp:631
void Run(QInterfacePtr qsim)
Run this circuit.
Definition: qcircuit.cpp:153
void Swap(bitLenInt q1, bitLenInt q2)
Add a Swap gate to the gate sequence.
Definition: qcircuit.hpp:646
bool IsNonPhaseTarget(bitLenInt qubit)
Check if an index is any target qubit of this circuit.
Definition: qcircuit.hpp:703
std::list< QCircuitGatePtr > gates
Definition: qcircuit.hpp:578
void INC(bitCapInt toAdd, bitLenInt start, bitLenInt length)
Add integer (without sign)
Definition: arithmetic_qcircuit.cpp:23
bool isCollapsed
Definition: qcircuit.hpp:575
Definition: complex16x2simd.hpp:25
std::complex< half_float::half > complex
Definition: qrack_types.hpp:62
std::shared_ptr< QInterface > QInterfacePtr
Definition: qinterface.hpp:28
void mul2x2(complex const *left, complex const *right, complex *out)
Definition: functions.cpp:97
std::istream & operator>>(std::istream &os, QCircuitGatePtr &g)
Definition: qcircuit.cpp:44
QRACK_CONST real1 FP_NORM_EPSILON
Definition: qrack_types.hpp:243
bitCapInt pow2(const bitLenInt &p)
Definition: qrack_functions.hpp:22
double norm(const complex2 &c)
Definition: complex16x2simd.hpp:101
QRACK_CONST complex ONE_CMPLX
Definition: qrack_types.hpp:239
std::shared_ptr< QCircuitGate > QCircuitGatePtr
Definition: qcircuit.hpp:48
std::shared_ptr< QCircuit > QCircuitPtr
Definition: qcircuit.hpp:570
std::ostream & operator<<(std::ostream &os, const QCircuitGatePtr g)
Definition: qcircuit.cpp:19
QRACK_CONST complex ZERO_CMPLX
Definition: qrack_types.hpp:240
bitCapIntOcl pow2Ocl(const bitLenInt &p)
Definition: qrack_functions.hpp:23
MICROSOFT_QUANTUM_DECL void U(_In_ uintq sid, _In_ uintq q, _In_ double theta, _In_ double phi, _In_ double lambda)
(External API) 3-parameter unitary gate
Definition: pinvoke_api.cpp:1362
#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:150
#define bitLenInt
Definition: qrack_types.hpp:44
#define bitCapInt
Definition: qrack_types.hpp:105
#define bitCapIntOcl
Definition: qrack_types.hpp:91
Definition: qcircuit.hpp:51
std::unique_ptr< complex[]> MakeUniformlyControlledPayload()
To run as a uniformly controlled gate, generate my payload array.
Definition: qcircuit.hpp:508
std::set< bitLenInt > controls
Definition: qcircuit.hpp:54
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:255
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:402
bool TryCombine(QCircuitGatePtr other, bool clifford=false)
Check if I can combine with gate other, and do so, if possible.
Definition: qcircuit.hpp:321
QCircuitGate()
Identity gate constructor.
Definition: qcircuit.hpp:59
std::vector< bitLenInt > GetControlsVector()
Convert my set of qubit indices to a vector.
Definition: qcircuit.hpp:531
void Clear()
Set this gate to the identity operator.
Definition: qcircuit.hpp:156
void RemoveControl(bitLenInt c)
Remove control qubit.
Definition: qcircuit.hpp:235
bool CanPass(QCircuitGatePtr other)
Do I commute with gate other?
Definition: qcircuit.hpp:457
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:268
QCircuitGatePtr Clone()
Definition: qcircuit.hpp:116
QCircuitGate(bitLenInt trgt, const complex matrix[], const std::set< bitLenInt > &ctrls, bitCapInt perm)
Controlled gate constructor.
Definition: qcircuit.hpp:93
bool IsPhaseInvert()
Am I a combination of "phase" and "invert" payloads?
Definition: qcircuit.hpp:386
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:202
bool IsClifford()
Am I a Clifford gate?
Definition: qcircuit.hpp:419
bitLenInt target
Definition: qcircuit.hpp:52
bool IsPhase()
Am I a phase gate?
Definition: qcircuit.hpp:356
bool IsIdentity()
Am I an identity gate?
Definition: qcircuit.hpp:334
bool IsInvert()
Am I a Pauli X plus a phase gate?
Definition: qcircuit.hpp:371
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:536