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]))
53 std::map<bitCapInt, std::shared_ptr<complex>>
payloads;
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());
106 bitLenInt trgt,
const std::map<
bitCapInt, std::shared_ptr<complex>>& pylds,
const std::set<bitLenInt>& ctrls)
110 for (
const auto& payload : pylds) {
112 std::copy(payload.second.get(), payload.second.get() + 4U,
payloads[payload.first].get());
123 if (
target != other->target) {
128 if (
controls.empty() && other->controls.empty()) {
133 const bool oc = other->IsClifford();
140 return controls.empty() || other->controls.empty() ||
141 (*(
controls.begin()) == *(other->controls.begin()));
145 if (
controls.empty() || other->controls.empty()) {
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());
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);
190 nPayloads.emplace(nKey, payload.second);
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());
195 nPayloads.emplace(nKey, np);
209 for (
const auto& payload :
payloads) {
210 bitCapInt nKey = ~midPow & payload.first;
245 const bitCapInt highMask = ~(lowMask | midPow);
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);
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()));
278 if (
controls.size() < other->controls.size()) {
279 for (
const bitLenInt& oc : other->controls) {
282 }
else if (
controls.size() > other->controls.size()) {
284 other->AddControl(c);
288 for (
const auto& payload : other->payloads) {
289 const auto& pit =
payloads.find(payload.first);
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());
298 complex* p = pit->second.get();
300 mul2x2(payload.second.get(), p, out);
309 std::copy(out, out + 4U, p);
340 if (
payloads.size() == controlPow) {
347 for (
const auto& payload :
payloads) {
348 complex* p = payload.second.get();
358 for (
const auto& payload :
payloads) {
359 complex* p = payload.second.get();
374 for (
const auto& payload :
payloads) {
375 complex* p = payload.second.get();
389 for (
const auto& payload :
payloads) {
390 complex* p = payload.second.get();
404 for (
const auto& payload :
payloads) {
405 complex* p = payload.second.get();
469 for (
const auto& kvPair :
payloads) {
470 const complex* p = kvPair.second.get();
494 const std::set<bitLenInt>::iterator c = other->controls.find(
target);
495 if (c == other->controls.end()) {
497 return other->IsPhase();
500 return (
target != other->target) || (
IsPhase() && other->IsPhase());
504 return IsPhase() && other->IsPhase();
512 !std::includes(other->controls.begin(), other->controls.end(),
controls.begin(),
controls.end())) {
516 std::vector<bitCapInt> opfPows;
519 opfPows.emplace_back(
pow2(std::distance(other->controls.begin(), other->controls.find(ctrl))));
521 const bitCapInt p =
pow2(std::distance(other->controls.begin(), c));
522 std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
523 for (
const auto& payload : other->payloads) {
525 for (
size_t i = 0
U; i < opfPows.size(); ++i) {
530 const auto& poi =
payloads.find(pf);
532 nPayloads[payload.first] = payload.second;
534 nPayloads[payload.first ^ p] = payload.second;
537 other->payloads = nPayloads;
548 std::unique_ptr<complex[]> toRet(
new complex[maxQPower << 2U]);
551 complex* mtrx = toRet.get() + (i << 2U);
554 std::copy(identity, identity + 4U, mtrx);
558 const complex* oMtrx = p->second.get();
559 std::copy(oMtrx, oMtrx + 4U, mtrx);
575 const auto controlIt =
controls.find(c);
580 const size_t cpos = std::distance(
controls.begin(), controlIt);
584 const bitCapInt highMask = ~(lowMask | midPow);
588 std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
589 for (
const auto& payload :
payloads) {
590 if (
bi_compare(payload.first & qubitPow, eigenPow) != 0) {
593 nPayloads.emplace((payload.first & lowMask) | ((payload.first & highMask) >> 1U), payload.second);
618 bool setsIntersect(
const std::set<bitLenInt>& set1,
const std::set<bitLenInt>& set2)
620 auto it1 = set1.begin();
621 auto it2 = set2.begin();
623 while (it1 != set1.end() && it2 != set2.end()) {
626 }
else if (*it1 < *it2) {
640 QCircuit(
bool collapse =
true,
bool clifford =
false)
652 QCircuit(
bitLenInt qbCount,
const std::list<QCircuitGatePtr>& g,
bool collapse =
true,
bool clifford =
false)
657 for (
auto gIt = g.begin(); gIt != g.end(); ++gIt) {
658 gates.push_back((*gIt)->Clone());
667 for (
auto gIt = clone->gates.begin(); gIt != clone->gates.end(); ++gIt) {
668 for (
auto& p : (*gIt)->payloads) {
669 const complex* m = p.second.get();
670 complex inv[4U]{ conj(m[0
U]), conj(m[2U]), conj(m[1U]), conj(m[3U]) };
671 std::copy(inv, inv + 4U, p.second.get());
674 clone->gates.reverse();
715 const std::set<bitLenInt> s1{ q1 };
716 const std::set<bitLenInt> s2{ q2 };
730 gates.insert(
gates.end(), circuit->gates.begin(), circuit->gates.end());
742 for (
auto gIt = circuit->gates.begin(); gIt != circuit->gates.end(); ++gIt) {
762 if (gate->target != qubit) {
765 if (gate->IsInvert() && gate->controls.empty()) {
768 if (!(gate->IsPhase())) {
782 if (gate->target != qubit) {
785 if (gate->IsInvert() && gate->controls.empty()) {
789 if (!(gate->IsPhase())) {
802 std::list<QCircuitGatePtr> nGates;
805 if (gate->target == qubit) {
806 if (gate->IsInvert()) {
809 nGates.insert(nGates.begin(), nGate);
814 nGate->PostSelectControl(qubit, eigen);
815 nGates.insert(nGates.begin(), nGate);
826 std::list<QCircuitGatePtr> nGates;
828 for (
auto gIt =
gates.rbegin(); gIt !=
gates.rend(); ++gIt) {
831 std::set<bitLenInt> toCheck = gate->controls;
832 toCheck.insert(gate->target);
840 nGates.insert(nGates.begin(), gate->Clone());
843 qubits.insert(gate->target);
844 qubits.insert(gate->controls.begin(), gate->controls.end());
859 std::list<QCircuitGatePtr> oGates;
860 std::list<QCircuitGatePtr> nGates;
862 for (
auto gIt =
gates.rbegin(); gIt !=
gates.rend(); ++gIt) {
865 std::set<bitLenInt> toCheck = gate->controls;
866 toCheck.insert(gate->target);
870 oGates.insert(oGates.begin(), gate);
875 nGates.insert(nGates.begin(), gate);
877 qubits.insert(gate->target);
878 qubits.insert(gate->controls.begin(), gate->controls.end());
void bi_or_ip(BigInteger *left, const BigInteger &right)
Definition: big_integer.hpp:444
void bi_decrement(BigInteger *pBigInt, const BIG_INTEGER_WORD &value)
Definition: big_integer.hpp:237
int bi_compare_0(const BigInteger &left)
Definition: big_integer.hpp:140
int bi_compare(const BigInteger &left, const BigInteger &right)
Definition: big_integer.hpp:125
Definition: qcircuit.hpp:610
std::list< QCircuitGatePtr > GetGateList()
Return the raw list of gates.
Definition: qcircuit.hpp:692
bool isNearClifford
Definition: qcircuit.hpp:613
bitLenInt GetQubitCount()
Get the (automatically calculated) count of qubits in this circuit, so far.
Definition: qcircuit.hpp:682
bool DeleteClassicalTarget(bitLenInt qubit, bool eigen)
(If the qubit is not a target of a non-classical gate...) Delete this qubits' controls and phase targ...
Definition: qcircuit.hpp:800
void SetGateList(std::list< QCircuitGatePtr > gl)
Set the raw list of gates.
Definition: qcircuit.hpp:697
bitLenInt qubitCount
Definition: qcircuit.hpp:614
bool IsNonClassicalTarget(bitLenInt qubit, bool *eigen)
Check if an index is any target qubit of a nonclassical gate in this circuit.
Definition: qcircuit.hpp:779
bool setsIntersect(const std::set< bitLenInt > &set1, const std::set< bitLenInt > &set2)
Definition: qcircuit.hpp:618
void Append(QCircuitPtr circuit)
Append circuit (with identical qubit index mappings) at the end of this circuit.
Definition: qcircuit.hpp:725
bool IsNonClassicalTarget(bitLenInt qubit)
Check if an index is any target qubit of a nonclassical gate in this circuit.
Definition: qcircuit.hpp:759
void INC(const bitCapInt &toAdd, bitLenInt start, bitLenInt length)
Add integer (without sign)
Definition: arithmetic_qcircuit.cpp:23
QCircuitPtr RemovePastLightCone(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:857
QCircuit(bitLenInt qbCount, const std::list< QCircuitGatePtr > &g, bool collapse=true, bool clifford=false)
Manual constructor.
Definition: qcircuit.hpp:652
QCircuitPtr Inverse()
Definition: qcircuit.hpp:664
void Combine(QCircuitPtr circuit)
Combine circuit (with identical qubit index mappings) at the end of this circuit, by acting all addit...
Definition: qcircuit.hpp:737
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:824
QCircuit(bool collapse=true, bool clifford=false)
Default constructor.
Definition: qcircuit.hpp:640
bool AppendGate(QCircuitGatePtr nGate)
Add a gate to the gate sequence.
Definition: qcircuit.cpp:101
QCircuitPtr Clone()
Definition: qcircuit.hpp:662
void SetQubitCount(bitLenInt n)
Set the count of qubits in this circuit, so far.
Definition: qcircuit.hpp:687
void Run(QInterfacePtr qsim)
Run this circuit.
Definition: qcircuit.cpp:173
void Swap(bitLenInt q1, bitLenInt q2)
Add a Swap gate to the gate sequence.
Definition: qcircuit.hpp:702
std::list< QCircuitGatePtr > gates
Definition: qcircuit.hpp:615
bool isCollapsed
Definition: qcircuit.hpp:612
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:113
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:1199
std::istream & operator>>(std::istream &os, QCircuitGatePtr &g)
Definition: qcircuit.cpp:38
std::complex< real1 > complex
Definition: qrack_types.hpp:136
QRACK_CONST real1 FP_NORM_EPSILON
Definition: qrack_types.hpp:268
bitCapInt pow2(const bitLenInt &p)
Definition: qrack_functions.hpp:143
double norm(const complex2 &c)
Definition: complex16x2simd.hpp:122
QRACK_CONST complex ONE_CMPLX
Definition: qrack_types.hpp:262
std::shared_ptr< QCircuitGate > QCircuitGatePtr
Definition: qcircuit.hpp:48
std::shared_ptr< QCircuit > QCircuitPtr
Definition: qcircuit.hpp:607
std::ostream & operator<<(std::ostream &os, const QCircuitGatePtr g)
Definition: qcircuit.cpp:17
QRACK_CONST complex ZERO_CMPLX
Definition: qrack_types.hpp:263
const bitCapInt ONE_BCI
Definition: qrack_types.hpp:137
const bitCapInt ZERO_BCI
Definition: qrack_types.hpp:138
bitCapIntOcl pow2Ocl(const bitLenInt &p)
Definition: qrack_functions.hpp:144
#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:182
#define bitLenInt
Definition: qrack_types.hpp:42
#define bitCapInt
Definition: qrack_types.hpp:66
#define bitCapIntOcl
Definition: qrack_types.hpp:54
Definition: qcircuit.hpp:51
std::unique_ptr< complex[]> MakeUniformlyControlledPayload()
To run as a uniformly controlled gate, generate my payload array.
Definition: qcircuit.hpp:545
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:418
bool TryCombine(QCircuitGatePtr other, bool clifford=false)
Check if I can combine with gate other, and do so, if possible.
Definition: qcircuit.hpp:324
QCircuitGate()
Identity gate constructor.
Definition: qcircuit.hpp:59
std::vector< bitLenInt > GetControlsVector()
Convert my set of qubit indices to a vector.
Definition: qcircuit.hpp:568
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:492
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:436
bool IsPhaseInvert()
Am I a combination of "phase" and "invert" payloads?
Definition: qcircuit.hpp:402
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:454
bitLenInt target
Definition: qcircuit.hpp:52
bool IsPhase()
Am I a phase gate?
Definition: qcircuit.hpp:372
bool IsIdentity()
Am I an identity gate?
Definition: qcircuit.hpp:337
bool IsInvert()
Am I a Pauli X plus a phase gate?
Definition: qcircuit.hpp:387
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:573