From 06fc34c6e96a78da590eefbfd660c03ad0947287 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Mon, 3 Jun 2024 17:13:18 -0400 Subject: [PATCH 01/18] Default wires=1; fix endianness of outputs --- pennylane_qrack/qrack_device.cpp | 27 ++++++++++++++------------- pennylane_qrack/qrack_device.py | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index fa08eb2..9349f33 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -408,7 +408,10 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { keyMap["'is_gpu'"] = 8; keyMap["'is_host_pointer'"] = 9; - bitLenInt wires = 0U; + // If no argument is present, allocate one wire by default + bitLenInt wires = 1U; + qubit_map[0U] = 0U; + bool is_hybrid_stabilizer = true; bool is_tensor_network = false; bool is_schmidt_decomposed = true; @@ -423,6 +426,10 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { kwargs.erase(0, pos + 1U); if (key == "'wires'") { + // Clear the default wire map setup + wires = 0U; + qubit_map.clear(); + // Handle if integer pos = kwargs.find(","); bool isInt = true; @@ -757,6 +764,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { void PartialProbs(DataView &p, const std::vector &wires) override { RT_FAIL_IF((size_t)Qrack::pow2(wires.size()) != p.size(), "Invalid size for the pre-allocated probabilities vector"); + reverseWires(); auto &&dev_wires = getDeviceWires(wires); #if FPPOW == 6 qsim->ProbBitsAll(dev_wires, &(*(p.begin()))); @@ -765,6 +773,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->ProbBitsAll(dev_wires, _p.get()); std::copy(_p.get(), _p.get() + p.size(), p.begin()); #endif + reverseWires(); } void Sample(DataView &samples, size_t shots) override { @@ -772,11 +781,9 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { // that could be instead implied by the size of "samples." RT_FAIL_IF(samples.size() != shots, "Invalid size for the pre-allocated samples"); - reverseWires(); - std::vector qPowers(qsim->GetQubitCount()); for (bitLenInt i = 0U; i < qPowers.size(); ++i) { - qPowers[i] = Qrack::pow2(i); + qPowers[i] = Qrack::pow2(qPowers.size() - (i + 1U)); } auto q_samples = qsim->MultiShotMeasureMask(qPowers, shots); @@ -787,8 +794,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { *(samplesIter++) = bi_to_double((sample >> wire) & 1U); } } - - reverseWires(); } void PartialSample(DataView &samples, const std::vector &wires, size_t shots) override { @@ -799,7 +804,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { auto &&dev_wires = getDeviceWires(wires); std::vector qPowers(dev_wires.size()); for (size_t i = 0U; i < qPowers.size(); ++i) { - qPowers[i] = Qrack::pow2((bitLenInt)dev_wires[i]); + qPowers[i] = Qrack::pow2((bitLenInt)dev_wires[qPowers.size() - (i + 1U)]); } auto q_samples = qsim->MultiShotMeasureMask(qPowers, shots); @@ -822,11 +827,9 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { RT_FAIL_IF(eigvals.size() != numElements || counts.size() != numElements, "Invalid size for the pre-allocated counts"); - reverseWires(); - std::vector qPowers(numQubits); for (bitLenInt i = 0U; i < qPowers.size(); ++i) { - qPowers[i] = Qrack::pow2(i); + qPowers[i] = Qrack::pow2(qPowers.size() - (i + 1U)); } auto q_samples = qsim->MultiShotMeasureMask(qPowers, shots); @@ -842,8 +845,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { } ++counts(static_cast(basisState.to_ulong())); } - - reverseWires(); } void PartialCounts(DataView &eigvals, DataView &counts, @@ -860,7 +861,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { auto &&dev_wires = getDeviceWires(wires); std::vector qPowers(dev_wires.size()); for (size_t i = 0U; i < qPowers.size(); ++i) { - qPowers[i] = Qrack::pow2(dev_wires[i]); + qPowers[i] = Qrack::pow2(dev_wires[qPowers.size() - (i + 1U)]); } auto q_samples = qsim->MultiShotMeasureMask(qPowers, shots); diff --git a/pennylane_qrack/qrack_device.py b/pennylane_qrack/qrack_device.py index 8394afa..6585f98 100644 --- a/pennylane_qrack/qrack_device.py +++ b/pennylane_qrack/qrack_device.py @@ -154,7 +154,7 @@ def get_c_interface(): os.path.dirname(sys.modules[__name__].__file__) + "/libqrack_device.so", ) - def __init__(self, wires=0, shots=None, **kwargs): + def __init__(self, wires=1, shots=None, **kwargs): super().__init__(wires=wires, shots=shots) if "isTensorNetwork" in kwargs: From 62f1529b6a340c104dd7781a859745d2314b28cd Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Mon, 3 Jun 2024 20:31:47 -0400 Subject: [PATCH 02/18] Default 0 qubits --- pennylane_qrack/qrack_device.cpp | 13 ++++++------- pennylane_qrack/qrack_device.py | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index 9349f33..a5fbdd1 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -391,6 +391,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { , shots(1U) , qsim(nullptr) { + std::cout << kwargs << std::endl; // Cut leading '{' and trailing '}' kwargs.erase(0U, 1U); kwargs.erase(kwargs.size() - 1U); @@ -408,10 +409,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { keyMap["'is_gpu'"] = 8; keyMap["'is_host_pointer'"] = 9; - // If no argument is present, allocate one wire by default - bitLenInt wires = 1U; - qubit_map[0U] = 0U; - + bitLenInt wires = 0U; bool is_hybrid_stabilizer = true; bool is_tensor_network = false; bool is_schmidt_decomposed = true; @@ -426,9 +424,10 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { kwargs.erase(0, pos + 1U); if (key == "'wires'") { - // Clear the default wire map setup - wires = 0U; - qubit_map.clear(); + // Handle if empty: + if (kwargs.find("") != std::string::npos) { + continue; + } // Handle if integer pos = kwargs.find(","); diff --git a/pennylane_qrack/qrack_device.py b/pennylane_qrack/qrack_device.py index 6585f98..8394afa 100644 --- a/pennylane_qrack/qrack_device.py +++ b/pennylane_qrack/qrack_device.py @@ -154,7 +154,7 @@ def get_c_interface(): os.path.dirname(sys.modules[__name__].__file__) + "/libqrack_device.so", ) - def __init__(self, wires=1, shots=None, **kwargs): + def __init__(self, wires=0, shots=None, **kwargs): super().__init__(wires=wires, shots=shots) if "isTensorNetwork" in kwargs: From f46ef4023832763056f9c270ab289f5d8321fc5b Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Mon, 3 Jun 2024 21:35:09 -0400 Subject: [PATCH 03/18] Fix kwargs parsing edge case --- pennylane_qrack/qrack_device.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index a5fbdd1..3290759 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -424,8 +424,9 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { kwargs.erase(0, pos + 1U); if (key == "'wires'") { - // Handle if empty: - if (kwargs.find("") != std::string::npos) { + // Handle if empty + // We look for ',' or npos, to respect other Wires value kwargs + if (kwargs.find("") != kwargs.find(",")) { continue; } From a520a0c8db04fcc95e2e06de16c5f09bf00db3df Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Mon, 3 Jun 2024 21:57:53 -0400 Subject: [PATCH 04/18] Quantitative exception message (@vprusso) --- pennylane_qrack/qrack_device.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index 3290759..d83ae8f 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -544,7 +544,9 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { auto AllocateQubit() -> QubitIdType override { if (allocated_qubits >= qubit_map.size()) { - throw std::runtime_error("Catalyst has requested more qubits than exist in device. (Set your wires count high enough, for the device.)"); + throw std::runtime_error("Catalyst has requested more qubits than exist in device, with " + + std::to_string(allocated_qubits) + " allocated qubits. " + + "(Set your wires count high enough, for the device.)"); } auto it = qubit_map.begin(); std::advance(it, allocated_qubits); From 0efb550f78501c5721bfa5625e956d60ff496623 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 13:52:54 -0400 Subject: [PATCH 05/18] qjit unit test --- tests/test_integration.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index 8200fc4..38886a8 100755 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -15,7 +15,7 @@ import numpy as np import pennylane as qml from pennylane_qrack.qrack_device import QrackDevice - +from catalyst import qjit class TestIntegration: """Some basic integration tests.""" @@ -46,3 +46,22 @@ def circuit(): res = circuit() expected = np.array([np.sin(-theta) * np.sin(phi), np.sin(phi)]) assert np.allclose(res, expected, atol=0.05) + + def test_expectation_qjit(self): + """Test that expectation of a non-trivial circuit is correct.""" + dev = QrackDevice(2, shots=int(1e6), isOpenCL=False) + + theta = 0.432 + phi = 0.123 + + @qjit + @qml.qnode(dev) + def circuit(): + qml.adjoint(qml.RY(theta, wires=[0])) + qml.RY(phi, wires=[1]) + qml.CNOT(wires=[0, 1]) + return qml.expval(qml.PauliX(wires=0)), qml.expval(qml.PauliX(wires=1)) + + res = circuit() + expected = np.array([np.sin(-theta) * np.sin(phi), np.sin(phi)]) + assert np.allclose(res, expected, atol=0.05) From f80b796676fde2418cd04bf5d8d44306f88b9319 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 15:03:38 -0400 Subject: [PATCH 06/18] Unit tests and debugging --- pennylane_qrack/qrack_device.cpp | 62 +++++++++++++++++--------------- pennylane_qrack/qrack_device.py | 18 +++++----- tests/test_apply.py | 47 +++++++++++++++++++++++- 3 files changed, 90 insertions(+), 37 deletions(-) diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index d83ae8f..e64102c 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -183,18 +183,24 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { } else if (name == "U3") { for (const bitLenInt& target : wires) { if (inverse) { - qsim->U(target, -params[0U], -params[1U], -params[2U]); + qsim->U(target, -params[0U], -params[2U], -params[1U]); } else { qsim->U(target, params[0U], params[1U], params[2U]); } } } else if (name == "U2") { + const Qrack::real1 th = inverse ? -params[0U] : params[0U]; + const Qrack::real1 ph = inverse ? -params[1U] : params[1U]; + const Qrack::complex u2Mtrx[4U] = { + Qrack::SQRT1_2_R1, + Qrack::SQRT1_2_R1 * -exp(Qrack::complex(ZERO_R1, ph)), + Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th)), + Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th + ph)), + }; + Qrack::complex iU2Mtrx[4U]; + Qrack::inv2x2(u2Mtrx, iU2Mtrx); for (const bitLenInt& target : wires) { - if (inverse) { - qsim->U(target, -Qrack::PI_R1 / 2, -params[0U], -params[1U]); - } else { - qsim->U(target, Qrack::PI_R1 / 2, params[0U], params[1U]); - } + qsim->Mtrx(inverse ? iU2Mtrx : u2Mtrx, target); } } else if (name != "Identity") { throw std::domain_error("Unrecognized gate name: " + name); @@ -351,34 +357,35 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->UCMtrx(control_wires, mtrx, target, controlPerm); } } else if (name == "U3") { - const Qrack::real1 theta = inverse ? -params[0U] : params[0U]; - const Qrack::real1 phi = inverse ? -params[1U] : params[1U]; - const Qrack::real1 lambda = inverse ? -params[2U] : params[2U]; - const Qrack::real1 cos0 = (Qrack::real1)cos(theta / 2); - const Qrack::real1 sin0 = (Qrack::real1)sin(theta / 2); + const Qrack::real1 th = params[0U]; + const Qrack::real1 ph = params[1U]; + const Qrack::real1 lm = params[2U]; + const Qrack::real1 cos0 = (Qrack::real1)cos(th / 2); + const Qrack::real1 sin0 = (Qrack::real1)sin(th / 2); const Qrack::complex mtrx[4U]{ - Qrack::complex(cos0, ZERO_R1), sin0 * Qrack::complex((Qrack::real1)(-cos(lambda)), - (Qrack::real1)(-sin(lambda))), - sin0 * Qrack::complex((Qrack::real1)cos(phi), (Qrack::real1)sin(phi)), - cos0 * Qrack::complex((Qrack::real1)cos(phi + lambda), (Qrack::real1)sin(phi + lambda)) + Qrack::complex(cos0, ZERO_R1), sin0 * Qrack::complex((Qrack::real1)(-cos(lm)), + (Qrack::real1)(-sin(lm))), + sin0 * Qrack::complex((Qrack::real1)cos(ph), (Qrack::real1)sin(ph)), + cos0 * Qrack::complex((Qrack::real1)cos(ph + lm), (Qrack::real1)sin(ph + lm)) }; + Qrack::complex iMtrx[4U]; + Qrack::inv2x2(mtrx, iMtrx); for (const bitLenInt& target : wires) { - qsim->UCMtrx(control_wires, mtrx, target, controlPerm); + qsim->UCMtrx(control_wires, inverse ? iMtrx : mtrx, target, controlPerm); } } else if (name == "U2") { - const Qrack::real1 theta = (inverse ? -Qrack::PI_R1 : Qrack::PI_R1) / 2; - const Qrack::real1 phi = inverse ? -params[0U] : params[0U]; - const Qrack::real1 lambda = inverse ? -params[1U] : params[1U]; - const Qrack::real1 cos0 = (Qrack::real1)cos(theta / 2); - const Qrack::real1 sin0 = (Qrack::real1)sin(theta / 2); - const Qrack::complex mtrx[4U]{ - Qrack::complex(cos0, ZERO_R1), sin0 * Qrack::complex((Qrack::real1)(-cos(lambda)), - (Qrack::real1)(-sin(lambda))), - sin0 * Qrack::complex((Qrack::real1)cos(phi), (Qrack::real1)sin(phi)), - cos0 * Qrack::complex((Qrack::real1)cos(phi + lambda), (Qrack::real1)sin(phi + lambda)) + const Qrack::real1 th = params[0U]; + const Qrack::real1 ph = params[1U]; + const Qrack::complex u2Mtrx[4U] = { + Qrack::SQRT1_2_R1, + Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, ph)), + Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th)), + Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th + ph)), }; + Qrack::complex iU2Mtrx[4U]; + Qrack::inv2x2(u2Mtrx, iU2Mtrx); for (const bitLenInt& target : wires) { - qsim->UCMtrx(control_wires, mtrx, target, controlPerm); + qsim->UCMtrx(control_wires, inverse ? iU2Mtrx : u2Mtrx, target, controlPerm); } } else if (name != "Identity") { throw std::domain_error("Unrecognized gate name: " + name); @@ -391,7 +398,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { , shots(1U) , qsim(nullptr) { - std::cout << kwargs << std::endl; // Cut leading '{' and trailing '}' kwargs.erase(0U, 1U); kwargs.erase(kwargs.size() - 1U); diff --git a/pennylane_qrack/qrack_device.py b/pennylane_qrack/qrack_device.py index 8394afa..d673675 100644 --- a/pennylane_qrack/qrack_device.py +++ b/pennylane_qrack/qrack_device.py @@ -515,20 +515,22 @@ def _apply_gate(self, op): device_wires.labels[-1], ) elif opname == "U2": + sqrt1_2 = 1/math.sqrt(2) u2_mtrx = [ - 1, - cmath.exp(1j * par[1]), - cmath.exp(1j * par[0]), - cmath.exp(1j * (par[0] + par[1])), + sqrt1_2, + sqrt1_2 * cmath.exp(1j * par[1]), + sqrt1_2 * cmath.exp(1j * par[0]), + sqrt1_2 * cmath.exp(1j * (par[0] + par[1])), ] for label in device_wires.labels: self._state.mtrx(u2_mtrx, label) elif opname == "U2.inv": + sqrt1_2 = 1/math.sqrt(2) iu2_mtrx = [ - 1, - cmath.exp(1j * -par[1]), - cmath.exp(1j * -par[0]), - cmath.exp(1j * (-par[0] - par[1])), + sqrt1_2, + sqrt1_2 * cmath.exp(1j * -par[1]), + sqrt1_2 * cmath.exp(1j * -par[0]), + sqrt1_2 * cmath.exp(1j * (-par[0] + -par[1])), ] for label in device_wires.labels: self._state.mtrx(iu2_mtrx, label) diff --git a/tests/test_apply.py b/tests/test_apply.py index 3a3a215..29b69fc 100755 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -18,6 +18,7 @@ import pennylane as qml from scipy.linalg import block_diag from pennylane_qrack.qrack_device import QrackDevice +from catalyst import qjit from conftest import U, U2, A @@ -26,6 +27,7 @@ # ========================================================== # Some useful global variables +sqrt1_2 = 1 / np.sqrt(2) # non-parametrized qubit gates I = np.identity(2) @@ -53,7 +55,7 @@ ry = lambda theta: np.cos(theta / 2) * I + 1j * np.sin(-theta / 2) * Y rz = lambda theta: np.cos(theta / 2) * I + 1j * np.sin(-theta / 2) * Z u2 = lambda phi, delta: np.array( - [[1, np.exp(1j * delta)], [np.exp(1j * phi), np.exp(1j * (phi + delta))]] + [[sqrt1_2, sqrt1_2 * np.exp(1j * delta)], [sqrt1_2 * np.exp(1j * phi), sqrt1_2 * np.exp(1j * (phi + delta))]] ) u3 = lambda theta, phi, delta: np.array( [ @@ -307,6 +309,26 @@ def test_single_qubit_no_parameters(self, init_state, op, mat, tol): expected = mat @ state assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("op,mat", single_qubit) + def test_single_qubit_no_parameters_qjit(self, init_state, op, mat, tol): + """Test PauliX application""" + dev = QrackDevice(1, isOpenCL=False) + state = init_state(1) + + @qjit + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=[0]) + qml.apply(op) + return qml.probs() + + dev._obs_queue = [] + + res = circuit() + expected = mat @ state + expected = [(x * x.conj()).real for x in expected] + assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("theta", [0.5432, -0.232]) @pytest.mark.parametrize("op,func", single_qubit_param) def test_single_qubit_parameters(self, init_state, op, func, theta, tol): @@ -322,6 +344,29 @@ def test_single_qubit_parameters(self, init_state, op, func, theta, tol): expected = func(theta) @ state assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", single_qubit_param) + def test_single_qubit_parameters_qjit(self, init_state, op, func, theta, tol): + """Test PauliX application""" + dev = QrackDevice(1, isOpenCL=False) + state = init_state(1) + + op.data = [theta] + + @qjit + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=[0]) + qml.apply(op) + return qml.probs() + + dev._obs_queue = [] + + res = circuit() + expected = func(theta) @ state + expected = [(x * x.conj()).real for x in expected] + assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("phi", [0.126, -0.721]) @pytest.mark.parametrize("delta", [0.5432, -0.232]) @pytest.mark.parametrize("op,func", single_qubit_two_param) From cfa2ee0b20d5a43e01c42cd98aebf5d21002d58a Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 15:25:58 -0400 Subject: [PATCH 07/18] Debugging and phasse gates --- pennylane_qrack/QrackDeviceConfig.toml | 4 +- pennylane_qrack/qrack_device.cpp | 32 +------------- pennylane_qrack/qrack_device.py | 58 +++----------------------- tests/test_apply.py | 35 +++++++++------- 4 files changed, 29 insertions(+), 100 deletions(-) diff --git a/pennylane_qrack/QrackDeviceConfig.toml b/pennylane_qrack/QrackDeviceConfig.toml index ca3a67e..3006a79 100644 --- a/pennylane_qrack/QrackDeviceConfig.toml +++ b/pennylane_qrack/QrackDeviceConfig.toml @@ -44,8 +44,6 @@ CRY = { properties = [ "controllable", "invertible" ] } CRZ = { properties = [ "controllable", "invertible" ] } CRot = { properties = [ "controllable", "invertible" ] } U3 = { properties = [ "controllable", "invertible" ] } -U2 = { properties = [ "controllable", "invertible" ] } -U1 = { properties = [ "controllable", "invertible" ] } MultiControlledX = { properties = [ "controllable", "invertible" ] } Identity = { properties = [ "controllable", "invertible" ] } @@ -78,6 +76,8 @@ Identity = { properties = [ "controllable", "invertible" ] } # IsingYY = {} # IsingZZ = {} # IsingXY = {} +# U2 = {} +# U1 = {} # QFT = {} # Gates which should be translated to QubitUnitary diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index e64102c..6a1294f 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -151,7 +151,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->CU(c, wires[1U], ZERO_R1, ZERO_R1, inverse ? -params[0U] : params[0U]); qsim->Swap(wires[0U], wires[1U]); qsim->CU(c, wires[1U], ZERO_R1, ZERO_R1, inverse ? -params[0U] : params[0U]); - } else if ((name == "PhaseShift") || (name == "U1")) { + } else if (name == "PhaseShift") { const Qrack::complex bottomRight = exp(Qrack::I_CMPLX * (Qrack::real1)(inverse ? -params[0U] : params[0U])); for (const bitLenInt& target : wires) { qsim->Phase(Qrack::ONE_CMPLX, bottomRight, target); @@ -188,20 +188,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->U(target, params[0U], params[1U], params[2U]); } } - } else if (name == "U2") { - const Qrack::real1 th = inverse ? -params[0U] : params[0U]; - const Qrack::real1 ph = inverse ? -params[1U] : params[1U]; - const Qrack::complex u2Mtrx[4U] = { - Qrack::SQRT1_2_R1, - Qrack::SQRT1_2_R1 * -exp(Qrack::complex(ZERO_R1, ph)), - Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th)), - Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th + ph)), - }; - Qrack::complex iU2Mtrx[4U]; - Qrack::inv2x2(u2Mtrx, iU2Mtrx); - for (const bitLenInt& target : wires) { - qsim->Mtrx(inverse ? iU2Mtrx : u2Mtrx, target); - } } else if (name != "Identity") { throw std::domain_error("Unrecognized gate name: " + name); } @@ -305,7 +291,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->X(control_wires[i]); } } - } else if ((name == "PhaseShift") || (name == "U1") || (name == "ControlledPhaseShift") || (name == "CPhase")) { + } else if ((name == "PhaseShift") || (name == "ControlledPhaseShift") || (name == "CPhase")) { const Qrack::complex bottomRight = exp(Qrack::I_CMPLX * (Qrack::real1)(inverse ? -params[0U] : params[0U])); for (const bitLenInt& target : wires) { qsim->UCPhase(control_wires, Qrack::ONE_CMPLX, bottomRight, target, controlPerm); @@ -373,20 +359,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { for (const bitLenInt& target : wires) { qsim->UCMtrx(control_wires, inverse ? iMtrx : mtrx, target, controlPerm); } - } else if (name == "U2") { - const Qrack::real1 th = params[0U]; - const Qrack::real1 ph = params[1U]; - const Qrack::complex u2Mtrx[4U] = { - Qrack::SQRT1_2_R1, - Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, ph)), - Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th)), - Qrack::SQRT1_2_R1 * exp(Qrack::complex(ZERO_R1, th + ph)), - }; - Qrack::complex iU2Mtrx[4U]; - Qrack::inv2x2(u2Mtrx, iU2Mtrx); - for (const bitLenInt& target : wires) { - qsim->UCMtrx(control_wires, inverse ? iU2Mtrx : u2Mtrx, target, controlPerm); - } } else if (name != "Identity") { throw std::domain_error("Unrecognized gate name: " + name); } diff --git a/pennylane_qrack/qrack_device.py b/pennylane_qrack/qrack_device.py index d673675..fdcd25a 100644 --- a/pennylane_qrack/qrack_device.py +++ b/pennylane_qrack/qrack_device.py @@ -127,10 +127,6 @@ class QrackDevice(QubitDevice): "C(SX)", "PhaseShift", "C(PhaseShift)", - "U1", - "C(U1)", - "U2", - "C(U2)", "U3", "C(U3)", "Rot", @@ -472,21 +468,21 @@ def _apply_gate(self, op): [(1 + 1j) / 2, (1 - 1j) / 2, (1 - 1j) / 2, (1 + 1j) / 2], device_wires.labels[-1], ) - elif opname in ["PhaseShift", "U1"]: + elif opname == "PhaseShift": p_mtrx = [1, 0, 0, cmath.exp(1j * par[0])] for label in device_wires.labels: self._state.mtrx(p_mtrx, label) - elif opname in ["PhaseShift.inv", "U1.inv"]: + elif opname == "PhaseShift.inv": ip_mtrx = [1, 0, 0, cmath.exp(1j * -par[0])] for label in device_wires.labels: self._state.mtrx(ip_mtrx, label) - elif opname in ["C(PhaseShift)", "C(U1)"]: + elif opname == "C(PhaseShift)": self._state.mtrx( device_wires.labels[:-1], [1, 0, 0, cmath.exp(1j * par[0])], device_wires.labels[-1], ) - elif opname in ["C(PhaseShift).inv", "C(U1).inv"]: + elif opname == "C(PhaseShift).inv": self._state.mtrx( device_wires.labels[:-1], [1, 0, 0, cmath.exp(1j * -par[0])], @@ -514,54 +510,12 @@ def _apply_gate(self, op): [1, 0, 0, cmath.exp(1j * -par[0])], device_wires.labels[-1], ) - elif opname == "U2": - sqrt1_2 = 1/math.sqrt(2) - u2_mtrx = [ - sqrt1_2, - sqrt1_2 * cmath.exp(1j * par[1]), - sqrt1_2 * cmath.exp(1j * par[0]), - sqrt1_2 * cmath.exp(1j * (par[0] + par[1])), - ] - for label in device_wires.labels: - self._state.mtrx(u2_mtrx, label) - elif opname == "U2.inv": - sqrt1_2 = 1/math.sqrt(2) - iu2_mtrx = [ - sqrt1_2, - sqrt1_2 * cmath.exp(1j * -par[1]), - sqrt1_2 * cmath.exp(1j * -par[0]), - sqrt1_2 * cmath.exp(1j * (-par[0] + -par[1])), - ] - for label in device_wires.labels: - self._state.mtrx(iu2_mtrx, label) - elif opname == "C(U2)": - self._state.mcmtrx( - device_wires.labels[:-1], - [ - 1, - cmath.exp(1j * par[1]), - cmath.exp(1j * par[0]), - cmath.exp(1j * (par[0] + par[1])), - ], - device_wires.labels[-1], - ) - elif opname == "C(U2).inv": - self._state.mcmtrx( - device_wires.labels[:-1], - [ - 1, - cmath.exp(1j * -par[1]), - cmath.exp(1j * -par[0]), - cmath.exp(1j * (-par[0] - par[1])), - ], - device_wires.labels[-1], - ) elif opname == "U3": for label in device_wires.labels: self._state.u(label, par[0], par[1], par[2]) elif opname == "U3.inv": for label in device_wires.labels: - self._state.u(label, -par[0], -par[1], -par[2]) + self._state.u(label, -par[0], -par[2], -par[1]) elif opname == "Rot": for label in device_wires.labels: self._state.r(Pauli.PauliZ, par[0], label) @@ -585,8 +539,8 @@ def _apply_gate(self, op): device_wires.labels[:-1], device_wires.labels[-1], -par[0], - -par[1], -par[2], + -par[1], ) elif opname not in [ "Identity", diff --git a/tests/test_apply.py b/tests/test_apply.py index 29b69fc..44dc3c7 100755 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -54,9 +54,6 @@ rx = lambda theta: np.cos(theta / 2) * I + 1j * np.sin(-theta / 2) * X ry = lambda theta: np.cos(theta / 2) * I + 1j * np.sin(-theta / 2) * Y rz = lambda theta: np.cos(theta / 2) * I + 1j * np.sin(-theta / 2) * Z -u2 = lambda phi, delta: np.array( - [[sqrt1_2, sqrt1_2 * np.exp(1j * delta)], [sqrt1_2 * np.exp(1j * phi), sqrt1_2 * np.exp(1j * (phi + delta))]] -) u3 = lambda theta, phi, delta: np.array( [ [np.cos(theta / 2), -np.exp(1j * delta) * np.sin(theta / 2)], @@ -141,15 +138,11 @@ (qml.adjoint(qml.RZ(0, wires=0)), lambda theta: rz(-theta)), (qml.adjoint(qml.PhaseShift(0, wires=0)), lambda theta: phase_shift(-theta)), ] -single_qubit_two_param = [ - (qml.U2(0, 0, wires=0), u2), - (qml.adjoint(qml.U2(0, 0, wires=0)), lambda phi, delta: u2(-phi, -delta)), -] single_qubit_three_param = [ (qml.U3(0, 0, 0, wires=0), u3), ( qml.adjoint(qml.U3(0, 0, 0, wires=0)), - lambda theta, phi, delta: u3(-theta, -phi, -delta), + lambda theta, phi, delta: u3(-theta, -delta, -phi), ), ] # list of all non-parametrized two-qubit gates @@ -368,26 +361,29 @@ def circuit(): assert np.allclose(res, expected, tol) @pytest.mark.parametrize("phi", [0.126, -0.721]) - @pytest.mark.parametrize("delta", [0.5432, -0.232]) - @pytest.mark.parametrize("op,func", single_qubit_two_param) - def test_single_qubit_two_parameters(self, init_state, op, func, phi, delta, tol): + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("omega", [1.213, -0.221]) + @pytest.mark.parametrize("op,func", single_qubit_three_param) + def test_single_qubit_three_parameters( + self, init_state, op, func, phi, theta, omega, tol + ): """Test PauliX application""" dev = QrackDevice(1, isOpenCL=False) state = init_state(1) - op.data = [phi, delta] + op.data = [phi, theta, omega] dev.apply([qml.QubitStateVector(state, wires=[0]), op]) dev._obs_queue = [] res = dev.state - expected = func(phi, delta) @ state + expected = func(phi, theta, omega) @ state assert np.allclose(res, expected, tol) @pytest.mark.parametrize("phi", [0.126, -0.721]) @pytest.mark.parametrize("theta", [0.5432, -0.232]) @pytest.mark.parametrize("omega", [1.213, -0.221]) @pytest.mark.parametrize("op,func", single_qubit_three_param) - def test_single_qubit_three_parameters( + def test_single_qubit_three_parameters_qjit( self, init_state, op, func, phi, theta, omega, tol ): """Test PauliX application""" @@ -395,11 +391,18 @@ def test_single_qubit_three_parameters( state = init_state(1) op.data = [phi, theta, omega] - dev.apply([qml.QubitStateVector(state, wires=[0]), op]) + @qjit + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=[0]) + qml.apply(op) + return qml.probs() + dev._obs_queue = [] - res = dev.state + res = circuit() expected = func(phi, theta, omega) @ state + expected = [(x * x.conj()).real for x in expected] assert np.allclose(res, expected, tol) @pytest.mark.parametrize("op, mat", two_qubit) From ec4b63d2bf1eb6c9f39f608f8863b3629615028f Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 16:03:40 -0400 Subject: [PATCH 08/18] Unit tests --- tests/test_apply.py | 82 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/tests/test_apply.py b/tests/test_apply.py index 44dc3c7..c6f23f7 100755 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -418,6 +418,25 @@ def test_two_qubit_no_parameters(self, init_state, op, mat, tol): expected = mat @ state assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("op, mat", two_qubit) + def test_two_qubit_no_parameters_qjit(self, init_state, op, mat, tol): + """Test PauliX application""" + dev = QrackDevice(2, isOpenCL=False) + state = init_state(2) + + @qjit + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=[0, 1]) + qml.apply(op) + return qml.probs() + dev._obs_queue = [] + + res = circuit() + expected = mat @ state + expected = [(x * x.conj()).real for x in expected] + assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("mat", [U]) def test_qubit_unitary(self, init_state, mat, tol): """Test QubitUnitary application""" @@ -434,6 +453,28 @@ def test_qubit_unitary(self, init_state, mat, tol): expected = mat @ state assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("mat", [U]) + def test_qubit_unitary_qjit(self, init_state, mat, tol): + """Test QubitUnitary application""" + + N = int(np.log2(len(mat))) + dev = QrackDevice(N, isOpenCL=False) + state = init_state(N) + + op = qml.QubitUnitary(mat, wires=list(range(N))) + @qjit + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=list(range(N))) + qml.apply(op) + return qml.probs() + dev._obs_queue = [] + + res = circuit() + expected = mat @ state + expected = [(x * x.conj()).real for x in expected] + assert np.allclose(res, expected, tol) + def test_invalid_qubit_state_unitary(self): """Test that an exception is raised if the unitary matrix is the wrong size""" @@ -454,6 +495,24 @@ def test_three_qubit_no_parameters(self, init_state, op, mat, tol): expected = mat @ state assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("op, mat", three_qubit) + def test_three_qubit_no_parameters_qjit(self, init_state, op, mat, tol): + dev = QrackDevice(3, isOpenCL=False) + state = init_state(3) + + @qjit + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=[0, 1, 2]) + qml.apply(op) + return qml.probs() + dev._obs_queue = [] + + res = circuit() + expected = mat @ state + expected = [(x * x.conj()).real for x in expected] + assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("op, mat", four_qubit) def test_four_qubit_no_parameters(self, init_state, op, mat, tol): dev = QrackDevice(4, isOpenCL=False) @@ -482,6 +541,28 @@ def test_two_qubit_parameters(self, init_state, op, func, theta, tol): expected = func(theta) @ state assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("theta", [0.5432, -0.232]) + @pytest.mark.parametrize("op,func", two_qubit_param) + def test_two_qubit_parameters_qjit(self, init_state, op, func, theta, tol): + """Test parametrized two qubit gates application""" + dev = QrackDevice(2, isOpenCL=False) + state = init_state(2) + + op.data = [theta] + @qjit + @qml.qnode(dev) + def circuit(): + qml.StatePrep(state, wires=[0, 1]) + qml.apply(op) + return qml.probs() + + dev._obs_queue = [] + + res = circuit() + expected = func(theta) @ state + expected = [(x * x.conj()).real for x in expected] + assert np.allclose(res, expected, tol) + @pytest.mark.parametrize("phi", [0.126, -0.721]) @pytest.mark.parametrize("theta", [0.5432, -0.232]) @pytest.mark.parametrize("omega", [1.213, -0.221]) @@ -495,7 +576,6 @@ def test_two_qubit_three_parameters( op.data = [phi, theta, omega] dev.apply([qml.QubitStateVector(state, wires=[0, 1]), op]) - dev._obs_queue = [] res = dev.state From c11e871d1c8b7deeca94a271db17a2418f815750 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 16:32:42 -0400 Subject: [PATCH 09/18] Fix CRot --- pennylane_qrack/qrack_device.cpp | 25 ++++++++++++++----------- pennylane_qrack/qrack_device.py | 7 ++++--- tests/test_apply.py | 4 +++- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index 6a1294f..1017d38 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -169,16 +169,19 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->RZ(inverse ? -params[0U] : params[0U], target); } } else if (name == "Rot") { + const Qrack::real1 phi = inverse ? -params[2U] : params[0U]; + const Qrack::real1 theta = inverse ? -params[1U] : params[1U]; + const Qrack::real1 omega = inverse ? -params[0U] : params[2U]; + const Qrack::real1 cos0 = (Qrack::real1)cos(theta / 2); + const Qrack::real1 sin0 = (Qrack::real1)sin(theta / 2); + const Qrack::complex expP = exp(Qrack::I_CMPLX * (phi + omega) / (2 * ONE_R1)); + const Qrack::complex expM = exp(Qrack::I_CMPLX * (phi - omega) / (2 * ONE_R1)); + const Qrack::complex mtrx[4U]{ + cos0 / expP, -sin0 * expM, + sin0 / expM, cos0 * expP + }; for (const bitLenInt& target : wires) { - if (inverse) { - qsim->RZ(-params[2U], target); - qsim->RY(-params[1U], target); - qsim->RZ(-params[0U], target); - } else { - qsim->RZ(params[0U], target); - qsim->RY(params[1U], target); - qsim->RZ(params[2U], target); - } + qsim->Mtrx(mtrx, target); } } else if (name == "U3") { for (const bitLenInt& target : wires) { @@ -328,9 +331,9 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->UCPhase(control_wires, conj(bottomRight), bottomRight, target, controlPerm); } } else if ((name == "Rot") || (name == "CRot")) { - const Qrack::real1 phi = inverse ? -params[0U] : params[0U]; + const Qrack::real1 phi = inverse ? -params[2U] : params[0U]; const Qrack::real1 theta = inverse ? -params[1U] : params[1U]; - const Qrack::real1 omega = inverse ? -params[2U] : params[2U]; + const Qrack::real1 omega = inverse ? -params[0U] : params[2U]; const Qrack::real1 cos0 = (Qrack::real1)cos(theta / 2); const Qrack::real1 sin0 = (Qrack::real1)sin(theta / 2); const Qrack::complex expP = exp(Qrack::I_CMPLX * (phi + omega) / (2 * ONE_R1)); diff --git a/pennylane_qrack/qrack_device.py b/pennylane_qrack/qrack_device.py index fdcd25a..3837f95 100644 --- a/pennylane_qrack/qrack_device.py +++ b/pennylane_qrack/qrack_device.py @@ -338,16 +338,17 @@ def _apply_gate(self, op): theta = par[1] omega = par[2] if ".inv" in opname: - phi = -phi + tmp = phi + phi = -omega theta = -theta - omega = -omega + omega = -phi c = math.cos(theta / 2) s = math.sin(theta / 2) mtrx = [ cmath.exp(-0.5j * (phi + omega)) * c, cmath.exp(0.5j * (phi - omega)) * s, cmath.exp(-0.5j * (phi - omega)) * s, - cmath.exp(0.5j * (phi + omega)) * c, + cmath.exp(0.5j * (phi + omega)) * np.cos(theta / 2), ] self._state.mcmtrx(device_wires.labels[:-1], mtrx, device_wires.labels[-1]) elif opname in ["SWAP", "SWAP.inv"]: diff --git a/tests/test_apply.py b/tests/test_apply.py index c6f23f7..37bfc5a 100755 --- a/tests/test_apply.py +++ b/tests/test_apply.py @@ -174,7 +174,7 @@ (qml.CRot(0, 0, 0, wires=[0, 1]), crot), ( qml.adjoint(qml.CRot(0, 0, 0, wires=[0, 1])), - lambda phi, theta, omega: crot(-phi, -theta, -omega), + lambda phi, theta, omega: crot(-omega, -theta, -phi), ), ] # list of all three-qubit gates @@ -579,7 +579,9 @@ def test_two_qubit_three_parameters( dev._obs_queue = [] res = dev.state + res = [(x * np.conjugate(x)).real for x in res] expected = func(phi, theta, omega) @ state + expected = [(x * x.conj()).real for x in expected] assert np.allclose(res, expected, tol) def test_apply_errors_qubit_state_vector(self): From 9c395e6e26bc58b21690994d748c5f764d912c66 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 16:36:59 -0400 Subject: [PATCH 10/18] Add Catalyst to requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 3d8ded2..2f5b670 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ pennylane>=0.32 +pennylane-catalyst>=0.6 pyqrack>=0.13.0 numpy~=1.16 scikit-build From e4ede09216f06bb8409538305f167f63a2735c39 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 16:55:54 -0400 Subject: [PATCH 11/18] Fix endiannnes --- pennylane_qrack/qrack_device.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pennylane_qrack/qrack_device.cpp b/pennylane_qrack/qrack_device.cpp index 1017d38..6d281d8 100644 --- a/pennylane_qrack/qrack_device.cpp +++ b/pennylane_qrack/qrack_device.cpp @@ -747,8 +747,8 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { void PartialProbs(DataView &p, const std::vector &wires) override { RT_FAIL_IF((size_t)Qrack::pow2(wires.size()) != p.size(), "Invalid size for the pre-allocated probabilities vector"); - reverseWires(); auto &&dev_wires = getDeviceWires(wires); + std::reverse(dev_wires.begin(), dev_wires.end()); #if FPPOW == 6 qsim->ProbBitsAll(dev_wires, &(*(p.begin()))); #else @@ -756,7 +756,6 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { qsim->ProbBitsAll(dev_wires, _p.get()); std::copy(_p.get(), _p.get() + p.size(), p.begin()); #endif - reverseWires(); } void Sample(DataView &samples, size_t shots) override { @@ -787,7 +786,7 @@ struct QrackDevice final : public Catalyst::Runtime::QuantumDevice { auto &&dev_wires = getDeviceWires(wires); std::vector qPowers(dev_wires.size()); for (size_t i = 0U; i < qPowers.size(); ++i) { - qPowers[i] = Qrack::pow2((bitLenInt)dev_wires[qPowers.size() - (i + 1U)]); + qPowers[i] = Qrack::pow2(dev_wires[qPowers.size() - (i + 1U)]); } auto q_samples = qsim->MultiShotMeasureMask(qPowers, shots); From 225aef8858a64598b045ec8f4bdbdac06a446b5c Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 17:42:39 -0400 Subject: [PATCH 12/18] Fix kwarg parsing for tests --- pennylane_qrack/QrackDeviceConfig.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pennylane_qrack/QrackDeviceConfig.toml b/pennylane_qrack/QrackDeviceConfig.toml index 3006a79..3d18afb 100644 --- a/pennylane_qrack/QrackDeviceConfig.toml +++ b/pennylane_qrack/QrackDeviceConfig.toml @@ -132,19 +132,19 @@ wires = "wires" # Number of shots per job shots = "shots" # Use "hybrid" stabilizer optimization? (Default is "true"; non-Clifford circuits will fall back to near-Clifford or universal simulation) -is_hybrid_stabilizer = "is_hybrid_stabilizer" +is_hybrid_stabilizer = "isStabilizerHybrid" # Use "tensor network" optimization? (Default is "false"; prevents dynamic qubit de-allocation; might function sub-optimally with "hybrid" stabilizer enabled) -is_tensor_network = "is_tensor_network" +is_tensor_network = "isTensorNetwork" # Use Schmidt decomposition optimizations? (Default is "true") -is_schmidt_decomposed = "is_schmidt_decomposed" +is_schmidt_decomposed = "isSchmidtDecompose" # Distribute Schmidt-decomposed qubit subsystems to multiple GPUs or accelerators, if available? (Default is "true"; mismatched device capacities might hurt overall performance) -is_schmidt_decomposition_parallel = "is_schmidt_decomposition_parallel" +is_schmidt_decomposition_parallel = "isSchmidtDecomposeMulti" # Use "quantum binary decision diagram" ("QBDD") methods? (Default is "false"; note that QBDD is CPU-only) -is_qbdd = "is_qbdd" +is_qbdd = "isBinaryDecisionTree" # Use GPU acceleration? (Default is "true") -is_gpu = "is_gpu" +is_gpu = "isOpenCL" # Allocate GPU buffer from general host heap? (Default is "false"; "true" might improve performance or reliability in certain cases, like if using an Intel HD as accelerator) -is_host_pointer = "is_host_pointer" +is_host_pointer = "isHostPointer" # In the above example, a dictionary will be constructed at run time. # The dictionary will contain the string key "option_key" and its value From a3cc8c982f3e7def0c05994df72ade3644337a88 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 17:58:54 -0400 Subject: [PATCH 13/18] Build/install Catalyst from source for tests --- .github/workflows/tests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e9ed47e..fbe5c04 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,6 +41,11 @@ jobs: cmake .. sudo make install cd ../.. + cd catalyst + git submodule update --init --depth=1 + pip3 install -r requirements.txt + make all + cd .. - name: Install Plugin run: | From 7092ccb420ef346479a8bcf482c27533063db0cf Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 18:07:18 -0400 Subject: [PATCH 14/18] Don't build Qrack for Ubuntu workflows --- .github/workflows/tests.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fbe5c04..7358f4d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,21 +29,16 @@ jobs: - name: Install dependencies run: | - sudo apt install ocl-icd-opencl-dev opencl-headers + sudo apt install software-properties-common + sudo add-apt-repository ppa:wrathfulspatula/vm6502q + sudo apt install ocl-icd-opencl-dev opencl-headers pyqrack python -m pip install --upgrade pip pip install -r requirements.txt pip install wheel pytest pytest-cov pytest-mock --upgrade git clone https://github.com/PennyLaneAI/catalyst.git - git clone https://github.com/unitaryfund/qrack.git - cd qrack - mkdir _build - cd _build - cmake .. - sudo make install - cd ../.. cd catalyst git submodule update --init --depth=1 - pip3 install -r requirements.txt + pip install -r requirements.txt make all cd .. From eb15405df6d68c8776fdc1f1911f15c8fc3f61f4 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 18:26:33 -0400 Subject: [PATCH 15/18] Install ninja-build for Catalyst, for tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7358f4d..6e66212 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,7 +31,7 @@ jobs: run: | sudo apt install software-properties-common sudo add-apt-repository ppa:wrathfulspatula/vm6502q - sudo apt install ocl-icd-opencl-dev opencl-headers pyqrack + sudo apt install ocl-icd-opencl-dev opencl-headers pyqrack ninja-build python -m pip install --upgrade pip pip install -r requirements.txt pip install wheel pytest pytest-cov pytest-mock --upgrade From 914e5438d13763297aae1ea1afee8a58ec6108d0 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 18:34:02 -0400 Subject: [PATCH 16/18] Install OpenMP for Catalyst, for tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6e66212..7a7a773 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,7 +31,7 @@ jobs: run: | sudo apt install software-properties-common sudo add-apt-repository ppa:wrathfulspatula/vm6502q - sudo apt install ocl-icd-opencl-dev opencl-headers pyqrack ninja-build + sudo apt install ocl-icd-opencl-dev opencl-headers pyqrack ninja-build libomp-dev python -m pip install --upgrade pip pip install -r requirements.txt pip install wheel pytest pytest-cov pytest-mock --upgrade From cfa5af4c8b809aeeb65301de9f5e099b0d614357 Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 20:21:04 -0400 Subject: [PATCH 17/18] Don't build Catalyst for tests (at all) --- .github/workflows/tests.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7a7a773..ed21854 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,12 +35,6 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt pip install wheel pytest pytest-cov pytest-mock --upgrade - git clone https://github.com/PennyLaneAI/catalyst.git - cd catalyst - git submodule update --init --depth=1 - pip install -r requirements.txt - make all - cd .. - name: Install Plugin run: | From 2c1f3d5781bad74e3604fd68d5c5b2adf950437e Mon Sep 17 00:00:00 2001 From: WrathfulSpatula Date: Tue, 4 Jun 2024 20:47:27 -0400 Subject: [PATCH 18/18] Restore Qrack build and Catalyst headers from repo --- .github/workflows/tests.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ed21854..e9ed47e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,12 +29,18 @@ jobs: - name: Install dependencies run: | - sudo apt install software-properties-common - sudo add-apt-repository ppa:wrathfulspatula/vm6502q - sudo apt install ocl-icd-opencl-dev opencl-headers pyqrack ninja-build libomp-dev + sudo apt install ocl-icd-opencl-dev opencl-headers python -m pip install --upgrade pip pip install -r requirements.txt pip install wheel pytest pytest-cov pytest-mock --upgrade + git clone https://github.com/PennyLaneAI/catalyst.git + git clone https://github.com/unitaryfund/qrack.git + cd qrack + mkdir _build + cd _build + cmake .. + sudo make install + cd ../.. - name: Install Plugin run: |