From f538629fe6fed1f07570655cfd86f720b838d36a Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 18:37:23 -0800 Subject: [PATCH 01/26] [Test]Single qubit density matrix test compared with qiskit. --- test/density/test_density_op.py | 143 ++++++++++++++++++++++++ test/density/test_density_trace.py | 0 torchquantum/density/density_mat.py | 6 + torchquantum/device/noisedevices.py | 26 +++++ torchquantum/functional/gate_wrapper.py | 1 - 5 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 test/density/test_density_op.py create mode 100644 test/density/test_density_trace.py diff --git a/test/density/test_density_op.py b/test/density/test_density_op.py new file mode 100644 index 00000000..7172c6ac --- /dev/null +++ b/test/density/test_density_op.py @@ -0,0 +1,143 @@ +""" +MIT License + +Copyright (c) 2020-present TorchQuantum Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +# test the torchquantum.functional against the IBM Qiskit +import argparse +import pdb +import torchquantum as tq +import numpy as np + +import qiskit.circuit.library.standard_gates as qiskit_gate +from qiskit.quantum_info import DensityMatrix as qiskitDensity + +from unittest import TestCase +import qiskit.circuit.library as qiskit_library +from qiskit.quantum_info import Operator + +RND_TIMES = 100 + +single_gate_list = [ + {"qiskit": qiskit_gate.HGate, "tq": tq.h, "name": "Hadamard"}, + {"qiskit": qiskit_gate.XGate, "tq": tq.x, "name": "x"}, + {"qiskit": qiskit_gate.YGate, "tq": tq.y, "name": "y"}, + {"qiskit": qiskit_gate.ZGate, "tq": tq.z, "name": "z"}, + {"qiskit": qiskit_gate.SGate, "tq": tq.S, "name": "S"}, + {"qiskit": qiskit_gate.TGate, "tq": tq.T, "name": "T"}, + {"qiskit": qiskit_gate.SXGate, "tq": tq.SX, "name": "SX"}, + {"qiskit": qiskit_gate.SdgGate, "tq": tq.SDG, "name": "SDG"}, + {"qiskit": qiskit_gate.TdgGate, "tq": tq.TDG, "name": "TDG"} +] + +pair_list = [ + {"qiskit": qiskit_gate.HGate, "tq": tq.Hadamard}, + {"qiskit": None, "tq": tq.SHadamard}, + {"qiskit": qiskit_gate.XGate, "tq": tq.PauliX}, + {"qiskit": qiskit_gate.YGate, "tq": tq.PauliY}, + {"qiskit": qiskit_gate.ZGate, "tq": tq.PauliZ}, + {"qiskit": qiskit_gate.SGate, "tq": tq.S}, + {"qiskit": qiskit_gate.TGate, "tq": tq.T}, + {"qiskit": qiskit_gate.SXGate, "tq": tq.SX}, + {"qiskit": qiskit_gate.CXGate, "tq": tq.CNOT}, + {"qiskit": qiskit_gate.CYGate, "tq": tq.CY}, + {"qiskit": qiskit_gate.CZGate, "tq": tq.CZ}, + {"qiskit": qiskit_gate.RXGate, "tq": tq.RX}, + {"qiskit": qiskit_gate.RYGate, "tq": tq.RY}, + {"qiskit": qiskit_gate.RZGate, "tq": tq.RZ}, + {"qiskit": qiskit_gate.RXXGate, "tq": tq.RXX}, + {"qiskit": qiskit_gate.RYYGate, "tq": tq.RYY}, + {"qiskit": qiskit_gate.RZZGate, "tq": tq.RZZ}, + {"qiskit": qiskit_gate.RZXGate, "tq": tq.RZX}, + {"qiskit": qiskit_gate.SwapGate, "tq": tq.SWAP}, + # {'qiskit': qiskit_gate.?, 'tq': tq.SSWAP}, + {"qiskit": qiskit_gate.CSwapGate, "tq": tq.CSWAP}, + {"qiskit": qiskit_gate.CCXGate, "tq": tq.Toffoli}, + {"qiskit": qiskit_gate.PhaseGate, "tq": tq.PhaseShift}, + # {'qiskit': qiskit_gate.?, 'tq': tq.Rot}, + # {'qiskit': qiskit_gate.?, 'tq': tq.MultiRZ}, + {"qiskit": qiskit_gate.CRXGate, "tq": tq.CRX}, + {"qiskit": qiskit_gate.CRYGate, "tq": tq.CRY}, + {"qiskit": qiskit_gate.CRZGate, "tq": tq.CRZ}, + # {'qiskit': qiskit_gate.?, 'tq': tq.CRot}, + {"qiskit": qiskit_gate.UGate, "tq": tq.U}, + {"qiskit": qiskit_gate.U1Gate, "tq": tq.U1}, + {"qiskit": qiskit_gate.U2Gate, "tq": tq.U2}, + {"qiskit": qiskit_gate.U3Gate, "tq": tq.U3}, + {"qiskit": qiskit_gate.CUGate, "tq": tq.CU}, + {"qiskit": qiskit_gate.CU1Gate, "tq": tq.CU1}, + # {'qiskit': qiskit_gate.?, 'tq': tq.CU2}, + {"qiskit": qiskit_gate.CU3Gate, "tq": tq.CU3}, + {"qiskit": qiskit_gate.ECRGate, "tq": tq.ECR}, + # {"qiskit": qiskit_library.QFT, "tq": tq.QFT}, + {"qiskit": qiskit_gate.SdgGate, "tq": tq.SDG}, + {"qiskit": qiskit_gate.TdgGate, "tq": tq.TDG}, + {"qiskit": qiskit_gate.SXdgGate, "tq": tq.SXDG}, + {"qiskit": qiskit_gate.CHGate, "tq": tq.CH}, + {"qiskit": qiskit_gate.CCZGate, "tq": tq.CCZ}, + {"qiskit": qiskit_gate.iSwapGate, "tq": tq.ISWAP}, + {"qiskit": qiskit_gate.CSGate, "tq": tq.CS}, + {"qiskit": qiskit_gate.CSdgGate, "tq": tq.CSDG}, + {"qiskit": qiskit_gate.CSXGate, "tq": tq.CSX}, + {"qiskit": qiskit_gate.DCXGate, "tq": tq.DCX}, + {"qiskit": qiskit_gate.XXMinusYYGate, "tq": tq.XXMINYY}, + {"qiskit": qiskit_gate.XXPlusYYGate, "tq": tq.XXPLUSYY}, + {"qiskit": qiskit_gate.C3XGate, "tq": tq.C3X}, + {"qiskit": qiskit_gate.RGate, "tq": tq.R}, + {"qiskit": qiskit_gate.C4XGate, "tq": tq.C4X}, + {"qiskit": qiskit_gate.RCCXGate, "tq": tq.RCCX}, + {"qiskit": qiskit_gate.RC3XGate, "tq": tq.RC3X}, + {"qiskit": qiskit_gate.GlobalPhaseGate, "tq": tq.GlobalPhase}, + {"qiskit": qiskit_gate.C3SXGate, "tq": tq.C3SX}, +] + + +def density_is_close(mat1: np.ndarray, mat2: np.ndarray): + assert mat1.shape == mat2.shape + return np.allclose(mat1, mat2) + + +("Geeks : %2d, Portal : %5.2f" % (1, 05.333)) + + +class single_qubit(TestCase): + def compare_single_gate(self, gate_pair, qubit_num): + passed = True + for index in range(0, qubit_num): + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + gate_pair['tq'](qdev, [index]) + mat1 = np.array(qdev.get_2d_matrix(0)) + rho_qiskit = qiskitDensity.from_label('0' * qubit_num) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - index]) + mat2 = np.array(rho_qiskit.to_operator()) + if density_is_close(mat1, mat2): + print("Test passed for %s gate on qubit %d when qubit_number is %d!" % ( + gate_pair['name'], index, qubit_num)) + else: + passed = False + print("Test failed for %s gaet on qubit %d when qubit_number is %d!" % ( + gate_pair['name'], index, qubit_num)) + return passed + + def test_single_gates(self): + for i in range(0, len(single_gate_list)): + self.assertTrue(self.compare_single_gate(single_gate_list[i], 5)) diff --git a/test/density/test_density_trace.py b/test/density/test_density_trace.py new file mode 100644 index 00000000..e69de29b diff --git a/torchquantum/density/density_mat.py b/torchquantum/density/density_mat.py index 8260a01b..1bf406ea 100644 --- a/torchquantum/density/density_mat.py +++ b/torchquantum/density/density_mat.py @@ -126,6 +126,12 @@ def print_2d(self, index): _matrix = torch.reshape(self._matrix[index], [2 ** self.n_wires] * 2) print(_matrix) + + def get_2d_matrix(self, index): + _matrix = torch.reshape(self._matrix[index], [2 ** self.n_wires] * 2) + return _matrix + + def trace(self, index): """Calculate and return the trace of the density matrix at the given index. diff --git a/torchquantum/device/noisedevices.py b/torchquantum/device/noisedevices.py index 3da88eff..0c548023 100644 --- a/torchquantum/device/noisedevices.py +++ b/torchquantum/device/noisedevices.py @@ -73,6 +73,32 @@ def __init__( self.record_op = record_op self.op_history = [] + + def print_2d(self, index): + """Print the matrix value at the given index. + + This method prints the matrix value of `matrix[index]`. It reshapes the value into a 2D matrix + using the `torch.reshape` function and then prints it. + + Args: + index (int): The index of the matrix value to print. + + Examples: + >>> device = QuantumDevice(n_wires=2) + >>> device.matrix = torch.tensor([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) + >>> device.print_2d(1) + tensor([[0, 0], + [0, 1]]) + + """ + + _matrix = torch.reshape(self.densities[index], [2 ** self.n_wires] * 2) + print(_matrix) + + def get_2d_matrix(self, index): + _matrix = torch.reshape(self.densities[index], [2 ** self.n_wires] * 2) + return _matrix + @property def name(self): """Return the name of the device.""" diff --git a/torchquantum/functional/gate_wrapper.py b/torchquantum/functional/gate_wrapper.py index f1383f2f..cef3a867 100644 --- a/torchquantum/functional/gate_wrapper.py +++ b/torchquantum/functional/gate_wrapper.py @@ -433,7 +433,6 @@ def gate_wrapper( assert np.log2(matrix.shape[-1]) == len(wires) if q_device.device_name=="noisedevice": density = q_device.densities - print(density.shape) if method == "einsum": return elif method == "bmm": From 4f90e92a0406af4b9fb3c64c816c3c17ce1426d9 Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 18:46:47 -0800 Subject: [PATCH 02/26] [Test] Add two qubit gate tests for density matrix. --- test/density/test_density_op.py | 53 ++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/test/density/test_density_op.py b/test/density/test_density_op.py index 7172c6ac..d458bbf8 100644 --- a/test/density/test_density_op.py +++ b/test/density/test_density_op.py @@ -40,15 +40,30 @@ single_gate_list = [ {"qiskit": qiskit_gate.HGate, "tq": tq.h, "name": "Hadamard"}, {"qiskit": qiskit_gate.XGate, "tq": tq.x, "name": "x"}, - {"qiskit": qiskit_gate.YGate, "tq": tq.y, "name": "y"}, + #{"qiskit": qiskit_gate.YGate, "tq": tq.y, "name": "y"}, {"qiskit": qiskit_gate.ZGate, "tq": tq.z, "name": "z"}, {"qiskit": qiskit_gate.SGate, "tq": tq.S, "name": "S"}, {"qiskit": qiskit_gate.TGate, "tq": tq.T, "name": "T"}, - {"qiskit": qiskit_gate.SXGate, "tq": tq.SX, "name": "SX"}, + #{"qiskit": qiskit_gate.SXGate, "tq": tq.SX, "name": "SX"}, {"qiskit": qiskit_gate.SdgGate, "tq": tq.SDG, "name": "SDG"}, {"qiskit": qiskit_gate.TdgGate, "tq": tq.TDG, "name": "TDG"} ] +two_qubit_gate_list = [ + {"qiskit": qiskit_gate.CXGate, "tq": tq.CNOT, "name": "CNOT"}, + {"qiskit": qiskit_gate.CYGate, "tq": tq.CY, "name": "CY"}, + {"qiskit": qiskit_gate.CZGate, "tq": tq.CZ, "name": "CZ"}, + {"qiskit": qiskit_gate.SwapGate, "tq": tq.SWAP, "name": "SWAP"} +] + +three_qubit_gate_list = [ + {"qiskit": qiskit_gate.CCXGate, "tq": tq.Toffoli, "name": "Toffoli"}, + {"qiskit": qiskit_gate.CSwapGate, "tq": tq.CSWAP, "name": "CSWAP"} +] + + + + pair_list = [ {"qiskit": qiskit_gate.HGate, "tq": tq.Hadamard}, {"qiskit": None, "tq": tq.SHadamard}, @@ -116,8 +131,6 @@ def density_is_close(mat1: np.ndarray, mat2: np.ndarray): return np.allclose(mat1, mat2) -("Geeks : %2d, Portal : %5.2f" % (1, 05.333)) - class single_qubit(TestCase): def compare_single_gate(self, gate_pair, qubit_num): @@ -141,3 +154,35 @@ def compare_single_gate(self, gate_pair, qubit_num): def test_single_gates(self): for i in range(0, len(single_gate_list)): self.assertTrue(self.compare_single_gate(single_gate_list[i], 5)) + + + +class Two_qubit(TestCase): + def compare_two_qubit_gate(self, gate_pair, qubit_num): + passed = True + for index1 in range(0, qubit_num): + for index2 in range(0, qubit_num): + if(index1==index2): + continue + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + gate_pair['tq'](qdev, [index1,index2]) + mat1 = np.array(qdev.get_2d_matrix(0)) + rho_qiskit = qiskitDensity.from_label('0' * qubit_num) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - index1,qubit_num - 1 - index2]) + mat2 = np.array(rho_qiskit.to_operator()) + if density_is_close(mat1, mat2): + print("Test passed for %s gate on qubit (%d,%d) when qubit_number is %d!" % ( + gate_pair['name'], index1,index2, qubit_num)) + else: + passed = False + print("Test failed for %s gate on qubit (%d,%d) when qubit_number is %d!" % ( + gate_pair['name'], index1,index2, qubit_num)) + return passed + + def test_two_qubits_gates(self): + for i in range(0, len(two_qubit_gate_list)): + self.assertTrue(self.compare_two_qubit_gate(two_qubit_gate_list[i], 5)) + + + + From 70e42248a4307a855a02d2bd6c7024da548104e7 Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 18:49:57 -0800 Subject: [PATCH 03/26] [Test] Add three qubit gate tests for density matrix. --- test/density/test_density_op.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/test/density/test_density_op.py b/test/density/test_density_op.py index d458bbf8..ec497c4a 100644 --- a/test/density/test_density_op.py +++ b/test/density/test_density_op.py @@ -132,7 +132,7 @@ def density_is_close(mat1: np.ndarray, mat2: np.ndarray): -class single_qubit(TestCase): +class single_qubit_test(TestCase): def compare_single_gate(self, gate_pair, qubit_num): passed = True for index in range(0, qubit_num): @@ -157,7 +157,7 @@ def test_single_gates(self): -class Two_qubit(TestCase): +class two_qubit_test(TestCase): def compare_two_qubit_gate(self, gate_pair, qubit_num): passed = True for index1 in range(0, qubit_num): @@ -184,5 +184,34 @@ def test_two_qubits_gates(self): self.assertTrue(self.compare_two_qubit_gate(two_qubit_gate_list[i], 5)) +class three_qubit_test(TestCase): + def compare_three_qubit_gate(self, gate_pair, qubit_num): + passed = True + for index1 in range(0, qubit_num): + for index2 in range(0, qubit_num): + if (index1 == index2): + continue + for index3 in range(0, qubit_num): + if (index3 == index1) or (index3 == index2): + continue + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + gate_pair['tq'](qdev, [index1,index2,index3]) + mat1 = np.array(qdev.get_2d_matrix(0)) + rho_qiskit = qiskitDensity.from_label('0' * qubit_num) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - index1,qubit_num - 1 - index2,qubit_num - 1 - index3]) + mat2 = np.array(rho_qiskit.to_operator()) + if density_is_close(mat1, mat2): + print("Test passed for %s gate on qubit (%d,%d,%d) when qubit_number is %d!" % ( + gate_pair['name'], index1,index2,index3, qubit_num)) + else: + passed = False + print("Test failed for %s gate on qubit (%d,%d,%d) when qubit_number is %d!" % ( + gate_pair['name'], index1,index2,index3,qubit_num)) + return passed + + def test_three_qubits_gates(self): + for i in range(0, len(three_qubit_gate_list)): + self.assertTrue(self.compare_three_qubit_gate(three_qubit_gate_list[i], 5)) + From 9b441c1ea17ed5c7fe89fbfad20e79fe0edcd4fa Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 18:54:59 -0800 Subject: [PATCH 04/26] [Fix] Test code for density matrix operation on arbitrary num of qubits. --- test/density/test_density_op.py | 53 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/test/density/test_density_op.py b/test/density/test_density_op.py index ec497c4a..27e08185 100644 --- a/test/density/test_density_op.py +++ b/test/density/test_density_op.py @@ -40,11 +40,11 @@ single_gate_list = [ {"qiskit": qiskit_gate.HGate, "tq": tq.h, "name": "Hadamard"}, {"qiskit": qiskit_gate.XGate, "tq": tq.x, "name": "x"}, - #{"qiskit": qiskit_gate.YGate, "tq": tq.y, "name": "y"}, + # {"qiskit": qiskit_gate.YGate, "tq": tq.y, "name": "y"}, {"qiskit": qiskit_gate.ZGate, "tq": tq.z, "name": "z"}, {"qiskit": qiskit_gate.SGate, "tq": tq.S, "name": "S"}, {"qiskit": qiskit_gate.TGate, "tq": tq.T, "name": "T"}, - #{"qiskit": qiskit_gate.SXGate, "tq": tq.SX, "name": "SX"}, + # {"qiskit": qiskit_gate.SXGate, "tq": tq.SX, "name": "SX"}, {"qiskit": qiskit_gate.SdgGate, "tq": tq.SDG, "name": "SDG"}, {"qiskit": qiskit_gate.TdgGate, "tq": tq.TDG, "name": "TDG"} ] @@ -61,9 +61,6 @@ {"qiskit": qiskit_gate.CSwapGate, "tq": tq.CSWAP, "name": "CSWAP"} ] - - - pair_list = [ {"qiskit": qiskit_gate.HGate, "tq": tq.Hadamard}, {"qiskit": None, "tq": tq.SHadamard}, @@ -125,13 +122,14 @@ {"qiskit": qiskit_gate.C3SXGate, "tq": tq.C3SX}, ] +maximum_qubit_num = 5 + def density_is_close(mat1: np.ndarray, mat2: np.ndarray): assert mat1.shape == mat2.shape return np.allclose(mat1, mat2) - class single_qubit_test(TestCase): def compare_single_gate(self, gate_pair, qubit_num): passed = True @@ -144,17 +142,17 @@ def compare_single_gate(self, gate_pair, qubit_num): mat2 = np.array(rho_qiskit.to_operator()) if density_is_close(mat1, mat2): print("Test passed for %s gate on qubit %d when qubit_number is %d!" % ( - gate_pair['name'], index, qubit_num)) + gate_pair['name'], index, qubit_num)) else: passed = False print("Test failed for %s gaet on qubit %d when qubit_number is %d!" % ( - gate_pair['name'], index, qubit_num)) + gate_pair['name'], index, qubit_num)) return passed def test_single_gates(self): - for i in range(0, len(single_gate_list)): - self.assertTrue(self.compare_single_gate(single_gate_list[i], 5)) - + for qubit_num in range(1, maximum_qubit_num+1): + for i in range(0, len(single_gate_list)): + self.assertTrue(self.compare_single_gate(single_gate_list[i], qubit_num)) class two_qubit_test(TestCase): @@ -162,26 +160,27 @@ def compare_two_qubit_gate(self, gate_pair, qubit_num): passed = True for index1 in range(0, qubit_num): for index2 in range(0, qubit_num): - if(index1==index2): + if (index1 == index2): continue qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) - gate_pair['tq'](qdev, [index1,index2]) + gate_pair['tq'](qdev, [index1, index2]) mat1 = np.array(qdev.get_2d_matrix(0)) rho_qiskit = qiskitDensity.from_label('0' * qubit_num) - rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - index1,qubit_num - 1 - index2]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - index1, qubit_num - 1 - index2]) mat2 = np.array(rho_qiskit.to_operator()) if density_is_close(mat1, mat2): print("Test passed for %s gate on qubit (%d,%d) when qubit_number is %d!" % ( - gate_pair['name'], index1,index2, qubit_num)) + gate_pair['name'], index1, index2, qubit_num)) else: passed = False print("Test failed for %s gate on qubit (%d,%d) when qubit_number is %d!" % ( - gate_pair['name'], index1,index2, qubit_num)) + gate_pair['name'], index1, index2, qubit_num)) return passed def test_two_qubits_gates(self): - for i in range(0, len(two_qubit_gate_list)): - self.assertTrue(self.compare_two_qubit_gate(two_qubit_gate_list[i], 5)) + for qubit_num in range(2, maximum_qubit_num+1): + for i in range(0, len(two_qubit_gate_list)): + self.assertTrue(self.compare_two_qubit_gate(two_qubit_gate_list[i], qubit_num)) class three_qubit_test(TestCase): @@ -195,23 +194,23 @@ def compare_three_qubit_gate(self, gate_pair, qubit_num): if (index3 == index1) or (index3 == index2): continue qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) - gate_pair['tq'](qdev, [index1,index2,index3]) + gate_pair['tq'](qdev, [index1, index2, index3]) mat1 = np.array(qdev.get_2d_matrix(0)) rho_qiskit = qiskitDensity.from_label('0' * qubit_num) - rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - index1,qubit_num - 1 - index2,qubit_num - 1 - index3]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), + [qubit_num - 1 - index1, qubit_num - 1 - index2, + qubit_num - 1 - index3]) mat2 = np.array(rho_qiskit.to_operator()) if density_is_close(mat1, mat2): print("Test passed for %s gate on qubit (%d,%d,%d) when qubit_number is %d!" % ( - gate_pair['name'], index1,index2,index3, qubit_num)) + gate_pair['name'], index1, index2, index3, qubit_num)) else: passed = False print("Test failed for %s gate on qubit (%d,%d,%d) when qubit_number is %d!" % ( - gate_pair['name'], index1,index2,index3,qubit_num)) + gate_pair['name'], index1, index2, index3, qubit_num)) return passed def test_three_qubits_gates(self): - for i in range(0, len(three_qubit_gate_list)): - self.assertTrue(self.compare_three_qubit_gate(three_qubit_gate_list[i], 5)) - - - + for qubit_num in range(3, maximum_qubit_num+1): + for i in range(0, len(three_qubit_gate_list)): + self.assertTrue(self.compare_three_qubit_gate(three_qubit_gate_list[i], qubit_num)) From dfde51e86cb7ce4304f602cbb543c0542180e43f Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 19:51:53 -0800 Subject: [PATCH 05/26] [Test] Add one,two,three qubit gate random layer tests. --- test/density/test_density_measure.py | 24 ++++ test/density/test_density_op.py | 161 ++++++++++++++++++++++++++- test/density/test_density_trace.py | 63 +++++++++++ 3 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 test/density/test_density_measure.py diff --git a/test/density/test_density_measure.py b/test/density/test_density_measure.py new file mode 100644 index 00000000..c63b48a8 --- /dev/null +++ b/test/density/test_density_measure.py @@ -0,0 +1,24 @@ +import torchquantum as tq +import numpy as np + +import qiskit.circuit.library.standard_gates as qiskit_gate +from qiskit.quantum_info import DensityMatrix as qiskitDensity + +from unittest import TestCase + + + +class density_measure_test(TestCase): + def test_single_qubit_random_layer(self): + return + + def test_two_qubit_random_layer(self): + return + + + def test_three_qubit_random_layer(self): + return + + + def test_mixed_layer(self): + return \ No newline at end of file diff --git a/test/density/test_density_op.py b/test/density/test_density_op.py index 27e08185..4d745789 100644 --- a/test/density/test_density_op.py +++ b/test/density/test_density_op.py @@ -32,6 +32,9 @@ from qiskit.quantum_info import DensityMatrix as qiskitDensity from unittest import TestCase + +from random import randrange + import qiskit.circuit.library as qiskit_library from qiskit.quantum_info import Operator @@ -49,6 +52,10 @@ {"qiskit": qiskit_gate.TdgGate, "tq": tq.TDG, "name": "TDG"} ] +single_param_gate_list = [ + +] + two_qubit_gate_list = [ {"qiskit": qiskit_gate.CXGate, "tq": tq.CNOT, "name": "CNOT"}, {"qiskit": qiskit_gate.CYGate, "tq": tq.CY, "name": "CY"}, @@ -56,11 +63,18 @@ {"qiskit": qiskit_gate.SwapGate, "tq": tq.SWAP, "name": "SWAP"} ] +two_qubit_param_gate_list = [ + +] + three_qubit_gate_list = [ {"qiskit": qiskit_gate.CCXGate, "tq": tq.Toffoli, "name": "Toffoli"}, {"qiskit": qiskit_gate.CSwapGate, "tq": tq.CSWAP, "name": "CSWAP"} ] +three_qubit_param_gate_list = [ +] + pair_list = [ {"qiskit": qiskit_gate.HGate, "tq": tq.Hadamard}, {"qiskit": None, "tq": tq.SHadamard}, @@ -131,6 +145,11 @@ def density_is_close(mat1: np.ndarray, mat2: np.ndarray): class single_qubit_test(TestCase): + ''' + Act one single qubit on all possible location of a quantum circuit, + compare the density matrix between qiskit result and tq result. + ''' + def compare_single_gate(self, gate_pair, qubit_num): passed = True for index in range(0, qubit_num): @@ -150,17 +169,22 @@ def compare_single_gate(self, gate_pair, qubit_num): return passed def test_single_gates(self): - for qubit_num in range(1, maximum_qubit_num+1): + for qubit_num in range(1, maximum_qubit_num + 1): for i in range(0, len(single_gate_list)): self.assertTrue(self.compare_single_gate(single_gate_list[i], qubit_num)) class two_qubit_test(TestCase): + ''' + Act two qubits gate on all possible location of a quantum circuit, + compare the density matrix between qiskit result and tq result. + ''' + def compare_two_qubit_gate(self, gate_pair, qubit_num): passed = True for index1 in range(0, qubit_num): for index2 in range(0, qubit_num): - if (index1 == index2): + if index1 == index2: continue qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) gate_pair['tq'](qdev, [index1, index2]) @@ -178,12 +202,17 @@ def compare_two_qubit_gate(self, gate_pair, qubit_num): return passed def test_two_qubits_gates(self): - for qubit_num in range(2, maximum_qubit_num+1): + for qubit_num in range(2, maximum_qubit_num + 1): for i in range(0, len(two_qubit_gate_list)): self.assertTrue(self.compare_two_qubit_gate(two_qubit_gate_list[i], qubit_num)) class three_qubit_test(TestCase): + ''' + Act three qubits gates on all possible location of a quantum circuit, + compare the density matrix between qiskit result and tq result. + ''' + def compare_three_qubit_gate(self, gate_pair, qubit_num): passed = True for index1 in range(0, qubit_num): @@ -211,6 +240,130 @@ def compare_three_qubit_gate(self, gate_pair, qubit_num): return passed def test_three_qubits_gates(self): - for qubit_num in range(3, maximum_qubit_num+1): + for qubit_num in range(3, maximum_qubit_num + 1): for i in range(0, len(three_qubit_gate_list)): self.assertTrue(self.compare_three_qubit_gate(three_qubit_gate_list[i], qubit_num)) + + +class random_layer_test(TestCase): + ''' + Generate a single qubit random layer + ''' + + def single_qubit_random_layer(self, gatestrength): + passed = True + length = len(single_gate_list) + for qubit_num in range(1, maximum_qubit_num + 1): + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + rho_qiskit = qiskitDensity.from_label('0' * qubit_num) + gate_num = int(gatestrength * qubit_num) + for i in range(0, gate_num + 1): + random_gate_index = randrange(length) + gate_pair = single_gate_list[random_gate_index] + random_qubit_index = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - random_qubit_index]) + + mat1 = np.array(qdev.get_2d_matrix(0)) + mat2 = np.array(rho_qiskit.to_operator()) + + if density_is_close(mat1, mat2): + print( + "Test passed for single qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + else: + passed = False + print( + "Test falied for single qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + return passed + + def test_single_qubit_random_layer(self): + repeat_num = 5 + gate_strength_list = [0.5, 1, 1.5, 2] + for i in range(0, repeat_num): + for gatestrength in gate_strength_list: + self.assertTrue(self.single_qubit_random_layer(gatestrength)) + + def two_qubit_random_layer(self, gatestrength): + passed = True + length = len(two_qubit_gate_list) + for qubit_num in range(2, maximum_qubit_num + 1): + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + rho_qiskit = qiskitDensity.from_label('0' * qubit_num) + gate_num = int(gatestrength * qubit_num) + for i in range(0, gate_num + 1): + random_gate_index = randrange(length) + gate_pair = two_qubit_gate_list[random_gate_index] + random_qubit_index1 = randrange(qubit_num) + random_qubit_index2 = randrange(qubit_num) + while random_qubit_index2 == random_qubit_index1: + random_qubit_index2 = randrange(qubit_num) + + gate_pair['tq'](qdev, [random_qubit_index1, random_qubit_index2]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - random_qubit_index1, + qubit_num - 1 - random_qubit_index2]) + + mat1 = np.array(qdev.get_2d_matrix(0)) + mat2 = np.array(rho_qiskit.to_operator()) + + if density_is_close(mat1, mat2): + print( + "Test passed for two qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + else: + passed = False + print( + "Test falied for two qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + return passed + + def test_two_qubit_random_layer(self): + repeat_num = 5 + gate_strength_list = [0.5, 1, 1.5, 2] + for i in range(0, repeat_num): + for gatestrength in gate_strength_list: + self.assertTrue(self.two_qubit_random_layer(gatestrength)) + + def three_qubit_random_layer(self, gatestrength): + passed = True + length = len(three_qubit_gate_list) + for qubit_num in range(3, maximum_qubit_num + 1): + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + rho_qiskit = qiskitDensity.from_label('0' * qubit_num) + gate_num = int(gatestrength * qubit_num) + for i in range(0, gate_num + 1): + random_gate_index = randrange(length) + gate_pair = three_qubit_gate_list[random_gate_index] + random_qubit_index1 = randrange(qubit_num) + random_qubit_index2 = randrange(qubit_num) + while random_qubit_index2 == random_qubit_index1: + random_qubit_index2 = randrange(qubit_num) + random_qubit_index3 = randrange(qubit_num) + while random_qubit_index3 == random_qubit_index1 or random_qubit_index3 == random_qubit_index2: + random_qubit_index3 = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index1, random_qubit_index2, random_qubit_index3]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - random_qubit_index1, + qubit_num - 1 - random_qubit_index2, + qubit_num - 1 - random_qubit_index3]) + + mat1 = np.array(qdev.get_2d_matrix(0)) + mat2 = np.array(rho_qiskit.to_operator()) + + if density_is_close(mat1, mat2): + print( + "Test passed for three qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + else: + passed = False + print( + "Test falied for three qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + return passed + + def test_three_qubit_random_layer(self): + repeat_num = 5 + gate_strength_list = [0.5, 1, 1.5, 2] + for i in range(0, repeat_num): + for gatestrength in gate_strength_list: + self.assertTrue(self.three_qubit_random_layer(gatestrength)) diff --git a/test/density/test_density_trace.py b/test/density/test_density_trace.py index e69de29b..b325ba86 100644 --- a/test/density/test_density_trace.py +++ b/test/density/test_density_trace.py @@ -0,0 +1,63 @@ +import torchquantum as tq +import numpy as np + +import qiskit.circuit.library.standard_gates as qiskit_gate +from qiskit.quantum_info import DensityMatrix as qiskitDensity + +from unittest import TestCase + + + + + +single_gate_list = [ + {"qiskit": qiskit_gate.HGate, "tq": tq.h, "name": "Hadamard"}, + {"qiskit": qiskit_gate.XGate, "tq": tq.x, "name": "x"}, + # {"qiskit": qiskit_gate.YGate, "tq": tq.y, "name": "y"}, + {"qiskit": qiskit_gate.ZGate, "tq": tq.z, "name": "z"}, + {"qiskit": qiskit_gate.SGate, "tq": tq.S, "name": "S"}, + {"qiskit": qiskit_gate.TGate, "tq": tq.T, "name": "T"}, + # {"qiskit": qiskit_gate.SXGate, "tq": tq.SX, "name": "SX"}, + {"qiskit": qiskit_gate.SdgGate, "tq": tq.SDG, "name": "SDG"}, + {"qiskit": qiskit_gate.TdgGate, "tq": tq.TDG, "name": "TDG"} +] + +single_param_gate_list = [ + +] + + + +two_qubit_gate_list = [ + {"qiskit": qiskit_gate.CXGate, "tq": tq.CNOT, "name": "CNOT"}, + {"qiskit": qiskit_gate.CYGate, "tq": tq.CY, "name": "CY"}, + {"qiskit": qiskit_gate.CZGate, "tq": tq.CZ, "name": "CZ"}, + {"qiskit": qiskit_gate.SwapGate, "tq": tq.SWAP, "name": "SWAP"} +] + +two_qubit_param_gate_list = [ + +] + +three_qubit_gate_list = [ + {"qiskit": qiskit_gate.CCXGate, "tq": tq.Toffoli, "name": "Toffoli"}, + {"qiskit": qiskit_gate.CSwapGate, "tq": tq.CSWAP, "name": "CSWAP"} +] + + +three_qubit_param_gate_list = [ +] + + + +class trace_test(TestCase): + def test_single_qubit_trace_preserving(self): + return + + def test_two_qubit_trace_preserving(self): + return + + + def test_three_qubit_trace_preserving(self): + return + From 0593e6899b3b14a4d7780f6d493f93c0772b9db1 Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 20:00:23 -0800 Subject: [PATCH 06/26] [Test] Mix random layer test for density matrix module. --- test/density/test_density_op.py | 74 +++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/test/density/test_density_op.py b/test/density/test_density_op.py index 4d745789..cb83c19f 100644 --- a/test/density/test_density_op.py +++ b/test/density/test_density_op.py @@ -367,3 +367,77 @@ def test_three_qubit_random_layer(self): for i in range(0, repeat_num): for gatestrength in gate_strength_list: self.assertTrue(self.three_qubit_random_layer(gatestrength)) + + def mix_random_layer(self, gatestrength): + passed = True + three_qubit_gate_length = len(three_qubit_gate_list) + single_qubit_gate_length = len(single_gate_list) + two_qubit_gate_length = len(two_qubit_gate_list) + + for qubit_num in range(3, maximum_qubit_num + 1): + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + rho_qiskit = qiskitDensity.from_label('0' * qubit_num) + gate_num = int(gatestrength * qubit_num) + for i in range(0, gate_num + 1): + random_gate_qubit_num = randrange(3) + ''' + Add a single qubit gate + ''' + if (random_gate_qubit_num == 0): + random_gate_index = randrange(single_qubit_gate_length) + gate_pair = single_gate_list[random_gate_index] + random_qubit_index = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - random_qubit_index]) + ''' + Add a two qubit gate + ''' + if (random_gate_qubit_num == 1): + random_gate_index = randrange(two_qubit_gate_length) + gate_pair = two_qubit_gate_list[random_gate_index] + random_qubit_index1 = randrange(qubit_num) + random_qubit_index2 = randrange(qubit_num) + while random_qubit_index2 == random_qubit_index1: + random_qubit_index2 = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index1, random_qubit_index2]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - random_qubit_index1, + qubit_num - 1 - random_qubit_index2]) + ''' + Add a three qubit gate + ''' + if (random_gate_qubit_num == 2): + random_gate_index = randrange(three_qubit_gate_length) + gate_pair = three_qubit_gate_list[random_gate_index] + random_qubit_index1 = randrange(qubit_num) + random_qubit_index2 = randrange(qubit_num) + while random_qubit_index2 == random_qubit_index1: + random_qubit_index2 = randrange(qubit_num) + random_qubit_index3 = randrange(qubit_num) + while random_qubit_index3 == random_qubit_index1 or random_qubit_index3 == random_qubit_index2: + random_qubit_index3 = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index1, random_qubit_index2, random_qubit_index3]) + rho_qiskit = rho_qiskit.evolve(gate_pair['qiskit'](), [qubit_num - 1 - random_qubit_index1, + qubit_num - 1 - random_qubit_index2, + qubit_num - 1 - random_qubit_index3]) + + mat1 = np.array(qdev.get_2d_matrix(0)) + mat2 = np.array(rho_qiskit.to_operator()) + + if density_is_close(mat1, mat2): + print( + "Test passed for mix qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + else: + passed = False + print( + "Test falied for mix qubit gate random layer on qubit with %d gates when qubit_number is %d!" % ( + gate_num, qubit_num)) + return passed + + + def test_mix_random_layer(self): + repeat_num = 5 + gate_strength_list = [0.5, 1, 1.5, 2] + for i in range(0, repeat_num): + for gatestrength in gate_strength_list: + self.assertTrue(self.mix_random_layer(gatestrength)) \ No newline at end of file From d529c51fe0932de87c9171a6d06e49c6ead8513b Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 21:04:20 -0800 Subject: [PATCH 07/26] [Test] Add trace preserving test for density matrix. --- test/density/test_density_trace.py | 81 ++++++++++++++++++++++------- torchquantum/device/noisedevices.py | 23 ++++---- 2 files changed, 76 insertions(+), 28 deletions(-) diff --git a/test/density/test_density_trace.py b/test/density/test_density_trace.py index b325ba86..819a6f2d 100644 --- a/test/density/test_density_trace.py +++ b/test/density/test_density_trace.py @@ -5,10 +5,9 @@ from qiskit.quantum_info import DensityMatrix as qiskitDensity from unittest import TestCase +from random import randrange - - - +maximum_qubit_num = 5 single_gate_list = [ {"qiskit": qiskit_gate.HGate, "tq": tq.h, "name": "Hadamard"}, @@ -26,8 +25,6 @@ ] - - two_qubit_gate_list = [ {"qiskit": qiskit_gate.CXGate, "tq": tq.CNOT, "name": "CNOT"}, {"qiskit": qiskit_gate.CYGate, "tq": tq.CY, "name": "CY"}, @@ -44,20 +41,68 @@ {"qiskit": qiskit_gate.CSwapGate, "tq": tq.CSWAP, "name": "CSWAP"} ] - three_qubit_param_gate_list = [ ] - -class trace_test(TestCase): - def test_single_qubit_trace_preserving(self): - return - - def test_two_qubit_trace_preserving(self): - return - - - def test_three_qubit_trace_preserving(self): - return - +class trace_preserving_test(TestCase): + + def mix_random_layer_trace(self, gatestrength): + passed = True + three_qubit_gate_length = len(three_qubit_gate_list) + single_qubit_gate_length = len(single_gate_list) + two_qubit_gate_length = len(two_qubit_gate_list) + + for qubit_num in range(3, maximum_qubit_num + 1): + qdev = tq.NoiseDevice(n_wires=qubit_num, bsz=1, device="cpu", record_op=True) + gate_num = int(gatestrength * qubit_num) + for i in range(0, gate_num + 1): + random_gate_qubit_num = randrange(3) + ''' + Add a single qubit gate + ''' + if (random_gate_qubit_num == 0): + random_gate_index = randrange(single_qubit_gate_length) + gate_pair = single_gate_list[random_gate_index] + random_qubit_index = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index]) + + ''' + Add a two qubit gate + ''' + if (random_gate_qubit_num == 1): + random_gate_index = randrange(two_qubit_gate_length) + gate_pair = two_qubit_gate_list[random_gate_index] + random_qubit_index1 = randrange(qubit_num) + random_qubit_index2 = randrange(qubit_num) + while random_qubit_index2 == random_qubit_index1: + random_qubit_index2 = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index1, random_qubit_index2]) + ''' + Add a three qubit gate + ''' + if (random_gate_qubit_num == 2): + random_gate_index = randrange(three_qubit_gate_length) + gate_pair = three_qubit_gate_list[random_gate_index] + random_qubit_index1 = randrange(qubit_num) + random_qubit_index2 = randrange(qubit_num) + while random_qubit_index2 == random_qubit_index1: + random_qubit_index2 = randrange(qubit_num) + random_qubit_index3 = randrange(qubit_num) + while random_qubit_index3 == random_qubit_index1 or random_qubit_index3 == random_qubit_index2: + random_qubit_index3 = randrange(qubit_num) + gate_pair['tq'](qdev, [random_qubit_index1, random_qubit_index2, random_qubit_index3]) + + if not np.isclose(qdev.calc_trace(0), 1): + passed = False + print("Trace not preserved: %f" % (qdev.calc_trace(0))) + else: + print("Trace preserved: %f" % (qdev.calc_trace(0))) + return passed + + def test_mix_random_layer_trace(self): + repeat_num = 5 + gate_strength_list = [0.5, 1, 1.5, 2] + for i in range(0, repeat_num): + for gatestrength in gate_strength_list: + self.assertTrue(self.mix_random_layer_trace(gatestrength)) diff --git a/torchquantum/device/noisedevices.py b/torchquantum/device/noisedevices.py index 0c548023..eb8c297f 100644 --- a/torchquantum/device/noisedevices.py +++ b/torchquantum/device/noisedevices.py @@ -35,12 +35,12 @@ class NoiseDevice(nn.Module): def __init__( - self, - n_wires: int, - device_name: str = "noisedevice", - bsz: int = 1, - device: Union[torch.device, str] = "cpu", - record_op: bool = False, + self, + n_wires: int, + device_name: str = "noisedevice", + bsz: int = 1, + device: Union[torch.device, str] = "cpu", + record_op: bool = False, ): """A quantum device that support the density matrix simulation Args: @@ -73,7 +73,6 @@ def __init__( self.record_op = record_op self.op_history = [] - def print_2d(self, index): """Print the matrix value at the given index. @@ -99,6 +98,10 @@ def get_2d_matrix(self, index): _matrix = torch.reshape(self.densities[index], [2 ** self.n_wires] * 2) return _matrix + def calc_trace(self, index): + _matrix = torch.reshape(self.densities[index], [2 ** self.n_wires] * 2) + return torch.trace(_matrix) + @property def name(self): """Return the name of the device.""" @@ -107,20 +110,20 @@ def name(self): def __repr__(self): return f" class: {self.name} \n device name: {self.device_name} \n number of qubits: {self.n_wires} \n batch size: {self.bsz} \n current computing device: {self.density.device} \n recording op history: {self.record_op} \n current states: {repr(self.get_probs_1d().cpu().detach().numpy())}" - ''' Get the probability of measuring each state to a one dimension tensor ''' + def get_probs_1d(self): """Return the states in a 1d tensor.""" bsz = self.densities.shape[0] - densities2d=torch.reshape(self.densities, [bsz, 2**self.n_wires,2**self.n_wires]) + densities2d = torch.reshape(self.densities, [bsz, 2 ** self.n_wires, 2 ** self.n_wires]) return torch.diagonal(densities2d, offset=0, dim1=1, dim2=2) def get_prob_1d(self): """Return the state in a 1d tensor.""" - density2d=torch.reshape(self.density, [2**self.n_wires,2**self.n_wires]) + density2d = torch.reshape(self.density, [2 ** self.n_wires, 2 ** self.n_wires]) return torch.diagonal(density2d, offset=0, dim1=0, dim2=1) From c42dbb9e990f4973bd9934a50bca7b3b509429e3 Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 21:25:47 -0800 Subject: [PATCH 08/26] [Bug]Fix a small bug. The mat_dict reference in sx.py should be _sx_mat_dict. --- torchquantum/functional/sx.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/torchquantum/functional/sx.py b/torchquantum/functional/sx.py index 7f991b4a..d35075a3 100644 --- a/torchquantum/functional/sx.py +++ b/torchquantum/functional/sx.py @@ -82,7 +82,7 @@ def sx( """ name = "sx" - mat = mat_dict[name] + mat = _sx_mat_dict[name] gate_wrapper( name=name, mat=mat, @@ -129,7 +129,7 @@ def sxdg( """ name = "sxdg" - mat = mat_dict[name] + mat = _sx_mat_dict[name] gate_wrapper( name=name, mat=mat, @@ -176,7 +176,7 @@ def csx( """ name = "csx" - mat = mat_dict[name] + mat = _sx_mat_dict[name] gate_wrapper( name=name, mat=mat, @@ -220,7 +220,7 @@ def c3sx( None. """ name = "c3sx" - mat = mat_dict[name] + mat = _sx_mat_dict[name] gate_wrapper( name=name, mat=mat, From 3b3809507dc0c4fb57177c61208478a67abdba41 Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 22:44:51 -0800 Subject: [PATCH 09/26] [Example] Add the minist example that run on noisedevice --- examples/mnist/mnist_noise.py | 250 ++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 examples/mnist/mnist_noise.py diff --git a/examples/mnist/mnist_noise.py b/examples/mnist/mnist_noise.py new file mode 100644 index 00000000..801e6621 --- /dev/null +++ b/examples/mnist/mnist_noise.py @@ -0,0 +1,250 @@ +""" +MIT License + +Copyright (c) 2020-present TorchQuantum Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import torch +import torch.nn.functional as F +import torch.optim as optim +import argparse +import random +import numpy as np + +import torchquantum as tq +from torchquantum.plugin import ( + tq2qiskit_measurement, + qiskit_assemble_circs, + op_history2qiskit, + op_history2qiskit_expand_params, +) + +from torchquantum.dataset import MNIST +from torch.optim.lr_scheduler import CosineAnnealingLR + + +class QFCModel(tq.QuantumModule): + class QLayer(tq.QuantumModule): + def __init__(self): + super().__init__() + self.n_wires = 4 + self.random_layer = tq.RandomLayer( + n_ops=50, wires=list(range(self.n_wires)) + ) + + # gates with trainable parameters + self.rx0 = tq.RX(has_params=True, trainable=True) + self.ry0 = tq.RY(has_params=True, trainable=True) + self.rz0 = tq.RZ(has_params=True, trainable=True) + self.crx0 = tq.CRX(has_params=True, trainable=True) + + def forward(self, qdev: tq.NoiseDevice): + self.random_layer(qdev) + + # some trainable gates (instantiated ahead of time) + self.rx0(qdev, wires=0) + self.ry0(qdev, wires=1) + self.rz0(qdev, wires=3) + self.crx0(qdev, wires=[0, 2]) + + # add some more non-parameterized gates (add on-the-fly) + qdev.h(wires=3) # type: ignore + qdev.sx(wires=2) # type: ignore + qdev.cnot(wires=[3, 0]) # type: ignore + qdev.rx( + wires=1, + params=torch.tensor([0.1]), + static=self.static_mode, + parent_graph=self.graph, + ) # type: ignore + + def __init__(self): + super().__init__() + self.n_wires = 4 + self.encoder = tq.GeneralEncoder(tq.encoder_op_list_name_dict["4x4_u3_h_rx"]) + + self.q_layer = self.QLayer() + self.measure = tq.MeasureAll(tq.PauliZ) + + def forward(self, x, use_qiskit=False): + qdev = tq.NoiseDevice( + n_wires=self.n_wires, bsz=x.shape[0], device=x.device, record_op=True + ) + + bsz = x.shape[0] + x = F.avg_pool2d(x, 6).view(bsz, 16) + devi = x.device + + if use_qiskit: + # use qiskit to process the circuit + # create the qiskit circuit for encoder + self.encoder(qdev, x) + op_history_parameterized = qdev.op_history + qdev.reset_op_history() + encoder_circs = op_history2qiskit_expand_params(self.n_wires, op_history_parameterized, bsz=bsz) + + # create the qiskit circuit for trainable quantum layers + self.q_layer(qdev) + op_history_fixed = qdev.op_history + qdev.reset_op_history() + q_layer_circ = op_history2qiskit(self.n_wires, op_history_fixed) + + # create the qiskit circuit for measurement + measurement_circ = tq2qiskit_measurement(qdev, self.measure) + + # assemble the encoder, trainable quantum layers, and measurement circuits + assembled_circs = qiskit_assemble_circs( + encoder_circs, q_layer_circ, measurement_circ + ) + + # call the qiskit processor to process the circuit + x0 = self.qiskit_processor.process_ready_circs(qdev, assembled_circs).to( # type: ignore + devi + ) + x = x0 + + else: + # use torchquantum to process the circuit + self.encoder(qdev, x) + qdev.reset_op_history() + self.q_layer(qdev) + x = self.measure(qdev) + + x = x.reshape(bsz, 2, 2).sum(-1).squeeze() + x = F.log_softmax(x, dim=1) + + return x + + +def train(dataflow, model, device, optimizer): + for feed_dict in dataflow["train"]: + inputs = feed_dict["image"].to(device) + targets = feed_dict["digit"].to(device) + + outputs = model(inputs) + loss = F.nll_loss(outputs, targets) + optimizer.zero_grad() + loss.backward() + optimizer.step() + print(f"loss: {loss.item()}", end="\r") + + +def valid_test(dataflow, split, model, device, qiskit=False): + target_all = [] + output_all = [] + with torch.no_grad(): + for feed_dict in dataflow[split]: + inputs = feed_dict["image"].to(device) + targets = feed_dict["digit"].to(device) + + outputs = model(inputs, use_qiskit=qiskit) + + target_all.append(targets) + output_all.append(outputs) + target_all = torch.cat(target_all, dim=0) + output_all = torch.cat(output_all, dim=0) + + _, indices = output_all.topk(1, dim=1) + masks = indices.eq(target_all.view(-1, 1).expand_as(indices)) + size = target_all.shape[0] + corrects = masks.sum().item() + accuracy = corrects / size + loss = F.nll_loss(output_all, target_all).item() + + print(f"{split} set accuracy: {accuracy}") + print(f"{split} set loss: {loss}") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--static", action="store_true", help="compute with " "static mode" + ) + parser.add_argument("--pdb", action="store_true", help="debug with pdb") + parser.add_argument( + "--wires-per-block", type=int, default=2, help="wires per block int static mode" + ) + parser.add_argument( + "--epochs", type=int, default=2, help="number of training epochs" + ) + + args = parser.parse_args() + + if args.pdb: + import pdb + + pdb.set_trace() + + seed = 0 + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + + dataset = MNIST( + root="./mnist_data", + train_valid_split_ratio=[0.9, 0.1], + digits_of_interest=[3, 6], + n_test_samples=75, + ) + dataflow = dict() + + for split in dataset: + sampler = torch.utils.data.RandomSampler(dataset[split]) + dataflow[split] = torch.utils.data.DataLoader( + dataset[split], + batch_size=256, + sampler=sampler, + num_workers=8, + pin_memory=True, + ) + + use_cuda = torch.cuda.is_available() + device = torch.device("cuda" if use_cuda else "cpu") + + model = QFCModel().to(device) + + n_epochs = args.epochs + optimizer = optim.Adam(model.parameters(), lr=5e-3, weight_decay=1e-4) + scheduler = CosineAnnealingLR(optimizer, T_max=n_epochs) + + if args.static: + # optionally to switch to the static mode, which can bring speedup + # on training + model.q_layer.static_on(wires_per_block=args.wires_per_block) + + for epoch in range(1, n_epochs + 1): + # train + print(f"Epoch {epoch}:") + train(dataflow, model, device, optimizer) + print(optimizer.param_groups[0]["lr"]) + + # valid + valid_test(dataflow, "valid", model, device) + scheduler.step() + + # test + valid_test(dataflow, "test", model, device, qiskit=False) + + + + +if __name__ == "__main__": + main() From 135446bf9b08546c17e477db5ea3697c716aefdd Mon Sep 17 00:00:00 2001 From: Zhuoyang Ye Date: Fri, 2 Feb 2024 22:53:18 -0800 Subject: [PATCH 10/26] [Bug] Fix a minor bug in batch multiplication of density matrix. --- torchquantum/density/density_func.py | 2 +- torchquantum/device/noisedevices.py | 6 ++++++ torchquantum/functional/gate_wrapper.py | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/torchquantum/density/density_func.py b/torchquantum/density/density_func.py index fb15bf3d..5bde99a8 100644 --- a/torchquantum/density/density_func.py +++ b/torchquantum/density/density_func.py @@ -217,7 +217,7 @@ def apply_unitary_density_bmm(density, mat, wires): permute_to_dag = permute_to_dag + devices_dims_dag permute_back_dag = list(np.argsort(permute_to_dag)) original_shape = new_density.shape - permuted_dag = new_density.permute(permute_to_dag).reshape([original_shape[0], -1, matdag.shape[0]]) + permuted_dag = new_density.permute(permute_to_dag).reshape([original_shape[0], -1, matdag.shape[-1]]) if len(matdag.shape) > 2: # both matrix and state are in batch mode diff --git a/torchquantum/device/noisedevices.py b/torchquantum/device/noisedevices.py index eb8c297f..e573c3d7 100644 --- a/torchquantum/device/noisedevices.py +++ b/torchquantum/device/noisedevices.py @@ -73,6 +73,12 @@ def __init__( self.record_op = record_op self.op_history = [] + + def reset_op_history(self): + """Resets the all Operation of the quantum device""" + self.op_history = [] + + def print_2d(self, index): """Print the matrix value at the given index. diff --git a/torchquantum/functional/gate_wrapper.py b/torchquantum/functional/gate_wrapper.py index cef3a867..29b5f5f1 100644 --- a/torchquantum/functional/gate_wrapper.py +++ b/torchquantum/functional/gate_wrapper.py @@ -307,7 +307,7 @@ def apply_unitary_density_bmm(density, mat, wires): del permute_to_dag[d] permute_to_dag = permute_to_dag + devices_dims_dag permute_back_dag = list(np.argsort(permute_to_dag)) - permuted_dag = new_density.permute(permute_to_dag).reshape([original_shape[0], -1, matdag.shape[0]]) + permuted_dag = new_density.permute(permute_to_dag).reshape([original_shape[0], -1, matdag.shape[-1]]) if len(matdag.shape) > 2: # both matrix and state are in batch mode @@ -431,6 +431,7 @@ def gate_wrapper( else: matrix = matrix.permute(1, 0) assert np.log2(matrix.shape[-1]) == len(wires) + #TODO: There might be a better way to discriminate noisedevice and normal statevector device if q_device.device_name=="noisedevice": density = q_device.densities if method == "einsum": From 8f0bbd07dd64d3a851604aa9b55d57c89f52accf Mon Sep 17 00:00:00 2001 From: GenericP3rson <41024739+GenericP3rson@users.noreply.github.com> Date: Sun, 4 Feb 2024 10:21:35 -0500 Subject: [PATCH 11/26] [minor] update OneQubitEulerDecomposer --- torchquantum/plugin/qiskit/qiskit_unitary_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torchquantum/plugin/qiskit/qiskit_unitary_gate.py b/torchquantum/plugin/qiskit/qiskit_unitary_gate.py index 6e520b96..ce46ff04 100644 --- a/torchquantum/plugin/qiskit/qiskit_unitary_gate.py +++ b/torchquantum/plugin/qiskit/qiskit_unitary_gate.py @@ -25,7 +25,7 @@ from qiskit.circuit.library.standard_gates import U3Gate from qiskit.quantum_info.operators.predicates import matrix_equal from qiskit.quantum_info.operators.predicates import is_unitary_matrix -from qiskit.quantum_info.synthesis.one_qubit_decompose import OneQubitEulerDecomposer +from qiskit.quantum_info import OneQubitEulerDecomposer from qiskit.quantum_info.synthesis.two_qubit_decompose import two_qubit_cnot_decompose from qiskit.extensions.exceptions import ExtensionError From 02a81c3c8d2463ca4ad4d210f28ade2d4f621d62 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:19:22 -0500 Subject: [PATCH 12/26] [minor] adding yaml file for docs --- readthedocs.yaml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 readthedocs.yaml diff --git a/readthedocs.yaml b/readthedocs.yaml new file mode 100644 index 00000000..aeceb064 --- /dev/null +++ b/readthedocs.yaml @@ -0,0 +1,35 @@ +# Read the Docs configuration file for Sphinx projects +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 0.1.7 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.12" + # You can also specify other tool versions: + # nodejs: "20" + # rust: "1.70" + # golang: "1.20" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/source/conf.py + # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs + # builder: "dirhtml" + # Fail on all warnings to avoid broken references + # fail_on_warning: true + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt From efff2e49242c82b0b538b381abbfe3a256aaa358 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:20:40 -0500 Subject: [PATCH 13/26] [minor] fixing the version --- readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs.yaml b/readthedocs.yaml index aeceb064..a83c2f35 100644 --- a/readthedocs.yaml +++ b/readthedocs.yaml @@ -2,7 +2,7 @@ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required -version: 0.1.7 +version: 2 # Set the OS, Python version and other tools you might need build: From 9700cb997e6f49c9f2f870e8fccfd7024eb7a9ab Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:23:23 -0500 Subject: [PATCH 14/26] [minor] rm furo import --- docs/source/conf.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 86fbdc7a..537edece 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -29,7 +29,6 @@ import sys import os sys.path.insert(0, os.path.abspath('../..')) -import furo #import pathlib #sys.path.insert(0, pathlib.Path(__file__).parents[2].resolve().as_posix()) @@ -160,4 +159,4 @@ display_gitlab = False show_source = True # -- Options for EPUB output -epub_show_urls = 'footnote' \ No newline at end of file +epub_show_urls = 'footnote' From 830747f06c83021ed56367553f5dfe291c8f1948 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:25:15 -0500 Subject: [PATCH 15/26] [minor] add proper docs imports --- readthedocs.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readthedocs.yaml b/readthedocs.yaml index a83c2f35..e952a46c 100644 --- a/readthedocs.yaml +++ b/readthedocs.yaml @@ -30,6 +30,6 @@ sphinx: # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# python: -# install: -# - requirements: docs/requirements.txt +python: + install: + - requirements: docs/requirements.txt From 36abad4a71ec26f590265bf26399be989ed55aa0 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:27:10 -0500 Subject: [PATCH 16/26] [minor --- docs/requirements.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/requirements.txt diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..88a06d50 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,22 @@ +furo @ git+https://github.com/frogcjn/torchquantum-doc-furo-theme.git +dill==0.3.4 +matplotlib>=3.3.2 +nbsphinx +numpy>=1.19.2 + +opt_einsum +pathos>=0.2.7 +pylatexenc>=2.10 +pyscf>=2.0.1 +qiskit>=0.39.0 +recommonmark + +scipy>=1.5.2 +setuptools>=52.0.0 +tensorflow>=2.4.1 +torch>=1.8.0 +torchdiffeq>=0.2.3 +torchpack>=0.3.0 +torchquantum>=0.1 +torchvision>=0.9.0.dev20210130 +tqdm>=4.56.0 From 74d270266a39c79519db3d5ffecda5504334e1cc Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:29:13 -0500 Subject: [PATCH 17/26] [minor] reduced number of imports --- docs/requirements.txt | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 88a06d50..b81d89e7 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,22 +1,2 @@ furo @ git+https://github.com/frogcjn/torchquantum-doc-furo-theme.git -dill==0.3.4 -matplotlib>=3.3.2 nbsphinx -numpy>=1.19.2 - -opt_einsum -pathos>=0.2.7 -pylatexenc>=2.10 -pyscf>=2.0.1 -qiskit>=0.39.0 -recommonmark - -scipy>=1.5.2 -setuptools>=52.0.0 -tensorflow>=2.4.1 -torch>=1.8.0 -torchdiffeq>=0.2.3 -torchpack>=0.3.0 -torchquantum>=0.1 -torchvision>=0.9.0.dev20210130 -tqdm>=4.56.0 From f6f950bd92bf6f3d93355af3a112578f741459f4 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:31:15 -0500 Subject: [PATCH 18/26] [minor] add recommonmark --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index b81d89e7..c7df643a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ furo @ git+https://github.com/frogcjn/torchquantum-doc-furo-theme.git nbsphinx +recommonmark From defac195bac0bd51e74c52373aab59317e6fee6d Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:34:54 -0500 Subject: [PATCH 19/26] [minor] adding tq? --- docs/requirements.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index c7df643a..5d42657e 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,6 @@ furo @ git+https://github.com/frogcjn/torchquantum-doc-furo-theme.git nbsphinx recommonmark + +torchquantum>=0.1 + From 112c5e428847a296febcf19121fb941bbcc8fad4 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:42:50 -0500 Subject: [PATCH 20/26] [minor] lowering the python version if that helps --- readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs.yaml b/readthedocs.yaml index e952a46c..b664f319 100644 --- a/readthedocs.yaml +++ b/readthedocs.yaml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.12" + python: "3.10" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" From a805b4318ea6412e0f084ef41e3c97ad139bdac8 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Fri, 9 Feb 2024 21:48:18 -0500 Subject: [PATCH 21/26] [minor] add opt_einsum --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 5d42657e..597c0496 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,4 +3,4 @@ nbsphinx recommonmark torchquantum>=0.1 - +opt_einsum From 0b0097906ccc8509ddc7ff7d9a59e319c5918e09 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 20 Feb 2024 19:09:46 -0500 Subject: [PATCH 22/26] [major] removed deprecated IBMQ dependency and restricted to qiskit<1.0.0 --- torchquantum/util/utils.py | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/torchquantum/util/utils.py b/torchquantum/util/utils.py index 58ef4e03..caeee471 100644 --- a/torchquantum/util/utils.py +++ b/torchquantum/util/utils.py @@ -30,7 +30,7 @@ import torch.nn as nn import torch.nn.functional as F from opt_einsum import contract -from qiskit import IBMQ +from qiskit_ibm_runtime import QiskitRuntimeService from qiskit.exceptions import QiskitError from qiskit.providers.aer.noise.device.parameters import gate_error_values from torchpack.utils.config import Config @@ -738,7 +738,6 @@ def get_success_rate(properties, transpiled_circ): return success_rate - def get_provider(backend_name, hub=None): """ Get the provider object for a specific backend from IBM Quantum. @@ -753,13 +752,9 @@ def get_provider(backend_name, hub=None): # mass-inst-tech-1 or MIT-1 if backend_name in ["ibmq_casablanca", "ibmq_rome", "ibmq_bogota", "ibmq_jakarta"]: if hub == "mass" or hub is None: - provider = IBMQ.get_provider( - hub="ibm-q-research", group="mass-inst-tech-1", project="main" - ) + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = "ibm-q-research/mass-inst-tech-1/main") elif hub == "mit": - provider = IBMQ.get_provider( - hub="ibm-q-research", group="MIT-1", project="main" - ) + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = "ibm-q-research/MIT-1/main") else: raise ValueError(f"not supported backend {backend_name} in hub " f"{hub}") elif backend_name in [ @@ -769,33 +764,25 @@ def get_provider(backend_name, hub=None): "ibmq_guadalupe", "ibmq_montreal", ]: - provider = IBMQ.get_provider(hub="ibm-q-ornl", group="anl", project="csc428") + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = "ibm-q-ornl/anl/csc428") else: if hub == "mass" or hub is None: try: - provider = IBMQ.get_provider( - hub="ibm-q-research", group="mass-inst-tech-1", project="main" - ) + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = "ibm-q-research/mass-inst-tech-1/main") except QiskitError: # logger.warning(f"Cannot use MIT backend, roll back to open") logger.warning(f"Use the open backend") - provider = IBMQ.get_provider(hub="ibm-q", group="open", project="main") + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = "ibm-q/open/main") elif hub == "mit": - provider = IBMQ.get_provider( - hub="ibm-q-research", group="MIT-1", project="main" - ) + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = "ibm-q-research/MIT-1/main") else: - provider = IBMQ.get_provider(hub="ibm-q", group="open", project="main") + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = "ibm-q/open/main") return provider def get_provider_hub_group_project(hub="ibm-q", group="open", project="main"): - provider = IBMQ.get_provider( - hub=hub, - group=group, - project=project, - ) + provider = QiskitRuntimeService(channel = "ibm_quantum", instance = f"{hub}/{group}/{project}") return provider @@ -1085,4 +1072,4 @@ def clone_model(model_to_clone):#i have to note:this clone_model function was ma state_dict_minus_shift[key] += shift_rate gradient_of_par[idx-2] = (expectation_plus_shift - expectation_minus_shift) * 0.5 - return gradient_of_par \ No newline at end of file + return gradient_of_par From b9851929743fab7272a7ec037d949f26c3e75923 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 20 Feb 2024 19:28:09 -0500 Subject: [PATCH 23/26] [minor] added missing dependency --- .github/workflows/functional_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/functional_tests.yaml b/.github/workflows/functional_tests.yaml index fb8a7ea1..f1d2770e 100644 --- a/.github/workflows/functional_tests.yaml +++ b/.github/workflows/functional_tests.yaml @@ -25,7 +25,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install flake8 pytest qiskit-aer qiskit-ibmq-provider + python -m pip install flake8 pytest qiskit-aer qiskit_ibm_runtime if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: Lint with flake8 run: | From 1f7bcf0866ff830dab93f27aa26f24f6c445f7a0 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 20 Feb 2024 19:37:47 -0500 Subject: [PATCH 24/26] [minor] flipping order of imports --- .github/workflows/functional_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/functional_tests.yaml b/.github/workflows/functional_tests.yaml index f1d2770e..4be0f73d 100644 --- a/.github/workflows/functional_tests.yaml +++ b/.github/workflows/functional_tests.yaml @@ -25,8 +25,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install flake8 pytest qiskit-aer qiskit_ibm_runtime if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + python -m pip install flake8 pytest qiskit-aer qiskit_ibm_runtime - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names From d6fffa184ec8a3c1f1cf299ca5814c3e392c7926 Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 20 Feb 2024 19:42:34 -0500 Subject: [PATCH 25/26] [minor] updating the requirements --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 88a06d50..a43fc839 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ opt_einsum pathos>=0.2.7 pylatexenc>=2.10 pyscf>=2.0.1 -qiskit>=0.39.0 +qiskit>=0.39.0,<1.0.0 recommonmark scipy>=1.5.2 From 511fbfaf0583e0a8c4a68d39d9500ca5ca6c9a5b Mon Sep 17 00:00:00 2001 From: GenericP3rson Date: Tue, 20 Feb 2024 20:15:17 -0500 Subject: [PATCH 26/26] [minor] moved density tests to not be included for now --- .../density/{test_density_measure.py => _test_density_measure.py} | 0 test/density/{test_density_op.py => _test_density_op.py} | 0 test/density/{test_density_trace.py => _test_density_trace.py} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename test/density/{test_density_measure.py => _test_density_measure.py} (100%) rename test/density/{test_density_op.py => _test_density_op.py} (100%) rename test/density/{test_density_trace.py => _test_density_trace.py} (100%) diff --git a/test/density/test_density_measure.py b/test/density/_test_density_measure.py similarity index 100% rename from test/density/test_density_measure.py rename to test/density/_test_density_measure.py diff --git a/test/density/test_density_op.py b/test/density/_test_density_op.py similarity index 100% rename from test/density/test_density_op.py rename to test/density/_test_density_op.py diff --git a/test/density/test_density_trace.py b/test/density/_test_density_trace.py similarity index 100% rename from test/density/test_density_trace.py rename to test/density/_test_density_trace.py