From 93cb5cc89f73df6a8029843779bf26f04f592cda Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 14:37:43 +0530 Subject: [PATCH 01/61] Create generalized_uniform_superposition_gate.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $ (where 1< M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a generalized uniform superposition state of the form, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(log_2 (M))$ qubits and $O(log_2 (M))$ gates. This provides an exponential improvement (in the context of reduced resources and complexity) over other approaches in the literature. Reference: [SV24] A. Shukla and P. Vedula, “An efficient quantum algorithm for preparation of uniform quantum superposition states,” Quantum Information Processing, 23(38): pp. 1-32 (2024). --- .../generalized_uniform_superposition_gate.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 cirq-core/cirq/ops/generalized_uniform_superposition_gate.py diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py new file mode 100644 index 00000000000..858e4da300c --- /dev/null +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -0,0 +1,75 @@ +def generalized_uniform_superposition_cirqx(M, num_qubits): + """ + Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $ (where 1< M <= 2^n), + using n qubits, according to the Shukla-Vedula algorithm [SV24]. + + Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a generalized uniform superposition + state of the form, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(log_2 (M))$ qubits and $O(log_2 (M))$ + gates. This represents an exponential improvement (in the context of reduced resources and complexity) over other approaches + in the literature. + + Args: + M (integer): + A positive integer M (> 1) representing the number of computational basis states with an amplitude of 1/sqrt(M) + in the uniform superposition state ($\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $). Note that the remaining + (2^n - M) computational basis states have zero amplitudes. Here M need not be an integer power of 2. + + n (integer): + A positive integer representing the number of qubits used. + + Returns: + A quantum circuit that creates the uniform superposition state: $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $. + + References: + [SV24] + A. Shukla and P. Vedula, “An efficient quantum algorithm for preparation of uniform quantum superposition states,” + Quantum Information Processing, 23(38): pp. 1-32 (2024). + """ + + if (num_qubits < np.log2(M)): + print('Error Message: Not enough qubits! Try increasing num_qubits ..') + return + + qreg = cirq.LineQubit.range(num_qubits) + qreg.reverse() + qcircuit = cirq.Circuit() + + # Delete the line below + # [qcircuit.append(cirq.I(qreg[i])) for i in range(num_qubits)] + + if (M & (M-1)) == 0: #if M is an integer power of 2 + m = int(np.log2(M)) + for i in range(m): + qcircuit.append(cirq.H(qreg[i])) + return qcircuit + + N = [int(x) for x in list(np.binary_repr(M))][::-1] + k = len(N) + L = [index for (index,item) in enumerate(N) if item==1] #Locations of '1's + + for i in L[1:k]: + qcircuit.append(cirq.X(qreg[i])) + + Mcurrent = 2**(L[0]) + theta = -2*np.arccos(np.sqrt(Mcurrent/M)) + + if L[0]>0: #if M is even + for i in range(L[0]): + qcircuit.append(cirq.H(qreg[i])) + + qcircuit.append(cirq.ry(theta).on(qreg[L[1]])) + + for i in range(L[0], L[1]): + qcircuit.append(cirq.H(qreg[i]).controlled_by(qreg[L[1]], control_values=[False])) + + for m in range(1,len(L)-1): + theta = -2*np.arccos(np.sqrt(2**L[m]/ (M-Mcurrent))) + qcircuit.append(cirq.ControlledGate(cirq.ry(theta), control_values=[False])(qreg[L[m]], qreg[L[m+1]])) + for i in range(L[m], L[m+1]): + qcircuit.append(cirq.ControlledGate(cirq.H, control_values=[False])(qreg[L[m+1]], qreg[i])) + + Mcurrent = Mcurrent + 2**(L[m]) + + qreg.reverse() + + return qcircuit From 45d204bea1bfce7582144ed2f8aafbc65df5b70a Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 20:14:26 +0530 Subject: [PATCH 02/61] Update generalized_uniform_superposition_gate.py --- cirq-core/cirq/ops/generalized_uniform_superposition_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index 858e4da300c..ac4ad907a46 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -5,7 +5,7 @@ def generalized_uniform_superposition_cirqx(M, num_qubits): Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a generalized uniform superposition state of the form, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(log_2 (M))$ qubits and $O(log_2 (M))$ - gates. This represents an exponential improvement (in the context of reduced resources and complexity) over other approaches + gates. This provides an exponential improvement (in the context of reduced resources and complexity) over other approaches in the literature. Args: From 879c804bfa1a5de07972547750c1355497f23a99 Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 20:17:01 +0530 Subject: [PATCH 03/61] Update generalized_uniform_superposition_gate.py --- .../ops/generalized_uniform_superposition_gate.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index ac4ad907a46..f0968051133 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -1,3 +1,17 @@ +# Copyright 2024 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + def generalized_uniform_superposition_cirqx(M, num_qubits): """ Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $ (where 1< M <= 2^n), From 402626178163dd8e8345ac97c41ed71d9a8890e2 Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 20:20:01 +0530 Subject: [PATCH 04/61] Update generalized_uniform_superposition_gate.py --- cirq-core/cirq/ops/generalized_uniform_superposition_gate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index f0968051133..1e6c8eba8fa 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import cirq + def generalized_uniform_superposition_cirqx(M, num_qubits): """ Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $ (where 1< M <= 2^n), From 6d8a4d79f056df2efea0895fe969adf19f71ab70 Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 20:25:52 +0530 Subject: [PATCH 05/61] Update generalized_uniform_superposition_gate.py --- cirq-core/cirq/ops/generalized_uniform_superposition_gate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index 1e6c8eba8fa..d1abb80c45d 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -13,6 +13,7 @@ # limitations under the License. import cirq +import numpy as np def generalized_uniform_superposition_cirqx(M, num_qubits): """ From ab2e2b6f8cd87f2576940ebfeb9d1ed07b2b9719 Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 21:13:28 +0530 Subject: [PATCH 06/61] Create generalized_uniform_superposition_gate_test.py Code tests the creation of M uniform superposition states using generalized_uniform_superposition_gate. --- ...ralized_uniform_superposition_gate_test.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py new file mode 100644 index 00000000000..3285d25b37e --- /dev/null +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py @@ -0,0 +1,22 @@ +def check_uniform_superposition_error(M, n): + + gate = generalized_uniform_superposition_gate(M, n) + qregx = cirq.LineQubit.range(n) + qcircuit = cirq.Circuit(gate.on(*qregx)) + + unitary_matrix1 = np.real(qcircuit.unitary()) + + np.testing.assert_allclose( + unitary_matrix1[:,0], + (1/np.sqrt(M))*np.array([1]*M + [0]*(2**n - M)), + atol=1e-8, + ) + +"""The following code tests the creation of M uniform superposition states, where M ranges from 3 to 1024.""" +M=1025 +for mm in range(3, M): + if (mm & (mm-1)) == 0: + n = int(np.log2(mm)) + else: + n = int(np.ceil(np.log2(M))) + check_uniform_superposition_error(mm, n) From eb9f19fdcb16ecf88413abf9f777f828d1ea5935 Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 21:14:30 +0530 Subject: [PATCH 07/61] Update generalized_uniform_superposition_gate_test.py --- ...neralized_uniform_superposition_gate_test.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py index 3285d25b37e..a9d9ab4b103 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py @@ -1,3 +1,20 @@ +# Copyright 2024 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import cirq +import numpy as np + def check_uniform_superposition_error(M, n): gate = generalized_uniform_superposition_gate(M, n) From 3303a9410451c8c82dd6dc92eb0705365b780493 Mon Sep 17 00:00:00 2001 From: prag16 <163991062+prag16@users.noreply.github.com> Date: Tue, 19 Mar 2024 21:17:18 +0530 Subject: [PATCH 08/61] Update generalized_uniform_superposition_gate_test.py --- ...generalized_uniform_superposition_gate_test.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py index a9d9ab4b103..4b22715e99a 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py @@ -30,10 +30,11 @@ def check_uniform_superposition_error(M, n): ) """The following code tests the creation of M uniform superposition states, where M ranges from 3 to 1024.""" -M=1025 -for mm in range(3, M): - if (mm & (mm-1)) == 0: - n = int(np.log2(mm)) - else: - n = int(np.ceil(np.log2(M))) - check_uniform_superposition_error(mm, n) +def test1_check_uniform(): + M=1025 + for mm in range(3, M): + if (mm & (mm-1)) == 0: + n = int(np.log2(mm)) + else: + n = int(np.ceil(np.log2(M))) + check_uniform_superposition_error(mm, n) From 1145e11fc0dc73c6dd94b9d683f8c645f7edae36 Mon Sep 17 00:00:00 2001 From: Pragya Alok Shukla <163991062+prag16@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:41:41 +0530 Subject: [PATCH 09/61] Updated generalized_uniform_superposition_gate.py based on PR review comments Thanks to dstrain115 for the review and helpful comments. The following changes were made based on these comments: 1) The code has been modified to implement the functionality as a Gate. 2) The missing type information was provided. 3) The code for appropriate value errors was included --- .../generalized_uniform_superposition_gate.py | 142 +++++++++++------- 1 file changed, 88 insertions(+), 54 deletions(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index d1abb80c45d..de9d7fba867 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -12,81 +12,115 @@ # See the License for the specific language governing permissions and # limitations under the License. -import cirq +import typing import Sequence import numpy as np -def generalized_uniform_superposition_cirqx(M, num_qubits): +class generalized_uniform_superposition_gate(cirq.Gate) -> gate: """ Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $ (where 1< M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a generalized uniform superposition - state of the form, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(log_2 (M))$ qubits and $O(log_2 (M))$ + state of the form, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(\log_2 (M))$ qubits and $O(\log_2 (M))$ gates. This provides an exponential improvement (in the context of reduced resources and complexity) over other approaches in the literature. Args: - M (integer): + M (int): A positive integer M (> 1) representing the number of computational basis states with an amplitude of 1/sqrt(M) in the uniform superposition state ($\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $). Note that the remaining (2^n - M) computational basis states have zero amplitudes. Here M need not be an integer power of 2. - n (integer): + num_qubits (int): A positive integer representing the number of qubits used. Returns: - A quantum circuit that creates the uniform superposition state: $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $. + cirq.Circuit: A quantum circuit that creates the uniform superposition state: $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $. References: [SV24] A. Shukla and P. Vedula, “An efficient quantum algorithm for preparation of uniform quantum superposition states,” Quantum Information Processing, 23(38): pp. 1-32 (2024). """ - - if (num_qubits < np.log2(M)): - print('Error Message: Not enough qubits! Try increasing num_qubits ..') - return - - qreg = cirq.LineQubit.range(num_qubits) - qreg.reverse() - qcircuit = cirq.Circuit() - - # Delete the line below - # [qcircuit.append(cirq.I(qreg[i])) for i in range(num_qubits)] - - if (M & (M-1)) == 0: #if M is an integer power of 2 - m = int(np.log2(M)) - for i in range(m): - qcircuit.append(cirq.H(qreg[i])) - return qcircuit - - N = [int(x) for x in list(np.binary_repr(M))][::-1] - k = len(N) - L = [index for (index,item) in enumerate(N) if item==1] #Locations of '1's - - for i in L[1:k]: - qcircuit.append(cirq.X(qreg[i])) - - Mcurrent = 2**(L[0]) - theta = -2*np.arccos(np.sqrt(Mcurrent/M)) - - if L[0]>0: #if M is even - for i in range(L[0]): - qcircuit.append(cirq.H(qreg[i])) - - qcircuit.append(cirq.ry(theta).on(qreg[L[1]])) - - for i in range(L[0], L[1]): - qcircuit.append(cirq.H(qreg[i]).controlled_by(qreg[L[1]], control_values=[False])) - - for m in range(1,len(L)-1): - theta = -2*np.arccos(np.sqrt(2**L[m]/ (M-Mcurrent))) - qcircuit.append(cirq.ControlledGate(cirq.ry(theta), control_values=[False])(qreg[L[m]], qreg[L[m+1]])) - for i in range(L[m], L[m+1]): - qcircuit.append(cirq.ControlledGate(cirq.H, control_values=[False])(qreg[L[m+1]], qreg[i])) - - Mcurrent = Mcurrent + 2**(L[m]) - - qreg.reverse() - - return qcircuit + def __init__(self, M: int, num_qubits: int) -> None: + """ + Initializes generalized_uniform_superposition_gate. + + Args: + M (int): The number of computational basis states with amplitude 1/sqrt(M). + num_qubits (int): The number of qubits used. + """ + super(generalized_uniform_superposition_gate, self).__init__() + if not (isinstance(M, int) and (M > 1)): + raise ValueError('M must be a positive integer greater than 1.') + if not (isinstance(num_qubits, int) and (num_qubits >= np.log2(M))): + raise ValueError('num_qubits must be an integer greater than or equal to log2(M).') + self.M = M + self._num_qubits = num_qubits + + def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': + """ + Decomposes the gate into a sequence of standard gates. + + Args: + qubits (list[cirq.Qid]): Qubits to apply the gate on. + + Yields: + cirq.Operation: Operations implementing the gate. + """ + qreg = list(qubits) + + if (self.M & (self.M-1)) == 0: #if M is an integer power of 2 + m = int(np.log2(self.M)) + for i in range(m): + yield cirq.H(qreg[i]) + return + + N = [int(x) for x in list(np.binary_repr(self.M))][::-1] + k = len(N) + L = [index for (index,item) in enumerate(N) if item==1] #Locations of '1's + + qreg.reverse() + + for i in L[1:k]: + yield cirq.X(qreg[i]) + + Mcurrent = 2**(L[0]) + theta = -2*np.arccos(np.sqrt(Mcurrent/self.M)) + + if L[0]>0: #if M is even + for i in range(L[0]): + yield cirq.H(qreg[i]) + + yield cirq.ry(theta).on(qreg[L[1]]) + + for i in range(L[0], L[1]): + yield cirq.H(qreg[i]).controlled_by(qreg[L[1]], control_values=[False]) + + for m in range(1,len(L)-1): + theta = -2*np.arccos(np.sqrt(2**L[m]/ (self.M-Mcurrent))) + yield cirq.ControlledGate(cirq.ry(theta), control_values=[False])(qreg[L[m]], qreg[L[m+1]]) + for i in range(L[m], L[m+1]): + yield cirq.ControlledGate(cirq.H, control_values=[False])(qreg[L[m+1]], qreg[i]) + + Mcurrent = Mcurrent + 2**(L[m]) + + + + def num_qubits(self) -> int: + """ + Returns the number of qubits used by the gate. + + Returns: + int: The number of qubits. + """ + return self._num_qubits + + def __repr__(self) -> str: + """ + Returns a string representation of the gate. + + Returns: + str: String representation of the gate. + """ + return f'generalized_uniform_superposition_gate(M={self.M}, num_qubits={self._num_qubits})' From 5b4ecc30d40fc758ccefc16ff727a3a1ffeeba0a Mon Sep 17 00:00:00 2001 From: Pragya Alok Shukla <163991062+prag16@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:11:14 +0530 Subject: [PATCH 10/61] Updated generalized_uniform_superposition_gate_test.py based on PR review comments. Added the docstrings and changed the name of the function to make it more meaningful. --- ...eneralized_uniform_superposition_gate_test.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py index 4b22715e99a..c2f91721106 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py @@ -15,8 +15,13 @@ import cirq import numpy as np -def check_uniform_superposition_error(M, n): - +def _assert_generated_unitary_is_uniform(M :int, n :int) -> None: +""" +The code checks that the unitary matrix corresponds to the generated uniform superposition states (see generalized_uniform_superposition_gate.py). +It is enough to check that the first colum of the unitary matrix (which corresponds to the action of +the gate on $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$ entries +are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. +""" gate = generalized_uniform_superposition_gate(M, n) qregx = cirq.LineQubit.range(n) qcircuit = cirq.Circuit(gate.on(*qregx)) @@ -29,12 +34,13 @@ def check_uniform_superposition_error(M, n): atol=1e-8, ) -"""The following code tests the creation of M uniform superposition states, where M ranges from 3 to 1024.""" -def test1_check_uniform(): + +def _test1_check_uniform(): + """The code tests the creation of M uniform superposition states, where M ranges from 3 to 1024.""" M=1025 for mm in range(3, M): if (mm & (mm-1)) == 0: n = int(np.log2(mm)) else: n = int(np.ceil(np.log2(M))) - check_uniform_superposition_error(mm, n) + _assert_generated_unitary_is_uniform(mm, n) From 659adf2d47f114a16cea4b980b791022798c5e07 Mon Sep 17 00:00:00 2001 From: Pragya Alok Shukla <163991062+prag16@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:20:59 +0530 Subject: [PATCH 11/61] Updated generalized_uniform_superposition_gate.py to fix the import statements --- .../cirq/ops/generalized_uniform_superposition_gate.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index de9d7fba867..a736c8838b9 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -12,10 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import typing import Sequence import numpy as np +from typing import Sequence +from cirq.ops import raw_types -class generalized_uniform_superposition_gate(cirq.Gate) -> gate: +if TYPE_CHECKING: + import cirq + +class generalized_uniform_superposition_gate(raw_types.Gate): """ Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $ (where 1< M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. From e811f3aa62d76f474667f96a5660f23f5b1df191 Mon Sep 17 00:00:00 2001 From: Pragya Alok Shukla <163991062+prag16@users.noreply.github.com> Date: Tue, 9 Apr 2024 13:16:08 +0530 Subject: [PATCH 12/61] Update generalized_uniform_superposition_gate_test.py Fixed a minor typo and added some comments for clarification. --- .../cirq/ops/generalized_uniform_superposition_gate_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py index c2f91721106..a1944df5a8e 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py @@ -39,8 +39,8 @@ def _test1_check_uniform(): """The code tests the creation of M uniform superposition states, where M ranges from 3 to 1024.""" M=1025 for mm in range(3, M): - if (mm & (mm-1)) == 0: + if (mm & (mm-1)) == 0: #if mm is an integer power of 2 n = int(np.log2(mm)) - else: - n = int(np.ceil(np.log2(M))) + else: #if mm is not an integer power of 2 + n = int(np.ceil(np.log2(mm))) _assert_generated_unitary_is_uniform(mm, n) From 998a765459b4770bdbe443e1088966c13c09549d Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:01:13 +0530 Subject: [PATCH 13/61] Update generalized_uniform_superposition_gate_test.py Indentation error fixed. --- .../generalized_uniform_superposition_gate_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py index a1944df5a8e..445c3c8cb54 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py @@ -16,12 +16,12 @@ import numpy as np def _assert_generated_unitary_is_uniform(M :int, n :int) -> None: -""" -The code checks that the unitary matrix corresponds to the generated uniform superposition states (see generalized_uniform_superposition_gate.py). -It is enough to check that the first colum of the unitary matrix (which corresponds to the action of -the gate on $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$ entries -are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. -""" + """ + The code checks that the unitary matrix corresponds to the generated uniform superposition states (see generalized_uniform_superposition_gate.py). + It is enough to check that the first colum of the unitary matrix (which corresponds to the action of + the gate on $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$ entries + are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. + """ gate = generalized_uniform_superposition_gate(M, n) qregx = cirq.LineQubit.range(n) qcircuit = cirq.Circuit(gate.on(*qregx)) From 0930e1df0041907d32297bf31047cacda8ef11a4 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:13:20 +0530 Subject: [PATCH 14/61] Update generalized_uniform_superposition_gate.py From 3d3abb51aa637609c23eb8ce870c90c5e2447554 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:17:38 +0530 Subject: [PATCH 15/61] Update generalized_uniform_superposition_gate.py --- cirq-core/cirq/ops/generalized_uniform_superposition_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index a736c8838b9..369544ff86c 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -43,7 +43,7 @@ class generalized_uniform_superposition_gate(raw_types.Gate): References: [SV24] - A. Shukla and P. Vedula, “An efficient quantum algorithm for preparation of uniform quantum superposition states,” + A. Shukla and P. Vedula, "An efficient quantum algorithm for preparation of uniform quantum superposition states," Quantum Information Processing, 23(38): pp. 1-32 (2024). """ def __init__(self, M: int, num_qubits: int) -> None: From 4b31c3b1e55e1e3b85787393375866a1998a394c Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:27:16 +0530 Subject: [PATCH 16/61] Update generalized_uniform_superposition_gate.py used black to correct formatting --- cirq-core/cirq/ops/generalized_uniform_superposition_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index 369544ff86c..a736c8838b9 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -43,7 +43,7 @@ class generalized_uniform_superposition_gate(raw_types.Gate): References: [SV24] - A. Shukla and P. Vedula, "An efficient quantum algorithm for preparation of uniform quantum superposition states," + A. Shukla and P. Vedula, “An efficient quantum algorithm for preparation of uniform quantum superposition states,” Quantum Information Processing, 23(38): pp. 1-32 (2024). """ def __init__(self, M: int, num_qubits: int) -> None: From 803f178a714d9fec042370dd8e2a22e4ba30ade7 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 10 Apr 2024 21:33:15 +0530 Subject: [PATCH 17/61] Update generalized_uniform_superposition_gate_test.py Used black to format the code From f370dadf707a6e19c74d68c5d651474ab29abf75 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:07:40 +0530 Subject: [PATCH 18/61] Update generalized_uniform_superposition_gate.py --- cirq-core/cirq/ops/generalized_uniform_superposition_gate.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py index a736c8838b9..b0e28268cee 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py @@ -16,8 +16,7 @@ from typing import Sequence from cirq.ops import raw_types -if TYPE_CHECKING: - import cirq + class generalized_uniform_superposition_gate(raw_types.Gate): """ @@ -43,7 +42,7 @@ class generalized_uniform_superposition_gate(raw_types.Gate): References: [SV24] - A. Shukla and P. Vedula, “An efficient quantum algorithm for preparation of uniform quantum superposition states,” + A. Shukla and P. Vedula, "An efficient quantum algorithm for preparation of uniform quantum superposition states," Quantum Information Processing, 23(38): pp. 1-32 (2024). """ def __init__(self, M: int, num_qubits: int) -> None: From 4df3af8982f7a8d99a0d7de79f385a769ddda32c Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:10:19 +0530 Subject: [PATCH 19/61] Update generalized_uniform_superposition_gate_test.py --- .../cirq/ops/generalized_uniform_superposition_gate_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py index 445c3c8cb54..3231496b0f2 100644 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py @@ -22,7 +22,7 @@ def _assert_generated_unitary_is_uniform(M :int, n :int) -> None: the gate on $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$ entries are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. """ - gate = generalized_uniform_superposition_gate(M, n) + gate = cirq.generalized_uniform_superposition_gate(M, n) qregx = cirq.LineQubit.range(n) qcircuit = cirq.Circuit(gate.on(*qregx)) From 46e035c1d6437c97ef78d66a67de852d007f25f6 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Fri, 10 May 2024 11:23:39 +0530 Subject: [PATCH 20/61] Update and rename generalized_uniform_superposition_gate.py to uniform_superposition_gate.py Updated the names of the variables to conform to Cirq conventions and Pylint rules. --- .../generalized_uniform_superposition_gate.py | 129 ---------------- .../cirq/ops/uniform_superposition_gate.py | 145 ++++++++++++++++++ 2 files changed, 145 insertions(+), 129 deletions(-) delete mode 100644 cirq-core/cirq/ops/generalized_uniform_superposition_gate.py create mode 100644 cirq-core/cirq/ops/uniform_superposition_gate.py diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py deleted file mode 100644 index b0e28268cee..00000000000 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2024 The Cirq Developers -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import numpy as np -from typing import Sequence -from cirq.ops import raw_types - - - -class generalized_uniform_superposition_gate(raw_types.Gate): - """ - Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $ (where 1< M <= 2^n), - using n qubits, according to the Shukla-Vedula algorithm [SV24]. - - Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a generalized uniform superposition - state of the form, $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(\log_2 (M))$ qubits and $O(\log_2 (M))$ - gates. This provides an exponential improvement (in the context of reduced resources and complexity) over other approaches - in the literature. - - Args: - M (int): - A positive integer M (> 1) representing the number of computational basis states with an amplitude of 1/sqrt(M) - in the uniform superposition state ($\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $). Note that the remaining - (2^n - M) computational basis states have zero amplitudes. Here M need not be an integer power of 2. - - num_qubits (int): - A positive integer representing the number of qubits used. - - Returns: - cirq.Circuit: A quantum circuit that creates the uniform superposition state: $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $. - - References: - [SV24] - A. Shukla and P. Vedula, "An efficient quantum algorithm for preparation of uniform quantum superposition states," - Quantum Information Processing, 23(38): pp. 1-32 (2024). - """ - def __init__(self, M: int, num_qubits: int) -> None: - """ - Initializes generalized_uniform_superposition_gate. - - Args: - M (int): The number of computational basis states with amplitude 1/sqrt(M). - num_qubits (int): The number of qubits used. - """ - super(generalized_uniform_superposition_gate, self).__init__() - if not (isinstance(M, int) and (M > 1)): - raise ValueError('M must be a positive integer greater than 1.') - if not (isinstance(num_qubits, int) and (num_qubits >= np.log2(M))): - raise ValueError('num_qubits must be an integer greater than or equal to log2(M).') - self.M = M - self._num_qubits = num_qubits - - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': - """ - Decomposes the gate into a sequence of standard gates. - - Args: - qubits (list[cirq.Qid]): Qubits to apply the gate on. - - Yields: - cirq.Operation: Operations implementing the gate. - """ - qreg = list(qubits) - - if (self.M & (self.M-1)) == 0: #if M is an integer power of 2 - m = int(np.log2(self.M)) - for i in range(m): - yield cirq.H(qreg[i]) - return - - N = [int(x) for x in list(np.binary_repr(self.M))][::-1] - k = len(N) - L = [index for (index,item) in enumerate(N) if item==1] #Locations of '1's - - qreg.reverse() - - for i in L[1:k]: - yield cirq.X(qreg[i]) - - Mcurrent = 2**(L[0]) - theta = -2*np.arccos(np.sqrt(Mcurrent/self.M)) - - if L[0]>0: #if M is even - for i in range(L[0]): - yield cirq.H(qreg[i]) - - yield cirq.ry(theta).on(qreg[L[1]]) - - for i in range(L[0], L[1]): - yield cirq.H(qreg[i]).controlled_by(qreg[L[1]], control_values=[False]) - - for m in range(1,len(L)-1): - theta = -2*np.arccos(np.sqrt(2**L[m]/ (self.M-Mcurrent))) - yield cirq.ControlledGate(cirq.ry(theta), control_values=[False])(qreg[L[m]], qreg[L[m+1]]) - for i in range(L[m], L[m+1]): - yield cirq.ControlledGate(cirq.H, control_values=[False])(qreg[L[m+1]], qreg[i]) - - Mcurrent = Mcurrent + 2**(L[m]) - - - - def num_qubits(self) -> int: - """ - Returns the number of qubits used by the gate. - - Returns: - int: The number of qubits. - """ - return self._num_qubits - - def __repr__(self) -> str: - """ - Returns a string representation of the gate. - - Returns: - str: String representation of the gate. - """ - return f'generalized_uniform_superposition_gate(M={self.M}, num_qubits={self._num_qubits})' diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py new file mode 100644 index 00000000000..6a74dff4150 --- /dev/null +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -0,0 +1,145 @@ +# Copyright 2024 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Sequence, TYPE_CHECKING + +import math +import numpy as np +from cirq.ops.common_gates import H, ry +from cirq.ops.pauli_gates import X +from cirq.ops import controlled_gate, raw_types + + +if TYPE_CHECKING: + import cirq + + +class UniformSuperpositionGate(raw_types.Gate): + r""" + Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$ + (where 1< M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. + + Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a + generalized uniform superposition state of the form, + $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(\log_2 (M))$ qubits and + $O(\log_2 (M))$ gates. This provides an exponential improvement (in the context of reduced + resources and complexity) over other approaches in the literature. + + Args: + m_value (int): + A positive integer M = m_value (> 1) representing the number of computational basis + states with an amplitude of 1/sqrt(M) in the uniform superposition state + ($\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $). Note that the remaining (2^n - M) + computational basis states have zero amplitudes. Here M need not be an integer + power of 2. + + num_qubits (int): + A positive integer representing the number of qubits used. + + Returns: + cirq.Circuit: A quantum circuit that creates the uniform superposition state: + $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $. + + References: + [SV24] + A. Shukla and P. Vedula, "An efficient quantum algorithm for preparation of uniform + quantum superposition states," Quantum Information Processing, 23(38): pp. 1-32 (2024). + """ + + def __init__(self, m_value: int, num_qubits: int) -> None: + """ + Initializes UniformSuperpositionGate. + + Args: + m_value (int): The number of computational basis states with amplitude 1/sqrt(M). + num_qubits (int): The number of qubits used. + """ + if not (isinstance(m_value, int) and (m_value > 1)): + raise ValueError('m_value must be a positive integer greater than 1.') + if not (isinstance(num_qubits, int) and (num_qubits >= math.log2(m_value))): + raise ValueError( + 'num_qubits must be an integer greater than or equal to log2(m_value).' + ) + self._m_value = m_value + self._num_qubits = num_qubits + # super(UniformSuperpositionGate, self).__init__() + + def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': + """ + Decomposes the gate into a sequence of standard gates. + + Args: + qubits (list[cirq.Qid]): Qubits to apply the gate on. + + Yields: + cirq.Operation: Operations implementing the gate. + """ + qreg = list(qubits) + + if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2 + m = int(math.log2(self._m_value)) + for i in range(m): + yield H(qreg[i]) + return + + n_value = [int(x) for x in list(np.binary_repr(self._m_value))][::-1] + k = len(n_value) + l_value = [index for (index, item) in enumerate(n_value) if item == 1] # Locations of '1's + + qreg.reverse() + + for i in l_value[1:k]: + yield X(qreg[i]) + + m_current = 2 ** (l_value[0]) + theta = -2 * np.arccos(np.sqrt(m_current / self._m_value)) + + if l_value[0] > 0: # if m_value is even + for i in range(l_value[0]): + yield H(qreg[i]) + + yield ry(theta).on(qreg[l_value[1]]) + + for i in range(l_value[0], l_value[1]): + yield H(qreg[i]).controlled_by(qreg[l_value[1]], control_values=[False]) + + for m in range(1, len(l_value) - 1): + theta = -2 * np.arccos(np.sqrt(2 ** l_value[m] / (self._m_value - m_current))) + yield controlled_gate.ControlledGate(ry(theta), control_values=[False])( + qreg[l_value[m]], qreg[l_value[m + 1]] + ) + for i in range(l_value[m], l_value[m + 1]): + yield controlled_gate.ControlledGate(H, control_values=[False])( + qreg[l_value[m + 1]], qreg[i] + ) + + m_current = m_current + 2 ** (l_value[m]) + + def num_qubits(self) -> int: + """ + Returns the number of qubits used by the gate. + + Returns: + int: The number of qubits. + """ + return self._num_qubits + + def __repr__(self) -> str: + """ + Returns a string representation of the gate. + + Returns: + str: String representation of the gate. + """ + return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})' From 8708d0444160d4bd8e5c01d54d5769335ece69b3 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Fri, 10 May 2024 11:27:32 +0530 Subject: [PATCH 21/61] Update and rename generalized_uniform_superposition_gate_test.py to uniform_superposition_gate_test.py Made changes to fix the unit test error --- ...ralized_uniform_superposition_gate_test.py | 46 ------------------ .../ops/uniform_superposition_gate_test.py | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 46 deletions(-) delete mode 100644 cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py create mode 100644 cirq-core/cirq/ops/uniform_superposition_gate_test.py diff --git a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py b/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py deleted file mode 100644 index 3231496b0f2..00000000000 --- a/cirq-core/cirq/ops/generalized_uniform_superposition_gate_test.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2024 The Cirq Developers -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import cirq -import numpy as np - -def _assert_generated_unitary_is_uniform(M :int, n :int) -> None: - """ - The code checks that the unitary matrix corresponds to the generated uniform superposition states (see generalized_uniform_superposition_gate.py). - It is enough to check that the first colum of the unitary matrix (which corresponds to the action of - the gate on $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$ entries - are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. - """ - gate = cirq.generalized_uniform_superposition_gate(M, n) - qregx = cirq.LineQubit.range(n) - qcircuit = cirq.Circuit(gate.on(*qregx)) - - unitary_matrix1 = np.real(qcircuit.unitary()) - - np.testing.assert_allclose( - unitary_matrix1[:,0], - (1/np.sqrt(M))*np.array([1]*M + [0]*(2**n - M)), - atol=1e-8, - ) - - -def _test1_check_uniform(): - """The code tests the creation of M uniform superposition states, where M ranges from 3 to 1024.""" - M=1025 - for mm in range(3, M): - if (mm & (mm-1)) == 0: #if mm is an integer power of 2 - n = int(np.log2(mm)) - else: #if mm is not an integer power of 2 - n = int(np.ceil(np.log2(mm))) - _assert_generated_unitary_is_uniform(mm, n) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py new file mode 100644 index 00000000000..60afcf00647 --- /dev/null +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -0,0 +1,47 @@ +# Copyright 2024 The Cirq Developers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import numpy as np +import cirq + + +def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: + r""" + The code checks that the unitary matrix corresponds to the generated uniform superposition + states (see uniform_superposition_gate.py). It is enough to check that the + first colum of the unitary matrix (which corresponds to the action of the gate on + $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$ + entries are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the + remaining $2^n-M$ entries are all "0"s. + """ + gate = cirq.UniformSuperpositionGate(m_value, n) + #gate = UniformSuperpositionGate(m_value, n) + qregx = cirq.LineQubit.range(n) + qcircuit = cirq.Circuit(gate.on(*qregx)) + + unitary_matrix1 = np.real(qcircuit.unitary()) + + np.testing.assert_allclose( + unitary_matrix1[:, 0], + (1 / np.sqrt(m_value)) * np.array([1] * m_value + [1] * (2**n - m_value)), + atol=1e-8, + ) + +def test_uniform_superposition_gate(): + r"""The code tests the creation of M uniform superposition states, + where M ranges from 3 to 1024.""" + m_value = 127 + for mm in range(3, m_value): + n = int(np.ceil(np.log2(mm))) + _assert_generated_unitary_is_uniform(mm, n) From 06b35ab0f95861746d169ef9f34fc6efaa03e7c4 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Fri, 10 May 2024 11:29:39 +0530 Subject: [PATCH 22/61] Update __init__.py Added UniformSuperpositionGate --- cirq-core/cirq/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-core/cirq/__init__.py b/cirq-core/cirq/__init__.py index 2dc2034600a..4ed88abb575 100644 --- a/cirq-core/cirq/__init__.py +++ b/cirq-core/cirq/__init__.py @@ -332,6 +332,7 @@ ZPowGate, ZZ, ZZPowGate, + UniformSuperpositionGate, ) from cirq.transformers import ( From e3a1ff6019425a2b4d3ce23c6277dce7b705c926 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Fri, 10 May 2024 11:32:06 +0530 Subject: [PATCH 23/61] Update __init__.py Added import to UniformSuperpositionGate --- cirq-core/cirq/ops/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cirq-core/cirq/ops/__init__.py b/cirq-core/cirq/ops/__init__.py index 5cadb6ad9af..25db2fc710a 100644 --- a/cirq-core/cirq/ops/__init__.py +++ b/cirq-core/cirq/ops/__init__.py @@ -217,3 +217,5 @@ from cirq.ops.state_preparation_channel import StatePreparationChannel from cirq.ops.control_values import AbstractControlValues, ProductOfSums, SumOfProducts + +from cirq.ops.uniform_superposition_gate import UniformSuperpositionGate From f63207c467ba03fa12558f595f2962cdb8b23bd6 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 11 May 2024 00:13:44 +0530 Subject: [PATCH 24/61] Update uniform_superposition_gate.py The code was improved according to the review feedback provided by NoureldinYosri. --- .../cirq/ops/uniform_superposition_gate.py | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index 6a74dff4150..151df6fcd09 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -88,26 +88,25 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': qreg = list(qubits) if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2 - m = int(math.log2(self._m_value)) - for i in range(m): - yield H(qreg[i]) + m = self._m_value.bit_length() - 1 + yield H.on_each(qreg[:m]) return - - n_value = [int(x) for x in list(np.binary_repr(self._m_value))][::-1] - k = len(n_value) - l_value = [index for (index, item) in enumerate(n_value) if item == 1] # Locations of '1's + + k = self._m_value.bit_length() + l_value = [] + for i in range(self._m_value.bit_length()): + if (self._m_value >> i) & 1: + l_value.append(i) # Locations of '1's qreg.reverse() - for i in l_value[1:k]: - yield X(qreg[i]) - + yield X.on_each(qreg[q_bit] for q_bit in l_value[1:k]) + m_current = 2 ** (l_value[0]) theta = -2 * np.arccos(np.sqrt(m_current / self._m_value)) if l_value[0] > 0: # if m_value is even - for i in range(l_value[0]): - yield H(qreg[i]) + yield H.on_each(qreg[:l_value[0]]) yield ry(theta).on(qreg[l_value[1]]) From 1386270c2711695a90444632c1b34d7c279f268b Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 11 May 2024 00:17:14 +0530 Subject: [PATCH 25/61] Update uniform_superposition_gate_test.py Added parametrized test using pytest for test_uniform_superposition_gate(m_value) --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 60afcf00647..defdad75aad 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -13,6 +13,7 @@ # limitations under the License. import numpy as np +import pytest import cirq @@ -26,7 +27,6 @@ def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: remaining $2^n-M$ entries are all "0"s. """ gate = cirq.UniformSuperpositionGate(m_value, n) - #gate = UniformSuperpositionGate(m_value, n) qregx = cirq.LineQubit.range(n) qcircuit = cirq.Circuit(gate.on(*qregx)) @@ -34,14 +34,14 @@ def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: np.testing.assert_allclose( unitary_matrix1[:, 0], - (1 / np.sqrt(m_value)) * np.array([1] * m_value + [1] * (2**n - m_value)), + (1 / np.sqrt(m_value)) * np.array([1] * m_value + [0] * (2**n - m_value)), atol=1e-8, ) -def test_uniform_superposition_gate(): +@pytest.mark.parametrize('m_value', [127]) +def test_uniform_superposition_gate(m_value): r"""The code tests the creation of M uniform superposition states, - where M ranges from 3 to 1024.""" - m_value = 127 + where M ranges from 3 to m_value.""" for mm in range(3, m_value): n = int(np.ceil(np.log2(mm))) _assert_generated_unitary_is_uniform(mm, n) From b3d1f346d8bd8085b4bb4edc2c79bb57d4f35adf Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 11 May 2024 00:34:39 +0530 Subject: [PATCH 26/61] Update uniform_superposition_gate_test.py further improved the parametrized test. --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index defdad75aad..d05685181ac 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -38,10 +38,10 @@ def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: atol=1e-8, ) -@pytest.mark.parametrize('m_value', [127]) -def test_uniform_superposition_gate(m_value): +@pytest.mark.parametrize('low_value, max_value', [(3,127)]) +def test_uniform_superposition_gate(low_value,max_value): r"""The code tests the creation of M uniform superposition states, - where M ranges from 3 to m_value.""" - for mm in range(3, m_value): + where M ranges from low_value to max_value.""" + for mm in range(low_value, max_value): n = int(np.ceil(np.log2(mm))) _assert_generated_unitary_is_uniform(mm, n) From 599c94eba04e4b5d03fad5127e45a9e666cc0ef9 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 11 May 2024 03:15:42 +0530 Subject: [PATCH 27/61] Update uniform_superposition_gate_test.py Added several test cases for @pytest.mark.parametrize --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index d05685181ac..10ccd48133f 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -38,7 +38,7 @@ def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: atol=1e-8, ) -@pytest.mark.parametrize('low_value, max_value', [(3,127)]) +@pytest.mark.parametrize('low_value, max_value', [(3,17),(17,29),(30,89),(89,127),(128,257)]) def test_uniform_superposition_gate(low_value,max_value): r"""The code tests the creation of M uniform superposition states, where M ranges from low_value to max_value.""" From a4e80a5023387a36084f42331b18a1f6fd7ca17d Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 11 May 2024 06:06:29 +0530 Subject: [PATCH 28/61] Update uniform_superposition_gate.py Removed __repr__(self) as suggested. --- .../cirq/ops/uniform_superposition_gate.py | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index 151df6fcd09..643235dc5b2 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -73,8 +73,6 @@ def __init__(self, m_value: int, num_qubits: int) -> None: ) self._m_value = m_value self._num_qubits = num_qubits - # super(UniformSuperpositionGate, self).__init__() - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': """ Decomposes the gate into a sequence of standard gates. @@ -86,25 +84,22 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': cirq.Operation: Operations implementing the gate. """ qreg = list(qubits) + qreg.reverse() if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2 m = self._m_value.bit_length() - 1 yield H.on_each(qreg[:m]) return - k = self._m_value.bit_length() l_value = [] for i in range(self._m_value.bit_length()): if (self._m_value >> i) & 1: l_value.append(i) # Locations of '1's - qreg.reverse() yield X.on_each(qreg[q_bit] for q_bit in l_value[1:k]) - m_current = 2 ** (l_value[0]) theta = -2 * np.arccos(np.sqrt(m_current / self._m_value)) - if l_value[0] > 0: # if m_value is even yield H.on_each(qreg[:l_value[0]]) @@ -126,19 +121,4 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': m_current = m_current + 2 ** (l_value[m]) def num_qubits(self) -> int: - """ - Returns the number of qubits used by the gate. - - Returns: - int: The number of qubits. - """ return self._num_qubits - - def __repr__(self) -> str: - """ - Returns a string representation of the gate. - - Returns: - str: String representation of the gate. - """ - return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})' From 72b109b5c36c1dd29a3f7b615e4f63c3759459f6 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 11 May 2024 06:09:17 +0530 Subject: [PATCH 29/61] Update uniform_superposition_gate_test.py test_uniform_superposition_gate() removed. Correct parameterization is done as per the review comments. --- .../cirq/ops/uniform_superposition_gate_test.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 10ccd48133f..cbb980a8902 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -16,8 +16,9 @@ import pytest import cirq - -def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: +@pytest.mark.parameterize(['m', 'n'],[[m, n] for n in range(3, 7) + for m in np.random.randint(1, 1 << n, size=3)]) +def test_generated_unitary_is_uniform(m: int, n: int) -> None: r""" The code checks that the unitary matrix corresponds to the generated uniform superposition states (see uniform_superposition_gate.py). It is enough to check that the @@ -26,7 +27,7 @@ def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: entries are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. """ - gate = cirq.UniformSuperpositionGate(m_value, n) + gate = cirq.UniformSuperpositionGate(int(m), int(n)) qregx = cirq.LineQubit.range(n) qcircuit = cirq.Circuit(gate.on(*qregx)) @@ -34,14 +35,6 @@ def _assert_generated_unitary_is_uniform(m_value: int, n: int) -> None: np.testing.assert_allclose( unitary_matrix1[:, 0], - (1 / np.sqrt(m_value)) * np.array([1] * m_value + [0] * (2**n - m_value)), + (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8, ) - -@pytest.mark.parametrize('low_value, max_value', [(3,17),(17,29),(30,89),(89,127),(128,257)]) -def test_uniform_superposition_gate(low_value,max_value): - r"""The code tests the creation of M uniform superposition states, - where M ranges from low_value to max_value.""" - for mm in range(low_value, max_value): - n = int(np.ceil(np.log2(mm))) - _assert_generated_unitary_is_uniform(mm, n) From c113212a7778076055a550036a2f1d9de8936747 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 11 May 2024 06:33:48 +0530 Subject: [PATCH 30/61] Update uniform_superposition_gate_test.py A minor change - to make sure that m > 1. --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index cbb980a8902..55e91ed38cc 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -17,7 +17,7 @@ import cirq @pytest.mark.parameterize(['m', 'n'],[[m, n] for n in range(3, 7) - for m in np.random.randint(1, 1 << n, size=3)]) + for m in np.random.randint(2, 1 << n, size=3)]) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r""" The code checks that the unitary matrix corresponds to the generated uniform superposition From c2765a9f1944d71f0719651c4da0ef3c56edf0a0 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 14 May 2024 00:52:51 +0530 Subject: [PATCH 31/61] Update uniform_superposition_gate_test.py The typo in "@pytest.mark.parameterize" was fixed. A test case for m=1 was added as suggested. --- .../ops/uniform_superposition_gate_test.py | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 55e91ed38cc..f7022feaec9 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -16,25 +16,29 @@ import pytest import cirq -@pytest.mark.parameterize(['m', 'n'],[[m, n] for n in range(3, 7) - for m in np.random.randint(2, 1 << n, size=3)]) + +@pytest.mark.parametrize( + ['m', 'n'], [[m, n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] +) def test_generated_unitary_is_uniform(m: int, n: int) -> None: - r""" - The code checks that the unitary matrix corresponds to the generated uniform superposition + r"""The code checks that the unitary matrix corresponds to the generated uniform superposition states (see uniform_superposition_gate.py). It is enough to check that the first colum of the unitary matrix (which corresponds to the action of the gate on $\ket{0}^n$ is $\frac{1}{\sqrt{M}} [1 1 \cdots 1 0 \cdots 0]^T$, where the first $M$ entries are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. """ - gate = cirq.UniformSuperpositionGate(int(m), int(n)) - qregx = cirq.LineQubit.range(n) - qcircuit = cirq.Circuit(gate.on(*qregx)) - unitary_matrix1 = np.real(qcircuit.unitary()) + if m == 1: + with pytest.raises(ValueError, match='m_value must be a positive integer greater than 1.'): + gate = cirq.UniformSuperpositionGate(int(m), int(n)) + else: + gate = cirq.UniformSuperpositionGate(int(m), int(n)) + qregx = cirq.LineQubit.range(n) + qcircuit = cirq.Circuit(gate.on(*qregx)) + + unitary_matrix1 = np.real(qcircuit.unitary()) - np.testing.assert_allclose( - unitary_matrix1[:, 0], - (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), - atol=1e-8, - ) + np.testing.assert_allclose( + unitary_matrix1[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8 + ) From cfc456175b9383d090f0a1d600ef54f4a9641dd3 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 14 May 2024 00:53:20 +0530 Subject: [PATCH 32/61] Update uniform_superposition_gate.py The unit test and Lint errors were fixed. --- cirq-core/cirq/ops/uniform_superposition_gate.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index 643235dc5b2..3f5997399cd 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -64,6 +64,10 @@ def __init__(self, m_value: int, num_qubits: int) -> None: Args: m_value (int): The number of computational basis states with amplitude 1/sqrt(M). num_qubits (int): The number of qubits used. + + Raises: + ValueError: If `m_value` is not a positive integer greater than 1, or + if `num_qubits` is not an integer greater than or equal to log2(m_value). """ if not (isinstance(m_value, int) and (m_value > 1)): raise ValueError('m_value must be a positive integer greater than 1.') @@ -73,6 +77,7 @@ def __init__(self, m_value: int, num_qubits: int) -> None: ) self._m_value = m_value self._num_qubits = num_qubits + def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': """ Decomposes the gate into a sequence of standard gates. @@ -94,14 +99,13 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': l_value = [] for i in range(self._m_value.bit_length()): if (self._m_value >> i) & 1: - l_value.append(i) # Locations of '1's - + l_value.append(i) # Locations of '1's yield X.on_each(qreg[q_bit] for q_bit in l_value[1:k]) m_current = 2 ** (l_value[0]) theta = -2 * np.arccos(np.sqrt(m_current / self._m_value)) if l_value[0] > 0: # if m_value is even - yield H.on_each(qreg[:l_value[0]]) + yield H.on_each(qreg[: l_value[0]]) yield ry(theta).on(qreg[l_value[1]]) @@ -120,5 +124,8 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': m_current = m_current + 2 ** (l_value[m]) + def __repr__(self) -> str: + return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})' + def num_qubits(self) -> int: return self._num_qubits From 318f76a160b6224f5e9356346c5299f6b270c21c Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 14 May 2024 13:09:11 +0530 Subject: [PATCH 33/61] Update uniform_superposition_gate.py Included m=1 case, as suggested. --- .../cirq/ops/uniform_superposition_gate.py | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index 3f5997399cd..377f6ac0082 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -26,9 +26,8 @@ class UniformSuperpositionGate(raw_types.Gate): - r""" - Creates a generalized uniform superposition state, $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$ - (where 1< M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. + r"""Creates a uniform superposition state, $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$ + (where 1<= M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a generalized uniform superposition state of the form, @@ -38,7 +37,7 @@ class UniformSuperpositionGate(raw_types.Gate): Args: m_value (int): - A positive integer M = m_value (> 1) representing the number of computational basis + A positive integer M = m_value representing the number of computational basis states with an amplitude of 1/sqrt(M) in the uniform superposition state ($\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $). Note that the remaining (2^n - M) computational basis states have zero amplitudes. Here M need not be an integer @@ -58,19 +57,18 @@ class UniformSuperpositionGate(raw_types.Gate): """ def __init__(self, m_value: int, num_qubits: int) -> None: - """ - Initializes UniformSuperpositionGate. + """Initializes UniformSuperpositionGate. Args: m_value (int): The number of computational basis states with amplitude 1/sqrt(M). num_qubits (int): The number of qubits used. Raises: - ValueError: If `m_value` is not a positive integer greater than 1, or + ValueError: If `m_value` is not a positive integer, or if `num_qubits` is not an integer greater than or equal to log2(m_value). """ - if not (isinstance(m_value, int) and (m_value > 1)): - raise ValueError('m_value must be a positive integer greater than 1.') + if not (isinstance(m_value, int) and (m_value > 0)): + raise ValueError('m_value must be a positive integer.') if not (isinstance(num_qubits, int) and (num_qubits >= math.log2(m_value))): raise ValueError( 'num_qubits must be an integer greater than or equal to log2(m_value).' @@ -79,8 +77,7 @@ def __init__(self, m_value: int, num_qubits: int) -> None: self._num_qubits = num_qubits def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': - """ - Decomposes the gate into a sequence of standard gates. + """Decomposes the gate into a sequence of standard gates. Args: qubits (list[cirq.Qid]): Qubits to apply the gate on. @@ -91,6 +88,8 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': qreg = list(qubits) qreg.reverse() + if self._m_value == 1: # if m_value is 1, do nothing + return if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2 m = self._m_value.bit_length() - 1 yield H.on_each(qreg[:m]) From 6dc054dfd4f9cdabede667f3c9b1aa3c24372aa3 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 14 May 2024 13:17:56 +0530 Subject: [PATCH 34/61] Update uniform_superposition_gate_test.py Added more test cases. --- .../ops/uniform_superposition_gate_test.py | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index f7022feaec9..0c1616ae648 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -18,7 +18,9 @@ @pytest.mark.parametrize( - ['m', 'n'], [[m, n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] + ['m', 'n'], + [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] + + [(1, 1), (-2, 1), (-3.1, 2), (6, -4)], ) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r"""The code checks that the unitary matrix corresponds to the generated uniform superposition @@ -29,16 +31,32 @@ def test_generated_unitary_is_uniform(m: int, n: int) -> None: remaining $2^n-M$ entries are all "0"s. """ - if m == 1: - with pytest.raises(ValueError, match='m_value must be a positive integer greater than 1.'): + if not (isinstance(m, int)): + with pytest.raises(ValueError, match='m_value must be a positive integer.'): + gate = cirq.UniformSuperpositionGate(m, n) + elif not (isinstance(n, int)): + with pytest.raises( + ValueError, + match='num_qubits must be an integer greater than or equal to log2\\(m_value\\).', + ): + gate = cirq.UniformSuperpositionGate(m, n) + elif m < 1: + with pytest.raises(ValueError, match='m_value must be a positive integer.'): gate = cirq.UniformSuperpositionGate(int(m), int(n)) + elif n < np.log2(m): + with pytest.raises( + ValueError, + match='num_qubits must be an integer greater than or equal to log2\\(m_value\\).', + ): + gate = cirq.UniformSuperpositionGate(m, n) else: - gate = cirq.UniformSuperpositionGate(int(m), int(n)) + gate = cirq.UniformSuperpositionGate(m, n) qregx = cirq.LineQubit.range(n) qcircuit = cirq.Circuit(gate.on(*qregx)) unitary_matrix1 = np.real(qcircuit.unitary()) - - np.testing.assert_allclose( - unitary_matrix1[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8 + np.testing.assert_allclose( + unitary_matrix1[:, 0], + (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), + atol=1e-8, ) From 4244373cad01816a74611ee95d2bfeb18c38c6a2 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 14 May 2024 16:27:21 +0530 Subject: [PATCH 35/61] Update json_resolver_cache.py Added UniformSuperpositionGate --- cirq-core/cirq/json_resolver_cache.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-core/cirq/json_resolver_cache.py b/cirq-core/cirq/json_resolver_cache.py index 4880046618a..65dea9c7587 100644 --- a/cirq-core/cirq/json_resolver_cache.py +++ b/cirq-core/cirq/json_resolver_cache.py @@ -247,6 +247,7 @@ def _symmetricalqidpair(qids): 'ZipLongest': cirq.ZipLongest, 'ZPowGate': cirq.ZPowGate, 'ZZPowGate': cirq.ZZPowGate, + 'UniformSuperpositionGate': cirq.UniformSuperpositionGate, # Old types, only supported for backwards-compatibility 'BooleanHamiltonian': _boolean_hamiltonian_gate_op, # Removed in v0.15 'CrossEntropyResult': _cross_entropy_result, # Removed in v0.16 From 9472a77ed0c6dfd43bda9ed25589f3865bbb791d Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 04:11:52 +0530 Subject: [PATCH 36/61] Update uniform_superposition_gate_test.py Added one more test case. --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 0c1616ae648..31c128e2989 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -20,7 +20,7 @@ @pytest.mark.parametrize( ['m', 'n'], [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] - + [(1, 1), (-2, 1), (-3.1, 2), (6, -4)], + + [(1, 1), (-2, 1), (-3.1, 2), (6, -4), (5, 6.1)], ) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r"""The code checks that the unitary matrix corresponds to the generated uniform superposition From 763885258cc466d969d7a47c060bba5939fdf5f0 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 04:13:02 +0530 Subject: [PATCH 37/61] Update uniform_superposition_gate.py Removed repr --- cirq-core/cirq/ops/uniform_superposition_gate.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index 377f6ac0082..8f1988396e0 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -123,8 +123,5 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': m_current = m_current + 2 ** (l_value[m]) - def __repr__(self) -> str: - return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})' - def num_qubits(self) -> int: return self._num_qubits From a71fe41e608508a80166f573712aa39923ebecb5 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 04:13:59 +0530 Subject: [PATCH 38/61] Update json_resolver_cache.py --- cirq-core/cirq/json_resolver_cache.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cirq-core/cirq/json_resolver_cache.py b/cirq-core/cirq/json_resolver_cache.py index 65dea9c7587..4880046618a 100644 --- a/cirq-core/cirq/json_resolver_cache.py +++ b/cirq-core/cirq/json_resolver_cache.py @@ -247,7 +247,6 @@ def _symmetricalqidpair(qids): 'ZipLongest': cirq.ZipLongest, 'ZPowGate': cirq.ZPowGate, 'ZZPowGate': cirq.ZZPowGate, - 'UniformSuperpositionGate': cirq.UniformSuperpositionGate, # Old types, only supported for backwards-compatibility 'BooleanHamiltonian': _boolean_hamiltonian_gate_op, # Removed in v0.15 'CrossEntropyResult': _cross_entropy_result, # Removed in v0.16 From 519f46db38fed76851650ad0c2f6b8b86012c946 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 04:15:00 +0530 Subject: [PATCH 39/61] Update spec.py UniformSuperpositionGate is not yet serializable --- cirq-core/cirq/protocols/json_test_data/spec.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-core/cirq/protocols/json_test_data/spec.py b/cirq-core/cirq/protocols/json_test_data/spec.py index 22ae86051e0..cfbf41b9105 100644 --- a/cirq-core/cirq/protocols/json_test_data/spec.py +++ b/cirq-core/cirq/protocols/json_test_data/spec.py @@ -57,6 +57,7 @@ 'TwoQubitGateTabulationResult', 'StateVectorTrialResult', 'ZerosSampler', + 'UniformSuperpositionGate', ], should_not_be_serialized=[ 'ClassicalStateSimulator', From fab4973d5c5887cc7560171eeeb5351ccb1622d2 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 09:30:08 +0530 Subject: [PATCH 40/61] Update uniform_superposition_gate.py Suggested changes were made. --- cirq-core/cirq/ops/uniform_superposition_gate.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index 8f1988396e0..a2ba40ca40c 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -18,7 +18,7 @@ import numpy as np from cirq.ops.common_gates import H, ry from cirq.ops.pauli_gates import X -from cirq.ops import controlled_gate, raw_types +from cirq.ops import raw_types if TYPE_CHECKING: @@ -113,13 +113,11 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': for m in range(1, len(l_value) - 1): theta = -2 * np.arccos(np.sqrt(2 ** l_value[m] / (self._m_value - m_current))) - yield controlled_gate.ControlledGate(ry(theta), control_values=[False])( - qreg[l_value[m]], qreg[l_value[m + 1]] + yield ry(theta).on(qreg[l_value[m + 1]]).controlled_by( + qreg[l_value[m]], control_values=[0] ) for i in range(l_value[m], l_value[m + 1]): - yield controlled_gate.ControlledGate(H, control_values=[False])( - qreg[l_value[m + 1]], qreg[i] - ) + yield H.on(qreg[i]).controlled_by(qreg[l_value[m + 1]], control_values=[0]) m_current = m_current + 2 ** (l_value[m]) From d1ec56af4fc3108ede683d40cb9077b1d8bbc477 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 09:30:35 +0530 Subject: [PATCH 41/61] Update uniform_superposition_gate_test.py Suggested changes were made --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 31c128e2989..4ad06fb633b 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -51,12 +51,9 @@ def test_generated_unitary_is_uniform(m: int, n: int) -> None: gate = cirq.UniformSuperpositionGate(m, n) else: gate = cirq.UniformSuperpositionGate(m, n) - qregx = cirq.LineQubit.range(n) - qcircuit = cirq.Circuit(gate.on(*qregx)) - - unitary_matrix1 = np.real(qcircuit.unitary()) + matrix = np.real(cirq.unitary(gate)) np.testing.assert_allclose( - unitary_matrix1[:, 0], + matrix[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8, ) From 9bceb57cdfec4393bf462dfd5baa9fb1cfd7c402 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 23:05:13 +0530 Subject: [PATCH 42/61] Update gate_operation_test.py Included UniformSuperpositionGate in skip_classes to fix the json error. --- cirq-core/cirq/ops/gate_operation_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-core/cirq/ops/gate_operation_test.py b/cirq-core/cirq/ops/gate_operation_test.py index 46cf3cae1a5..b203f0b91ec 100644 --- a/cirq-core/cirq/ops/gate_operation_test.py +++ b/cirq-core/cirq/ops/gate_operation_test.py @@ -509,6 +509,7 @@ def all_subclasses(cls): cirq.ops.raw_types._InverseCompositeGate, cirq.circuits.qasm_output.QasmTwoQubitGate, cirq.ops.MSGate, + cirq.ops.UniformSuperpositionGate, # Interop gates cirq.interop.quirk.QuirkQubitPermutationGate, cirq.interop.quirk.QuirkArithmeticGate, From ff7f8842e7badfa69beb71040bd9ba0371972ff2 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 23:06:15 +0530 Subject: [PATCH 43/61] Update uniform_superposition_gate_test.py --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 4ad06fb633b..b5793a36c7b 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -53,7 +53,5 @@ def test_generated_unitary_is_uniform(m: int, n: int) -> None: gate = cirq.UniformSuperpositionGate(m, n) matrix = np.real(cirq.unitary(gate)) np.testing.assert_allclose( - matrix[:, 0], - (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), - atol=1e-8, + matrix[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8 ) From a34dca8605d0defdc85e73b3b7ee233c83ab0a92 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Wed, 15 May 2024 23:49:22 +0530 Subject: [PATCH 44/61] Update uniform_superposition_gate.py Changed according to review comments by @NoureldinYosri --- .../cirq/ops/uniform_superposition_gate.py | 42 +++++-------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index a2ba40ca40c..ad8cc5f4b6c 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -26,42 +26,23 @@ class UniformSuperpositionGate(raw_types.Gate): - r"""Creates a uniform superposition state, $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$ + r"""Creates a uniform superposition state on the states $[0, M)$ + + The gate creates the state $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$ (where 1<= M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. - Note: The Shukla-Vedula algorithm [SV24] offers an efficient approach for creation of a - generalized uniform superposition state of the form, - $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $, requiring only $O(\log_2 (M))$ qubits and - $O(\log_2 (M))$ gates. This provides an exponential improvement (in the context of reduced - resources and complexity) over other approaches in the literature. - - Args: - m_value (int): - A positive integer M = m_value representing the number of computational basis - states with an amplitude of 1/sqrt(M) in the uniform superposition state - ($\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $). Note that the remaining (2^n - M) - computational basis states have zero amplitudes. Here M need not be an integer - power of 2. - - num_qubits (int): - A positive integer representing the number of qubits used. - - Returns: - cirq.Circuit: A quantum circuit that creates the uniform superposition state: - $\frac{1}{\sqrt{M}} \sum_{j=0}^{M-1} \ket{j} $. - References: [SV24] - A. Shukla and P. Vedula, "An efficient quantum algorithm for preparation of uniform - quantum superposition states," Quantum Information Processing, 23(38): pp. 1-32 (2024). + [An efficient quantum algorithm for preparation of uniform quantum superposition states +](https://arxiv.org/abs/2306.11747) """ def __init__(self, m_value: int, num_qubits: int) -> None: """Initializes UniformSuperpositionGate. Args: - m_value (int): The number of computational basis states with amplitude 1/sqrt(M). - num_qubits (int): The number of qubits used. + m_value: The number of computational basis states. + num_qubits: The number of qubits used. Raises: ValueError: If `m_value` is not a positive integer, or @@ -69,7 +50,7 @@ def __init__(self, m_value: int, num_qubits: int) -> None: """ if not (isinstance(m_value, int) and (m_value > 0)): raise ValueError('m_value must be a positive integer.') - if not (isinstance(num_qubits, int) and (num_qubits >= math.log2(m_value))): + if not (isinstance(num_qubits, int) and (num_qubits >= m_value.bit_length())): raise ValueError( 'num_qubits must be an integer greater than or equal to log2(m_value).' ) @@ -79,11 +60,8 @@ def __init__(self, m_value: int, num_qubits: int) -> None: def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': """Decomposes the gate into a sequence of standard gates. - Args: - qubits (list[cirq.Qid]): Qubits to apply the gate on. - - Yields: - cirq.Operation: Operations implementing the gate. + Implements the construction from https://arxiv.org/pdf/2306.11747. + """ qreg = list(qubits) qreg.reverse() From 7036c1b710f84ae37d833c35af89c289e3f796c6 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Thu, 16 May 2024 01:14:20 +0530 Subject: [PATCH 45/61] Update uniform_superposition_gate.py Removed import to math --- .../cirq/ops/uniform_superposition_gate.py | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index ad8cc5f4b6c..ebb2fbadbe4 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -14,7 +14,6 @@ from typing import Sequence, TYPE_CHECKING -import math import numpy as np from cirq.ops.common_gates import H, ry from cirq.ops.pauli_gates import X @@ -26,15 +25,13 @@ class UniformSuperpositionGate(raw_types.Gate): - r"""Creates a uniform superposition state on the states $[0, M)$ - + r"""Creates a uniform superposition state on the states $[0, M)$ The gate creates the state $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$ (where 1<= M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. - References: [SV24] - [An efficient quantum algorithm for preparation of uniform quantum superposition states -](https://arxiv.org/abs/2306.11747) + [An efficient quantum algorithm for preparation of uniform quantum superposition + states](https://arxiv.org/abs/2306.11747) """ def __init__(self, m_value: int, num_qubits: int) -> None: @@ -49,26 +46,26 @@ def __init__(self, m_value: int, num_qubits: int) -> None: if `num_qubits` is not an integer greater than or equal to log2(m_value). """ if not (isinstance(m_value, int) and (m_value > 0)): - raise ValueError('m_value must be a positive integer.') + raise ValueError("m_value must be a positive integer.") if not (isinstance(num_qubits, int) and (num_qubits >= m_value.bit_length())): raise ValueError( - 'num_qubits must be an integer greater than or equal to log2(m_value).' + "num_qubits must be an integer greater than or equal to log2(m_value)." ) self._m_value = m_value self._num_qubits = num_qubits - def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': + def _decompose_(self, qubits: Sequence["cirq.Qid"]) -> "cirq.OP_TREE": """Decomposes the gate into a sequence of standard gates. - Implements the construction from https://arxiv.org/pdf/2306.11747. - """ qreg = list(qubits) qreg.reverse() if self._m_value == 1: # if m_value is 1, do nothing return - if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2 + if ( + self._m_value & (self._m_value - 1) + ) == 0: # if m_value is an integer power of 2 m = self._m_value.bit_length() - 1 yield H.on_each(qreg[:m]) return @@ -90,12 +87,16 @@ def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': yield H(qreg[i]).controlled_by(qreg[l_value[1]], control_values=[False]) for m in range(1, len(l_value) - 1): - theta = -2 * np.arccos(np.sqrt(2 ** l_value[m] / (self._m_value - m_current))) + theta = -2 * np.arccos( + np.sqrt(2 ** l_value[m] / (self._m_value - m_current)) + ) yield ry(theta).on(qreg[l_value[m + 1]]).controlled_by( qreg[l_value[m]], control_values=[0] ) for i in range(l_value[m], l_value[m + 1]): - yield H.on(qreg[i]).controlled_by(qreg[l_value[m + 1]], control_values=[0]) + yield H.on(qreg[i]).controlled_by( + qreg[l_value[m + 1]], control_values=[0] + ) m_current = m_current + 2 ** (l_value[m]) From 9e61adb850ed044eab4472236fe091afc2f192a6 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Thu, 16 May 2024 01:16:50 +0530 Subject: [PATCH 46/61] Update uniform_superposition_gate_test.py Split the test into 2 tests. one for correctness (checking the unitary) and another for argument validation --- .../ops/uniform_superposition_gate_test.py | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index b5793a36c7b..8771ebc3157 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -18,9 +18,8 @@ @pytest.mark.parametrize( - ['m', 'n'], - [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] - + [(1, 1), (-2, 1), (-3.1, 2), (6, -4), (5, 6.1)], + ["m", "n"], + [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)], ) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r"""The code checks that the unitary matrix corresponds to the generated uniform superposition @@ -30,28 +29,38 @@ def test_generated_unitary_is_uniform(m: int, n: int) -> None: entries are all "1"s (excluding the normalization factor of $\frac{1}{\sqrt{M}}$ and the remaining $2^n-M$ entries are all "0"s. """ + gate = cirq.UniformSuperpositionGate(m, n) + matrix = np.array(cirq.unitary(gate)) + np.testing.assert_allclose( + matrix[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8 + ) + + +@pytest.mark.parametrize( + ["m", "n"], + [(1, 1), (-2, 1), (-3.1, 2), (6, -4), (5, 6.1)], +) +def test_incompatible_m_value_and_qubit_args(m: int, n: int) -> None: + r"""The code checks that test errors are raised if the arguments m (number of + superposition states and n (number of qubits) are positive integers and are compatible + (i.e., n >= log2(m)). + """ if not (isinstance(m, int)): - with pytest.raises(ValueError, match='m_value must be a positive integer.'): - gate = cirq.UniformSuperpositionGate(m, n) + with pytest.raises(ValueError, match="m_value must be a positive integer."): + cirq.UniformSuperpositionGate(m, n) elif not (isinstance(n, int)): with pytest.raises( ValueError, - match='num_qubits must be an integer greater than or equal to log2\\(m_value\\).', + match="num_qubits must be an integer greater than or equal to log2\\(m_value\\).", ): - gate = cirq.UniformSuperpositionGate(m, n) + cirq.UniformSuperpositionGate(m, n) elif m < 1: - with pytest.raises(ValueError, match='m_value must be a positive integer.'): - gate = cirq.UniformSuperpositionGate(int(m), int(n)) + with pytest.raises(ValueError, match="m_value must be a positive integer."): + cirq.UniformSuperpositionGate(int(m), int(n)) elif n < np.log2(m): with pytest.raises( ValueError, - match='num_qubits must be an integer greater than or equal to log2\\(m_value\\).', + match="num_qubits must be an integer greater than or equal to log2\\(m_value\\).", ): - gate = cirq.UniformSuperpositionGate(m, n) - else: - gate = cirq.UniformSuperpositionGate(m, n) - matrix = np.real(cirq.unitary(gate)) - np.testing.assert_allclose( - matrix[:, 0], (1 / np.sqrt(m)) * np.array([1] * m + [0] * (2**n - m)), atol=1e-8 - ) + cirq.UniformSuperpositionGate(m, n) From a00e5d7fcdc7148da551926841a5120f14cd3c9b Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 18 May 2024 00:42:41 +0530 Subject: [PATCH 47/61] Update uniform_superposition_gate.py Implemented the suggested change. --- cirq-core/cirq/ops/uniform_superposition_gate.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index ebb2fbadbe4..bc44d1614b5 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -27,7 +27,7 @@ class UniformSuperpositionGate(raw_types.Gate): r"""Creates a uniform superposition state on the states $[0, M)$ The gate creates the state $\frac{1}{\sqrt{M}}\sum_{j=0}^{M-1}\ket{j}$ - (where 1<= M <= 2^n), using n qubits, according to the Shukla-Vedula algorithm [SV24]. + (where $1\leq M \leq 2^n$), using n qubits, according to the Shukla-Vedula algorithm [SV24]. References: [SV24] [An efficient quantum algorithm for preparation of uniform quantum superposition @@ -63,9 +63,7 @@ def _decompose_(self, qubits: Sequence["cirq.Qid"]) -> "cirq.OP_TREE": if self._m_value == 1: # if m_value is 1, do nothing return - if ( - self._m_value & (self._m_value - 1) - ) == 0: # if m_value is an integer power of 2 + if (self._m_value & (self._m_value - 1)) == 0: # if m_value is an integer power of 2 m = self._m_value.bit_length() - 1 yield H.on_each(qreg[:m]) return @@ -87,16 +85,12 @@ def _decompose_(self, qubits: Sequence["cirq.Qid"]) -> "cirq.OP_TREE": yield H(qreg[i]).controlled_by(qreg[l_value[1]], control_values=[False]) for m in range(1, len(l_value) - 1): - theta = -2 * np.arccos( - np.sqrt(2 ** l_value[m] / (self._m_value - m_current)) - ) + theta = -2 * np.arccos(np.sqrt(2 ** l_value[m] / (self._m_value - m_current))) yield ry(theta).on(qreg[l_value[m + 1]]).controlled_by( qreg[l_value[m]], control_values=[0] ) for i in range(l_value[m], l_value[m + 1]): - yield H.on(qreg[i]).controlled_by( - qreg[l_value[m + 1]], control_values=[0] - ) + yield H.on(qreg[i]).controlled_by(qreg[l_value[m + 1]], control_values=[0]) m_current = m_current + 2 ** (l_value[m]) From c2def1ee3fec106b1c2b3188630e34d14091ee22 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 18 May 2024 00:43:27 +0530 Subject: [PATCH 48/61] Update uniform_superposition_gate_test.py Fixed formatting. --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 8771ebc3157..3040282b146 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -18,8 +18,7 @@ @pytest.mark.parametrize( - ["m", "n"], - [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)], + ["m", "n"], [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] ) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r"""The code checks that the unitary matrix corresponds to the generated uniform superposition @@ -36,10 +35,7 @@ def test_generated_unitary_is_uniform(m: int, n: int) -> None: ) -@pytest.mark.parametrize( - ["m", "n"], - [(1, 1), (-2, 1), (-3.1, 2), (6, -4), (5, 6.1)], -) +@pytest.mark.parametrize(["m", "n"], [(1, 1), (-2, 1), (-3.1, 2), (6, -4), (5, 6.1)]) def test_incompatible_m_value_and_qubit_args(m: int, n: int) -> None: r"""The code checks that test errors are raised if the arguments m (number of superposition states and n (number of qubits) are positive integers and are compatible From ff8bcd5752220d9a9ec5fcb39526edb1acf8dc70 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 18 May 2024 04:11:33 +0530 Subject: [PATCH 49/61] Update uniform_superposition_gate.py Fixed log2(m_value) implementation error. --- cirq-core/cirq/ops/uniform_superposition_gate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index bc44d1614b5..612eb69ba4e 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -47,7 +47,10 @@ def __init__(self, m_value: int, num_qubits: int) -> None: """ if not (isinstance(m_value, int) and (m_value > 0)): raise ValueError("m_value must be a positive integer.") - if not (isinstance(num_qubits, int) and (num_qubits >= m_value.bit_length())): + log_two_m_value = m_value.bit_length() + if (m_value & (m_value -1)) == 0: + log_two_m_value = log_two_m_value - 1 + if not (isinstance(num_qubits, int) and (num_qubits >= log_two_m_value)): raise ValueError( "num_qubits must be an integer greater than or equal to log2(m_value)." ) From 607cb408aa170e931d21e50d0b67d03993b740af Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sat, 18 May 2024 04:12:24 +0530 Subject: [PATCH 50/61] Update uniform_superposition_gate_test.py Included some more test cases (in addition to random tests) to ensure coverage. --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 3040282b146..dddc2ca7436 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -18,7 +18,8 @@ @pytest.mark.parametrize( - ["m", "n"], [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] + ["m", "n"], [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] + + [(1,2), (4,2), (6,3), (7,3)] ) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r"""The code checks that the unitary matrix corresponds to the generated uniform superposition From 8279b9a1a8c2f33774da706e7ef11ff6fb5f59f8 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sun, 19 May 2024 20:55:42 +0530 Subject: [PATCH 51/61] Update spec.py Removed UnifromSuperpositionGate from not_yet_serializable --- cirq-core/cirq/protocols/json_test_data/spec.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cirq-core/cirq/protocols/json_test_data/spec.py b/cirq-core/cirq/protocols/json_test_data/spec.py index cfbf41b9105..22ae86051e0 100644 --- a/cirq-core/cirq/protocols/json_test_data/spec.py +++ b/cirq-core/cirq/protocols/json_test_data/spec.py @@ -57,7 +57,6 @@ 'TwoQubitGateTabulationResult', 'StateVectorTrialResult', 'ZerosSampler', - 'UniformSuperpositionGate', ], should_not_be_serialized=[ 'ClassicalStateSimulator', From 77c951ab3cb8886fe1c68b96566826c1694488bc Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sun, 19 May 2024 20:57:53 +0530 Subject: [PATCH 52/61] Update gate_operation_test.py Removed cirq.ops.UniformSuperpositionGate form skip_classes --- cirq-core/cirq/ops/gate_operation_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cirq-core/cirq/ops/gate_operation_test.py b/cirq-core/cirq/ops/gate_operation_test.py index b203f0b91ec..46cf3cae1a5 100644 --- a/cirq-core/cirq/ops/gate_operation_test.py +++ b/cirq-core/cirq/ops/gate_operation_test.py @@ -509,7 +509,6 @@ def all_subclasses(cls): cirq.ops.raw_types._InverseCompositeGate, cirq.circuits.qasm_output.QasmTwoQubitGate, cirq.ops.MSGate, - cirq.ops.UniformSuperpositionGate, # Interop gates cirq.interop.quirk.QuirkQubitPermutationGate, cirq.interop.quirk.QuirkArithmeticGate, From c789426b77645d7c547d8940b08ffb9aef05fe2d Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sun, 19 May 2024 20:58:50 +0530 Subject: [PATCH 53/61] Update json_resolver_cache.py Added UniformSuperpositionGate --- cirq-core/cirq/json_resolver_cache.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cirq-core/cirq/json_resolver_cache.py b/cirq-core/cirq/json_resolver_cache.py index 4880046618a..65dea9c7587 100644 --- a/cirq-core/cirq/json_resolver_cache.py +++ b/cirq-core/cirq/json_resolver_cache.py @@ -247,6 +247,7 @@ def _symmetricalqidpair(qids): 'ZipLongest': cirq.ZipLongest, 'ZPowGate': cirq.ZPowGate, 'ZZPowGate': cirq.ZZPowGate, + 'UniformSuperpositionGate': cirq.UniformSuperpositionGate, # Old types, only supported for backwards-compatibility 'BooleanHamiltonian': _boolean_hamiltonian_gate_op, # Removed in v0.15 'CrossEntropyResult': _cross_entropy_result, # Removed in v0.16 From 24cd113753716ae33542bcfac791148fca752b51 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sun, 19 May 2024 21:04:10 +0530 Subject: [PATCH 54/61] Create UniformSuperpositionGate.repr --- .../cirq/protocols/json_test_data/UniformSuperpositionGate.repr | 1 + 1 file changed, 1 insertion(+) create mode 100644 cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.repr diff --git a/cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.repr b/cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.repr new file mode 100644 index 00000000000..62b2bdac0f2 --- /dev/null +++ b/cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.repr @@ -0,0 +1 @@ + cirq.UniformSuperpositionGate(m_value=7, num_qubits=3) From b4a82077e241c02da3e6a454482943dc935f76c5 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sun, 19 May 2024 21:05:31 +0530 Subject: [PATCH 55/61] Create UniformSuperpositionGate.json --- .../protocols/json_test_data/UniformSuperpositionGate.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.json diff --git a/cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.json b/cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.json new file mode 100644 index 00000000000..52203d8538e --- /dev/null +++ b/cirq-core/cirq/protocols/json_test_data/UniformSuperpositionGate.json @@ -0,0 +1,5 @@ +{ + "cirq_type": "UniformSuperpositionGate", + "m_value": 7, + "num_qubits": 3 +} From 8def6df84a1179b754c8b6ff8e2cba46efe0b02c Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sun, 19 May 2024 21:25:01 +0530 Subject: [PATCH 56/61] Update uniform_superposition_gate.py Added _json_dict_ and related functionality --- .../cirq/ops/uniform_superposition_gate.py | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index 612eb69ba4e..c25d86cf654 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Sequence, TYPE_CHECKING +from typing import Sequence, Any, Dict, TYPE_CHECKING import numpy as np from cirq.ops.common_gates import H, ry @@ -48,7 +48,8 @@ def __init__(self, m_value: int, num_qubits: int) -> None: if not (isinstance(m_value, int) and (m_value > 0)): raise ValueError("m_value must be a positive integer.") log_two_m_value = m_value.bit_length() - if (m_value & (m_value -1)) == 0: + + if (m_value & (m_value - 1)) == 0: log_two_m_value = log_two_m_value - 1 if not (isinstance(num_qubits, int) and (num_qubits >= log_two_m_value)): raise ValueError( @@ -99,3 +100,27 @@ def _decompose_(self, qubits: Sequence["cirq.Qid"]) -> "cirq.OP_TREE": def num_qubits(self) -> int: return self._num_qubits + + @property + def m_value(self) -> int: + return self._m_value + + def __eq__(self, other): + if isinstance(other, UniformSuperpositionGate): + return (self._m_value == other._m_value) and (self._num_qubits == other._num_qubits) + return False + + def _value_equality_values_(self): + return tuple(self._m_value, self._num_qubits) + + def __repr__(self) -> str: + return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})' + + def _json_dict_(self) -> Dict[str, Any]: + d = {} + d['m_value'] = self._m_value + d['num_qubits'] = self._num_qubits + return d + + def __str__(self) -> str: + return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})' From cfcf363fb27c203785cd2a33188fdf660eda355d Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Sun, 19 May 2024 21:25:44 +0530 Subject: [PATCH 57/61] Update uniform_superposition_gate_test.py Added json and repr tests --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index dddc2ca7436..090e6b95f2e 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -61,3 +61,14 @@ def test_incompatible_m_value_and_qubit_args(m: int, n: int) -> None: match="num_qubits must be an integer greater than or equal to log2\\(m_value\\).", ): cirq.UniformSuperpositionGate(m, n) + + +def test_repr(): + assert ( + repr(cirq.UniformSuperpositionGate(7,3)) == + 'UniformSuperpositionGate(m_value=7, num_qubits=3)' + ) + + +def test_uniform_superposition_gate_json_dict(): + assert cirq.UniformSuperpositionGate(7,3)._json_dict_() == {'m_value': 7, 'num_qubits': 3} From 41803bfd2b9f9bd0d3fd1c321c66f369a7fd2e34 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 21 May 2024 02:09:16 +0530 Subject: [PATCH 58/61] Update uniform_superposition_gate.py --- cirq-core/cirq/ops/uniform_superposition_gate.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate.py b/cirq-core/cirq/ops/uniform_superposition_gate.py index c25d86cf654..87349482704 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate.py @@ -110,9 +110,6 @@ def __eq__(self, other): return (self._m_value == other._m_value) and (self._num_qubits == other._num_qubits) return False - def _value_equality_values_(self): - return tuple(self._m_value, self._num_qubits) - def __repr__(self) -> str: return f'UniformSuperpositionGate(m_value={self._m_value}, num_qubits={self._num_qubits})' From 0fcf60bf037abb4ab6c0a64fd19441c8be9ef415 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 21 May 2024 02:11:18 +0530 Subject: [PATCH 59/61] Update uniform_superposition_gate_test.py Corrected formatting and added more tests to fix ci coverage check errors --- .../ops/uniform_superposition_gate_test.py | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 090e6b95f2e..37569e58b34 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -18,8 +18,9 @@ @pytest.mark.parametrize( - ["m", "n"], [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] + - [(1,2), (4,2), (6,3), (7,3)] + ["m", "n"], + [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] + + [(1, 2), (4, 2), (6, 3), (7, 3)] ) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r"""The code checks that the unitary matrix corresponds to the generated uniform superposition @@ -65,10 +66,25 @@ def test_incompatible_m_value_and_qubit_args(m: int, n: int) -> None: def test_repr(): assert ( - repr(cirq.UniformSuperpositionGate(7,3)) == - 'UniformSuperpositionGate(m_value=7, num_qubits=3)' + repr(cirq.UniformSuperpositionGate(7, 3)) + == 'UniformSuperpositionGate(m_value=7, num_qubits=3)' ) def test_uniform_superposition_gate_json_dict(): - assert cirq.UniformSuperpositionGate(7,3)._json_dict_() == {'m_value': 7, 'num_qubits': 3} + assert cirq.UniformSuperpositionGate(7, 3)._json_dict_() == {'m_value': 7, 'num_qubits': 3} + +def test_str(): + assert ( + str(cirq.UniformSuperpositionGate(7, 3)) + == 'UniformSuperpositionGate(m_value=7, num_qubits=3)' + ) + +@pytest.mark.parametrize(["m", "n"], [(5, 3), (10, 4)]) +def test_eq(m: int, n: int) -> None: + a = cirq.UniformSuperpositionGate(m, n) + b = cirq.UniformSuperpositionGate(m, n) + c = cirq.UniformSuperpositionGate(m + 1, n) + assert a.m_value == b.m_value + assert (a.__eq__(b)) + assert not (a.__eq__(c)) From ac491bc0fb3a53698c949acf481cef732efdca77 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 21 May 2024 03:22:46 +0530 Subject: [PATCH 60/61] Update uniform_superposition_gate_test.py Added one more test case --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index 37569e58b34..b450513471c 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -20,7 +20,7 @@ @pytest.mark.parametrize( ["m", "n"], [[int(m), n] for n in range(3, 7) for m in np.random.randint(1, 1 << n, size=3)] - + [(1, 2), (4, 2), (6, 3), (7, 3)] + + [(1, 2), (4, 2), (6, 3), (7, 3)], ) def test_generated_unitary_is_uniform(m: int, n: int) -> None: r"""The code checks that the unitary matrix corresponds to the generated uniform superposition @@ -85,6 +85,8 @@ def test_eq(m: int, n: int) -> None: a = cirq.UniformSuperpositionGate(m, n) b = cirq.UniformSuperpositionGate(m, n) c = cirq.UniformSuperpositionGate(m + 1, n) + d = cirq.X assert a.m_value == b.m_value - assert (a.__eq__(b)) + assert a.__eq__(b) assert not (a.__eq__(c)) + assert not (a.__eq__(d)) From 389260e40a4d63d46af74534b42b9a6365e01338 Mon Sep 17 00:00:00 2001 From: Pragya <163991062+prag16@users.noreply.github.com> Date: Tue, 21 May 2024 19:04:03 +0530 Subject: [PATCH 61/61] Update uniform_superposition_gate_test.py Fixed the format check error --- cirq-core/cirq/ops/uniform_superposition_gate_test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cirq-core/cirq/ops/uniform_superposition_gate_test.py b/cirq-core/cirq/ops/uniform_superposition_gate_test.py index b450513471c..6f3e472d19a 100644 --- a/cirq-core/cirq/ops/uniform_superposition_gate_test.py +++ b/cirq-core/cirq/ops/uniform_superposition_gate_test.py @@ -74,12 +74,14 @@ def test_repr(): def test_uniform_superposition_gate_json_dict(): assert cirq.UniformSuperpositionGate(7, 3)._json_dict_() == {'m_value': 7, 'num_qubits': 3} + def test_str(): assert ( str(cirq.UniformSuperpositionGate(7, 3)) == 'UniformSuperpositionGate(m_value=7, num_qubits=3)' ) + @pytest.mark.parametrize(["m", "n"], [(5, 3), (10, 4)]) def test_eq(m: int, n: int) -> None: a = cirq.UniformSuperpositionGate(m, n)