From 1170ce53b45ff1a54d8fe7c92b9d8fec177c27b0 Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Fri, 5 Apr 2024 12:55:21 +0100 Subject: [PATCH] refactor: Move `OpBox` to a new module --- src/circuit_json.rs | 179 +----------------------------------------- src/lib.rs | 4 + src/opbox.rs | 185 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 178 deletions(-) create mode 100644 src/opbox.rs diff --git a/src/circuit_json.rs b/src/circuit_json.rs index 77da8b0..9f90e1a 100644 --- a/src/circuit_json.rs +++ b/src/circuit_json.rs @@ -1,6 +1,7 @@ //! Contains structs for serializing and deserializing TKET circuits to and from //! JSON. +use crate::opbox::OpBox; use crate::optype::OpType; use serde::{Deserialize, Serialize}; @@ -45,174 +46,6 @@ pub struct ClassicalExp { op: String, } -/// A simple struct for Pauli strings with +/- phase, used to represent Pauli -/// strings in a stabiliser subgroup. -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)] -pub struct PauliStabiliser { - coeff: bool, - string: Vec, -} - -/// Unique identifier for an [`OpBox`]. -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)] -pub struct BoxID(uuid::Uuid); - -/// Box for an operation, the enum variant names come from the names -/// of the C++ operations and are renamed if the string corresponding -/// to the operation is differently named when serializing. -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[serde(tag = "type")] -#[allow(missing_docs)] -#[non_exhaustive] -pub enum OpBox { - /// Operation defined as a circuit. - CircBox { - id: BoxID, - /// The circuit defining the operation. - circuit: SerialCircuit, - }, - /// One-qubit operation defined as a unitary matrix. - Unitary1qBox { - id: BoxID, - /// 2x2 matrix of complex numbers - matrix: [[(f32, f32); 2]; 2], - }, - /// Two-qubit operation defined as a unitary matrix. - Unitary2qBox { - id: BoxID, - /// 4x4 matrix of complex numbers - matrix: [[(f32, f32); 4]; 4], - }, - /// Three-qubit operation defined as a unitary matrix. - Unitary3qBox { - id: BoxID, - /// 8x8 matrix of complex numbers - matrix: Box<[[(f32, f32); 8]; 8]>, - }, - /// Two-qubit operation defined in terms of a hermitian matrix and a phase. - ExpBox { - id: BoxID, - /// 4x4 matrix of complex numbers - matrix: [[(f32, f32); 4]; 4], - /// Phase of the operation. - phase: f64, - }, - /// Operation defined as the exponential of a tensor of Pauli operators. - PauliExpBox { - id: BoxID, - /// List of Pauli operators. - paulis: Vec, - /// Symengine expression. - phase: String, - /// Config param for decomposition of Pauli exponentials. - #[serde(default)] - cx_config: String, - }, - /// Operation defined as a pair of exponential of a tensor of Pauli operators. - PauliExpPairBox { - id: BoxID, - /// List of List of Pauli operators. - paulis: Vec>, - /// List of Symengine expressions. - phase: Vec, - /// Config param for decomposition of Pauli exponentials. - cx_config: String, - }, - /// Operation defined as a set of commuting exponentials of a tensor of Pauli operators. - PauliExpCommutingSetBox { - id: BoxID, - /// List of List of Pauli operators. - paulis: Vec<(Vec, String)>, - /// List of Symengine expressions. - pauli_gadgets: Vec<(Vec, String)>, - /// Config param for decomposition of Pauli exponentials. - cx_config: String, - }, - /// An operation capable of representing arbitrary Circuits made up of CNOT - /// and RZ, as a PhasePolynomial plus a boolean matrix representing an - /// additional linear transformation. - PhasePolyBox { - id: BoxID, - /// Number of qubits. - n_qubits: u32, - qubit_indices: Vec<(Register, u32)>, - }, - /// A user-defined assertion specified by a list of Pauli stabilisers. - StabiliserAssertionBox { - id: BoxID, - stabilisers: Vec, - }, - /// A user-defined assertion specified by a 2x2, 4x4, or 8x8 projector matrix. - ProjectorAssertionBox { - id: BoxID, - matrix: Vec>, - }, - /// A user-defined gate defined by a parametrized Circuit. - Composite { - id: BoxID, - gate: CompositeGate, - // Vec of Symengine Expr - params: Vec, - }, - /// Wraps another quantum op, adding control qubits. - QControlBox { - id: BoxID, - /// Number of control qubits. - n_controls: u32, - /// The operation to be controlled. - op: Box, - /// The state of the control. - #[serde(default)] - control_state: u32, - }, - /// Holding box for abstract expressions on Bits. - ClassicalExpBox { - id: BoxID, - n_i: u32, - n_io: u32, - n_o: u32, - exp: ClassicalExp, - }, - /// A user-defined multiplexor specified by a map from bitstrings to Operations. - MultiplexorBox { - id: BoxID, - op_map: Vec<(Vec, Operation)>, - }, - /// A user-defined multiplexed rotation gate specified by a map from - /// bitstrings to Operations. - MultiplexedRotationBox { - id: BoxID, - op_map: Vec<(Vec, Operation)>, - }, - /// A user-defined multiplexed rotation gate specified by a map from - /// bitstrings to Operations. - MultiplexedU2Box { - id: BoxID, - op_map: Vec<(Vec, Operation)>, - #[serde(default = "default_impl_diag")] - impl_diag: bool, - }, - /// An operation that constructs a circuit to implement the specified - /// permutation of classical basis states. - ToffoliBox { - id: BoxID, - /// The classical basis state permutation. - permutation: Permutation, - // Synthesis strategy. See [`ToffoliBoxSynthStrat`]. - strat: ToffoliBoxSynthStrat, - // The rotation axis of the multiplexors used in the decomposition. Can - // be either `Rx` or `Ry`. Only applicable to the - // [`ToffoliBoxSynthStrat::Matching`] strategy. Default to `Ry`. - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(default)] - rotation_axis: Option, - }, -} - -fn default_impl_diag() -> bool { - true -} - /// Decorates another op, adding a QASM-style classical condition. #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] pub struct Conditional { @@ -295,13 +128,3 @@ impl

Operation

{ } } } - -/// Strategies for synthesising ToffoliBoxes. -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] -#[non_exhaustive] -pub enum ToffoliBoxSynthStrat { - /// Use multiplexors to perform parallel swaps on hypercubes. - Matching, - /// Use CnX gates to perform transpositions. - Cycle, -} diff --git a/src/lib.rs b/src/lib.rs index bd20c8a..f529722 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,10 +3,14 @@ //! [TKET](https://github.com/CQCL/tket) quantum compiler. pub mod circuit_json; +pub mod opbox; pub mod optype; #[cfg(feature = "pyo3")] pub mod pytket; +pub use circuit_json::SerialCircuit; +pub use optype::OpType; + #[cfg(test)] mod tests { use crate::circuit_json::SerialCircuit; diff --git a/src/opbox.rs b/src/opbox.rs new file mode 100644 index 0000000..e3031d0 --- /dev/null +++ b/src/opbox.rs @@ -0,0 +1,185 @@ +//! Data definition for box operations. + +use crate::circuit_json::{ + ClassicalExp, CompositeGate, Operation, Permutation, Register, SerialCircuit, +}; +use crate::optype::OpType; +use serde::{Deserialize, Serialize}; + +/// Unique identifier for an [`OpBox`]. +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)] +pub struct BoxID(uuid::Uuid); + +/// Box for an operation, the enum variant names come from the names +/// of the C++ operations and are renamed if the string corresponding +/// to the operation is differently named when serializing. +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[serde(tag = "type")] +#[allow(missing_docs)] +#[non_exhaustive] +pub enum OpBox { + /// Operation defined as a circuit. + CircBox { + id: BoxID, + /// The circuit defining the operation. + circuit: SerialCircuit, + }, + /// One-qubit operation defined as a unitary matrix. + Unitary1qBox { + id: BoxID, + /// 2x2 matrix of complex numbers + matrix: [[(f32, f32); 2]; 2], + }, + /// Two-qubit operation defined as a unitary matrix. + Unitary2qBox { + id: BoxID, + /// 4x4 matrix of complex numbers + matrix: [[(f32, f32); 4]; 4], + }, + /// Three-qubit operation defined as a unitary matrix. + Unitary3qBox { + id: BoxID, + /// 8x8 matrix of complex numbers + matrix: Box<[[(f32, f32); 8]; 8]>, + }, + /// Two-qubit operation defined in terms of a hermitian matrix and a phase. + ExpBox { + id: BoxID, + /// 4x4 matrix of complex numbers + matrix: [[(f32, f32); 4]; 4], + /// Phase of the operation. + phase: f64, + }, + /// Operation defined as the exponential of a tensor of Pauli operators. + PauliExpBox { + id: BoxID, + /// List of Pauli operators. + paulis: Vec, + /// Symengine expression. + phase: String, + /// Config param for decomposition of Pauli exponentials. + #[serde(default)] + cx_config: String, + }, + /// Operation defined as a pair of exponential of a tensor of Pauli operators. + PauliExpPairBox { + id: BoxID, + /// List of List of Pauli operators. + paulis: Vec>, + /// List of Symengine expressions. + phase: Vec, + /// Config param for decomposition of Pauli exponentials. + cx_config: String, + }, + /// Operation defined as a set of commuting exponentials of a tensor of Pauli operators. + PauliExpCommutingSetBox { + id: BoxID, + /// List of List of Pauli operators. + paulis: Vec<(Vec, String)>, + /// List of Symengine expressions. + pauli_gadgets: Vec<(Vec, String)>, + /// Config param for decomposition of Pauli exponentials. + cx_config: String, + }, + /// An operation capable of representing arbitrary Circuits made up of CNOT + /// and RZ, as a PhasePolynomial plus a boolean matrix representing an + /// additional linear transformation. + PhasePolyBox { + id: BoxID, + /// Number of qubits. + n_qubits: u32, + qubit_indices: Vec<(Register, u32)>, + }, + /// A user-defined assertion specified by a list of Pauli stabilisers. + StabiliserAssertionBox { + id: BoxID, + stabilisers: Vec, + }, + /// A user-defined assertion specified by a 2x2, 4x4, or 8x8 projector matrix. + ProjectorAssertionBox { + id: BoxID, + matrix: Vec>, + }, + /// A user-defined gate defined by a parametrized Circuit. + Composite { + id: BoxID, + gate: CompositeGate, + // Vec of Symengine Expr + params: Vec, + }, + /// Wraps another quantum op, adding control qubits. + QControlBox { + id: BoxID, + /// Number of control qubits. + n_controls: u32, + /// The operation to be controlled. + op: Box, + /// The state of the control. + #[serde(default)] + control_state: u32, + }, + /// Holding box for abstract expressions on Bits. + ClassicalExpBox { + id: BoxID, + n_i: u32, + n_io: u32, + n_o: u32, + exp: ClassicalExp, + }, + /// A user-defined multiplexor specified by a map from bitstrings to Operations. + MultiplexorBox { + id: BoxID, + op_map: Vec<(Vec, Operation)>, + }, + /// A user-defined multiplexed rotation gate specified by a map from + /// bitstrings to Operations. + MultiplexedRotationBox { + id: BoxID, + op_map: Vec<(Vec, Operation)>, + }, + /// A user-defined multiplexed rotation gate specified by a map from + /// bitstrings to Operations. + MultiplexedU2Box { + id: BoxID, + op_map: Vec<(Vec, Operation)>, + #[serde(default = "default_impl_diag")] + impl_diag: bool, + }, + /// An operation that constructs a circuit to implement the specified + /// permutation of classical basis states. + ToffoliBox { + id: BoxID, + /// The classical basis state permutation. + permutation: Permutation, + // Synthesis strategy. See [`ToffoliBoxSynthStrat`]. + strat: ToffoliBoxSynthStrat, + // The rotation axis of the multiplexors used in the decomposition. Can + // be either `Rx` or `Ry`. Only applicable to the + // [`ToffoliBoxSynthStrat::Matching`] strategy. Default to `Ry`. + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + rotation_axis: Option, + }, +} + +fn default_impl_diag() -> bool { + true +} + +/// Strategies for synthesising ToffoliBoxes. +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] +#[non_exhaustive] +pub enum ToffoliBoxSynthStrat { + /// Use multiplexors to perform parallel swaps on hypercubes. + Matching, + /// Use CnX gates to perform transpositions. + Cycle, +} + +/// A simple struct for Pauli strings with +/- phase, used to represent Pauli +/// strings in a stabiliser subgroup. +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)] +pub struct PauliStabiliser { + coeff: bool, + string: Vec, +}