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);
341 if (
payloads.size() == controlPow) {
347 for (
const auto& payload :
payloads) {
348 complex* p = payload.second.get();
357 for (
const auto& payload :
payloads) {
358 complex* p = payload.second.get();
373 for (
const auto& payload :
payloads) {
374 complex* p = payload.second.get();
388 for (
const auto& payload :
payloads) {
389 complex* p = payload.second.get();
403 for (
const auto& payload :
payloads) {
404 complex* p = payload.second.get();
466 for (
const auto& kvPair :
payloads) {
467 const complex* p = kvPair.second.get();
491 const std::set<bitLenInt>::iterator c = other->controls.find(
target);
492 if (c == other->controls.end()) {
494 return other->IsPhase();
497 return (
target != other->target) || (
IsPhase() && other->IsPhase());
501 return IsPhase() && other->IsPhase();
507 !std::includes(other->controls.begin(), other->controls.end(),
controls.begin(),
controls.end())) {
511 std::vector<bitCapInt> opfPows;
514 opfPows.emplace_back(
pow2(std::distance(other->controls.begin(), other->controls.find(ctrl))));
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) {
520 for (
size_t i = 0
U; i < opfPows.size(); ++i) {
525 const auto& poi =
payloads.find(pf);
527 nPayloads[payload.first] = payload.second;
529 nPayloads[payload.first ^ p] = payload.second;
532 other->payloads = nPayloads;
543 std::unique_ptr<complex[]> toRet(
new complex[maxQPower << 2U]);
546 complex* mtrx = toRet.get() + (i << 2U);
549 std::copy(identity, identity + 4U, mtrx);
553 const complex* oMtrx = p->second.get();
554 std::copy(oMtrx, oMtrx + 4U, mtrx);
570 const auto controlIt =
controls.find(c);
575 const size_t cpos = std::distance(
controls.begin(), controlIt);
579 const bitCapInt highMask = ~(lowMask | midPow);
583 std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
584 for (
const auto& payload :
payloads) {
585 if (
bi_compare(payload.first & qubitPow, eigenPow) != 0) {
588 nPayloads.emplace((payload.first & lowMask) | ((payload.first & highMask) >> 1U), payload.second);
616 QCircuit(
bool collapse =
true,
bool clifford =
false)
628 QCircuit(
bitLenInt qbCount,
const std::list<QCircuitGatePtr>& g,
bool collapse =
true,
bool clifford =
false)
634 gates.push_back(gate->Clone());
644 for (
auto& p : gate->payloads) {
645 const complex* m = p.second.get();
646 complex inv[4U]{ conj(m[0
U]), conj(m[2U]), conj(m[1U]), conj(m[3U]) };
647 std::copy(inv, inv + 4U, p.second.get());
650 clone->gates.reverse();
691 const std::set<bitLenInt> s1 = { q1 };
692 const std::set<bitLenInt> s2 = { q2 };
706 gates.insert(
gates.end(), circuit->gates.begin(), circuit->gates.end());
738 if ((gate->target == qubit) && !(gate->IsPhase())) {
751 std::list<QCircuitGatePtr> nGates;
754 if (gate->target == qubit) {
758 nGate->PostSelectControl(qubit, eigen);
759 nGates.insert(nGates.begin(), nGate);
772 std::list<QCircuitGatePtr> nGates;
775 if (qubits.find(gate->target) == qubits.end()) {
777 bool isNonCausal =
true;
778 for (
const bitLenInt& c : gate->controls) {
779 if (qubits.find(c) != qubits.end()) {
791 nGates.insert(nGates.begin(), gate->Clone());
794 qubits.insert(gate->target);
795 qubits.insert(gate->controls.begin(), gate->controls.end());
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