Skip to content

Commit

Permalink
Add: Make Target Representable in Rust
Browse files Browse the repository at this point in the history
- Rename `InstructionProperties` as `BaseInstructionProperties`.
   - Remove `Calibration` from the rust space.
- Restore `gate_map`, `coupling_map`, `instruction_schedule_map`, and `instruction_durations` to rust.
- Remove all unnecessary data structures from rust space.
- Other tweaks and fixes.
  • Loading branch information
raynelfss committed May 28, 2024
1 parent 6e2742d commit 1e0f9c0
Show file tree
Hide file tree
Showing 6 changed files with 940 additions and 1,768 deletions.
178 changes: 0 additions & 178 deletions crates/accelerate/src/target_transpiler/gate_map.rs

This file was deleted.

118 changes: 11 additions & 107 deletions crates/accelerate/src/target_transpiler/instruction_properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

use pyo3::{
prelude::*,
pyclass,
types::{IntoPyDict, PyType},
};
use pyo3::{prelude::*, pyclass};

/**
A representation of the properties of a gate implementation.
Expand All @@ -27,18 +23,16 @@ custom attributes for those custom/additional properties by the backend.
*/
#[pyclass(subclass, module = "qiskit._accelerate.target")]
#[derive(Clone, Debug)]
pub struct InstructionProperties {
pub struct BaseInstructionProperties {
#[pyo3(get, set)]
pub duration: Option<f64>,
#[pyo3(get, set)]
pub error: Option<f64>,
#[pyo3(get)]
pub _calibration: PyObject,
}

#[pymethods]
impl InstructionProperties {
/// Create a new ``InstructionProperties`` object
impl BaseInstructionProperties {
/// Create a new ``BaseInstructionProperties`` object
///
/// Args:
/// duration (Option<f64>): The duration, in seconds, of the instruction on the
Expand All @@ -47,102 +41,26 @@ impl InstructionProperties {
/// set of qubits.
/// calibration (Option<PyObject>): The pulse representation of the instruction.
#[new]
#[pyo3(text_signature = "(/, duration: float | None = None,
error: float | None = None,
calibration: Schedule | ScheduleBlock | CalibrationEntry | None = None,)")]
pub fn new(
py: Python<'_>,
duration: Option<f64>,
error: Option<f64>,
calibration: Option<Bound<PyAny>>,
) -> Self {
let mut instruction_prop = InstructionProperties {
error,
duration,
_calibration: py.None(),
};
if let Some(calibration) = calibration {
let _ = instruction_prop.set_calibration(py, calibration);
}
instruction_prop
}

/// The pulse representation of the instruction.
///
/// .. note::
///
/// This attribute always returns a Qiskit pulse program, but it is internally
/// wrapped by the :class:`.CalibrationEntry` to manage unbound parameters
/// and to uniformly handle different data representation,
/// for example, un-parsed Pulse Qobj JSON that a backend provider may provide.
///
/// This value can be overridden through the property setter in following manner.
/// When you set either :class:`.Schedule` or :class:`.ScheduleBlock` this is
/// always treated as a user-defined (custom) calibration and
/// the transpiler may automatically attach the calibration data to the output circuit.
/// This calibration data may appear in the wire format as an inline calibration,
/// which may further update the backend standard instruction set architecture.
///
/// If you are a backend provider who provides a default calibration data
/// that is not needed to be attached to the transpiled quantum circuit,
/// you can directly set :class:`.CalibrationEntry` instance to this attribute,
/// in which you should set :code:`user_provided=False` when you define
/// calibration data for the entry. End users can still intentionally utilize
/// the calibration data, for example, to run pulse-level simulation of the circuit.
/// However, such entry doesn't appear in the wire format, and backend must
/// use own definition to compile the circuit down to the execution format.
#[getter]
pub fn get_calibration(&self, py: Python<'_>) -> PyResult<PyObject> {
if !&self._calibration.is_none(py) {
return self._calibration.call_method0(py, "get_schedule");
}
Ok(py.None())
#[pyo3(signature = (duration=None, error=None))]
pub fn new(_py: Python<'_>, duration: Option<f64>, error: Option<f64>) -> Self {
Self { error, duration }
}

#[setter]
pub fn set_calibration(&mut self, py: Python<'_>, calibration: Bound<PyAny>) -> PyResult<()> {
let module = py.import_bound("qiskit.pulse.schedule")?;
// Import Schedule and ScheduleBlock types.
let schedule_type = module.getattr("Schedule")?;
let schedule_type = schedule_type.downcast::<PyType>()?;
let schedule_block_type = module.getattr("ScheduleBlock")?;
let schedule_block_type = schedule_block_type.downcast::<PyType>()?;
if calibration.is_instance(schedule_block_type)?
|| calibration.is_instance(schedule_type)?
{
// Import the calibration_entries module
let calibration_entries = py.import_bound("qiskit.pulse.calibration_entries")?;
// Import the schedule def class.
let schedule_def = calibration_entries.getattr("ScheduleDef")?;
// Create a ScheduleDef instance.
let new_entry: Bound<PyAny> = schedule_def.call0()?;
// Definethe schedule, make sure it is user provided.
let args = (calibration,);
let kwargs = [("user_provided", true)].into_py_dict_bound(py);
new_entry.call_method("define", args, Some(&kwargs))?;
self._calibration = new_entry.unbind();
} else {
self._calibration = calibration.unbind();
}
Ok(())
}

fn __getstate__(&self) -> PyResult<(Option<f64>, Option<f64>, Option<&PyObject>)> {
Ok((self.duration, self.error, Some(&self._calibration)))
fn __getstate__(&self) -> PyResult<(Option<f64>, Option<f64>)> {
Ok((self.duration, self.error))
}

fn __setstate__(
&mut self,
py: Python<'_>,
_py: Python<'_>,
state: (Option<f64>, Option<f64>, Bound<PyAny>),
) -> PyResult<()> {
self.duration = state.0;
self.error = state.1;
self.set_calibration(py, state.2)?;
Ok(())
}

fn __repr__(&self, py: Python<'_>) -> PyResult<String> {
fn __repr__(&self, _py: Python<'_>) -> PyResult<String> {
let mut output = "InstructionProperties(".to_owned();
if let Some(duration) = self.duration {
output.push_str("duration=");
Expand All @@ -159,20 +77,6 @@ impl InstructionProperties {
} else {
output.push_str("error=None, ");
}

if !self.get_calibration(py)?.is_none(py) {
output.push_str(
format!(
"calibration={:?})",
self.get_calibration(py)?
.call_method0(py, "__str__")?
.extract::<String>(py)?
)
.as_str(),
);
} else {
output.push_str("calibration=None)");
}
Ok(output)
}
}
Loading

0 comments on commit 1e0f9c0

Please sign in to comment.