Skip to content

Commit

Permalink
Merge branch 'main' into move-equivalence
Browse files Browse the repository at this point in the history
  • Loading branch information
raynelfss committed Sep 20, 2024
2 parents b7c6316 + 597f2b2 commit b8e7cff
Show file tree
Hide file tree
Showing 28 changed files with 1,020 additions and 156 deletions.
187 changes: 128 additions & 59 deletions .mailmap

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions crates/accelerate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,6 @@ features = ["ndarray"]
[dependencies.pulp]
version = "0.18.22"
features = ["macro"]

[features]
cache_pygates = ["qiskit-circuit/cache_pygates"]
9 changes: 7 additions & 2 deletions crates/accelerate/src/dense_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct SubsetResult {
pub error: f64,
pub map: Vec<usize>,
pub subgraph: Vec<[usize; 2]>,
pub index: usize,
}

fn bfs_sort(adj_matrix: ArrayView2<f64>, start: usize, num_qubits: usize) -> Vec<usize> {
Expand Down Expand Up @@ -190,6 +191,7 @@ pub fn best_subset_inner(
error,
map: bfs,
subgraph,
index: k,
}
};

Expand All @@ -199,17 +201,20 @@ pub fn best_subset_inner(
map: Vec::new(),
error: f64::INFINITY,
subgraph: Vec::new(),
index: usize::MAX,
}
};

let reduce_fn = |best: SubsetResult, curr: SubsetResult| -> SubsetResult {
if use_error {
if curr.count >= best.count && curr.error < best.error {
if (curr.count >= best.count && curr.error < best.error)
|| (curr.count == best.count && curr.error == best.error && curr.index < best.index)
{
curr
} else {
best
}
} else if curr.count > best.count {
} else if curr.count > best.count || (curr.count == best.count && curr.index < best.index) {
curr
} else {
best
Expand Down
53 changes: 47 additions & 6 deletions crates/circuit/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use approx::relative_eq;
use std::f64::consts::PI;
use std::vec;

use crate::circuit_data::CircuitData;
use crate::circuit_instruction::ExtraInstructionAttributes;
Expand Down Expand Up @@ -163,6 +164,7 @@ pub trait Operation {
fn num_clbits(&self) -> u32;
fn num_params(&self) -> u32;
fn control_flow(&self) -> bool;
fn blocks(&self) -> Vec<CircuitData>;
fn matrix(&self, params: &[Param]) -> Option<Array2<Complex64>>;
fn definition(&self, params: &[Param]) -> Option<CircuitData>;
fn standard_gate(&self) -> Option<StandardGate>;
Expand Down Expand Up @@ -228,6 +230,15 @@ impl<'a> Operation for OperationRef<'a> {
}
}
#[inline]
fn blocks(&self) -> Vec<CircuitData> {
match self {
OperationRef::Standard(standard) => standard.blocks(),
OperationRef::Gate(gate) => gate.blocks(),
OperationRef::Instruction(instruction) => instruction.blocks(),
OperationRef::Operation(operation) => operation.blocks(),
}
}
#[inline]
fn matrix(&self, params: &[Param]) -> Option<Array2<Complex64>> {
match self {
Self::Standard(standard) => standard.matrix(params),
Expand Down Expand Up @@ -530,20 +541,20 @@ impl Operation for StandardGate {
STANDARD_GATE_NUM_QUBITS[*self as usize]
}

fn num_params(&self) -> u32 {
STANDARD_GATE_NUM_PARAMS[*self as usize]
}

fn num_clbits(&self) -> u32 {
0
}

fn num_params(&self) -> u32 {
STANDARD_GATE_NUM_PARAMS[*self as usize]
}

fn control_flow(&self) -> bool {
false
}

fn directive(&self) -> bool {
false
fn blocks(&self) -> Vec<CircuitData> {
vec![]
}

fn matrix(&self, params: &[Param]) -> Option<Array2<Complex64>> {
Expand Down Expand Up @@ -2043,6 +2054,10 @@ impl Operation for StandardGate {
fn standard_gate(&self) -> Option<StandardGate> {
Some(*self)
}

fn directive(&self) -> bool {
false
}
}

const FLOAT_ZERO: Param = Param::Float(0.0);
Expand Down Expand Up @@ -2145,6 +2160,26 @@ impl Operation for PyInstruction {
fn control_flow(&self) -> bool {
self.control_flow
}
fn blocks(&self) -> Vec<CircuitData> {
if !self.control_flow {
return vec![];
}
Python::with_gil(|py| -> Vec<CircuitData> {
// We expect that if PyInstruction::control_flow is true then the operation WILL
// have a 'blocks' attribute which is a tuple of the Python QuantumCircuit.
let raw_blocks = self.instruction.getattr(py, "blocks").unwrap();
let blocks: &Bound<PyTuple> = raw_blocks.downcast_bound::<PyTuple>(py).unwrap();
blocks
.iter()
.map(|b| {
b.getattr(intern!(py, "_data"))
.unwrap()
.extract::<CircuitData>()
.unwrap()
})
.collect()
})
}
fn matrix(&self, _params: &[Param]) -> Option<Array2<Complex64>> {
None
}
Expand Down Expand Up @@ -2211,6 +2246,9 @@ impl Operation for PyGate {
fn control_flow(&self) -> bool {
false
}
fn blocks(&self) -> Vec<CircuitData> {
vec![]
}
fn matrix(&self, _params: &[Param]) -> Option<Array2<Complex64>> {
Python::with_gil(|py| -> Option<Array2<Complex64>> {
match self.gate.getattr(py, intern!(py, "to_matrix")) {
Expand Down Expand Up @@ -2287,6 +2325,9 @@ impl Operation for PyOperation {
fn control_flow(&self) -> bool {
false
}
fn blocks(&self) -> Vec<CircuitData> {
vec![]
}
fn matrix(&self, _params: &[Param]) -> Option<Array2<Complex64>> {
None
}
Expand Down
4 changes: 4 additions & 0 deletions crates/circuit/src/packed_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@ impl Operation for PackedOperation {
self.view().control_flow()
}
#[inline]
fn blocks(&self) -> Vec<CircuitData> {
self.view().blocks()
}
#[inline]
fn matrix(&self, params: &[Param]) -> Option<Array2<Complex64>> {
self.view().matrix(params)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/pyext/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ crate-type = ["cdylib"]
# crates as standalone binaries, executables, we need `libpython` to be linked in, so we make the
# feature a default, and run `cargo test --no-default-features` to turn it off.
default = ["pyo3/extension-module"]
cache_pygates = ["pyo3/extension-module", "qiskit-circuit/cache_pygates"]
cache_pygates = ["pyo3/extension-module", "qiskit-circuit/cache_pygates", "qiskit-accelerate/cache_pygates"]

[dependencies]
pyo3.workspace = true
Expand Down
94 changes: 38 additions & 56 deletions crates/pyext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,6 @@

use pyo3::prelude::*;

use qiskit_accelerate::{
check_map::check_map_mod, circuit_library::circuit_library,
commutation_analysis::commutation_analysis, commutation_cancellation::commutation_cancellation,
commutation_checker::commutation_checker, convert_2q_block_matrix::convert_2q_block_matrix,
dense_layout::dense_layout, equivalence::equivalence, error_map::error_map,
euler_one_qubit_decomposer::euler_one_qubit_decomposer, filter_op_nodes::filter_op_nodes_mod,
gate_direction::gate_direction, inverse_cancellation::inverse_cancellation_mod,
isometry::isometry, nlayout::nlayout, optimize_1q_gates::optimize_1q_gates,
pauli_exp_val::pauli_expval,
remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, results::results,
sabre::sabre, sampled_exp_val::sampled_exp_val, sparse_pauli_op::sparse_pauli_op,
split_2q_unitaries::split_2q_unitaries_mod, star_prerouting::star_prerouting,
stochastic_swap::stochastic_swap, synthesis::synthesis, target_transpiler::target,
two_qubit_decompose::two_qubit_decompose, uc_gate::uc_gate, utils::utils,
vf2_layout::vf2_layout,
};

#[inline(always)]
#[doc(hidden)]
fn add_submodule<F>(m: &Bound<PyModule>, constructor: F, name: &str) -> PyResult<()>
Expand All @@ -40,46 +23,45 @@ where
m.add_submodule(&new_mod)
}

// Formatting is off here so every module import can just be a single line in sorted order, to help
// avoid merge conflicts as modules are added.
#[rustfmt::skip]
#[pymodule]
fn _accelerate(m: &Bound<PyModule>) -> PyResult<()> {
add_submodule(m, qiskit_circuit::circuit, "circuit")?;
add_submodule(m, qiskit_circuit::converters::converters, "converters")?;
add_submodule(m, qiskit_qasm2::qasm2, "qasm2")?;
add_submodule(m, qiskit_qasm3::qasm3, "qasm3")?;
add_submodule(m, circuit_library, "circuit_library")?;
add_submodule(m, check_map_mod, "check_map")?;
add_submodule(m, convert_2q_block_matrix, "convert_2q_block_matrix")?;
add_submodule(m, dense_layout, "dense_layout")?;
add_submodule(m, equivalence, "equivalence")?;
add_submodule(m, error_map, "error_map")?;
add_submodule(m, euler_one_qubit_decomposer, "euler_one_qubit_decomposer")?;
add_submodule(m, inverse_cancellation_mod, "inverse_cancellation")?;
add_submodule(m, filter_op_nodes_mod, "filter_op_nodes")?;
add_submodule(m, isometry, "isometry")?;
add_submodule(m, nlayout, "nlayout")?;
add_submodule(m, optimize_1q_gates, "optimize_1q_gates")?;
add_submodule(m, pauli_expval, "pauli_expval")?;
add_submodule(m, synthesis, "synthesis")?;
add_submodule(
m,
remove_diagonal_gates_before_measure,
"remove_diagonal_gates_before_measure",
)?;
add_submodule(m, results, "results")?;
add_submodule(m, sabre, "sabre")?;
add_submodule(m, sampled_exp_val, "sampled_exp_val")?;
add_submodule(m, sparse_pauli_op, "sparse_pauli_op")?;
add_submodule(m, split_2q_unitaries_mod, "split_2q_unitaries")?;
add_submodule(m, star_prerouting, "star_prerouting")?;
add_submodule(m, stochastic_swap, "stochastic_swap")?;
add_submodule(m, target, "target")?;
add_submodule(m, two_qubit_decompose, "two_qubit_decompose")?;
add_submodule(m, uc_gate, "uc_gate")?;
add_submodule(m, utils, "utils")?;
add_submodule(m, vf2_layout, "vf2_layout")?;
add_submodule(m, gate_direction, "gate_direction")?;
add_submodule(m, commutation_checker, "commutation_checker")?;
add_submodule(m, commutation_analysis, "commutation_analysis")?;
add_submodule(m, commutation_cancellation, "commutation_cancellation")?;
add_submodule(m, ::qiskit_accelerate::check_map::check_map_mod, "check_map")?;
add_submodule(m, ::qiskit_accelerate::circuit_library::circuit_library, "circuit_library")?;
add_submodule(m, ::qiskit_accelerate::commutation_analysis::commutation_analysis, "commutation_analysis")?;
add_submodule(m, ::qiskit_accelerate::commutation_cancellation::commutation_cancellation, "commutation_cancellation")?;
add_submodule(m, ::qiskit_accelerate::commutation_checker::commutation_checker, "commutation_checker")?;
add_submodule(m, ::qiskit_accelerate::convert_2q_block_matrix::convert_2q_block_matrix, "convert_2q_block_matrix")?;
add_submodule(m, ::qiskit_accelerate::dense_layout::dense_layout, "dense_layout")?;
add_submodule(m, ::qiskit_accelerate::equivalence::equivalence, "equivalence")?;
add_submodule(m, ::qiskit_accelerate::error_map::error_map, "error_map")?;
add_submodule(m, ::qiskit_accelerate::euler_one_qubit_decomposer::euler_one_qubit_decomposer, "euler_one_qubit_decomposer")?;
add_submodule(m, ::qiskit_accelerate::filter_op_nodes::filter_op_nodes_mod, "filter_op_nodes")?;
add_submodule(m, ::qiskit_accelerate::gate_direction::gate_direction, "gate_direction")?;
add_submodule(m, ::qiskit_accelerate::inverse_cancellation::inverse_cancellation_mod, "inverse_cancellation")?;
add_submodule(m, ::qiskit_accelerate::isometry::isometry, "isometry")?;
add_submodule(m, ::qiskit_accelerate::nlayout::nlayout, "nlayout")?;
add_submodule(m, ::qiskit_accelerate::optimize_1q_gates::optimize_1q_gates, "optimize_1q_gates")?;
add_submodule(m, ::qiskit_accelerate::pauli_exp_val::pauli_expval, "pauli_expval")?;
add_submodule(m, ::qiskit_accelerate::remove_diagonal_gates_before_measure::remove_diagonal_gates_before_measure, "remove_diagonal_gates_before_measure")?;
add_submodule(m, ::qiskit_accelerate::results::results, "results")?;
add_submodule(m, ::qiskit_accelerate::sabre::sabre, "sabre")?;
add_submodule(m, ::qiskit_accelerate::sampled_exp_val::sampled_exp_val, "sampled_exp_val")?;
add_submodule(m, ::qiskit_accelerate::sparse_pauli_op::sparse_pauli_op, "sparse_pauli_op")?;
add_submodule(m, ::qiskit_accelerate::split_2q_unitaries::split_2q_unitaries_mod, "split_2q_unitaries")?;
add_submodule(m, ::qiskit_accelerate::star_prerouting::star_prerouting, "star_prerouting")?;
add_submodule(m, ::qiskit_accelerate::stochastic_swap::stochastic_swap, "stochastic_swap")?;
add_submodule(m, ::qiskit_accelerate::synthesis::synthesis, "synthesis")?;
add_submodule(m, ::qiskit_accelerate::target_transpiler::target, "target")?;
add_submodule(m, ::qiskit_accelerate::two_qubit_decompose::two_qubit_decompose, "two_qubit_decompose")?;
add_submodule(m, ::qiskit_accelerate::uc_gate::uc_gate, "uc_gate")?;
add_submodule(m, ::qiskit_accelerate::utils::utils, "utils")?;
add_submodule(m, ::qiskit_accelerate::vf2_layout::vf2_layout, "vf2_layout")?;
add_submodule(m, ::qiskit_circuit::circuit, "circuit")?;
add_submodule(m, ::qiskit_circuit::converters::converters, "converters")?;
add_submodule(m, ::qiskit_qasm2::qasm2, "qasm2")?;
add_submodule(m, ::qiskit_qasm3::qasm3, "qasm3")?;
Ok(())
}
19 changes: 15 additions & 4 deletions crates/qasm3/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub trait PyRegister {
// or at a minimum
// fn iter<'a>(&'a self, py: Python<'a>) -> ::pyo3::types::iter::PyListIterator<'a>;
// but we can't use the former before Rust 1.75 and the latter before PyO3 0.21.
fn bit_list<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyList>;
fn bit_list<'a>(&'a self, py: Python<'a>) -> &'a Bound<'a, PyList>;
}

macro_rules! register_type {
Expand All @@ -38,7 +38,7 @@ macro_rules! register_type {
}

impl PyRegister for $name {
fn bit_list<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyList> {
fn bit_list<'a>(&'a self, py: Python<'a>) -> &'a Bound<'a, PyList> {
self.items.bind(py)
}
}
Expand All @@ -65,12 +65,23 @@ register_type!(PyClassicalRegister);

/// Information received from Python space about how to construct a Python-space object to
/// represent a given gate that might be declared.
#[pyclass(module = "qiskit._accelerate.qasm3", frozen, name = "CustomGate")]
#[pyclass(
module = "qiskit._accelerate.qasm3",
frozen,
name = "CustomGate",
get_all
)]
#[derive(Clone, Debug)]
pub struct PyGate {
/// A callable Python object that takes ``num_params`` angles as positional arguments, and
/// returns a :class:`~.circuit.Gate` object representing the gate.
constructor: Py<PyAny>,
/// The name of the gate as it appears in the OpenQASM 3 program. This is not necessarily
/// identical to the name that Qiskit gives the gate.
name: String,
/// The number of angle-like parameters the gate requires.
num_params: usize,
/// The number of qubits the gate acts on.
num_qubits: usize,
}

Expand Down Expand Up @@ -286,7 +297,7 @@ pub struct PyCircuit(Py<PyAny>);

impl PyCircuit {
/// Untyped access to the inner Python object.
pub fn inner<'a>(&'a self, py: Python<'a>) -> &Bound<'a, PyAny> {
pub fn inner<'a>(&'a self, py: Python<'a>) -> &'a Bound<'a, PyAny> {
self.0.bind(py)
}

Expand Down
4 changes: 2 additions & 2 deletions crates/qasm3/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use crate::error::QASM3ImporterError;
/// :class:`.QuantumCircuit`: the constructed circuit object.
///
/// Raises:
/// :class:`.QASM3ImporterError`: if an error occurred during parsing or semantic analysis.
/// :exc:`.QASM3ImporterError`: if an error occurred during parsing or semantic analysis.
/// In the case of a parsing error, most of the error messages are printed to the terminal
/// and formatted, for better legibility.
#[pyfunction]
Expand Down Expand Up @@ -120,7 +120,7 @@ pub fn loads(
/// :class:`.QuantumCircuit`: the constructed circuit object.
///
/// Raises:
/// :class:`.QASM3ImporterError`: if an error occurred during parsing or semantic analysis.
/// :exc:`.QASM3ImporterError`: if an error occurred during parsing or semantic analysis.
/// In the case of a parsing error, most of the error messages are printed to the terminal
/// and formatted, for better legibility.
#[pyfunction]
Expand Down
1 change: 1 addition & 0 deletions qiskit/qasm3/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
using the :class:`CustomGate` object:
.. autoclass:: CustomGate
:members:
In ``custom_gates`` is not given, Qiskit will attempt to use its standard-library gate objects for
the gates defined in OpenQASM 3 standard library file ``stdgates.inc``. This sequence of gates is
Expand Down
Loading

0 comments on commit b8e7cff

Please sign in to comment.