From 802ac5133bd1284547f0d9724917b5bcec44c335 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 21 Feb 2024 11:07:52 -0500 Subject: [PATCH 1/2] Deduplicate SliceOrInt (#11844) * Deduplicate SliceOrInt After doing some post-merge analysis on the impact of #11842 it turns out the enum being modified in that PR was duplicated in the rust code unnecessarily. The same enum was already defined in the euler_one_qubit_decomposer module for it's custom 1 qubit gate sequence return type. This commit updates the code so it just use the one defined in the circuit data module that has the fix from #11842 applied already. * Move enum to common location --- crates/accelerate/src/euler_one_qubit_decomposer.rs | 9 ++------- crates/accelerate/src/quantum_circuit/circuit_data.rs | 11 +---------- crates/accelerate/src/utils.rs | 11 +++++++++++ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/crates/accelerate/src/euler_one_qubit_decomposer.rs b/crates/accelerate/src/euler_one_qubit_decomposer.rs index 8fe0eaf87b45..e74f70006696 100644 --- a/crates/accelerate/src/euler_one_qubit_decomposer.rs +++ b/crates/accelerate/src/euler_one_qubit_decomposer.rs @@ -19,20 +19,15 @@ use std::f64::consts::PI; use pyo3::exceptions::{PyIndexError, PyTypeError}; use pyo3::prelude::*; -use pyo3::types::PySlice; use pyo3::wrap_pyfunction; use pyo3::Python; use ndarray::prelude::*; use numpy::PyReadonlyArray2; -const DEFAULT_ATOL: f64 = 1e-12; +use crate::utils::SliceOrInt; -#[derive(FromPyObject)] -enum SliceOrInt<'a> { - Slice(&'a PySlice), - Int(isize), -} +const DEFAULT_ATOL: f64 = 1e-12; #[pyclass(module = "qiskit._accelerate.euler_one_qubit_decomposer")] pub struct OneQubitGateErrorMap { diff --git a/crates/accelerate/src/quantum_circuit/circuit_data.rs b/crates/accelerate/src/quantum_circuit/circuit_data.rs index cbafeb79f38e..915285f6ad6d 100644 --- a/crates/accelerate/src/quantum_circuit/circuit_data.rs +++ b/crates/accelerate/src/quantum_circuit/circuit_data.rs @@ -13,6 +13,7 @@ use crate::quantum_circuit::circuit_instruction::CircuitInstruction; use crate::quantum_circuit::intern_context::{BitType, IndexType, InternContext}; use crate::quantum_circuit::py_ext; +use crate::utils::SliceOrInt; use hashbrown::HashMap; use pyo3::exceptions::{PyIndexError, PyKeyError, PyRuntimeError, PyValueError}; use pyo3::prelude::*; @@ -153,16 +154,6 @@ pub struct CircuitData { clbits: Py, } -/// A private enumeration type used to extract arguments to pymethods -/// that may be either an index or a slice. -#[derive(FromPyObject)] -pub enum SliceOrInt<'a> { - // The order here defines the order the variants are tried in the `FromPyObject` derivation. - // `Int` is _much_ more common, so that should be first. - Int(isize), - Slice(&'a PySlice), -} - #[pymethods] impl CircuitData { #[new] diff --git a/crates/accelerate/src/utils.rs b/crates/accelerate/src/utils.rs index 99e338c7024d..bc8a66568f9b 100644 --- a/crates/accelerate/src/utils.rs +++ b/crates/accelerate/src/utils.rs @@ -11,12 +11,23 @@ // that they have been altered from the originals. use pyo3::prelude::*; +use pyo3::types::PySlice; use faer::prelude::*; use faer::IntoFaerComplex; use num_complex::Complex; use numpy::{IntoPyArray, PyReadonlyArray2}; +/// A private enumeration type used to extract arguments to pymethod +/// that may be either an index or a slice +#[derive(FromPyObject)] +pub enum SliceOrInt<'a> { + // The order here defines the order the variants are tried in the FromPyObject` derivation. + // `Int` is _much_ more common, so that should be first. + Int(isize), + Slice(&'a PySlice), +} + /// Return indices that sort partially ordered data. /// If `data` contains two elements that are incomparable, /// an error will be thrown. From 9cb0a54c16b7db4829b1de39078a89cee721afb6 Mon Sep 17 00:00:00 2001 From: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:08:40 +0200 Subject: [PATCH 2/2] Add __call__ functions to synthesis docs (#11848) * add call function to TwoQubitBasisDecomposer docs * add call function to OneQubitEulerDecomposer docs * update TwoQubitBasisDecomposer docs * add call function to XXDecomposer docs * minor updates * minor fix --- .../one_qubit/one_qubit_decompose.py | 3 +++ .../two_qubit/two_qubit_decompose.py | 16 +++++++----- .../two_qubit/xx_decompose/decomposer.py | 25 +++++++++++-------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/qiskit/synthesis/one_qubit/one_qubit_decompose.py b/qiskit/synthesis/one_qubit/one_qubit_decompose.py index c29d29903ca3..5ca44d43d5b4 100644 --- a/qiskit/synthesis/one_qubit/one_qubit_decompose.py +++ b/qiskit/synthesis/one_qubit/one_qubit_decompose.py @@ -128,6 +128,8 @@ class OneQubitEulerDecomposer: - :math:`Z(\phi) Y(\theta) Z(\lambda)` - :math:`e^{i\gamma} R\left(-\pi,\frac{\phi-\lambda+\pi}{2}\right).` :math:`R\left(\theta+\pi,\frac{\pi}{2}-\lambda\right)` + + .. automethod:: __call__ """ def __init__(self, basis: str = "U3", use_dag: bool = False): @@ -192,6 +194,7 @@ def __call__( simplify: reduce gate count in decomposition [Default: True]. atol: absolute tolerance for checking angles when simplifying returned circuit [Default: 1e-12]. + Returns: QuantumCircuit: the decomposed single-qubit gate circuit diff --git a/qiskit/synthesis/two_qubit/two_qubit_decompose.py b/qiskit/synthesis/two_qubit/two_qubit_decompose.py index 9f3a5175b457..c8af4002fb27 100644 --- a/qiskit/synthesis/two_qubit/two_qubit_decompose.py +++ b/qiskit/synthesis/two_qubit/two_qubit_decompose.py @@ -903,6 +903,8 @@ class TwoQubitBasisDecomposer: optimal decomposition is not implemented. Currently, only [{CX, SX, RZ}] is known. If ``False``, don't attempt optimization. If ``None``, attempt optimization but don't raise if unknown. + + .. automethod:: __call__ """ def __init__( @@ -1153,19 +1155,21 @@ def __call__( *, _num_basis_uses: int | None = None, ) -> QuantumCircuit: - """Decompose a two-qubit ``unitary`` over fixed basis + SU(2) using the best approximation given - that each basis application has a finite ``basis_fidelity``. + r"""Decompose a two-qubit ``unitary`` over fixed basis and :math:`SU(2)` using the best + approximation given that each basis application has a finite ``basis_fidelity``. Args: - unitary (Operator or ndarray): 4x4 unitary to synthesize. + unitary (Operator or ndarray): :math:`4 \times 4` unitary to synthesize. basis_fidelity (float or None): Fidelity to be assumed for applications of KAK Gate. - If given, overrides basis_fidelity given at init. + If given, overrides ``basis_fidelity`` given at init. approximate (bool): Approximates if basis fidelities are less than 1.0. _num_basis_uses (int): force a particular approximation by passing a number in [0, 3]. + Returns: - QuantumCircuit: Synthesized circuit. + QuantumCircuit: Synthesized quantum circuit. + Raises: - QiskitError: if pulse_optimize is True but we don't know how to do it. + QiskitError: if ``pulse_optimize`` is True but we don't know how to do it. """ basis_fidelity = basis_fidelity or self.basis_fidelity if approximate is False: diff --git a/qiskit/synthesis/two_qubit/xx_decompose/decomposer.py b/qiskit/synthesis/two_qubit/xx_decompose/decomposer.py index 67690447e4cb..54a7b3b8da4f 100644 --- a/qiskit/synthesis/two_qubit/xx_decompose/decomposer.py +++ b/qiskit/synthesis/two_qubit/xx_decompose/decomposer.py @@ -64,7 +64,7 @@ class XXDecomposer: euler_basis: Basis string provided to :class:`.OneQubitEulerDecomposer` for 1Q synthesis. Defaults to ``"U"``. embodiments: A dictionary mapping interaction strengths alpha to native circuits which - embody the gate :math:`CAN(\alpha, 0, 0)`. Strengths are taken so that :math:`pi/2` + embody the gate :math:`CAN(\alpha, 0, 0)`. Strengths are taken so that :math:`\pi/2` represents the class of a full :class:`.CXGate`. backup_optimizer: If supplied, defers synthesis to this callable when :class:`.XXDecomposer` has no efficient decomposition of its own. Useful for special cases involving 2 or 3 @@ -74,6 +74,8 @@ class XXDecomposer: .. note:: If ``embodiments`` is not passed, or if an entry is missing, it will be populated as needed using the method ``_default_embodiment``. + + .. automethod:: __call__ """ def __init__( @@ -229,21 +231,22 @@ def __call__( basis_fidelity: dict | float | None = None, approximate: bool = True, ) -> QuantumCircuit: - """ - Fashions a circuit which (perhaps `approximate`ly) models the special unitary operation - `unitary`, using the circuit templates supplied at initialization as `embodiments`. The - routine uses `basis_fidelity` to select the optimal circuit template, including when - performing exact synthesis; the contents of `basis_fidelity` is a dictionary mapping - interaction strengths (scaled so that CX = RZX(pi/2) corresponds to pi/2) to circuit - fidelities. + r""" + Fashions a circuit which (perhaps approximately) models the special unitary operation + ``unitary``, using the circuit templates supplied at initialization as ``embodiments``. The + routine uses ``basis_fidelity`` to select the optimal circuit template, including when + performing exact synthesis; the contents of ``basis_fidelity`` is a dictionary mapping + interaction strengths (scaled so that :math:`CX = RZX(\pi/2)` corresponds to :math:`\pi/2`) + to circuit fidelities. Args: - unitary (Operator or ndarray): 4x4 unitary to synthesize. + unitary (Operator or ndarray): :math:`4 \times 4` unitary to synthesize. basis_fidelity (dict or float): Fidelity of basis gates. Can be either (1) a dictionary - mapping XX angle values to fidelity at that angle; or (2) a single float f, - interpreted as {pi: f, pi/2: f/2, pi/3: f/3}. + mapping ``XX`` angle values to fidelity at that angle; or (2) a single float ``f``, + interpreted as ``{pi: f, pi/2: f/2, pi/3: f/3}``. If given, overrides the basis_fidelity given at init. approximate (bool): Approximates if basis fidelities are less than 1.0 . + Returns: QuantumCircuit: Synthesized circuit. """