tket_json_rs/
circuit_json.rs

1//! Contains structs for serializing and deserializing TKET circuits to and from
2//! JSON.
3
4use crate::clexpr::ClExpr;
5use crate::opbox::OpBox;
6use crate::optype::OpType;
7use crate::register::{Bit, BitRegister, ElementId, Qubit};
8
9#[cfg(feature = "schemars")]
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12
13/// A gate defined by a circuit.
14///
15/// Previously known as `CompositeGate`.
16#[cfg_attr(feature = "schemars", derive(JsonSchema))]
17#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
18pub struct CustomGate {
19    /// Name of the composite gate.
20    pub name: String,
21    /// Expressions corresponding to parameter values of the composite gate, if it has parameters.
22    pub args: Vec<String>,
23    /// The circuit defining the gate.
24    pub definition: Box<SerialCircuit>,
25}
26
27/// A 2D matrix.
28#[cfg_attr(feature = "schemars", derive(JsonSchema))]
29#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)]
30#[serde(transparent)]
31pub struct Matrix<T = f64> {
32    /// A 2D vector of complex numbers.
33    pub data: Vec<Vec<(T, T)>>,
34}
35
36/// The units used in a [`ClassicalExp`].
37#[cfg_attr(feature = "schemars", derive(JsonSchema))]
38#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)]
39#[serde(untagged)]
40#[non_exhaustive]
41pub enum ClassicalExpUnit {
42    /// Unsigned 32-bit integer.
43    U32(u32),
44    /// Individual bit.
45    Bit(Bit),
46    /// Register of bits.
47    BitRegister(BitRegister),
48    /// A nested classical expression.
49    ClassicalExpUnit(ClassicalExp),
50}
51
52/// A box for holding classical expressions on Bits.
53#[cfg_attr(feature = "schemars", derive(JsonSchema))]
54#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)]
55pub struct ClassicalExp {
56    /// Arguments to the expression.
57    pub args: Vec<ClassicalExpUnit>,
58    /// The expression.
59    pub op: String,
60}
61
62/// Decorates another op, adding a QASM-style classical condition.
63#[cfg_attr(feature = "schemars", derive(JsonSchema))]
64#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
65pub struct Conditional {
66    /// Internal operation to conditionally apply.
67    pub op: Box<Operation>,
68    /// Number of bits in the classical condition.
69    pub width: u32,
70    /// Value to compare against.
71    pub value: u32,
72}
73
74/// Additional fields for classical operations,
75/// which only act on Bits classically.
76//
77// Note: The order of the variants here is important.
78// Serde will return the first matching variant when deserializing,
79// so CopyBits and SetBits must come after other variants that
80// define `values` and `n_i`.
81#[cfg_attr(feature = "schemars", derive(JsonSchema))]
82#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
83#[serde(untagged)]
84#[non_exhaustive]
85pub enum Classical {
86    /// Multi-bit operation.
87    MultiBit {
88        /// The inner operation.
89        op: Box<Operation>,
90        /// Multiplier on underlying op for MultiBitOp.
91        n: u32,
92    },
93    /// A range predicate.
94    RangePredicate {
95        /// Number of pure input wires to the RangePredicate.
96        n_i: u32,
97        /// The inclusive minimum of the RangePredicate.
98        lower: u64,
99        /// The inclusive maximum of the RangePredicate.
100        upper: u64,
101    },
102    /// ExplicitModifierOp/ExplicitPredicateOp.
103    Explicit {
104        /// Number of pure input wires to the ExplicitModifierOp/ExplicitPredicateOp.
105        n_i: u32,
106        /// Name of classical ExplicitModifierOp/ExplicitPredicateOp (e.g. AND).
107        name: String,
108        /// Truth table of ExplicitModifierOp/ExplicitPredicateOp.
109        values: Vec<bool>,
110    },
111    /// ClassicalTransformOp
112    ClassicalTransform {
113        /// Number of input/output wires.
114        n_io: u32,
115        /// Name of classical ClassicalTransformOp (e.g. ClassicalCX).
116        name: String,
117        /// Truth table of ClassicalTransformOp.
118        values: Vec<u32>,
119    },
120    /// CopyBitsOp.
121    CopyBits {
122        /// Number of input wires to the CopyBitsOp.
123        n_i: u32,
124    },
125    /// SetBitsOp.
126    SetBits {
127        /// List of bools that SetBitsOp sets bits to.
128        values: Vec<bool>,
129    },
130}
131
132/// Additional fields for Wasm operations.
133#[cfg_attr(feature = "schemars", derive(JsonSchema))]
134#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
135pub struct Wasm {
136    n: u64,
137    ww_n: u64,
138    width_i_parameter: Vec<u64>,
139    width_o_parameter: Vec<u64>,
140    func_name: String,
141    wasm_file_uid: String,
142}
143
144/// Serializable operation descriptor.
145#[cfg_attr(feature = "schemars", derive(JsonSchema))]
146#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
147#[non_exhaustive]
148pub struct Operation<P = String> {
149    /// The type of operation.
150    #[serde(rename = "type")]
151    pub op_type: OpType,
152    /// Number of input and output qubits.
153    #[serde(skip_serializing_if = "Option::is_none")]
154    pub n_qb: Option<u32>,
155    /// Additional string stored in the op
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub data: Option<String>,
158    /// Expressions for the parameters of the operation.
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub params: Option<Vec<P>>,
161    /// Internal box for the operation.
162    #[serde(rename = "box")]
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub op_box: Option<OpBox>,
165    /// Classical expression.
166    ///
167    /// Required if the operation is of type [`OpType::ClExpr`].
168    #[serde(skip_serializing_if = "Option::is_none")]
169    #[serde(rename = "expr")]
170    pub classical_expr: Option<ClExpr>,
171    /// The pre-computed signature.
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub signature: Option<Vec<String>>,
174    /// A QASM-style classical condition for the operation.
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub conditional: Option<Conditional>,
177    /// Data for commands which only act on Bits classically.
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub classical: Option<Box<Classical>>,
180    /// Data for commands which apply WASM operations.
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub wasm: Option<Box<Wasm>>,
183}
184
185/// Operation applied in a circuit, with defined arguments.
186#[cfg_attr(feature = "schemars", derive(JsonSchema))]
187#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
188pub struct Command<P = String> {
189    /// The operation to be applied.
190    pub op: Operation<P>,
191    /// The arguments to the operation.
192    ///
193    /// May correspond to either [`Qubit`]s or [`Bit`]s, depending on the operation.
194    pub args: Vec<ElementId>,
195    /// Operation group identifier.
196    #[serde(skip_serializing_if = "Option::is_none")]
197    pub opgroup: Option<String>,
198}
199
200/// A classic basis state permutation.
201/// Used when defining Toffoli boxes.
202#[cfg_attr(feature = "schemars", derive(JsonSchema))]
203#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)]
204#[serde(transparent)]
205pub struct Permutation(pub Vec<(Vec<bool>, Vec<bool>)>);
206
207/// An implicit permutation of the elements of a register.
208#[cfg_attr(feature = "schemars", derive(JsonSchema))]
209#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq, Hash)]
210pub struct ImplicitPermutation(pub Qubit, pub Qubit);
211
212/// Pytket canonical serialized circuit
213#[cfg_attr(feature = "schemars", derive(JsonSchema))]
214#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
215#[non_exhaustive]
216pub struct SerialCircuit<P = String> {
217    /// The name of the circuit.
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub name: Option<String>,
220    /// The global phase, as a symengine expression.
221    pub phase: P,
222    /// List of commands in the circuit.
223    pub commands: Vec<Command<P>>,
224    /// Input qubits.
225    pub qubits: Vec<Qubit>,
226    /// Input bits.
227    pub bits: Vec<Bit>,
228    /// Implicit permutation of the output qubits.
229    pub implicit_permutation: Vec<ImplicitPermutation>,
230    /// Number of wasm wires in the circuit.
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub number_of_ws: Option<u64>,
233    /// Number of RNG wires in the circuit.
234    #[serde(skip_serializing_if = "Option::is_none")]
235    pub number_of_rs: Option<u64>,
236    /// A list of qubits initialized at the start of the circuit.
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub created_qubits: Option<Vec<Qubit>>,
239    /// A list of qubits discarded at the end of the circuit.
240    #[serde(skip_serializing_if = "Option::is_none")]
241    pub discarded_qubits: Option<Vec<Bit>>,
242}
243
244impl<P> Default for Operation<P> {
245    fn default() -> Self {
246        Self {
247            op_type: Default::default(),
248            n_qb: None,
249            data: None,
250            params: None,
251            op_box: None,
252            classical_expr: None,
253            signature: None,
254            conditional: None,
255            classical: None,
256            wasm: None,
257        }
258    }
259}
260
261impl<P: Default> Default for SerialCircuit<P> {
262    fn default() -> Self {
263        Self {
264            name: None,
265            phase: Default::default(),
266            commands: Default::default(),
267            qubits: Default::default(),
268            bits: Default::default(),
269            implicit_permutation: Default::default(),
270            number_of_ws: None,
271            number_of_rs: None,
272            created_qubits: None,
273            discarded_qubits: None,
274        }
275    }
276}
277
278impl<P> Operation<P> {
279    /// Returns a default-initialized Operation with the given type.
280    ///
281    /// For optypes that require additional parameters, this may generate
282    /// invalid operations.
283    pub fn from_optype(op_type: OpType) -> Self {
284        Self {
285            op_type,
286            ..Operation::default()
287        }
288    }
289
290    /// Applies a function over the parameters of the operation.
291    ///
292    /// Returns a new Operation with the same data, but with a new generic
293    /// type for the parameters.
294    pub fn map_params<Q>(self, f: impl FnMut(P) -> Q) -> Operation<Q> {
295        Operation {
296            op_type: self.op_type,
297            n_qb: self.n_qb,
298            data: self.data,
299            params: self
300                .params
301                .map(|params| params.into_iter().map(f).collect()),
302            op_box: self.op_box,
303            classical_expr: self.classical_expr,
304            signature: self.signature,
305            conditional: self.conditional,
306            classical: self.classical,
307            wasm: self.wasm,
308        }
309    }
310}
311
312impl<P> Command<P> {
313    /// Applies a function over the parameters of the command.
314    ///
315    /// Returns a new Command with the same data, but with a new generic type
316    /// for the parameters.
317    pub fn map_params<Q>(self, f: impl FnMut(P) -> Q) -> Command<Q> {
318        Command {
319            op: self.op.map_params(f),
320            args: self.args,
321            opgroup: self.opgroup,
322        }
323    }
324}
325
326impl<P> SerialCircuit<P> {
327    /// Initialize a new SerialCircuit with the given name and phase.
328    pub fn new(name: Option<String>, phase: P) -> Self {
329        Self {
330            name,
331            phase,
332            commands: Vec::new(),
333            qubits: Vec::new(),
334            bits: Vec::new(),
335            implicit_permutation: Vec::new(),
336            number_of_ws: None,
337            number_of_rs: None,
338            created_qubits: None,
339            discarded_qubits: None,
340        }
341    }
342
343    /// Applies a function over the parameters of the circuit.
344    ///
345    /// Returns a new SerialCircuit with the same data, but with a new generic
346    /// type for the parameters.
347    pub fn map_params<Q>(self, mut f: impl FnMut(P) -> Q) -> SerialCircuit<Q> {
348        let phase = f(self.phase);
349        let commands = self
350            .commands
351            .into_iter()
352            .map(|c| c.map_params(&mut f))
353            .collect();
354        SerialCircuit {
355            name: self.name,
356            phase,
357            commands,
358            qubits: self.qubits,
359            bits: self.bits,
360            implicit_permutation: self.implicit_permutation,
361            number_of_ws: self.number_of_ws,
362            number_of_rs: self.number_of_rs,
363            created_qubits: self.created_qubits,
364            discarded_qubits: self.discarded_qubits,
365        }
366    }
367}