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;
87 std::copy(matrix, matrix + 4,
payloads[0].get());
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());
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() + 4,
payloads[payload.first].get());
123 if (
target != other->target) {
127 if (!
controls.size() && !other->controls.size()) {
133 const bool oc = other->IsClifford();
140 return !
controls.size() || !other->controls.size() ||
141 (*(
controls.begin()) == *(other->controls.begin()));
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())) {
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);
189 nPayloads.emplace(nKey, payload.second);
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);
207 for (
const auto& payload :
payloads) {
208 const bitCapInt nKey = payload.first & ~midPow;
210 if (nKey == payload.first) {
240 const bitCapInt highMask = ~(lowMask | midPow);
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);
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()));
274 if (
controls.size() < other->controls.size()) {
275 for (
const bitLenInt& oc : other->controls) {
278 }
else if (
controls.size() > other->controls.size()) {
280 other->AddControl(c);
284 for (
const auto& payload : other->payloads) {
285 const auto& pit =
payloads.find(payload.first);
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());
294 complex* p = pit->second.get();
296 mul2x2(payload.second.get(), p, out);
305 std::copy(out, out + 4U, p);
358 for (
const auto& payload :
payloads) {
359 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();
434 for (
const auto& kvPair :
payloads) {
435 const complex* p = kvPair.second.get();
459 std::set<bitLenInt>::iterator c = other->controls.find(
target);
460 if (c != other->controls.end()) {
462 return IsPhase() && other->IsPhase();
468 !std::includes(other->controls.begin(), other->controls.end(),
controls.begin(),
controls.end())) {
472 std::vector<bitCapInt> opfPows;
475 opfPows.emplace_back(
pow2(std::distance(other->controls.begin(), other->controls.find(ctrl))));
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) {
481 for (
size_t i = 0
U; i < opfPows.size(); ++i) {
482 if (payload.first & opfPows[i]) {
486 const auto& poi =
payloads.find(pf);
488 nPayloads[payload.first] = payload.second;
490 nPayloads[payload.first ^ p] = payload.second;
493 other->payloads = nPayloads;
499 return other->IsPhase();
502 return (
target != other->target) || (
IsPhase() && other->IsPhase());
511 std::unique_ptr<complex[]> toRet(
new complex[maxQPower << 2U]);
514 complex* mtrx = toRet.get() + (i << 2U);
517 std::copy(identity, identity + 4, mtrx);
521 const complex* oMtrx = p->second.get();
522 std::copy(oMtrx, oMtrx + 4U, mtrx);
538 const auto controlIt =
controls.find(c);
543 const size_t cpos = std::distance(
controls.begin(), controlIt);
546 const bitCapInt highMask = ~(lowMask | midPow);
548 const bitCapInt eigenPow = eigen ? qubitPow : 0
U;
550 std::map<bitCapInt, std::shared_ptr<complex>> nPayloads;
551 for (
const auto& payload :
payloads) {
552 if ((payload.first & qubitPow) != eigenPow) {
555 const bitCapInt nKey = (payload.first & lowMask) | ((payload.first & highMask) >> 1U);
556 nPayloads.emplace(nKey, payload.second);
584 QCircuit(
bool collapse =
true,
bool clifford =
false)
596 QCircuit(
bitLenInt qbCount,
const std::list<QCircuitGatePtr>& g,
bool collapse =
true,
bool clifford =
false)
602 gates.push_back(gate->Clone());
612 for (
auto& p : gate->payloads) {
613 const complex* m = p.second.get();
614 complex inv[4U]{ conj(m[0
U]), conj(m[2U]), conj(m[1U]), conj(m[3U]) };
615 std::copy(inv, inv + 4U, p.second.get());
618 clone->gates.reverse();
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));
674 gates.insert(
gates.end(), circuit->gates.begin(), circuit->gates.end());
706 if ((gate->target == qubit) && !(gate->IsPhase())) {
719 std::list<QCircuitGatePtr> nGates;
722 if (gate->target == qubit) {
726 nGate->PostSelectControl(qubit, eigen);
727 nGates.insert(nGates.begin(), nGate);
740 std::list<QCircuitGatePtr> nGates;
743 if (qubits.find(gate->target) == qubits.end()) {
745 bool isNonCausal =
true;
746 for (
const bitLenInt& c : gate->controls) {
747 if (qubits.find(c) != qubits.end()) {
759 nGates.insert(nGates.begin(), gate->Clone());
762 qubits.insert(gate->target);
763 qubits.insert(gate->controls.begin(), gate->controls.end());
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