Skip to content

Commit

Permalink
Merge branch 'main' of github.com:Qiskit/qiskit-terra into fixes/12902/1
Browse files Browse the repository at this point in the history
  • Loading branch information
1ucian0 committed Aug 9, 2024
2 parents 7206dd5 + 20b51e6 commit f424a7e
Show file tree
Hide file tree
Showing 19 changed files with 320 additions and 183 deletions.
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
83 changes: 67 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
17 changes: 12 additions & 5 deletions qiskit/primitives/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

from qiskit.circuit import QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.quantum_info import Statevector
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.utils.deprecation import deprecate_func

Expand All @@ -31,7 +30,7 @@
from .utils import (
_circuit_key,
_observable_key,
bound_circuit_to_instruction,
_statevector_from_circuit,
init_observable,
)

Expand All @@ -43,13 +42,21 @@ class Estimator(BaseEstimator[PrimitiveJob[EstimatorResult]]):
:Run Options:
- **shots** (None or int) --
The number of shots. If None, it calculates the exact expectation
values. Otherwise, it samples from normal distributions with standard errors as standard
The number of shots. If None, it calculates the expectation values
with full state vector simulation.
Otherwise, it samples from normal distributions with standard errors as standard
deviations using normal distribution approximation.
- **seed** (np.random.Generator or int) --
Set a fixed seed or generator for the normal distribution. If shots is None,
this option is ignored.
.. note::
The result of this class is exact if the circuit contains only unitary operations.
On the other hand, the result could be stochastic if the circuit contains a non-unitary
operation such as a reset for a some subsystems.
The stochastic result can be made reproducible by setting ``seed``, e.g.,
``Estimator(options={"seed":123})``.
"""

@deprecate_func(
Expand Down Expand Up @@ -112,7 +119,7 @@ def _call(
f"The number of qubits of a circuit ({circ.num_qubits}) does not match "
f"the number of qubits of a observable ({obs.num_qubits})."
)
final_state = Statevector(bound_circuit_to_instruction(circ))
final_state = _statevector_from_circuit(circ, rng)
expectation_value = final_state.expectation_value(obs)
if shots is None:
expectation_values.append(expectation_value)
Expand Down
Loading

0 comments on commit f424a7e

Please sign in to comment.