Skip to content

Commit

Permalink
Merge branch 'main' into circuit-data-accessible
Browse files Browse the repository at this point in the history
  • Loading branch information
raynelfss authored Jul 11, 2024
2 parents 544c82a + 99032fc commit 95de51a
Show file tree
Hide file tree
Showing 30 changed files with 674 additions and 129 deletions.
5 changes: 5 additions & 0 deletions crates/circuit/src/dag_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ impl DAGOpNode {
self.instruction.params.to_object(py)
}

#[setter]
fn set_params(&mut self, val: smallvec::SmallVec<[crate::operations::Param; 3]>) {
self.instruction.params = val;
}

pub fn is_parameterized(&self) -> bool {
self.instruction.is_parameterized()
}
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ sk = "qiskit.transpiler.passes.synthesis.solovay_kitaev_synthesis:SolovayKitaevS
"permutation.kms" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:KMSSynthesisPermutation"
"permutation.basic" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:BasicSynthesisPermutation"
"permutation.acg" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:ACGSynthesisPermutation"
"qft.full" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull"
"qft.line" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisLine"
"qft.default" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:QFTSynthesisFull"
"permutation.token_swapper" = "qiskit.transpiler.passes.synthesis.high_level_synthesis:TokenSwapperSynthesisPermutation"

[project.entry-points."qiskit.transpiler.init"]
Expand Down
7 changes: 4 additions & 3 deletions qiskit/circuit/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,12 @@ def __eq__(self, other):
return False

for self_param, other_param in zip_longest(self.params, other.params):
try:
if isinstance(self_param, numpy.ndarray):
if numpy.array_equal(self_param, other_param):
continue
else:
if self_param == other_param:
continue
except ValueError:
pass

try:
self_asarray = numpy.asarray(self_param)
Expand Down
3 changes: 2 additions & 1 deletion qiskit/circuit/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
:template: autosummary/class_no_inherited_members.rst
QFT
QFTGate
Arithmetic Circuits
===================
Expand Down Expand Up @@ -523,7 +524,7 @@
XOR,
InnerProduct,
)
from .basis_change import QFT
from .basis_change import QFT, QFTGate
from .arithmetic import (
FunctionalPauliRotations,
LinearPauliRotations,
Expand Down
2 changes: 1 addition & 1 deletion qiskit/circuit/library/basis_change/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@

"""The basis change circuits."""

from .qft import QFT
from .qft import QFT, QFTGate
46 changes: 40 additions & 6 deletions qiskit/circuit/library/basis_change/qft.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Quantum Fourier Transform Circuit."""
"""Define a Quantum Fourier Transform circuit (QFT) and a native gate (QFTGate)."""

from typing import Optional
from __future__ import annotations
import warnings
import numpy as np

from qiskit.circuit import QuantumCircuit, QuantumRegister, CircuitInstruction

from qiskit.circuit.quantumcircuit import QuantumCircuit, QuantumRegister, CircuitInstruction, Gate
from ..blueprintcircuit import BlueprintCircuit


Expand Down Expand Up @@ -75,12 +74,12 @@ class QFT(BlueprintCircuit):

def __init__(
self,
num_qubits: Optional[int] = None,
num_qubits: int | None = None,
approximation_degree: int = 0,
do_swaps: bool = True,
inverse: bool = False,
insert_barriers: bool = False,
name: Optional[str] = None,
name: str | None = None,
) -> None:
"""Construct a new QFT circuit.
Expand Down Expand Up @@ -293,3 +292,38 @@ def _build(self) -> None:

wrapped = circuit.to_instruction() if self.insert_barriers else circuit.to_gate()
self.compose(wrapped, qubits=self.qubits, inplace=True)


class QFTGate(Gate):
r"""Quantum Fourier Transform Gate.
The Quantum Fourier Transform (QFT) on :math:`n` qubits is the operation
.. math::
|j\rangle \mapsto \frac{1}{2^{n/2}} \sum_{k=0}^{2^n - 1} e^{2\pi ijk / 2^n} |k\rangle
"""

def __init__(
self,
num_qubits: int,
):
"""
Args:
num_qubits: The number of qubits on which the QFT acts.
"""
super().__init__(name="qft", num_qubits=num_qubits, params=[])

def __array__(self, dtype=complex):
"""Return a numpy array for the QFTGate."""
n = self.num_qubits
nums = np.arange(2**n)
outer = np.outer(nums, nums)
return np.exp(2j * np.pi * outer * (0.5**n), dtype=dtype) * (0.5 ** (n / 2))

def _define(self):
"""Provide a specific decomposition of the QFTGate into a quantum circuit."""
from qiskit.synthesis.qft import synth_qft_full

self.definition = synth_qft_full(num_qubits=self.num_qubits)
6 changes: 4 additions & 2 deletions qiskit/circuit/random/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from qiskit.circuit import Reset
from qiskit.circuit.library import standard_gates
from qiskit.circuit.exceptions import CircuitError
from qiskit.quantum_info.operators.symplectic.clifford_circuits import _BASIS_1Q, _BASIS_2Q


def random_circuit(
Expand Down Expand Up @@ -312,8 +313,9 @@ def random_clifford_circuit(num_qubits, num_gates, gates="all", seed=None):
QuantumCircuit: constructed circuit
"""

gates_1q = ["i", "x", "y", "z", "h", "s", "sdg", "sx", "sxdg"]
gates_2q = ["cx", "cz", "cy", "swap", "iswap", "ecr", "dcx"]
gates_1q = list(set(_BASIS_1Q.keys()) - {"v", "w", "id", "iden", "sinv"})
gates_2q = list(_BASIS_2Q.keys())

if gates == "all":
if num_qubits == 1:
gates = gates_1q
Expand Down
4 changes: 1 addition & 3 deletions qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1986,9 +1986,7 @@ def remove_op_node(self, node):
"node type was wrongly provided."
)

self._multi_graph.remove_node_retain_edges(
node._node_id, use_outgoing=False, condition=lambda edge1, edge2: edge1 == edge2
)
self._multi_graph.remove_node_retain_edges_by_id(node._node_id)
self._decrement_op(node.name)

def remove_ancestors_of(self, node):
Expand Down
63 changes: 44 additions & 19 deletions qiskit/providers/fake_provider/generic_backend_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ def __init__(
calibrate_instructions: bool | InstructionScheduleMap | None = None,
dtm: float | None = None,
seed: int | None = None,
pulse_channels: bool = True,
noise_info: bool = True,
):
"""
Args:
Expand Down Expand Up @@ -159,6 +161,10 @@ def __init__(
None by default.
seed: Optional seed for generation of default values.
pulse_channels: If true, sets default pulse channel information on the backend.
noise_info: If true, associates gates and qubits with default noise information.
"""

super().__init__(
Expand All @@ -175,6 +181,10 @@ def __init__(
self._control_flow = control_flow
self._calibrate_instructions = calibrate_instructions
self._supported_gates = get_standard_gate_name_mapping()
self._noise_info = noise_info

if calibrate_instructions and not noise_info:
raise QiskitError("Must set parameter noise_info when calibrating instructions.")

if coupling_map is None:
self._coupling_map = CouplingMap().from_full(num_qubits)
Expand All @@ -198,7 +208,10 @@ def __init__(
self._basis_gates.append(name)

self._build_generic_target()
self._build_default_channels()
if pulse_channels:
self._build_default_channels()
else:
self.channels_map = {}

@property
def target(self):
Expand Down Expand Up @@ -340,22 +353,31 @@ def _build_generic_target(self):
"""
# the qubit properties are sampled from default ranges
properties = _QUBIT_PROPERTIES
self._target = Target(
description=f"Generic Target with {self._num_qubits} qubits",
num_qubits=self._num_qubits,
dt=properties["dt"],
qubit_properties=[
QubitProperties(
t1=self._rng.uniform(properties["t1"][0], properties["t1"][1]),
t2=self._rng.uniform(properties["t2"][0], properties["t2"][1]),
frequency=self._rng.uniform(
properties["frequency"][0], properties["frequency"][1]
),
)
for _ in range(self._num_qubits)
],
concurrent_measurements=[list(range(self._num_qubits))],
)
if not self._noise_info:
self._target = Target(
description=f"Generic Target with {self._num_qubits} qubits",
num_qubits=self._num_qubits,
dt=properties["dt"],
qubit_properties=None,
concurrent_measurements=[list(range(self._num_qubits))],
)
else:
self._target = Target(
description=f"Generic Target with {self._num_qubits} qubits",
num_qubits=self._num_qubits,
dt=properties["dt"],
qubit_properties=[
QubitProperties(
t1=self._rng.uniform(properties["t1"][0], properties["t1"][1]),
t2=self._rng.uniform(properties["t2"][0], properties["t2"][1]),
frequency=self._rng.uniform(
properties["frequency"][0], properties["frequency"][1]
),
)
for _ in range(self._num_qubits)
],
concurrent_measurements=[list(range(self._num_qubits))],
)

# Generate instruction schedule map with calibrations to add to target.
calibration_inst_map = None
Expand All @@ -380,8 +402,11 @@ def _build_generic_target(self):
f"Provided basis gate {name} needs more qubits than {self.num_qubits}, "
f"which is the size of the backend."
)
noise_params = self._get_noise_defaults(name, gate.num_qubits)
self._add_noisy_instruction_to_target(gate, noise_params, calibration_inst_map)
if self._noise_info:
noise_params = self._get_noise_defaults(name, gate.num_qubits)
self._add_noisy_instruction_to_target(gate, noise_params, calibration_inst_map)
else:
self._target.add_instruction(gate, properties=None, name=name)

if self._control_flow:
self._target.add_instruction(IfElseOp, name="if_else")
Expand Down
2 changes: 2 additions & 0 deletions qiskit/qpy/binary_io/circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ def _read_instruction(
"DiagonalGate",
}:
gate = gate_class(params)
elif gate_name == "QFTGate":
gate = gate_class(len(qargs), *params)
else:
if gate_name == "Barrier":
params = [len(qargs)]
Expand Down
20 changes: 11 additions & 9 deletions qiskit/quantum_info/operators/symplectic/pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class Pauli(BasePauli):
An :math:`n`-qubit Pauli may be represented by a string consisting of
:math:`n` characters from ``['I', 'X', 'Y', 'Z']``, and optionally phase
coefficient in :math:`['', '-i', '-', 'i']`. For example: ``XYZ`` or
coefficient in ``['', '-i', '-', 'i']``. For example: ``'XYZ'`` or
``'-iZIZ'``.
In the string representation qubit-0 corresponds to the right-most
Expand Down Expand Up @@ -160,21 +160,23 @@ class initialization (``Pauli('-iXYZ')``). A ``Pauli`` object can be
_CANONICAL_PHASE_LABEL = {"": 0, "-i": 1, "-": 2, "i": 3}

def __init__(self, data: str | tuple | Pauli | ScalarOp | QuantumCircuit | None = None):
"""Initialize the Pauli.
r"""Initialize the Pauli.
When using the symplectic array input data both z and x arguments must
be provided, however the first (z) argument can be used alone for string
label, Pauli operator, or ScalarOp input data.
label, Pauli operator, or :class:`.ScalarOp` input data.
Args:
data (str or tuple or Pauli or ScalarOp): input data for Pauli. If input is
a tuple it must be of the form ``(z, x)`` or (z, x, phase)`` where
``z`` and ``x`` are boolean Numpy arrays, and phase is an integer from Z_4.
a tuple it must be of the form ``(z, x)`` or ``(z, x, phase)`` where
``z`` and ``x`` are boolean Numpy arrays, and phase is an integer from
:math:`\mathbb{Z}_4`.
If input is a string, it must be a concatenation of a phase and a Pauli string
(e.g. 'XYZ', '-iZIZ') where a phase string is a combination of at most three
characters from ['+', '-', ''], ['1', ''], and ['i', 'j', ''] in this order,
e.g. '', '-1j' while a Pauli string is 1 or more characters of 'I', 'X', 'Y' or 'Z',
e.g. 'Z', 'XIYY'.
(e.g. ``'XYZ', '-iZIZ'``) where a phase string is a combination of at most three
characters from ``['+', '-', '']``, ``['1', '']``, and ``['i', 'j', '']`` in this order,
e.g. ``''``, ``'-1j'`` while a Pauli string is 1 or more
characters of ``'I'``, ``'X'``, ``'Y'``, or ``'Z'``,
e.g. ``'Z'``, ``'XIYY'``.
Raises:
QiskitError: if input array is invalid shape.
Expand Down
3 changes: 2 additions & 1 deletion qiskit/synthesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
======================
.. autofunction:: synth_qft_line
.. autofunction:: synth_qft_full
Unitary Synthesis
=================
Expand Down Expand Up @@ -162,7 +163,7 @@
synth_circuit_from_stabilizers,
)
from .discrete_basis import SolovayKitaevDecomposition, generate_basic_approximations
from .qft import synth_qft_line
from .qft import synth_qft_line, synth_qft_full
from .unitary.qsd import qs_decomposition
from .unitary import aqc
from .one_qubit import OneQubitEulerDecomposer
Expand Down
1 change: 1 addition & 0 deletions qiskit/synthesis/qft/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
"""Module containing stabilizer QFT circuit synthesis."""

from .qft_decompose_lnn import synth_qft_line
from .qft_decompose_full import synth_qft_full
Loading

0 comments on commit 95de51a

Please sign in to comment.