From 7895708db90e56dd864dac7584b160d7bfaf7b80 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Sun, 14 Apr 2024 06:41:41 -0500 Subject: [PATCH 01/10] replace initializetion method by Isometry in StatePreparation --- .../data_preparation/state_preparation.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/qiskit/circuit/library/data_preparation/state_preparation.py b/qiskit/circuit/library/data_preparation/state_preparation.py index 2d48e5cd0776..4daf7539a70c 100644 --- a/qiskit/circuit/library/data_preparation/state_preparation.py +++ b/qiskit/circuit/library/data_preparation/state_preparation.py @@ -26,6 +26,7 @@ from qiskit.circuit.library.standard_gates.s import SGate, SdgGate from qiskit.circuit.library.standard_gates.ry import RYGate from qiskit.circuit.library.standard_gates.rz import RZGate +from qiskit.circuit.library.generalized_gates import Isometry from qiskit.circuit.exceptions import CircuitError from qiskit.quantum_info.states.statevector import Statevector # pylint: disable=cyclic-import @@ -119,7 +120,7 @@ def _define(self): elif self._from_int: self.definition = self._define_from_int() else: - self.definition = self._define_synthesis() + self.definition = self._define_synthesis_isom() def _define_from_label(self): q = QuantumRegister(self.num_qubits, "q") @@ -168,6 +169,21 @@ def _define_from_int(self): # we don't need to invert anything return initialize_circuit + def _define_synthesis_isom(self): + """Calculate a subcircuit that implements this initialization via isometry""" + q = QuantumRegister(self.num_qubits, "q") + initialize_circuit = QuantumCircuit(q, name="init_def") + + isom = Isometry(self._params_arg, 0, 0) + initialize_circuit.append(isom, q[:]) + + # invert the circuit to create the desired vector from zero (assuming + # the qubits are in the zero state) + if self._inverse is True: + return initialize_circuit.inverse() + + return initialize_circuit + def _define_synthesis(self): """Calculate a subcircuit that implements this initialization From f80a13823c3a549e3400711aeda63a3dc8a02be4 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 7 May 2024 03:59:37 -0500 Subject: [PATCH 02/10] add names to QuantumRegister and QuantumCircuit --- qiskit/circuit/library/generalized_gates/isometry.py | 8 ++++---- .../library/generalized_gates/mcg_up_to_diagonal.py | 8 ++++---- qiskit/circuit/library/generalized_gates/uc.py | 4 ++-- qiskit/circuit/library/generalized_gates/uc_pauli_rot.py | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/qiskit/circuit/library/generalized_gates/isometry.py b/qiskit/circuit/library/generalized_gates/isometry.py index 1294feb26342..927052d8d7ae 100644 --- a/qiskit/circuit/library/generalized_gates/isometry.py +++ b/qiskit/circuit/library/generalized_gates/isometry.py @@ -123,8 +123,8 @@ def _define(self): # later here instead. gate = self.inv_gate() gate = gate.inverse() - q = QuantumRegister(self.num_qubits) - iso_circuit = QuantumCircuit(q) + q = QuantumRegister(self.num_qubits, "q") + iso_circuit = QuantumCircuit(q, name="isom") iso_circuit.append(gate, q[:]) self.definition = iso_circuit @@ -139,8 +139,8 @@ def _gates_to_uncompute(self): Call to create a circuit with gates that take the desired isometry to the first 2^m columns of the 2^n*2^n identity matrix (see https://arxiv.org/abs/1501.06911) """ - q = QuantumRegister(self.num_qubits) - circuit = QuantumCircuit(q) + q = QuantumRegister(self.num_qubits, "q") + circuit = QuantumCircuit(q, name="isom") ( q_input, q_ancillas_for_output, diff --git a/qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py b/qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py index 49d7dc36958a..b95ec6f63e35 100644 --- a/qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py +++ b/qiskit/circuit/library/generalized_gates/mcg_up_to_diagonal.py @@ -68,8 +68,8 @@ def __init__( def _define(self): mcg_up_diag_circuit, _ = self._dec_mcg_up_diag() gate = mcg_up_diag_circuit.to_instruction() - q = QuantumRegister(self.num_qubits) - mcg_up_diag_circuit = QuantumCircuit(q) + q = QuantumRegister(self.num_qubits, "q") + mcg_up_diag_circuit = QuantumCircuit(q, name="mcg_up_to_diagonal") mcg_up_diag_circuit.append(gate, q[:]) self.definition = mcg_up_diag_circuit @@ -108,8 +108,8 @@ def _dec_mcg_up_diag(self): q=[q_target,q_controls,q_ancilla_zero,q_ancilla_dirty] """ diag = np.ones(2 ** (self.num_controls + 1)).tolist() - q = QuantumRegister(self.num_qubits) - circuit = QuantumCircuit(q) + q = QuantumRegister(self.num_qubits, "q") + circuit = QuantumCircuit(q, name="mcg_up_to_diagonal") (q_target, q_controls, q_ancillas_zero, q_ancillas_dirty) = self._define_qubit_role(q) # ToDo: Keep this threshold updated such that the lowest gate count is achieved: # ToDo: we implement the MCG with a UCGate up to diagonal if the number of controls is diff --git a/qiskit/circuit/library/generalized_gates/uc.py b/qiskit/circuit/library/generalized_gates/uc.py index 2d650e98466a..c6e2da3db7f2 100644 --- a/qiskit/circuit/library/generalized_gates/uc.py +++ b/qiskit/circuit/library/generalized_gates/uc.py @@ -152,10 +152,10 @@ def _dec_ucg(self): the diagonal gate is also returned. """ diag = np.ones(2**self.num_qubits).tolist() - q = QuantumRegister(self.num_qubits) + q = QuantumRegister(self.num_qubits, "q") q_controls = q[1:] q_target = q[0] - circuit = QuantumCircuit(q) + circuit = QuantumCircuit(q, name="uc") # If there is no control, we use the ZYZ decomposition if not q_controls: circuit.unitary(self.params[0], [q]) diff --git a/qiskit/circuit/library/generalized_gates/uc_pauli_rot.py b/qiskit/circuit/library/generalized_gates/uc_pauli_rot.py index 5b5633ec423f..6b637f7d2b2a 100644 --- a/qiskit/circuit/library/generalized_gates/uc_pauli_rot.py +++ b/qiskit/circuit/library/generalized_gates/uc_pauli_rot.py @@ -69,7 +69,7 @@ def __init__(self, angle_list: list[float], rot_axis: str) -> None: def _define(self): ucr_circuit = self._dec_ucrot() gate = ucr_circuit.to_instruction() - q = QuantumRegister(self.num_qubits) + q = QuantumRegister(self.num_qubits, "q") ucr_circuit = QuantumCircuit(q) ucr_circuit.append(gate, q[:]) self.definition = ucr_circuit @@ -79,7 +79,7 @@ def _dec_ucrot(self): Finds a decomposition of a UC rotation gate into elementary gates (C-NOTs and single-qubit rotations). """ - q = QuantumRegister(self.num_qubits) + q = QuantumRegister(self.num_qubits, "q") circuit = QuantumCircuit(q) q_target = q[0] q_controls = q[1:] From ae665b1355935a02a60d2be8e49cea2f22a8cc1d Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 7 May 2024 06:14:38 -0500 Subject: [PATCH 03/10] update docs to the new reference --- .../library/data_preparation/initializer.py | 7 +++++++ .../library/data_preparation/state_preparation.py | 14 +++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/qiskit/circuit/library/data_preparation/initializer.py b/qiskit/circuit/library/data_preparation/initializer.py index 394f863191d5..5098cbbef365 100644 --- a/qiskit/circuit/library/data_preparation/initializer.py +++ b/qiskit/circuit/library/data_preparation/initializer.py @@ -36,6 +36,13 @@ class Initialize(Instruction): the :class:`~.library.StatePreparation` class. Note that ``Initialize`` is an :class:`~.circuit.Instruction` and not a :class:`.Gate` since it contains a reset instruction, which is not unitary. + + The initial state is prepared based on the :class:`~.library.Isometry` synthesis described in [1]. + + **References:** + [1] Iten et al. Quantum circuits for isometries. + [`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`] + """ def __init__( diff --git a/qiskit/circuit/library/data_preparation/state_preparation.py b/qiskit/circuit/library/data_preparation/state_preparation.py index 4daf7539a70c..fc0be7d21788 100644 --- a/qiskit/circuit/library/data_preparation/state_preparation.py +++ b/qiskit/circuit/library/data_preparation/state_preparation.py @@ -72,13 +72,12 @@ def __init__( Raises: QiskitError: ``num_qubits`` parameter used when ``params`` is not an integer - When a Statevector argument is passed the state is prepared using a recursive - initialization algorithm, including optimizations, from [1], as well - as some additional optimizations including removing zero rotations and double cnots. + When a Statevector argument is passed the state is prepared based on the + :class:`~.library.Isometry` synthesis described in [1]. **References:** - [1] Shende, Bullock, Markov. Synthesis of Quantum Logic Circuits (2004) - [`https://arxiv.org/abs/quant-ph/0406176v5`] + [1] Iten et al. Quantum circuits for isometries. + [`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`] """ self._params_arg = params @@ -184,6 +183,11 @@ def _define_synthesis_isom(self): return initialize_circuit + ################################################################## + # This code is not used for the StatePreparation synthesis anymore, + # since we ust the code based on the Isometry synthesis, + # which has fewer CX gates + ################################################################# def _define_synthesis(self): """Calculate a subcircuit that implements this initialization From 49295cc868f6bc89bf486502034a7c3aa59a6f21 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 7 May 2024 08:42:01 -0500 Subject: [PATCH 04/10] remove old initialization code based on Shende et al --- .../data_preparation/state_preparation.py | 198 +----------------- 1 file changed, 3 insertions(+), 195 deletions(-) diff --git a/qiskit/circuit/library/data_preparation/state_preparation.py b/qiskit/circuit/library/data_preparation/state_preparation.py index fc0be7d21788..25674e17de47 100644 --- a/qiskit/circuit/library/data_preparation/state_preparation.py +++ b/qiskit/circuit/library/data_preparation/state_preparation.py @@ -75,9 +75,9 @@ def __init__( When a Statevector argument is passed the state is prepared based on the :class:`~.library.Isometry` synthesis described in [1]. - **References:** - [1] Iten et al. Quantum circuits for isometries. - [`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`] + References: + 1. Iten et al. Quantum circuits for isometries. + `PhysRevA.93.032318 <`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`>`_ """ self._params_arg = params @@ -183,37 +183,6 @@ def _define_synthesis_isom(self): return initialize_circuit - ################################################################## - # This code is not used for the StatePreparation synthesis anymore, - # since we ust the code based on the Isometry synthesis, - # which has fewer CX gates - ################################################################# - def _define_synthesis(self): - """Calculate a subcircuit that implements this initialization - - Implements a recursive initialization algorithm, including optimizations, - from "Synthesis of Quantum Logic Circuits" Shende, Bullock, Markov - https://arxiv.org/abs/quant-ph/0406176v5 - - Additionally implements some extra optimizations: remove zero rotations and - double cnots. - """ - # call to generate the circuit that takes the desired vector to zero - disentangling_circuit = self._gates_to_uncompute() - - # invert the circuit to create the desired vector from zero (assuming - # the qubits are in the zero state) - if self._inverse is False: - initialize_instr = disentangling_circuit.to_instruction().inverse() - else: - initialize_instr = disentangling_circuit.to_instruction() - - q = QuantumRegister(self.num_qubits, "q") - initialize_circuit = QuantumCircuit(q, name="init_def") - initialize_circuit.append(initialize_instr, q[:]) - - return initialize_circuit - def _get_num_qubits(self, num_qubits, params): """Get number of qubits needed for state preparation""" if isinstance(params, str): @@ -273,164 +242,3 @@ def validate_parameter(self, parameter): def _return_repeat(self, exponent: float) -> "Gate": return Gate(name=f"{self.name}*{exponent}", num_qubits=self.num_qubits, params=[]) - - def _gates_to_uncompute(self): - """Call to create a circuit with gates that take the desired vector to zero. - - Returns: - QuantumCircuit: circuit to take self.params vector to :math:`|{00\\ldots0}\\rangle` - """ - q = QuantumRegister(self.num_qubits) - circuit = QuantumCircuit(q, name="disentangler") - - # kick start the peeling loop, and disentangle one-by-one from LSB to MSB - remaining_param = self.params - - for i in range(self.num_qubits): - # work out which rotations must be done to disentangle the LSB - # qubit (we peel away one qubit at a time) - (remaining_param, thetas, phis) = StatePreparation._rotations_to_disentangle( - remaining_param - ) - - # perform the required rotations to decouple the LSB qubit (so that - # it can be "factored" out, leaving a shorter amplitude vector to peel away) - - add_last_cnot = True - if np.linalg.norm(phis) != 0 and np.linalg.norm(thetas) != 0: - add_last_cnot = False - - if np.linalg.norm(phis) != 0: - rz_mult = self._multiplex(RZGate, phis, last_cnot=add_last_cnot) - circuit.append(rz_mult.to_instruction(), q[i : self.num_qubits]) - - if np.linalg.norm(thetas) != 0: - ry_mult = self._multiplex(RYGate, thetas, last_cnot=add_last_cnot) - circuit.append(ry_mult.to_instruction().reverse_ops(), q[i : self.num_qubits]) - circuit.global_phase -= np.angle(sum(remaining_param)) - return circuit - - @staticmethod - def _rotations_to_disentangle(local_param): - """ - Static internal method to work out Ry and Rz rotation angles used - to disentangle the LSB qubit. - These rotations make up the block diagonal matrix U (i.e. multiplexor) - that disentangles the LSB. - - [[Ry(theta_1).Rz(phi_1) 0 . . 0], - [0 Ry(theta_2).Rz(phi_2) . 0], - . - . - 0 0 Ry(theta_2^n).Rz(phi_2^n)]] - """ - remaining_vector = [] - thetas = [] - phis = [] - - param_len = len(local_param) - - for i in range(param_len // 2): - # Ry and Rz rotations to move bloch vector from 0 to "imaginary" - # qubit - # (imagine a qubit state signified by the amplitudes at index 2*i - # and 2*(i+1), corresponding to the select qubits of the - # multiplexor being in state |i>) - (remains, add_theta, add_phi) = StatePreparation._bloch_angles( - local_param[2 * i : 2 * (i + 1)] - ) - - remaining_vector.append(remains) - - # rotations for all imaginary qubits of the full vector - # to move from where it is to zero, hence the negative sign - thetas.append(-add_theta) - phis.append(-add_phi) - - return remaining_vector, thetas, phis - - @staticmethod - def _bloch_angles(pair_of_complex): - """ - Static internal method to work out rotation to create the passed-in - qubit from the zero vector. - """ - [a_complex, b_complex] = pair_of_complex - # Force a and b to be complex, as otherwise numpy.angle might fail. - a_complex = complex(a_complex) - b_complex = complex(b_complex) - mag_a = abs(a_complex) - final_r = math.sqrt(mag_a**2 + abs(b_complex) ** 2) - if final_r < _EPS: - theta = 0 - phi = 0 - final_r = 0 - final_t = 0 - else: - theta = 2 * math.acos(mag_a / final_r) - a_arg = cmath.phase(a_complex) - b_arg = cmath.phase(b_complex) - final_t = a_arg + b_arg - phi = b_arg - a_arg - - return final_r * cmath.exp(1.0j * final_t / 2), theta, phi - - def _multiplex(self, target_gate, list_of_angles, last_cnot=True): - """ - Return a recursive implementation of a multiplexor circuit, - where each instruction itself has a decomposition based on - smaller multiplexors. - - The LSB is the multiplexor "data" and the other bits are multiplexor "select". - - Args: - target_gate (Gate): Ry or Rz gate to apply to target qubit, multiplexed - over all other "select" qubits - list_of_angles (list[float]): list of rotation angles to apply Ry and Rz - last_cnot (bool): add the last cnot if last_cnot = True - - Returns: - DAGCircuit: the circuit implementing the multiplexor's action - """ - list_len = len(list_of_angles) - local_num_qubits = int(math.log2(list_len)) + 1 - - q = QuantumRegister(local_num_qubits) - circuit = QuantumCircuit(q, name="multiplex" + str(local_num_qubits)) - - lsb = q[0] - msb = q[local_num_qubits - 1] - - # case of no multiplexing: base case for recursion - if local_num_qubits == 1: - circuit.append(target_gate(list_of_angles[0]), [q[0]]) - return circuit - - # calc angle weights, assuming recursion (that is the lower-level - # requested angles have been correctly implemented by recursion - angle_weight = np.kron([[0.5, 0.5], [0.5, -0.5]], np.identity(2 ** (local_num_qubits - 2))) - - # calc the combo angles - list_of_angles = angle_weight.dot(np.array(list_of_angles)).tolist() - - # recursive step on half the angles fulfilling the above assumption - multiplex_1 = self._multiplex(target_gate, list_of_angles[0 : (list_len // 2)], False) - circuit.append(multiplex_1.to_instruction(), q[0:-1]) - - # attach CNOT as follows, thereby flipping the LSB qubit - circuit.append(CXGate(), [msb, lsb]) - - # implement extra efficiency from the paper of cancelling adjacent - # CNOTs (by leaving out last CNOT and reversing (NOT inverting) the - # second lower-level multiplex) - multiplex_2 = self._multiplex(target_gate, list_of_angles[(list_len // 2) :], False) - if list_len > 1: - circuit.append(multiplex_2.to_instruction().reverse_ops(), q[0:-1]) - else: - circuit.append(multiplex_2.to_instruction(), q[0:-1]) - - # attach a final CNOT - if last_cnot: - circuit.append(CXGate(), [msb, lsb]) - - return circuit From 406d32bcc6ea3715e9322a0c8398807db1a23efc Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 7 May 2024 08:49:40 -0500 Subject: [PATCH 05/10] fix reference in docs --- .../circuit/library/data_preparation/initializer.py | 6 +++--- qiskit/circuit/library/generalized_gates/isometry.py | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/qiskit/circuit/library/data_preparation/initializer.py b/qiskit/circuit/library/data_preparation/initializer.py index 5098cbbef365..c48b33f4c6cf 100644 --- a/qiskit/circuit/library/data_preparation/initializer.py +++ b/qiskit/circuit/library/data_preparation/initializer.py @@ -39,9 +39,9 @@ class Initialize(Instruction): The initial state is prepared based on the :class:`~.library.Isometry` synthesis described in [1]. - **References:** - [1] Iten et al. Quantum circuits for isometries. - [`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`] + References: + 1. Iten et al. Quantum circuits for isometries. + `PhysRevA.93.032318 <`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`>`_ """ diff --git a/qiskit/circuit/library/generalized_gates/isometry.py b/qiskit/circuit/library/generalized_gates/isometry.py index 927052d8d7ae..70e1f2797989 100644 --- a/qiskit/circuit/library/generalized_gates/isometry.py +++ b/qiskit/circuit/library/generalized_gates/isometry.py @@ -45,10 +45,9 @@ class Isometry(Instruction): The decomposition is based on [1]. - **References:** - - [1] Iten et al., Quantum circuits for isometries (2016). - `Phys. Rev. A 93, 032318 `__. + References: + 1. Iten et al., Quantum circuits for isometries (2016). + `Phys. Rev. A 93, 032318 `__. """ @@ -124,7 +123,7 @@ def _define(self): gate = self.inv_gate() gate = gate.inverse() q = QuantumRegister(self.num_qubits, "q") - iso_circuit = QuantumCircuit(q, name="isom") + iso_circuit = QuantumCircuit(q, name="isometry") iso_circuit.append(gate, q[:]) self.definition = iso_circuit @@ -140,7 +139,7 @@ def _gates_to_uncompute(self): of the 2^n*2^n identity matrix (see https://arxiv.org/abs/1501.06911) """ q = QuantumRegister(self.num_qubits, "q") - circuit = QuantumCircuit(q, name="isom") + circuit = QuantumCircuit(q, name="isometry") ( q_input, q_ancillas_for_output, From a4795889c1871f2a4ca327b728b99d5ee871476f Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 7 May 2024 09:07:11 -0500 Subject: [PATCH 06/10] add release notes --- ...tialization-algorithm-by-isometry-41f9ffa58f72ece5.yaml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 releasenotes/notes/replace-initialization-algorithm-by-isometry-41f9ffa58f72ece5.yaml diff --git a/releasenotes/notes/replace-initialization-algorithm-by-isometry-41f9ffa58f72ece5.yaml b/releasenotes/notes/replace-initialization-algorithm-by-isometry-41f9ffa58f72ece5.yaml new file mode 100644 index 000000000000..5bf8e7a80b48 --- /dev/null +++ b/releasenotes/notes/replace-initialization-algorithm-by-isometry-41f9ffa58f72ece5.yaml @@ -0,0 +1,7 @@ +--- +features_circuits: + - | + Replacing the internal synthesis algorithm of :class:`~.library.StatePreparation` + and :class:`~.library.Initialize` of Shende et al. by the algorithm given in + :class:`~.library.Isometry` of Iten et al. + The new algorithm reduces the number of CX gates and the circuit depth by a factor of 2. From 7a9ff134a85a70f249ee345d38ece8b1c6094d3e Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 7 May 2024 09:47:34 -0500 Subject: [PATCH 07/10] fix lint errors --- qiskit/circuit/library/data_preparation/state_preparation.py | 5 +---- qiskit/circuit/library/generalized_gates/isometry.py | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/qiskit/circuit/library/data_preparation/state_preparation.py b/qiskit/circuit/library/data_preparation/state_preparation.py index 25674e17de47..b462d5248f73 100644 --- a/qiskit/circuit/library/data_preparation/state_preparation.py +++ b/qiskit/circuit/library/data_preparation/state_preparation.py @@ -11,7 +11,6 @@ # that they have been altered from the originals. """Prepare a quantum state from the state where all qubits are 0.""" -import cmath from typing import Union, Optional import math @@ -21,11 +20,9 @@ from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit.gate import Gate -from qiskit.circuit.library.standard_gates.x import CXGate, XGate +from qiskit.circuit.library.standard_gates.x import XGate from qiskit.circuit.library.standard_gates.h import HGate from qiskit.circuit.library.standard_gates.s import SGate, SdgGate -from qiskit.circuit.library.standard_gates.ry import RYGate -from qiskit.circuit.library.standard_gates.rz import RZGate from qiskit.circuit.library.generalized_gates import Isometry from qiskit.circuit.exceptions import CircuitError from qiskit.quantum_info.states.statevector import Statevector # pylint: disable=cyclic-import diff --git a/qiskit/circuit/library/generalized_gates/isometry.py b/qiskit/circuit/library/generalized_gates/isometry.py index 70e1f2797989..be0204e0bbf3 100644 --- a/qiskit/circuit/library/generalized_gates/isometry.py +++ b/qiskit/circuit/library/generalized_gates/isometry.py @@ -47,7 +47,8 @@ class Isometry(Instruction): References: 1. Iten et al., Quantum circuits for isometries (2016). - `Phys. Rev. A 93, 032318 `__. + `Phys. Rev. A 93, 032318 + `__. """ From eeb19609ef22b4f79ed80fbd28bd49873874555f Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 7 May 2024 11:17:03 -0500 Subject: [PATCH 08/10] fix references in docs --- qiskit/circuit/library/data_preparation/initializer.py | 5 +++-- qiskit/circuit/library/data_preparation/state_preparation.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/qiskit/circuit/library/data_preparation/initializer.py b/qiskit/circuit/library/data_preparation/initializer.py index c48b33f4c6cf..0e38f067403c 100644 --- a/qiskit/circuit/library/data_preparation/initializer.py +++ b/qiskit/circuit/library/data_preparation/initializer.py @@ -40,8 +40,9 @@ class Initialize(Instruction): The initial state is prepared based on the :class:`~.library.Isometry` synthesis described in [1]. References: - 1. Iten et al. Quantum circuits for isometries. - `PhysRevA.93.032318 <`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`>`_ + 1. Iten et al., Quantum circuits for isometries (2016). + `Phys. Rev. A 93, 032318 + `__. """ diff --git a/qiskit/circuit/library/data_preparation/state_preparation.py b/qiskit/circuit/library/data_preparation/state_preparation.py index b462d5248f73..43e80ead8836 100644 --- a/qiskit/circuit/library/data_preparation/state_preparation.py +++ b/qiskit/circuit/library/data_preparation/state_preparation.py @@ -73,8 +73,9 @@ def __init__( :class:`~.library.Isometry` synthesis described in [1]. References: - 1. Iten et al. Quantum circuits for isometries. - `PhysRevA.93.032318 <`https://journals.aps.org/pra/abstract/10.1103/PhysRevA.93.032318`>`_ + 1. Iten et al., Quantum circuits for isometries (2016). + `Phys. Rev. A 93, 032318 + `__. """ self._params_arg = params From 4dab85c44fc7a9655a2cf502d32b7471000a279b Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Wed, 8 May 2024 01:28:48 -0500 Subject: [PATCH 09/10] add a benchmark for state preparation --- test/benchmarks/statepreparation.py | 66 +++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 test/benchmarks/statepreparation.py diff --git a/test/benchmarks/statepreparation.py b/test/benchmarks/statepreparation.py new file mode 100644 index 000000000000..67dc1178fc24 --- /dev/null +++ b/test/benchmarks/statepreparation.py @@ -0,0 +1,66 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2024 +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +# pylint: disable=missing-docstring,invalid-name,no-member +# pylint: disable=attribute-defined-outside-init +# pylint: disable=unused-argument + +import numpy as np +from qiskit import QuantumRegister, QuantumCircuit +from qiskit.compiler import transpile +from qiskit.circuit.library.data_preparation import StatePreparation + + +class StatePreparationTranspileBench: + params = [4, 5, 6, 7, 8] + param_names = ["number of qubits in state"] + + def setup(self, n): + q = QuantumRegister(n) + qc = QuantumCircuit(q) + state = np.random.rand(2**n) + np.random.rand(2**n) * 1j + state = state / np.linalg.norm(state) + state_gate = StatePreparation(state) + qc.append(state_gate, q) + + self.circuit = qc + + def track_cnot_counts_after_mapping_to_ibmq_16_melbourne(self, *unused): + coupling = [ + [1, 0], + [1, 2], + [2, 3], + [4, 3], + [4, 10], + [5, 4], + [5, 6], + [5, 9], + [6, 8], + [7, 8], + [9, 8], + [9, 10], + [11, 3], + [11, 10], + [11, 12], + [12, 2], + [13, 1], + [13, 12], + ] + circuit = transpile( + self.circuit, + basis_gates=["u1", "u3", "u2", "cx"], + coupling_map=coupling, + seed_transpiler=0, + ) + counts = circuit.count_ops() + cnot_count = counts.get("cx", 0) + return cnot_count From d0391e1e236dfce9c67434ab40e93686dd7b27a8 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Wed, 8 May 2024 03:05:28 -0500 Subject: [PATCH 10/10] update circuit name following review --- qiskit/circuit/library/generalized_gates/isometry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/circuit/library/generalized_gates/isometry.py b/qiskit/circuit/library/generalized_gates/isometry.py index be0204e0bbf3..0b60705e7d57 100644 --- a/qiskit/circuit/library/generalized_gates/isometry.py +++ b/qiskit/circuit/library/generalized_gates/isometry.py @@ -140,7 +140,7 @@ def _gates_to_uncompute(self): of the 2^n*2^n identity matrix (see https://arxiv.org/abs/1501.06911) """ q = QuantumRegister(self.num_qubits, "q") - circuit = QuantumCircuit(q, name="isometry") + circuit = QuantumCircuit(q, name="isometry_to_uncompute") ( q_input, q_ancillas_for_output,