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 authored Aug 10, 2024
2 parents d12dee6 + 6aa933c commit bc9c83f
Show file tree
Hide file tree
Showing 26 changed files with 341 additions and 187 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ ndarray = "^0.15.6"
numpy = "0.21.0"
smallvec = "1.13"
thiserror = "1.0"
ahash = "0.8.11"

# Most of the crates don't need the feature `extension-module`, since only `qiskit-pyext` builds an
# actual C extension (the feature disables linking in `libpython`, which is forbidden in Python
Expand Down
2 changes: 1 addition & 1 deletion crates/accelerate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ numpy.workspace = true
rand = "0.8"
rand_pcg = "0.3"
rand_distr = "0.4.3"
ahash = "0.8.11"
ahash.workspace = true
num-traits = "0.2"
num-complex.workspace = true
num-bigint.workspace = true
Expand Down
5 changes: 3 additions & 2 deletions crates/accelerate/src/synthesis/clifford/greedy_synthesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

use ahash::RandomState;
use indexmap::IndexSet;
use ndarray::{s, ArrayView2};
use smallvec::smallvec;
Expand Down Expand Up @@ -102,7 +103,7 @@ pub struct GreedyCliffordSynthesis<'a> {
symplectic_matrix: SymplecticMatrix,

/// Unprocessed qubits.
unprocessed_qubits: IndexSet<usize>,
unprocessed_qubits: IndexSet<usize, RandomState>,
}

impl GreedyCliffordSynthesis<'_> {
Expand All @@ -121,7 +122,7 @@ impl GreedyCliffordSynthesis<'_> {
smat: tableau.slice(s![.., 0..2 * num_qubits]).to_owned(),
};

let unprocessed_qubits: IndexSet<usize> = (0..num_qubits).collect();
let unprocessed_qubits = (0..num_qubits).collect();

Ok(GreedyCliffordSynthesis {
tableau,
Expand Down
4 changes: 2 additions & 2 deletions crates/accelerate/src/target_transpiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ impl Target {
match instruction {
TargetOperation::Variadic(_) => {
qargs_val = PropsMap::with_capacity(1);
qargs_val.extend([(None, None)].into_iter());
qargs_val.extend([(None, None)]);
self.variable_class_operations.insert(name.to_string());
}
TargetOperation::Normal(_) => {
Expand Down Expand Up @@ -872,7 +872,7 @@ impl Target {
.unwrap()
.extract::<GateMapState>()?
.into_iter()
.map(|(name, prop_map)| (name, PropsMap::from_iter(prop_map.into_iter()))),
.map(|(name, prop_map)| (name, PropsMap::from_iter(prop_map))),
);
self._gate_name_map = state
.get_item("gate_name_map")?
Expand Down
10 changes: 3 additions & 7 deletions crates/accelerate/src/target_transpiler/nullable_index_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ where
pub fn iter(&self) -> Iter<K, V> {
Iter {
map: self.map.iter(),
null_value: &self.null_val,
null_value: self.null_val.as_ref(),
}
}

Expand Down Expand Up @@ -209,7 +209,7 @@ where
/// Iterator for the key-value pairs in `NullableIndexMap`.
pub struct Iter<'a, K, V> {
map: BaseIter<'a, K, V>,
null_value: &'a Option<V>,
null_value: Option<&'a V>,
}

impl<'a, K, V> Iterator for Iter<'a, K, V> {
Expand All @@ -218,12 +218,8 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> {
fn next(&mut self) -> Option<Self::Item> {
if let Some((key, val)) = self.map.next() {
Some((Some(key), val))
} else if let Some(value) = self.null_value {
let value = value;
self.null_value = &None;
Some((None, value))
} else {
None
self.null_value.take().map(|value| (None, value))
}
}

Expand Down
90 changes: 41 additions & 49 deletions crates/accelerate/src/two_qubit_decompose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,6 @@ impl Specialization {
}
}

type WeylCircuitSequence = Vec<(StandardGate, SmallVec<[Param; 3]>, SmallVec<[Qubit; 2]>)>;

#[derive(Clone, Debug)]
#[allow(non_snake_case)]
#[pyclass(module = "qiskit._accelerate.two_qubit_decompose", subclass)]
Expand Down Expand Up @@ -430,56 +428,49 @@ impl TwoQubitWeylDecomposition {
fn weyl_gate(
&self,
simplify: bool,
sequence: &mut WeylCircuitSequence,
sequence: &mut CircuitData,
atol: f64,
global_phase: &mut f64,
) {
) -> PyResult<()> {
match self.specialization {
Specialization::MirrorControlledEquiv => {
sequence.push((
StandardGate::SwapGate,
SmallVec::new(),
smallvec![Qubit(0), Qubit(1)],
));
sequence.push((
sequence.push_standard_gate(StandardGate::SwapGate, &[], &[Qubit(0), Qubit(1)])?;
sequence.push_standard_gate(
StandardGate::RZZGate,
smallvec![Param::Float((PI4 - self.c) * 2.)],
smallvec![Qubit(0), Qubit(1)],
));
&[Param::Float((PI4 - self.c) * 2.)],
&[Qubit(0), Qubit(1)],
)?;
*global_phase += PI4
}
Specialization::SWAPEquiv => {
sequence.push((
StandardGate::SwapGate,
SmallVec::new(),
smallvec![Qubit(0), Qubit(1)],
));
sequence.push_standard_gate(StandardGate::SwapGate, &[], &[Qubit(0), Qubit(1)])?;
*global_phase -= 3. * PI / 4.
}
_ => {
if !simplify || self.a.abs() > atol {
sequence.push((
sequence.push_standard_gate(
StandardGate::RXXGate,
smallvec![Param::Float(-self.a * 2.)],
smallvec![Qubit(0), Qubit(1)],
));
&[Param::Float(-self.a * 2.)],
&[Qubit(0), Qubit(1)],
)?;
}
if !simplify || self.b.abs() > atol {
sequence.push((
sequence.push_standard_gate(
StandardGate::RYYGate,
smallvec![Param::Float(-self.b * 2.)],
smallvec![Qubit(0), Qubit(1)],
));
&[Param::Float(-self.b * 2.)],
&[Qubit(0), Qubit(1)],
)?;
}
if !simplify || self.c.abs() > atol {
sequence.push((
sequence.push_standard_gate(
StandardGate::RZZGate,
smallvec![Param::Float(-self.c * 2.)],
smallvec![Qubit(0), Qubit(1)],
));
&[Param::Float(-self.c * 2.)],
&[Qubit(0), Qubit(1)],
)?;
}
}
}
Ok(())
}

/// Instantiate a new TwoQubitWeylDecomposition with rust native
Expand Down Expand Up @@ -1070,7 +1061,7 @@ impl TwoQubitWeylDecomposition {
};
let target_1q_basis_list: Vec<EulerBasis> = vec![euler_basis];

let mut gate_sequence: WeylCircuitSequence = Vec::with_capacity(21);
let mut gate_sequence = CircuitData::with_capacity(py, 2, 0, 21, Param::Float(0.))?;
let mut global_phase: f64 = self.global_phase;

let c2r = unitary_to_gate_sequence_inner(
Expand All @@ -1083,11 +1074,11 @@ impl TwoQubitWeylDecomposition {
)
.unwrap();
for gate in c2r.gates {
gate_sequence.push((
gate_sequence.push_standard_gate(
gate.0,
gate.1.into_iter().map(Param::Float).collect(),
smallvec![Qubit(0)],
))
&gate.1.into_iter().map(Param::Float).collect::<Vec<_>>(),
&[Qubit(0)],
)?
}
global_phase += c2r.global_phase;
let c2l = unitary_to_gate_sequence_inner(
Expand All @@ -1100,19 +1091,19 @@ impl TwoQubitWeylDecomposition {
)
.unwrap();
for gate in c2l.gates {
gate_sequence.push((
gate_sequence.push_standard_gate(
gate.0,
gate.1.into_iter().map(Param::Float).collect(),
smallvec![Qubit(1)],
))
&gate.1.into_iter().map(Param::Float).collect::<Vec<_>>(),
&[Qubit(1)],
)?
}
global_phase += c2l.global_phase;
self.weyl_gate(
simplify,
&mut gate_sequence,
atol.unwrap_or(ANGLE_ZERO_EPSILON),
&mut global_phase,
);
)?;
let c1r = unitary_to_gate_sequence_inner(
self.K1r.view(),
&target_1q_basis_list,
Expand All @@ -1123,11 +1114,11 @@ impl TwoQubitWeylDecomposition {
)
.unwrap();
for gate in c1r.gates {
gate_sequence.push((
gate_sequence.push_standard_gate(
gate.0,
gate.1.into_iter().map(Param::Float).collect(),
smallvec![Qubit(0)],
))
&gate.1.into_iter().map(Param::Float).collect::<Vec<_>>(),
&[Qubit(0)],
)?
}
global_phase += c2r.global_phase;
let c1l = unitary_to_gate_sequence_inner(
Expand All @@ -1140,13 +1131,14 @@ impl TwoQubitWeylDecomposition {
)
.unwrap();
for gate in c1l.gates {
gate_sequence.push((
gate_sequence.push_standard_gate(
gate.0,
gate.1.into_iter().map(Param::Float).collect(),
smallvec![Qubit(1)],
))
&gate.1.into_iter().map(Param::Float).collect::<Vec<_>>(),
&[Qubit(1)],
)?
}
CircuitData::from_standard_gates(py, 2, gate_sequence, Param::Float(global_phase))
gate_sequence.set_global_phase(py, Param::Float(global_phase))?;
Ok(gate_sequence)
}
}

Expand Down
88 changes: 72 additions & 16 deletions crates/circuit/src/circuit_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::cell::RefCell;

use crate::bit_data::BitData;
use crate::circuit_instruction::{CircuitInstruction, OperationFromPython};
use crate::imports::{ANNOTATED_OPERATION, QUANTUM_CIRCUIT, QUBIT};
use crate::imports::{ANNOTATED_OPERATION, CLBIT, QUANTUM_CIRCUIT, QUBIT};
use crate::interner::{IndexedInterner, Interner, InternerKey};
use crate::operations::{Operation, OperationRef, Param, StandardGate};
use crate::packed_instruction::PackedInstruction;
Expand Down Expand Up @@ -131,22 +131,13 @@ impl CircuitData {
I: IntoIterator<Item = (StandardGate, SmallVec<[Param; 3]>, SmallVec<[Qubit; 2]>)>,
{
let instruction_iter = instructions.into_iter();
let mut res = CircuitData {
data: Vec::with_capacity(instruction_iter.size_hint().0),
qargs_interner: IndexedInterner::new(),
cargs_interner: IndexedInterner::new(),
qubits: BitData::new(py, "qubits".to_string()),
clbits: BitData::new(py, "clbits".to_string()),
param_table: ParameterTable::new(),
let mut res = Self::with_capacity(
py,
num_qubits,
0,
instruction_iter.size_hint().0,
global_phase,
};
if num_qubits > 0 {
let qubit_cls = QUBIT.get_bound(py);
for _i in 0..num_qubits {
let bit = qubit_cls.call0()?;
res.add_qubit(py, &bit, true)?;
}
}
)?;
let no_clbit_index = (&mut res.cargs_interner)
.intern(InternerKey::Value(Vec::new()))?
.index;
Expand All @@ -169,6 +160,66 @@ impl CircuitData {
Ok(res)
}

/// Build an empty CircuitData object with an initially allocated instruction capacity
pub fn with_capacity(
py: Python,
num_qubits: u32,
num_clbits: u32,
instruction_capacity: usize,
global_phase: Param,
) -> PyResult<Self> {
let mut res = CircuitData {
data: Vec::with_capacity(instruction_capacity),
qargs_interner: IndexedInterner::new(),
cargs_interner: IndexedInterner::new(),
qubits: BitData::new(py, "qubits".to_string()),
clbits: BitData::new(py, "clbits".to_string()),
param_table: ParameterTable::new(),
global_phase,
};
if num_qubits > 0 {
let qubit_cls = QUBIT.get_bound(py);
for _i in 0..num_qubits {
let bit = qubit_cls.call0()?;
res.add_qubit(py, &bit, true)?;
}
}
if num_clbits > 0 {
let clbit_cls = CLBIT.get_bound(py);
for _i in 0..num_clbits {
let bit = clbit_cls.call0()?;
res.add_clbit(py, &bit, true)?;
}
}
Ok(res)
}

/// Append a standard gate to this CircuitData
pub fn push_standard_gate(
&mut self,
operation: StandardGate,
params: &[Param],
qargs: &[Qubit],
) -> PyResult<()> {
let no_clbit_index = (&mut self.cargs_interner)
.intern(InternerKey::Value(Vec::new()))?
.index;
let params = (!params.is_empty()).then(|| Box::new(params.iter().cloned().collect()));
let qubits = (&mut self.qargs_interner)
.intern(InternerKey::Value(qargs.to_vec()))?
.index;
self.data.push(PackedInstruction {
op: operation.into(),
qubits,
clbits: no_clbit_index,
params,
extra_attrs: None,
#[cfg(feature = "cache_pygates")]
py_op: RefCell::new(None),
});
Ok(())
}

/// Add the entries from the `PackedInstruction` at the given index to the internal parameter
/// table.
fn track_instruction_parameters(
Expand Down Expand Up @@ -1233,6 +1284,11 @@ impl CircuitData {
}
Ok(())
}

/// Retrieves the python `Param` object based on its `ParameterUuid`.
pub fn get_parameter_by_uuid(&self, uuid: ParameterUuid) -> Option<&Py<PyAny>> {
self.param_table.py_parameter_by_uuid(uuid)
}
}

/// Helper struct for `assign_parameters` to allow use of `Param::extract_no_coerce` in
Expand Down
Loading

0 comments on commit bc9c83f

Please sign in to comment.