From 13213d529c5a24478b5816e395b52092118034e0 Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Wed, 27 Sep 2023 15:58:25 +0200 Subject: [PATCH 01/11] feat: Add CircuitMut trait --- src/circuit.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 141 insertions(+), 3 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index 8f9e9a22..c675c814 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -9,10 +9,17 @@ pub use hash::CircuitHash; use hugr::HugrView; +use derive_more::From; +use hugr::hugr::hugrmut::HugrMut; +use hugr::hugr::{NodeType, PortIndex}; +use hugr::ops::dataflow::IOTrait; pub use hugr::ops::OpType; +use hugr::ops::{Input, Output, DFG}; use hugr::types::FunctionType; pub use hugr::types::{EdgeKind, Signature, Type, TypeRow}; pub use hugr::{Node, Port, Wire}; +use itertools::Itertools; +use thiserror::Error; use self::units::{filter, FilteredUnits, Units}; @@ -120,18 +127,132 @@ pub trait Circuit: HugrView { } } +/// A circuit object that can be mutated. +pub trait CircuitMut: Circuit + HugrMut { + /// Remove an empty wire from the circuit. + /// + /// Pass the index of the wire at the input port. + /// + /// This will return an error if the wire is not empty or if a HugrError + /// occurs. + fn remove_empty_wire(&mut self, input_port: usize) -> Result<(), CircuitMutError> { + let inp = self.input(); + let input_port = Port::new_outgoing(input_port); + let (out, output_port) = self + .linked_ports(inp, input_port) + .exactly_one() + .ok() + .expect("invalid circuit"); + if out != self.output() { + return Err(CircuitMutError::DeleteNonEmptyWire(input_port.index())); + } + self.disconnect(inp, input_port)?; + + // Shift ports at input + shift_ports(self, inp, input_port, self.num_outputs(inp))?; + // Shift ports at output + shift_ports(self, out, output_port, self.num_inputs(out))?; + // Update input node, output node and root signatures. + update_type_signature(self, input_port.index(), output_port.index()); + Ok(()) + } +} + +/// Errors that can occur when mutating a circuit. +#[derive(Debug, Clone, Error, PartialEq, Eq, From)] +pub enum CircuitMutError { + /// A Hugr error occurred. + #[error("Hugr error: {0:?}")] + HugrError(hugr::hugr::HugrError), + /// The wire to be deleted is not empty. + #[error("Wire {0} cannot be deleted: not empty")] + DeleteNonEmptyWire(usize), +} + +/// Shift ports in range (free_port + 1 .. max_ind) by -1. +fn shift_ports( + circ: &mut C, + node: Node, + mut free_port: Port, + max_ind: usize, +) -> Result { + let dir = free_port.direction(); + let port_range = (free_port.index() + 1..max_ind).map(|p| Port::new(dir, p)); + dbg!(&port_range); + for port in port_range { + if let Some(connected_to) = circ + .linked_ports(node, port) + .at_most_one() + .ok() + .expect("invalid circuit") + { + circ.disconnect(node, port)?; + circ.connect(node, free_port, connected_to.0, connected_to.1)?; + } + free_port = port; + } + Ok(free_port) +} + +// Update the signature of circ when removing the in_index-th input wire and +// the out_index-th output wire. +fn update_type_signature( + circ: &mut C, + in_index: usize, + out_index: usize, +) { + let inp = circ.input(); + // Update input node + let inp_types: TypeRow = { + let OpType::Input(Input { types }) = circ.get_optype(inp).clone() else { + panic!("invalid circuit") + }; + let mut types = types.into_owned(); + types.remove(in_index); + types.into() + }; + let new_inp_op = Input::new(inp_types.clone()); + let inp_exts = circ.get_nodetype(inp).input_extensions().cloned(); + circ.replace_op(inp, NodeType::new(new_inp_op, inp_exts)); + + // Update output node + let out = circ.output(); + let out_types: TypeRow = { + let OpType::Output(Output { types }) = circ.get_optype(out).clone() else { + panic!("invalid circuit") + }; + let mut types = types.into_owned(); + types.remove(out_index); + types.into() + }; + let new_out_op = Input::new(out_types.clone()); + let inp_exts = circ.get_nodetype(out).input_extensions().cloned(); + circ.replace_op(out, NodeType::new(new_out_op, inp_exts)); + + // Update root + let OpType::DFG(DFG { mut signature, .. }) = circ.get_optype(circ.root()).clone() else { + panic!("invalid circuit") + }; + signature.input = inp_types; + signature.output = out_types; + let new_dfg_op = DFG { signature }; + let inp_exts = circ.get_nodetype(circ.root()).input_extensions().cloned(); + circ.replace_op(circ.root(), NodeType::new(new_dfg_op, inp_exts)); +} + impl Circuit for T where T: HugrView {} +impl CircuitMut for T where T: Circuit + HugrMut {} #[cfg(test)] mod tests { use hugr::Hugr; - use crate::{circuit::Circuit, json::load_tk1_json_str}; + use super::*; + use crate::{json::load_tk1_json_str, utils::build_simple_circuit, T2Op}; fn test_circuit() -> Hugr { load_tk1_json_str( - r#"{ - "phase": "0", + r#"{ "phase": "0", "bits": [["c", [0]]], "qubits": [["q", [0]], ["q", [1]]], "commands": [ @@ -160,4 +281,21 @@ mod tests { assert_eq!(circ.linear_units().count(), 3); assert_eq!(circ.qubits().count(), 2); } + + #[test] + fn remove_qubit() { + let mut circ = build_simple_circuit(2, |circ| { + circ.append(T2Op::X, [0])?; + Ok(()) + }) + .unwrap(); + + assert_eq!(circ.qubit_count(), 2); + assert!(circ.remove_empty_wire(1).is_ok()); + assert_eq!(circ.qubit_count(), 1); + assert_eq!( + circ.remove_empty_wire(0).unwrap_err(), + CircuitMutError::DeleteNonEmptyWire(0) + ); + } } From 22bf6a695cc9fee7ea2920870fb4b2c3e0f83027 Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Wed, 27 Sep 2023 16:55:16 +0200 Subject: [PATCH 02/11] Support copyable wires --- src/circuit.rs | 90 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index c675c814..e7ceb19f 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -131,29 +131,42 @@ pub trait Circuit: HugrView { pub trait CircuitMut: Circuit + HugrMut { /// Remove an empty wire from the circuit. /// - /// Pass the index of the wire at the input port. + /// The wire to be removed is identified by the index of the outgoing port + /// at the circuit input node. + /// + /// This will change the circuit signature and will shift all ports after + /// the removed wire by -1. If the wire is connected to the output node, + /// this will also change the signature output and shift the ports after + /// the removed wire by -1. /// /// This will return an error if the wire is not empty or if a HugrError /// occurs. fn remove_empty_wire(&mut self, input_port: usize) -> Result<(), CircuitMutError> { let inp = self.input(); + if input_port >= self.num_outputs(inp) { + return Err(CircuitMutError::InvalidPortOffset(input_port)); + } let input_port = Port::new_outgoing(input_port); - let (out, output_port) = self + let link = self .linked_ports(inp, input_port) - .exactly_one() + .at_most_one() .ok() .expect("invalid circuit"); - if out != self.output() { + if link.is_some() && link.unwrap().0 != self.output() { return Err(CircuitMutError::DeleteNonEmptyWire(input_port.index())); } - self.disconnect(inp, input_port)?; + if link.is_some() { + self.disconnect(inp, input_port)?; + } // Shift ports at input shift_ports(self, inp, input_port, self.num_outputs(inp))?; // Shift ports at output - shift_ports(self, out, output_port, self.num_inputs(out))?; - // Update input node, output node and root signatures. - update_type_signature(self, input_port.index(), output_port.index()); + if let Some((out, output_port)) = link { + shift_ports(self, out, output_port, self.num_inputs(out))?; + } + // Update input node, output node (if necessary) and root signatures. + update_signature(self, input_port.index(), link.map(|(_, p)| p.index())); Ok(()) } } @@ -165,8 +178,13 @@ pub enum CircuitMutError { #[error("Hugr error: {0:?}")] HugrError(hugr::hugr::HugrError), /// The wire to be deleted is not empty. + #[from(ignore)] #[error("Wire {0} cannot be deleted: not empty")] DeleteNonEmptyWire(usize), + /// The wire does not exist. + #[from(ignore)] + #[error("Wire {0} does not exist")] + InvalidPortOffset(usize), } /// Shift ports in range (free_port + 1 .. max_ind) by -1. @@ -178,7 +196,6 @@ fn shift_ports( ) -> Result { let dir = free_port.direction(); let port_range = (free_port.index() + 1..max_ind).map(|p| Port::new(dir, p)); - dbg!(&port_range); for port in port_range { if let Some(connected_to) = circ .linked_ports(node, port) @@ -196,10 +213,10 @@ fn shift_ports( // Update the signature of circ when removing the in_index-th input wire and // the out_index-th output wire. -fn update_type_signature( +fn update_signature( circ: &mut C, in_index: usize, - out_index: usize, + out_index: Option, ) { let inp = circ.input(); // Update input node @@ -215,26 +232,31 @@ fn update_type_signature( let inp_exts = circ.get_nodetype(inp).input_extensions().cloned(); circ.replace_op(inp, NodeType::new(new_inp_op, inp_exts)); - // Update output node - let out = circ.output(); - let out_types: TypeRow = { - let OpType::Output(Output { types }) = circ.get_optype(out).clone() else { - panic!("invalid circuit") + // Update output node if necessary. + let out_types = out_index.map(|out_index| { + let out = circ.output(); + let out_types: TypeRow = { + let OpType::Output(Output { types }) = circ.get_optype(out).clone() else { + panic!("invalid circuit") + }; + let mut types = types.into_owned(); + types.remove(out_index); + types.into() }; - let mut types = types.into_owned(); - types.remove(out_index); - types.into() - }; - let new_out_op = Input::new(out_types.clone()); - let inp_exts = circ.get_nodetype(out).input_extensions().cloned(); - circ.replace_op(out, NodeType::new(new_out_op, inp_exts)); + let new_out_op = Input::new(out_types.clone()); + let inp_exts = circ.get_nodetype(out).input_extensions().cloned(); + circ.replace_op(out, NodeType::new(new_out_op, inp_exts)); + out_types + }); // Update root let OpType::DFG(DFG { mut signature, .. }) = circ.get_optype(circ.root()).clone() else { panic!("invalid circuit") }; signature.input = inp_types; - signature.output = out_types; + if let Some(out_types) = out_types { + signature.output = out_types; + } let new_dfg_op = DFG { signature }; let inp_exts = circ.get_nodetype(circ.root()).input_extensions().cloned(); circ.replace_op(circ.root(), NodeType::new(new_dfg_op, inp_exts)); @@ -245,7 +267,11 @@ impl CircuitMut for T where T: Circuit + HugrMut {} #[cfg(test)] mod tests { - use hugr::Hugr; + use hugr::{ + builder::{DFGBuilder, DataflowHugr}, + extension::{prelude::BOOL_T, PRELUDE_REGISTRY}, + Hugr, + }; use super::*; use crate::{json::load_tk1_json_str, utils::build_simple_circuit, T2Op}; @@ -298,4 +324,18 @@ mod tests { CircuitMutError::DeleteNonEmptyWire(0) ); } + + #[test] + fn remove_bit() { + let h = DFGBuilder::new(FunctionType::new(vec![BOOL_T], vec![])).unwrap(); + let mut circ = h.finish_hugr_with_outputs([], &PRELUDE_REGISTRY).unwrap(); + + assert_eq!(circ.units().count(), 1); + assert!(circ.remove_empty_wire(0).is_ok()); + assert_eq!(circ.units().count(), 0); + assert_eq!( + circ.remove_empty_wire(2).unwrap_err(), + CircuitMutError::InvalidPortOffset(2) + ); + } } From 2abeaf745c2d371129a8b28352bc0bd9d497d10a Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Wed, 27 Sep 2023 17:58:56 +0200 Subject: [PATCH 03/11] Bug fixes --- src/circuit.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index e7ceb19f..89769741 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -19,6 +19,7 @@ use hugr::types::FunctionType; pub use hugr::types::{EdgeKind, Signature, Type, TypeRow}; pub use hugr::{Node, Port, Wire}; use itertools::Itertools; +use portgraph::Direction; use thiserror::Error; use self::units::{filter, FilteredUnits, Units}; @@ -150,8 +151,7 @@ pub trait CircuitMut: Circuit + HugrMut { let link = self .linked_ports(inp, input_port) .at_most_one() - .ok() - .expect("invalid circuit"); + .map_err(|_| CircuitMutError::DeleteNonEmptyWire(input_port.index()))?; if link.is_some() && link.unwrap().0 != self.output() { return Err(CircuitMutError::DeleteNonEmptyWire(input_port.index())); } @@ -167,6 +167,11 @@ pub trait CircuitMut: Circuit + HugrMut { } // Update input node, output node (if necessary) and root signatures. update_signature(self, input_port.index(), link.map(|(_, p)| p.index())); + // Resize ports at input/output node + self.set_num_ports(inp, 0, self.num_outputs(inp) - 1); + if let Some((out, _)) = link { + self.set_num_ports(out, self.num_inputs(out) - 1, 0); + } Ok(()) } } @@ -197,14 +202,16 @@ fn shift_ports( let dir = free_port.direction(); let port_range = (free_port.index() + 1..max_ind).map(|p| Port::new(dir, p)); for port in port_range { - if let Some(connected_to) = circ - .linked_ports(node, port) - .at_most_one() - .ok() - .expect("invalid circuit") - { + let links = circ.linked_ports(node, port).collect_vec(); + if !links.is_empty() { circ.disconnect(node, port)?; - circ.connect(node, free_port, connected_to.0, connected_to.1)?; + } + for (other_n, other_p) in links { + // TODO: simplify when CQCL-DEV/hugr#565 is resolved + match dir { + Direction::Incoming => circ.connect(other_n, other_p, node, free_port), + Direction::Outgoing => circ.connect(node, free_port, other_n, other_p), + }?; } free_port = port; } @@ -243,7 +250,7 @@ fn update_signature( types.remove(out_index); types.into() }; - let new_out_op = Input::new(out_types.clone()); + let new_out_op = Output::new(out_types.clone()); let inp_exts = circ.get_nodetype(out).input_extensions().cloned(); circ.replace_op(out, NodeType::new(new_out_op, inp_exts)); out_types From 00d82fbab8c7b3a7d249bad6b816fdd1de27d47c Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Wed, 27 Sep 2023 16:46:46 +0200 Subject: [PATCH 04/11] fix: Remove empty wires in patterns --- src/rewrite/ecc_rewriter.rs | 86 +++++++++++++++++++++++++++++++++---- test_files/cx_cx_eccs.json | 8 ++++ 2 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 test_files/cx_cx_eccs.json diff --git a/src/rewrite/ecc_rewriter.rs b/src/rewrite/ecc_rewriter.rs index afd4ff10..375c86df 100644 --- a/src/rewrite/ecc_rewriter.rs +++ b/src/rewrite/ecc_rewriter.rs @@ -13,15 +13,17 @@ //! of the Quartz repository. use derive_more::{From, Into}; +use hugr::hugr::PortIndex; +use hugr::ops::OpTrait; use itertools::Itertools; use portmatching::PatternID; -use std::io; use std::path::Path; +use std::{collections::HashSet, io}; use hugr::Hugr; use crate::{ - circuit::Circuit, + circuit::{Circuit, CircuitMut}, optimiser::taso::{load_eccs_json_file, EqCircClass}, portmatching::{CircuitPattern, PatternMatcher}, }; @@ -47,6 +49,9 @@ pub struct ECCRewriter { /// target TargetIDs. The usize index of PatternID is used to index into /// the outer vector. rewrite_rules: Vec>, + /// Wires that have been removed in the pattern circuit -- to be removed + /// in the target circuit as well when generating a rewrite. + empty_wires: Vec>, } impl ECCRewriter { @@ -70,18 +75,34 @@ impl ECCRewriter { let eccs = eccs.into(); let rewrite_rules = get_rewrite_rules(&eccs); let patterns = get_patterns(&eccs); + let targets = into_targets(eccs); // Remove failed patterns - let (patterns, rewrite_rules): (Vec<_>, Vec<_>) = patterns + let (patterns, empty_wires, rewrite_rules): (Vec<_>, Vec<_>, Vec<_>) = patterns .into_iter() .zip(rewrite_rules) - .filter_map(|(p, r)| Some((p?, r))) - .unzip(); - let targets = into_targets(eccs); + .filter_map(|(p, r)| { + // Filter out target IDs where empty wires are not empty + let (pattern, pattern_empty_wires) = p?; + let targets = r + .into_iter() + .filter(|&id| { + let circ = &targets[id.0]; + let target_empty_wires: HashSet<_> = + empty_wires(&circ).into_iter().collect(); + pattern_empty_wires + .iter() + .all(|&w| target_empty_wires.contains(&w)) + }) + .collect(); + Some((pattern, pattern_empty_wires, targets)) + }) + .multiunzip(); let matcher = PatternMatcher::from_patterns(patterns); Self { matcher, targets, rewrite_rules, + empty_wires, } } @@ -101,7 +122,11 @@ impl Rewriter for ECCRewriter { .flat_map(|m| { let pattern_id = m.pattern_id(); self.get_targets(pattern_id).map(move |repl| { - m.to_rewrite(circ.base_hugr(), repl.clone()) + let mut repl = repl.clone(); + for &empty_qb in self.empty_wires[pattern_id.0].iter().rev() { + repl.remove_empty_wire(empty_qb).unwrap(); + } + m.to_rewrite(circ.base_hugr(), repl) .expect("invalid replacement") }) }) @@ -134,11 +159,43 @@ fn get_rewrite_rules(rep_sets: &[EqCircClass]) -> Vec> { rewrite_rules } -fn get_patterns(rep_sets: &[EqCircClass]) -> Vec> { +/// For an equivalence class, return all valid patterns together with the +/// indices of the wires that have been removed in the pattern circuit. +fn get_patterns(rep_sets: &[EqCircClass]) -> Vec)>> { rep_sets .iter() .flat_map(|rs| rs.circuits()) - .map(|circ| CircuitPattern::try_from_circuit(circ).ok()) + .map(|circ| { + let empty_qbs = empty_wires(circ); + let mut circ = circ.clone(); + for &qb in empty_qbs.iter().rev() { + circ.remove_empty_wire(qb).unwrap(); + } + CircuitPattern::try_from_circuit(&circ) + .ok() + .map(|circ| (circ, empty_qbs)) + }) + .collect() +} + +/// The port offsets of wires that are empty. +fn empty_wires(circ: &impl Circuit) -> Vec { + let inp = circ.input(); + circ.node_outputs(inp) + // Only consider dataflow edges + .filter(|&p| circ.get_optype(inp).signature().get(p).is_some()) + // Only consider ports linked to at most one other port + .filter_map(|p| Some((p, circ.linked_ports(inp, p).at_most_one().ok()?))) + // Ports are either connected to output or nothing + .filter_map(|(from, to)| { + if let Some((n, _)) = to { + // Wires connected to output + (n == circ.output()).then_some(from.index()) + } else { + // Wires connected to nothing + Some(from.index()) + } + }) .collect() } @@ -241,4 +298,15 @@ mod tests { let exp_n_eccs_of_len = [0, 4 * 2 + 5 * 3, 4, 5]; assert_eq!(n_eccs_of_len, exp_n_eccs_of_len); } + + /// Some inputs are left untouched: these parameters should be removed to + /// obtain convex patterns + #[test] + fn ecc_rewriter_empty_params() { + let test_file = "test_files/cx_cx_eccs.json"; + let rewriter = ECCRewriter::try_from_eccs_json_file(test_file).unwrap(); + + let cx_cx = cx_cx(); + assert_eq!(rewriter.get_rewrites(&cx_cx).len(), 1); + } } diff --git a/test_files/cx_cx_eccs.json b/test_files/cx_cx_eccs.json new file mode 100644 index 00000000..8cf933f3 --- /dev/null +++ b/test_files/cx_cx_eccs.json @@ -0,0 +1,8 @@ +[[], +{ +"7779_2": [ +[[3,0,0,0,["2acba3946000"],[7.23975983031379111e-02,-6.01244148396314765e-02]],[]] +,[[3,0,0,2,["2acba3946000"],[7.23975983031379111e-02,-6.01244148396314765e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +] +} +] \ No newline at end of file From 1bbb94b4a2c4e2c0d526dbda84d57cb266fdc28d Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Tue, 3 Oct 2023 09:38:16 +0200 Subject: [PATCH 05/11] feat: Improve TASO cost function and rewrite strategies --- src/ops.rs | 10 ++ src/optimiser/taso.rs | 139 +++++++++++++------ src/optimiser/taso/log.rs | 22 +-- src/rewrite/ecc_rewriter.rs | 6 +- src/rewrite/strategy.rs | 266 ++++++++++++++++++++++++++++++------ test_files/small_eccs.json | 5 + 6 files changed, 354 insertions(+), 94 deletions(-) diff --git a/src/ops.rs b/src/ops.rs index 1c1cb69a..1ac5c230 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -200,6 +200,16 @@ impl T2Op { _ => vec![], } } + + /// Check if this op is a quantum op. + pub fn is_quantum(&self) -> bool { + use T2Op::*; + match self { + H | CX | T | S | X | Y | Z | Tdg | Sdg | ZZMax | RzF64 | RxF64 | PhasedX | ZZPhase + | CZ | TK1 => true, + AngleAdd | Measure => false, + } + } } /// Initialize a new custom symbolic expression constant op from a string. diff --git a/src/optimiser/taso.rs b/src/optimiser/taso.rs index a231aaf8..7208d841 100644 --- a/src/optimiser/taso.rs +++ b/src/optimiser/taso.rs @@ -22,11 +22,12 @@ use crossbeam_channel::select; pub use eq_circ_class::{load_eccs_json_file, EqCircClass}; pub use log::TasoLogger; +use std::fmt; use std::num::NonZeroUsize; use std::time::{Duration, Instant}; use fxhash::FxHashSet; -use hugr::Hugr; +use hugr::{Hugr, HugrView}; use crate::circuit::CircuitHash; use crate::optimiser::taso::hugr_pchannel::HugrPriorityChannel; @@ -52,28 +53,30 @@ use crate::rewrite::Rewriter; /// [Quartz]: https://arxiv.org/abs/2204.09033 /// [TASO]: https://dl.acm.org/doi/10.1145/3341301.3359630 #[derive(Clone, Debug)] -pub struct TasoOptimiser { +pub struct TasoOptimiser { rewriter: R, strategy: S, - cost: C, } -impl TasoOptimiser { +impl TasoOptimiser { /// Create a new TASO optimiser. - pub fn new(rewriter: R, strategy: S, cost: C) -> Self { - Self { - rewriter, - strategy, - cost, - } + pub fn new(rewriter: R, strategy: S) -> Self { + Self { rewriter, strategy } + } + + fn cost(&self, circ: &Hugr) -> S::Cost + where + S: RewriteStrategy, + { + self.strategy.circuit_cost(circ) } } -impl TasoOptimiser +impl TasoOptimiser where R: Rewriter + Send + Clone + 'static, - S: RewriteStrategy + Send + Clone + 'static, - C: Fn(&Hugr) -> usize + Send + Sync + Clone + 'static, + S: RewriteStrategy + Send + Sync + Clone + 'static, + S::Cost: fmt::Debug + serde::Serialize, { /// Run the TASO optimiser on a circuit. /// @@ -103,15 +106,19 @@ where let start_time = Instant::now(); let mut best_circ = circ.clone(); - let mut best_circ_cost = (self.cost)(circ); - logger.log_best(best_circ_cost); + let mut best_circ_cost = self.cost(circ); + logger.log_best(&best_circ_cost); // Hash of seen circuits. Dot not store circuits as this map gets huge let mut seen_hashes: FxHashSet<_> = FromIterator::from_iter([(circ.circuit_hash())]); // The priority queue of circuits to be processed (this should not get big) const PRIORITY_QUEUE_CAPACITY: usize = 10_000; - let mut pq = HugrPQ::with_capacity(&self.cost, PRIORITY_QUEUE_CAPACITY); + let cost_fn = { + let strategy = self.strategy.clone(); + move |circ: &'_ Hugr| strategy.circuit_cost(circ) + }; + let mut pq = HugrPQ::with_capacity(cost_fn, PRIORITY_QUEUE_CAPACITY); pq.push(circ.clone()); let mut circ_cnt = 1; @@ -120,7 +127,7 @@ where if cost < best_circ_cost { best_circ = circ.clone(); best_circ_cost = cost; - logger.log_best(best_circ_cost); + logger.log_best(&best_circ_cost); } let rewrites = self.rewriter.get_rewrites(&circ); @@ -168,15 +175,19 @@ where const PRIORITY_QUEUE_CAPACITY: usize = 10_000; // multi-consumer priority channel for queuing circuits to be processed by the workers + let cost_fn = { + let strategy = self.strategy.clone(); + move |circ: &'_ Hugr| strategy.circuit_cost(circ) + }; let (tx_work, rx_work) = - HugrPriorityChannel::init((self.cost).clone(), PRIORITY_QUEUE_CAPACITY * n_threads); + HugrPriorityChannel::init(cost_fn, PRIORITY_QUEUE_CAPACITY * n_threads); // channel for sending circuits from threads back to main let (tx_result, rx_result) = crossbeam_channel::unbounded(); let initial_circ_hash = circ.circuit_hash(); let mut best_circ = circ.clone(); - let mut best_circ_cost = (self.cost)(&best_circ); - logger.log_best(best_circ_cost); + let mut best_circ_cost = self.cost(&best_circ); + logger.log_best(&best_circ_cost); // Hash of seen circuits. Dot not store circuits as this map gets huge let mut seen_hashes: FxHashSet<_> = FromIterator::from_iter([(initial_circ_hash)]); @@ -239,13 +250,13 @@ where } seen_hashes.insert(*circ_hash); - let cost = (self.cost)(circ); + let cost = self.cost(circ); // Check if we got a new best circuit if cost < best_circ_cost { best_circ = circ.clone(); best_circ_cost = cost; - logger.log_best(best_circ_cost); + logger.log_best(&best_circ_cost); } jobs_sent += 1; } @@ -289,32 +300,24 @@ where #[cfg(feature = "portmatching")] mod taso_default { - use hugr::ops::OpType; - use hugr::HugrView; use std::io; use std::path::Path; - use crate::ops::op_matches; use crate::rewrite::ecc_rewriter::RewriterSerialisationError; - use crate::rewrite::strategy::ExhaustiveRewriteStrategy; + use crate::rewrite::strategy::NonIncreasingCXCountStrategy; use crate::rewrite::ECCRewriter; - use crate::T2Op; use super::*; /// The default TASO optimiser using ECC sets. - pub type DefaultTasoOptimiser = TasoOptimiser< - ECCRewriter, - ExhaustiveRewriteStrategy bool>, - fn(&Hugr) -> usize, - >; + pub type DefaultTasoOptimiser = TasoOptimiser; impl DefaultTasoOptimiser { /// A sane default optimiser using the given ECC sets. pub fn default_with_eccs_json_file(eccs_path: impl AsRef) -> io::Result { let rewriter = ECCRewriter::try_from_eccs_json_file(eccs_path)?; - let strategy = ExhaustiveRewriteStrategy::exhaustive_cx(); - Ok(TasoOptimiser::new(rewriter, strategy, num_cx_gates)) + let strategy = NonIncreasingCXCountStrategy::default_cx(); + Ok(TasoOptimiser::new(rewriter, strategy)) } /// A sane default optimiser using a precompiled binary rewriter. @@ -322,16 +325,68 @@ mod taso_default { rewriter_path: impl AsRef, ) -> Result { let rewriter = ECCRewriter::load_binary(rewriter_path)?; - let strategy = ExhaustiveRewriteStrategy::exhaustive_cx(); - Ok(TasoOptimiser::new(rewriter, strategy, num_cx_gates)) + let strategy = NonIncreasingCXCountStrategy::default_cx(); + Ok(TasoOptimiser::new(rewriter, strategy)) } } - - fn num_cx_gates(circ: &Hugr) -> usize { - circ.nodes() - .filter(|&n| op_matches(circ.get_optype(n), T2Op::CX)) - .count() - } } #[cfg(feature = "portmatching")] pub use taso_default::DefaultTasoOptimiser; + +#[cfg(test)] +#[cfg(feature = "portmatching")] +mod tests { + use hugr::{ + builder::{DFGBuilder, Dataflow, DataflowHugr}, + extension::prelude::QB_T, + std_extensions::arithmetic::float_types::FLOAT64_TYPE, + types::FunctionType, + Hugr, + }; + use rstest::{fixture, rstest}; + + use crate::{extension::REGISTRY, Circuit, T2Op}; + + use super::{DefaultTasoOptimiser, TasoOptimiser}; + + #[fixture] + fn rz_rz() -> Hugr { + let input_t = vec![QB_T, FLOAT64_TYPE, FLOAT64_TYPE]; + let output_t = vec![QB_T]; + let mut h = DFGBuilder::new(FunctionType::new(input_t, output_t)).unwrap(); + + let mut inps = h.input_wires(); + let qb = inps.next().unwrap(); + let f1 = inps.next().unwrap(); + let f2 = inps.next().unwrap(); + + let res = h.add_dataflow_op(T2Op::RzF64, [qb, f1]).unwrap(); + let qb = res.outputs().next().unwrap(); + let res = h.add_dataflow_op(T2Op::RzF64, [qb, f2]).unwrap(); + let qb = res.outputs().next().unwrap(); + + h.finish_hugr_with_outputs([qb], ®ISTRY).unwrap() + } + + #[fixture] + fn taso_opt() -> DefaultTasoOptimiser { + TasoOptimiser::default_with_eccs_json_file("test_files/small_eccs.json").unwrap() + } + + #[rstest] + fn rz_rz_cancellation(rz_rz: Hugr, taso_opt: DefaultTasoOptimiser) { + let opt_rz = taso_opt.optimise(&rz_rz, None, 1.try_into().unwrap()); + let cmds = opt_rz + .commands() + .map(|cmd| { + ( + cmd.optype().try_into().unwrap(), + cmd.inputs().count(), + cmd.outputs().count(), + ) + }) + .collect::>(); + let exp_cmds = vec![(T2Op::AngleAdd, 2, 1), (T2Op::RzF64, 2, 1)]; + assert_eq!(cmds, exp_cmds); + } +} diff --git a/src/optimiser/taso/log.rs b/src/optimiser/taso/log.rs index 39969ee6..9a44f717 100644 --- a/src/optimiser/taso/log.rs +++ b/src/optimiser/taso/log.rs @@ -1,6 +1,6 @@ //! Logging utilities for the TASO optimiser. -use std::io; +use std::{fmt::Debug, io}; /// Logging configuration for the TASO optimiser. #[derive(Default)] @@ -35,8 +35,8 @@ impl<'w> TasoLogger<'w> { /// Log a new best candidate #[inline] - pub fn log_best(&mut self, best_cost: usize) { - self.log(format!("new best of size {}", best_cost)); + pub fn log_best(&mut self, best_cost: C) { + self.log(format!("new best of size {:?}", best_cost)); if let Some(csv_writer) = self.circ_candidates_csv.as_mut() { csv_writer.serialize(BestCircSer::new(best_cost)).unwrap(); csv_writer.flush().unwrap(); @@ -45,10 +45,10 @@ impl<'w> TasoLogger<'w> { /// Log the final optimised circuit #[inline] - pub fn log_processing_end( + pub fn log_processing_end( &self, circuit_count: usize, - best_cost: usize, + best_cost: C, needs_joining: bool, timeout: bool, ) { @@ -57,7 +57,7 @@ impl<'w> TasoLogger<'w> { } self.log("Optimisation finished"); self.log(format!("Tried {circuit_count} circuits")); - self.log(format!("END RESULT: {}", best_cost)); + self.log(format!("END RESULT: {:?}", best_cost)); if needs_joining { self.log("Joining worker threads"); } @@ -98,14 +98,14 @@ impl<'w> TasoLogger<'w> { // // TODO: Replace this fixed logging. Report back intermediate results. #[derive(serde::Serialize, Clone, Debug)] -struct BestCircSer { - circ_len: usize, +struct BestCircSer { + circ_cost: C, time: String, } -impl BestCircSer { - fn new(circ_len: usize) -> Self { +impl BestCircSer { + fn new(circ_cost: C) -> Self { let time = chrono::Local::now().to_rfc3339(); - Self { circ_len, time } + Self { circ_cost, time } } } diff --git a/src/rewrite/ecc_rewriter.rs b/src/rewrite/ecc_rewriter.rs index 8f0a5a8d..b5fd7a47 100644 --- a/src/rewrite/ecc_rewriter.rs +++ b/src/rewrite/ecc_rewriter.rs @@ -278,7 +278,7 @@ mod tests { let test_file = "test_files/small_eccs.json"; let rewriter = ECCRewriter::try_from_eccs_json_file(test_file).unwrap(); assert_eq!(rewriter.rewrite_rules.len(), rewriter.matcher.n_patterns()); - assert_eq!(rewriter.targets.len(), 5 * 4 + 4 * 3); + assert_eq!(rewriter.targets.len(), 5 * 4 + 5 * 3); // Assert that the rewrite rules are correct, i.e that the rewrite // rules in the slice (k..=k+t) is given by [[k+1, ..., k+t], [k], ..., [k]] @@ -301,8 +301,8 @@ mod tests { curr_repr = TargetID(i); } } - // There should be 4x ECCs of size 3 and 5x ECCs of size 4 - let exp_n_eccs_of_len = [0, 4 * 2 + 5 * 3, 4, 5]; + // There should be 5x ECCs of size 3 and 5x ECCs of size 4 + let exp_n_eccs_of_len = [0, 5 * 2 + 5 * 3, 5, 5]; assert_eq!(n_eccs_of_len, exp_n_eccs_of_len); } } diff --git a/src/rewrite/strategy.rs b/src/rewrite/strategy.rs index 3df7ceeb..fe5c51cb 100644 --- a/src/rewrite/strategy.rs +++ b/src/rewrite/strategy.rs @@ -8,12 +8,13 @@ //! times as there are possible rewrites and applies a different rewrite //! to every circuit. -use std::collections::HashSet; +use std::{collections::HashSet, fmt::Debug, iter::Sum}; +use derive_more::From; use hugr::{ops::OpType, Hugr, HugrView, Node}; use itertools::Itertools; -use crate::{ops::op_matches, T2Op}; +use crate::{ops::op_matches, Circuit, T2Op}; use super::CircuitRewrite; @@ -23,13 +24,22 @@ use super::CircuitRewrite; /// to a circuit according to a strategy. It returns a list of new circuits, /// each obtained by applying one or several non-overlapping rewrites to the /// original circuit. +/// +/// It also assign every circuit a totally ordered cost that can be used when +/// using rewrites for circuit optimisation. pub trait RewriteStrategy { + /// The circuit cost to be minised. + type Cost: Ord; + /// Apply a set of rewrites to a circuit. fn apply_rewrites( &self, rewrites: impl IntoIterator, circ: &Hugr, ) -> Vec; + + /// The cost of a circuit. + fn circuit_cost(&self, circ: &Hugr) -> Self::Cost; } /// A rewrite strategy applying as many non-overlapping rewrites as possible. @@ -45,6 +55,8 @@ pub trait RewriteStrategy { pub struct GreedyRewriteStrategy; impl RewriteStrategy for GreedyRewriteStrategy { + type Cost = usize; + #[tracing::instrument(skip_all)] fn apply_rewrites( &self, @@ -73,68 +85,168 @@ impl RewriteStrategy for GreedyRewriteStrategy { } vec![circ] } + + fn circuit_cost(&self, circ: &Hugr) -> Self::Cost { + circ.num_gates() + } } -/// A rewrite strategy that explores applying each rewrite to copies of the -/// circuit. +/// Exhaustive rewrite strategy allowing smaller or equal cost rewrites. +/// +/// Rewrites are permitted based on a cost function called the major cost: if +/// the major cost of the target of the rewrite is smaller or equal to the major +/// cost of the pattern, the rewrite is allowed. +/// +/// A second cost function, the minor cost, is used as a tie breaker: within +/// circuits with the same major cost, the circuit ordering prioritises circuits +/// with a smaller minor cost. +/// +/// An example would be to use the number of CX gates as major cost and the +/// total number of gates as minor cost. Compared to a [`ExhaustiveGammaStrategy`], +/// that would only order circuits based on the number of CX gates, this creates +/// a less flat optimisation landscape. +#[derive(Debug, Clone)] +pub struct NonIncreasingGateCountStrategy { + major_cost: C1, + minor_cost: C2, +} + +impl ExhaustiveThresholdStrategy for NonIncreasingGateCountStrategy +where + C1: Fn(&OpType) -> usize, + C2: Fn(&OpType) -> usize, +{ + type OpCost = MajorMinorCost; + type SumOpCost = MajorMinorCost; + + fn threshold(&self, pattern_cost: &Self::SumOpCost, target_cost: &Self::SumOpCost) -> bool { + target_cost.major <= pattern_cost.major + } + + fn op_cost(&self, op: &OpType) -> Self::OpCost { + ((self.major_cost)(op), (self.minor_cost)(op)).into() + } +} + +/// Non-increasing rewrite strategy based on CX count. +/// +/// The minor cost to break ties between equal CX counts is the number of +/// quantum gates. +pub type NonIncreasingCXCountStrategy = + NonIncreasingGateCountStrategy usize, fn(&OpType) -> usize>; + +impl NonIncreasingCXCountStrategy { + /// Create rewrite strategy based on non-increasing CX count. + pub fn default_cx() -> Self { + Self { + major_cost: |op| is_cx(op) as usize, + minor_cost: |op| is_quantum(op) as usize, + } + } +} + +/// Exhaustive rewrite strategy allowing rewrites with bounded cost increase. /// /// The parameter gamma controls how greedy the algorithm should be. It allows /// a rewrite C1 -> C2 if C2 has at most gamma times the cost of C1: /// /// $cost(C2) < gamma * cost(C1)$ /// -/// The cost function is given by the number of operations in the circuit that -/// satisfy a given Op predicate. This allows for instance to use the total -/// number of gates (true predicate) or the number of CX gates as cost function. +/// The cost function is given by the sum of the cost of each operation in the +/// circuit. This allows for instance to use of the total number of gates (true +/// predicate), the number of CX gates or a weighted sum of gate types as cost +/// functions. /// /// gamma = 1 is the greedy strategy where a rewrite is only allowed if it /// strictly reduces the gate count. The default is gamma = 1.0001 (as set in /// the Quartz paper) and the number of CX gates. This essentially allows /// rewrites that improve or leave the number of CX unchanged. #[derive(Debug, Clone)] -pub struct ExhaustiveRewriteStrategy

{ +pub struct ExhaustiveGammaStrategy { /// The gamma parameter. pub gamma: f64, - /// Ops to count for cost function. - pub op_predicate: P, + /// A cost function for each operation. + pub op_cost: C, } -impl

ExhaustiveRewriteStrategy

{ +impl usize> ExhaustiveThresholdStrategy for ExhaustiveGammaStrategy { + type OpCost = usize; + type SumOpCost = usize; + + fn threshold(&self, &pattern_cost: &Self::SumOpCost, &target_cost: &Self::SumOpCost) -> bool { + (target_cost as f64) < self.gamma * (pattern_cost as f64) + } + + fn op_cost(&self, op: &OpType) -> Self::OpCost { + (self.op_cost)(op) + } +} + +impl ExhaustiveGammaStrategy { /// New exhaustive rewrite strategy with provided predicate. /// /// The gamma parameter is set to the default 1.0001. - pub fn with_predicate(op_predicate: P) -> Self { + pub fn with_cost(op_cost: C) -> Self { Self { gamma: 1.0001, - op_predicate, + op_cost, } } /// New exhaustive rewrite strategy with provided gamma and predicate. - pub fn new(gamma: f64, op_predicate: P) -> Self { - Self { - gamma, - op_predicate, - } + pub fn new(gamma: f64, op_cost: C) -> Self { + Self { gamma, op_cost } } } -impl ExhaustiveRewriteStrategy bool> { +impl ExhaustiveGammaStrategy usize> { /// Exhaustive rewrite strategy with CX count cost function. /// /// The gamma parameter is set to the default 1.0001. This is a good default /// choice for NISQ-y circuits, where CX gates are the most expensive. pub fn exhaustive_cx() -> Self { - ExhaustiveRewriteStrategy::with_predicate(is_cx) + ExhaustiveGammaStrategy::with_cost(|op| is_cx(op) as usize) } /// Exhaustive rewrite strategy with CX count cost function and provided gamma. pub fn exhaustive_cx_with_gamma(gamma: f64) -> Self { - ExhaustiveRewriteStrategy::new(gamma, is_cx) + ExhaustiveGammaStrategy::new(gamma, |op| is_cx(op) as usize) } } -impl bool> RewriteStrategy for ExhaustiveRewriteStrategy

{ +/// Exhaustive strategies based on cost functions and thresholds. +/// +/// Every possible rewrite is applied to a copy of the input circuit. Thus for +/// one circuit, up to `n` rewritten circuits will be returned, each obtained +/// by applying one of the `n` rewrites to the original circuit. +/// +/// Whether a rewrite is allowed or not is determined by a cost function and a +/// threshold function: if the cost of the target of the rewrite is below the +/// threshold given by the cost of the original circuit, the rewrite is +/// performed. +/// +/// The cost function must return a value of type `Self::OpCost`. All op costs +/// are summed up to obtain a total cost that is then compared using the +/// threshold function. +pub trait ExhaustiveThresholdStrategy { + /// The cost of a single operation. + type OpCost; + /// The sum of the cost of all operations in a circuit. + type SumOpCost; + + /// Whether the rewrite is allowed or not, based on the cost of the pattern and target. + fn threshold(&self, pattern_cost: &Self::SumOpCost, target_cost: &Self::SumOpCost) -> bool; + + /// The cost of a single operation. + fn op_cost(&self, op: &OpType) -> Self::OpCost; +} + +impl RewriteStrategy for T +where + T::SumOpCost: Sum + Ord, +{ + type Cost = T::SumOpCost; + #[tracing::instrument(skip_all)] fn apply_rewrites( &self, @@ -144,9 +256,9 @@ impl bool> RewriteStrategy for ExhaustiveRewriteStrategy

{ rewrites .into_iter() .filter(|rw| { - let old_count = pre_rewrite_cost(rw, circ, &self.op_predicate) as f64; - let new_count = post_rewrite_cost(rw, circ, &self.op_predicate) as f64; - new_count < old_count * self.gamma + let pattern_cost = pre_rewrite_cost(rw, circ, |op| self.op_cost(op)); + let target_cost = post_rewrite_cost(rw, circ, |op| self.op_cost(op)); + self.threshold(&pattern_cost, &target_cost) }) .map(|rw| { let mut circ = circ.clone(); @@ -155,31 +267,85 @@ impl bool> RewriteStrategy for ExhaustiveRewriteStrategy

{ }) .collect() } + + fn circuit_cost(&self, circ: &Hugr) -> Self::Cost { + cost(circ.nodes(), circ, |op| self.op_cost(op)) + } +} + +/// A pair of major and minor cost. +/// +/// This is used to order circuits based on major cost first, then minor cost. +/// A typical example would be CX count as major cost and total gate count as +/// minor cost. +#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, From)] +pub struct MajorMinorCost { + major: usize, + minor: usize, +} + +// Serialise as string so that it is easy to write to CSV +impl serde::Serialize for MajorMinorCost { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_str(&format!("{:?}", self)) + } +} + +impl Debug for MajorMinorCost { + // TODO: A nicer print for the logs + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "(major={}, minor={})", self.major, self.minor) + } +} + +impl Sum for MajorMinorCost { + fn sum>(iter: I) -> Self { + iter.reduce(|a, b| (a.major + b.major, a.minor + b.minor).into()) + .unwrap_or_default() + } } fn is_cx(op: &OpType) -> bool { op_matches(op, T2Op::CX) } -fn cost( - nodes: impl IntoIterator, - circ: &Hugr, - pred: impl Fn(&OpType) -> bool, -) -> usize { +fn is_quantum(op: &OpType) -> bool { + let Ok(op): Result = op.try_into() else { + return false; + }; + op.is_quantum() +} + +fn cost(nodes: impl IntoIterator, circ: &Hugr, op_cost: C) -> S +where + C: Fn(&OpType) -> T, + S: Sum, +{ nodes .into_iter() - .filter(|n| { - let op = circ.get_optype(*n); - pred(op) + .map(|n| { + let op = circ.get_optype(n); + op_cost(op) }) - .count() + .sum() } -fn pre_rewrite_cost(rw: &CircuitRewrite, circ: &Hugr, pred: impl Fn(&OpType) -> bool) -> usize { +fn pre_rewrite_cost(rw: &CircuitRewrite, circ: &Hugr, pred: C) -> S +where + C: Fn(&OpType) -> T, + S: Sum, +{ cost(rw.subcircuit().nodes().iter().copied(), circ, pred) } -fn post_rewrite_cost(rw: &CircuitRewrite, circ: &Hugr, pred: impl Fn(&OpType) -> bool) -> usize { +fn post_rewrite_cost(rw: &CircuitRewrite, circ: &Hugr, pred: C) -> S +where + C: Fn(&OpType) -> T, + S: Sum, +{ cost(rw.replacement().nodes(), circ, pred) } @@ -258,7 +424,7 @@ mod tests { rw_to_empty(&circ, cx_gates[9..10].to_vec()), ]; - let strategy = ExhaustiveRewriteStrategy::exhaustive_cx(); + let strategy = ExhaustiveGammaStrategy::exhaustive_cx(); let rewritten = strategy.apply_rewrites(rws, &circ); let exp_circ_lens = HashSet::from_iter([8, 6, 9]); let circ_lens: HashSet<_> = rewritten.iter().map(|c| c.num_gates()).collect(); @@ -280,10 +446,34 @@ mod tests { rw_to_empty(&circ, cx_gates[9..10].to_vec()), ]; - let strategy = ExhaustiveRewriteStrategy::exhaustive_cx_with_gamma(10.); + let strategy = ExhaustiveGammaStrategy::exhaustive_cx_with_gamma(10.); let rewritten = strategy.apply_rewrites(rws, &circ); let exp_circ_lens = HashSet::from_iter([8, 17, 6, 9]); let circ_lens: HashSet<_> = rewritten.iter().map(|c| c.num_gates()).collect(); assert_eq!(circ_lens, exp_circ_lens); } + + #[test] + fn test_exhaustive_default_cx_cost() { + let strat = NonIncreasingCXCountStrategy::default_cx(); + let circ = n_cx(3); + assert_eq!(strat.circuit_cost(&circ), (3, 3).into()); + let circ = build_simple_circuit(2, |circ| { + circ.append(T2Op::CX, [0, 1])?; + circ.append(T2Op::X, [0])?; + circ.append(T2Op::X, [1])?; + Ok(()) + }) + .unwrap(); + assert_eq!(strat.circuit_cost(&circ), (1, 3).into()); + } + + #[test] + fn test_exhaustive_default_cx_threshold() { + let strat = NonIncreasingCXCountStrategy::default_cx(); + assert!(strat.threshold(&(3, 0).into(), &(3, 0).into())); + assert!(strat.threshold(&(3, 0).into(), &(3, 5).into())); + assert!(!strat.threshold(&(3, 10).into(), &(4, 0).into())); + assert!(strat.threshold(&(3, 0).into(), &(1, 5).into())); + } } diff --git a/test_files/small_eccs.json b/test_files/small_eccs.json index 787d10a6..06e29e54 100644 --- a/test_files/small_eccs.json +++ b/test_files/small_eccs.json @@ -50,5 +50,10 @@ ,[[2,0,0,3,["116baec0e00cd"],[5.53564910528592469e-01,2.63161770391809990e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] ,[[2,0,0,3,["116baec0e00cd"],[5.53564910528592469e-01,2.63161770391809990e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] ] +,"6701_3": [ +[[1,2,3,2,["a720832fadf2"],[2.22710267824423158e-01,2.92349563045663841e-01]],[["add", ["P2"],["P0", "P1"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[1,2,2,2,["a720832fadf2"],[2.22710267824423158e-01,2.92349563045663841e-01]],[["rz", ["Q0"],["Q0", "P0"]],["rz", ["Q0"],["Q0", "P1"]]]] +,[[1,2,2,2,["a720832fadf2"],[2.22710267824423103e-01,2.92349563045663619e-01]],[["rz", ["Q0"],["Q0", "P1"]],["rz", ["Q0"],["Q0", "P0"]]]] +] } ] \ No newline at end of file From 990d78f76098a32e403d2cfe9db0ae7326168a53 Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Tue, 3 Oct 2023 09:43:47 +0200 Subject: [PATCH 06/11] Remove unused import --- src/optimiser/taso.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/optimiser/taso.rs b/src/optimiser/taso.rs index 7208d841..67a3f249 100644 --- a/src/optimiser/taso.rs +++ b/src/optimiser/taso.rs @@ -27,7 +27,7 @@ use std::num::NonZeroUsize; use std::time::{Duration, Instant}; use fxhash::FxHashSet; -use hugr::{Hugr, HugrView}; +use hugr::Hugr; use crate::circuit::CircuitHash; use crate::optimiser::taso::hugr_pchannel::HugrPriorityChannel; From 4c10e519169b280e930f098b9b628c26b51378cf Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Tue, 3 Oct 2023 10:03:06 +0200 Subject: [PATCH 07/11] fix docs --- src/rewrite/strategy.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/rewrite/strategy.rs b/src/rewrite/strategy.rs index fe5c51cb..aae2e810 100644 --- a/src/rewrite/strategy.rs +++ b/src/rewrite/strategy.rs @@ -2,11 +2,15 @@ //! //! This module contains the [`RewriteStrategy`] trait, which is currently //! implemented by -//! - [`GreedyRewriteStrategy`], which applies as many rewrites as possible +//! - [`GreedyRewriteStrategy`], which applies as many rewrites as possible //! on one circuit, and -//! - [`ExhaustiveRewriteStrategy`], which clones the original circuit as many -//! times as there are possible rewrites and applies a different rewrite -//! to every circuit. +//! - exhaustive strategies, which clone the original circuit and explore every +//! possible rewrite (with some pruning strategy): +//! - [`NonIncreasingGateCountStrategy`], which only considers rewrites that +//! do not increase some cost function (e.g. cx gate count, implemented as +//! [`NonIncreasingCXCountStrategy`]), and +//! - [`ExhaustiveGammaStrategy`], which ignores rewrites that increase the +//! cost function beyond a threshold given by a f64 parameter gamma. use std::{collections::HashSet, fmt::Debug, iter::Sum}; From dc699af146d651b453a6faf990d2cc1161f18b0f Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Tue, 3 Oct 2023 12:07:29 +0200 Subject: [PATCH 08/11] Add termination test --- test_files/Nam_4_2_complete_ECC_set.json | 412 +++++++++++++++++++++++ tests/taso_termination.rs | 34 ++ 2 files changed, 446 insertions(+) create mode 100644 test_files/Nam_4_2_complete_ECC_set.json create mode 100644 tests/taso_termination.rs diff --git a/test_files/Nam_4_2_complete_ECC_set.json b/test_files/Nam_4_2_complete_ECC_set.json new file mode 100644 index 00000000..4e7b533b --- /dev/null +++ b/test_files/Nam_4_2_complete_ECC_set.json @@ -0,0 +1,412 @@ +[[], +{ +"0_2": [ +[[1,2,3,3,["1179296cd3522"],[4.99610675544946536e-01,3.58262240998448722e-01]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P0"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[1,2,3,3,["1179296cd3522"],[4.99610675544946536e-01,3.58262240998448722e-01]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P2"]],["rz", ["Q0"],["Q0", "P0"]]]] +] +,"1_2": [ +[[1,0,0,4,["1394b89e8edbb"],[-5.07456696783136207e-01,4.65972495953195120e-01]],[["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]]]] +,[[1,0,0,4,["1394b89e8edbb"],[5.07456696783136207e-01,-4.65972495953195120e-01]],[["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"2_2": [ +[[1,1,1,4,["1477aae520bc3"],[4.31331659005208645e-01,-5.76668527993072111e-01]],[["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]]]] +,[[1,1,1,4,["1477aae520bc3"],[4.31331659005208645e-01,-5.76668527993072111e-01]],[["rz", ["Q0"],["Q0", "P0"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"3_2": [ +[[1,1,1,4,["110a8c53d7174"],[4.42374675628790459e-01,-4.04729147371692966e-01]],[["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]]]] +,[[1,1,1,4,["110a8c53d7174"],[4.42374675628790459e-01,-4.04729147371692966e-01]],[["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["h", ["Q0"],["Q0"]]]] +] +,"4_2": [ +[[1,2,4,4,["12e69db784270"],[4.76648118332313575e-01,4.63735518426349913e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P2"]],["rz", ["Q0"],["Q0", "P3"]]]] +,[[1,2,4,4,["12e69db78426f"],[4.76648118332313575e-01,4.63735518426349802e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P3"]],["rz", ["Q0"],["Q0", "P2"]]]] +] +,"5_2": [ +[[1,2,2,4,["1c16fc733f209"],[-7.50808264948312098e-01,-6.42702537225969817e-01]],[["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]]]] +,[[1,2,2,4,["1c16fc733f209"],[-7.50808264948312098e-01,-6.42702537225969817e-01]],[["rz", ["Q0"],["Q0", "P0"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["x", ["Q0"],["Q0"]]]] +] +,"6_2": [ +[[1,1,2,5,["fb5051d0cd45"],[3.94855335833779630e-01,-3.86659428330336175e-01]],[["add", ["P1"],["P0", "P0"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]]]] +,[[1,1,2,5,["fb5051d0cd45"],[3.94855335833779408e-01,-3.86659428330336175e-01]],[["add", ["P1"],["P0", "P0"]],["rz", ["Q0"],["Q0", "P1"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"7_2": [ +[[1,1,2,5,["143b041acff44"],[4.54853410535677738e-01,5.47508485597311578e-01]],[["add", ["P1"],["P0", "P0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]]]] +,[[1,1,2,5,["143b041acff44"],[4.54853410535677738e-01,5.47508485597311578e-01]],[["add", ["P1"],["P0", "P0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["h", ["Q0"],["Q0"]]]] +] +,"8_2": [ +[[1,2,3,5,["1c3010c9785db"],[6.38076918057808085e-01,-7.59251345488965446e-01]],[["add", ["P2"],["P0", "P1"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[1,2,3,5,["1c3010c9785da"],[6.38076918057808085e-01,-7.59251345488965335e-01]],[["add", ["P2"],["P0", "P1"]],["rz", ["Q0"],["Q0", "P2"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"9_2": [ +[[1,2,3,5,["138b431ed8594"],[6.87553554699991243e-01,1.10981477210586356e-02]],[["add", ["P2"],["P0", "P1"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]]]] +,[[1,2,3,5,["138b431ed8594"],[6.87553554699991243e-01,1.10981477210586356e-02]],[["add", ["P2"],["P0", "P1"]],["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["h", ["Q0"],["Q0"]]]] +] +,"10_2": [ +[[1,2,3,5,["8f73dd31e7b7"],[-2.74822210392450028e-01,-1.54870855862913936e-01]],[["add", ["P2"],["P1", "P1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[1,2,3,5,["8f73dd31e7b7"],[-2.74822210392450028e-01,-1.54870855862913936e-01]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["x", ["Q0"],["Q0"]]]] +] +,"11_2": [ +[[1,2,3,5,["170abc6aefd17"],[-6.41727125364166873e-01,-4.95425975462358004e-01]],[["add", ["P2"],["P1", "P1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]]]] +,[[1,2,3,5,["170abc6aefd17"],[-6.41727125364166762e-01,-4.95425975462357948e-01]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P0"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q0"],["Q0"]]]] +] +,"12_2": [ +[[1,2,4,6,["1bee71a43d3cb"],[7.44655406244852491e-01,6.41315024830592328e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P3"]]]] +,[[1,2,4,6,["1bee71a43d3cb"],[7.44655406244852491e-01,6.41315024830592328e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P3"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q0"],["Q0"]]]] +] +,"13_2": [ +[[1,2,4,6,["c335f4196d9e"],[-2.88625171623649646e-01,-3.17759046997843630e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P3"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[1,2,4,6,["c335f4196d9e"],[-2.88625171623649535e-01,-3.17759046997843742e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P3"]],["x", ["Q0"],["Q0"]]]] +] +,"14_2": [ +[[2,0,0,2,["ba2e43527cef"],[4.02978446523274692e-01,-7.23160053854092627e-02]],[["x", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,3,["ba2e43527cef"],[4.02978446523274692e-01,-7.23160053854092627e-02]],[["x", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]]]] +] +,"15_2": [ +[[2,0,0,2,["d4a671872f1f"],[2.67572505081633660e-01,3.83504778061658003e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]]]] +,[[2,0,0,3,["d4a671872f1f"],[2.67572505081633660e-01,3.83504778061658003e-01]],[["x", ["Q0"],["Q0"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"16_2": [ +[[2,1,1,2,["a6a9abe424f3"],[1.00145497688299084e-01,-3.52547449378692868e-01]],[["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,1,1,2,["a6a9abe424f3"],[1.00145497688299084e-01,-3.52547449378692868e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q1"],["Q1", "P0"]]]] +] +,"17_2": [ +[[2,1,1,2,["c2e542e62f92"],[-3.93353760349960613e-01,1.70157304316007923e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]]]] +,[[2,1,1,4,["c2e542e62f92"],[-3.93353760349960613e-01,1.70157304316007923e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"18_2": [ +[[2,0,0,3,["11648eb6bbe2b"],[6.11420782017676689e-01,-2.55607747826418763e-02]],[["h", ["Q0"],["Q0"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,3,["11648eb6bbe2b"],[6.11420782017676689e-01,-2.55607747826418763e-02]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["h", ["Q1"],["Q1"]]]] +] +,"19_2": [ +[[2,0,0,3,["9025014df7ba"],[2.04714241805956210e-01,2.42005448901186193e-01]],[["h", ["Q0"],["Q0"]],["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,0,0,3,["9025014df7ba"],[2.04714241805956265e-01,2.42005448901186138e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]],["h", ["Q1"],["Q1"]]]] +] +,"20_2": [ +[[2,0,0,3,["dd108e601d1d"],[4.72465707879013486e-01,1.14433337103188565e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]]]] +,[[2,0,0,3,["dd108e601d1d"],[4.72465707879013541e-01,1.14433337103188593e-01]],[["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]]]] +] +,"21_2": [ +[[2,0,0,3,["126c365107094"],[5.92467397138391472e-01,2.62934022214009244e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]]]] +,[[2,0,0,3,["126c365107094"],[5.92467397138391472e-01,2.62934022214009244e-01]],[["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"22_2": [ +[[2,0,0,3,["10635e5e8a6db"],[3.66077655247273426e-01,-4.45491714911118164e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +,[[2,0,0,3,["10635e5e8a6db"],[3.66077655247273315e-01,-4.45491714911118108e-01]],[["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]]]] +] +,"23_2": [ +[[2,0,0,3,["a7b37651a72b"],[3.13443299174714085e-01,-1.94295766633558908e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]]]] +,[[2,0,0,3,["a7b37651a72b"],[3.13443299174714196e-01,-1.94295766633558881e-01]],[["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]]]] +] +,"24_2": [ +[[2,0,0,3,["e1ba8c939ba4"],[4.92246470150813520e-01,-6.39466570559793501e-02]],[["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,3,["e1ba8c939ba4"],[4.92246470150813520e-01,-6.39466570559793501e-02]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]]]] +] +,"25_2": [ +[[2,0,0,3,["c1a8c73ee4fa"],[2.92553538272223412e-01,3.09467703524959392e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,3,["c1a8c73ee4fa"],[2.92553538272223412e-01,3.09467703524959392e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"26_2": [ +[[2,1,2,3,["1207dc9a84f89"],[-6.28018317738627596e-01,-8.97515741507558529e-02]],[["add", ["P1"],["P0", "P0"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,1,2,3,["1207dc9a84f89"],[-6.28018317738627596e-01,-8.97515741507558529e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q1"],["Q1", "P1"]]]] +] +,"27_2": [ +[[2,1,2,3,["f19ed2779e4f"],[-4.57233476165699093e-01,-2.70643535172195249e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P1"]]]] +,[[2,1,2,5,["f19ed2779e4f"],[-4.57233476165699093e-01,-2.70643535172195249e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"28_2": [ +[[2,1,1,3,["1a81b4fb7f6b5"],[-1.27064046841455169e-01,9.23924053664822109e-01]],[["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["x", ["Q1"],["Q1"]]]] +,[[2,1,1,4,["1a81b4fb7f6b5"],[-1.27064046841455169e-01,9.23924053664822109e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +] +,"29_2": [ +[[2,1,1,3,["1a1bf525df70b"],[-1.06033579476926265e-01,9.12496156500379629e-01]],[["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,1,4,["1a1bf525df70b"],[-1.06033579476926265e-01,9.12496156500379629e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["x", ["Q1"],["Q1"]]]] +] +,"30_2": [ +[[2,1,1,3,["a4eb509eda88"],[-2.97625564677612142e-01,2.07224843261055863e-01]],[["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,1,1,3,["a4eb509eda88"],[-2.97625564677612142e-01,2.07224843261055863e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]]]] +] +,"31_2": [ +[[2,1,1,3,["1819ce0cf3f41"],[-8.36196316123303585e-01,-1.40824112729210082e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,1,3,["1819ce0cf3f41"],[-8.36196316123303585e-01,-1.40824112729210082e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"32_2": [ +[[2,1,1,3,["eb710d9a71d5"],[5.07619057058527501e-01,1.01878559238475636e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]]]] +,[[2,1,1,4,["eb710d9a71d5"],[5.07619057058527501e-01,1.01878559238475636e-01]],[["x", ["Q0"],["Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"33_2": [ +[[2,2,3,3,["e056fe7031c3"],[-3.29935816638865897e-01,-3.66763339515337183e-01]],[["add", ["P2"],["P0", "P1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,3,3,["e056fe7031c3"],[-3.29935816638865897e-01,-3.66763339515337183e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q1"],["Q1", "P2"]]]] +] +,"34_2": [ +[[2,2,3,3,["1264f8d843fae"],[-6.46427114379080070e-01,-3.15419523760087639e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[2,2,3,5,["1264f8d843fae"],[-6.46427114379080070e-01,-3.15419523760087639e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"35_2": [ +[[2,0,0,4,["bcc5aad19913"],[-3.94700581836206099e-01,-1.28574297981211894e-01]],[["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,0,0,4,["bcc5aad19913"],[-3.94700581836205933e-01,-1.28574297981211894e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]],["h", ["Q1"],["Q1"]]]] +] +,"36_2": [ +[[2,0,0,4,["132106926384f"],[6.73034479332706881e-01,-3.19931652392527882e-03]],[["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]]]] +,[[2,0,0,4,["132106926384f"],[6.73034479332706881e-01,-3.19931652392527882e-03]],[["x", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]]]] +] +,"37_2": [ +[[2,0,0,4,["f9af42cda15f"],[2.39616834211689611e-01,-4.94017357896040843e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +,[[2,0,0,4,["f9af42cda15f"],[2.39616834211689667e-01,-4.94017357896040843e-01]],[["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]]]] +] +,"38_2": [ +[[2,0,0,4,["d2be00337da5"],[4.39904120210297900e-01,-1.45770123648636174e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]]]] +,[[2,0,0,4,["d2be00337da5"],[4.39904120210297900e-01,-1.45770123648636118e-01]],[["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]]]] +] +,"39_2": [ +[[2,0,0,4,["7e74af8e7ccb"],[2.76755224540641498e-01,-2.71038154712245488e-02]],[["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,4,["7e74af8e7ccb"],[2.76755224540641498e-01,-2.71038154712245488e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]]]] +] +,"40_2": [ +[[2,0,0,4,["1296c27e14c3d"],[5.24914166953547978e-01,3.90169291330624612e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]],["x", ["Q1"],["Q1"]]]] +,[[2,0,0,4,["1296c27e14c3e"],[5.24914166953548089e-01,3.90169291330624612e-01]],[["h", ["Q1"],["Q1"]],["x", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]]]] +] +,"41_2": [ +[[2,0,0,4,["ec7172195b64"],[5.18640932175366887e-01,-3.67875690484726903e-02]],[["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]]]] +,[[2,0,0,4,["ec7172195b64"],[5.18640932175366887e-01,-3.67875690484727041e-02]],[["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]]]] +] +,"42_2": [ +[[2,0,0,4,["137bee14e04b3"],[5.46292172842038015e-01,4.14154928365670527e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]]]] +,[[2,0,0,4,["137bee14e04b3"],[5.46292172842038015e-01,4.14154928365670583e-01]],[["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"43_2": [ +[[2,0,0,4,["ad54a315dcd2"],[-3.20744297410717749e-01,-2.05923662368855565e-01]],[["h", ["Q1"],["Q1"]],["x", ["Q1"],["Q1"]],["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,0,0,4,["ad54a315dcd2"],[-3.20744297410717805e-01,-2.05923662368855565e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]],["x", ["Q1"],["Q1"]],["h", ["Q1"],["Q1"]]]] +] +,"44_2": [ +[[2,0,0,4,["16b8b1d1b770f"],[7.95386176674361622e-01,8.04102857176419439e-02]],[["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,4,["16b8b1d1b770f"],[7.95386176674361622e-01,8.04102857176419439e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q0"],["Q0"]]]] +] +,"45_2": [ +[[2,0,0,4,["e0416a45ff26"],[3.44046494932764180e-01,-3.53301779009805916e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,4,["e0416a45ff26"],[3.44046494932764180e-01,-3.53301779009805916e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"46_2": [ +[[2,0,0,4,["14b9a0a2e5d95"],[6.95934241526035446e-01,-2.17733804881456161e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,4,["14b9a0a2e5d95"],[6.95934241526035446e-01,-2.17733804881456161e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"47_2": [ +[[2,0,0,4,["19403bcb53fdd"],[5.82570985287794829e-01,6.70769880988775435e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,0,0,4,["19403bcb53fdd"],[5.82570985287794829e-01,6.70769880988775435e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +] +,"48_2": [ +[[2,0,0,4,["f227ec39545c"],[3.14160074283455826e-01,4.29961260963855119e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,4,["f227ec39545c"],[3.14160074283455826e-01,4.29961260963855119e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"49_2": [ +[[2,0,0,4,["8e99d5137822"],[3.06451128042800058e-01,-6.64967919579081412e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,0,0,4,["8e99d5137822"],[3.06451128042800058e-01,-6.64967919579081412e-02]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +] +,"50_2": [ +[[2,1,2,4,["d0b5d3937e00"],[-3.73900020208510209e-01,-2.66161373279159841e-01]],[["add", ["P1"],["P0", "P0"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["x", ["Q1"],["Q1"]]]] +,[[2,1,2,5,["d0b5d3937e00"],[-3.73900020208510209e-01,-2.66161373279159841e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +] +,"51_2": [ +[[2,1,2,4,["c801c81001f4"],[-3.66283501642580500e-01,-2.43470713612538414e-01]],[["add", ["P1"],["P0", "P0"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,2,5,["c801c81001f4"],[-3.66283501642580500e-01,-2.43470713612538414e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["x", ["Q1"],["Q1"]]]] +] +,"52_2": [ +[[2,1,2,4,["12220e5294dc5"],[-5.88707368963910294e-01,-2.45899888306207931e-01]],[["add", ["P1"],["P0", "P0"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,1,2,4,["12220e5294dc5"],[-5.88707368963910294e-01,-2.45899888306207931e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P1"]]]] +] +,"53_2": [ +[[2,1,2,4,["24b281e1f21a"],[7.06546289869234567e-02,3.89887609726142781e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,2,4,["24b281e1f21a"],[7.06546289869234567e-02,3.89887609726142781e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"54_2": [ +[[2,1,2,4,["1154b3dff5cd8"],[-4.43243772721956919e-01,-4.18761798849057731e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]]]] +,[[2,1,2,5,["1154b3dff5cd8"],[-4.43243772721956919e-01,-4.18761798849057731e-01]],[["add", ["P1"],["P0", "P0"]],["x", ["Q0"],["Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"55_2": [ +[[2,1,1,4,["b72446ac1ef6"],[-2.94617062780019312e-01,2.74580674291240279e-01]],[["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,1,4,["b72446ac1ef6"],[-2.94617062780019312e-01,2.74580674291240279e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]],["h", ["Q1"],["Q1"]]]] +] +,"56_2": [ +[[2,1,1,4,["65a10fff17e8"],[1.18220560156663906e-01,1.89655962349406626e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]]]] +,[[2,1,1,4,["65a10fff17e8"],[1.18220560156663879e-01,1.89655962349406709e-01]],[["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"57_2": [ +[[2,1,1,4,["dfe0a0886087"],[-4.26774656237966954e-01,2.45426608979808170e-01]],[["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P0"]]]] +,[[2,1,1,4,["dfe0a0886087"],[-4.26774656237966954e-01,2.45426608979808253e-01]],[["rz", ["Q0"],["Q0", "P0"]],["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"58_2": [ +[[2,1,1,4,["31984a83f8da"],[-2.33596621791979930e-02,1.06529232512171460e-01]],[["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,1,4,["31984a83f8da"],[-2.33596621791979930e-02,1.06529232512171460e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]],["h", ["Q1"],["Q1"]]]] +] +,"59_2": [ +[[2,1,1,4,["bc38374e6cec"],[-3.05489421296612607e-01,2.79264774619253975e-01]],[["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,1,1,4,["bc38374e6cec"],[-3.05489421296612607e-01,2.79264774619253975e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P0"]],["x", ["Q1"],["Q1"]]]] +] +,"60_2": [ +[[2,1,1,4,["696abeea1393"],[-2.17883328889995925e-01,-7.91502507536800959e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,1,4,["696abeea1393"],[-2.17883328889995925e-01,-7.91502507536800959e-02]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"61_2": [ +[[2,1,1,4,["68b145ff45e9"],[-1.63196547744800913e-01,-1.62384362412979460e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]]]] +,[[2,1,1,4,["68b145ff45e9"],[-1.63196547744800913e-01,-1.62384362412979460e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]],["x", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"62_2": [ +[[2,1,1,4,["11740b422996b"],[-5.53770327587918665e-01,-2.65399151150483015e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,1,4,["11740b422996b"],[-5.53770327587918665e-01,-2.65399151150483015e-01]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"63_2": [ +[[2,2,3,4,["14904594c5a54"],[-3.59075791128417476e-01,6.28124182668194142e-01]],[["add", ["P2"],["P0", "P1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q1"],["Q1"]]]] +,[[2,2,3,5,["14904594c5a54"],[-3.59075791128417476e-01,6.28124182668194142e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +] +,"64_2": [ +[[2,2,3,4,["145ecfc4176cb"],[-3.35694306132104714e-01,6.33241169138646365e-01]],[["add", ["P2"],["P0", "P1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["145ecfc4176cb"],[-3.35694306132104714e-01,6.33241169138646365e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q1"],["Q1"]]]] +] +,"65_2": [ +[[2,2,3,4,["127dac63c91ee"],[-6.50364020067731863e-01,1.71884851209546108e-02]],[["add", ["P2"],["P0", "P1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,3,4,["127dac63c91ee"],[-6.50364020067731863e-01,1.71884851209546108e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +] +,"66_2": [ +[[2,2,3,4,["1390ceafbc83b"],[-6.81567263431638426e-01,-9.67876228023531182e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,4,["1390ceafbc83b"],[-6.81567263431638426e-01,-9.67876228023531182e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"67_2": [ +[[2,2,3,4,["6d420eed73be"],[1.47802058046897111e-01,-1.89419867032258354e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]]]] +,[[2,2,3,5,["6d420eed73be"],[1.47802058046897111e-01,-1.89419867032258354e-01]],[["add", ["P2"],["P0", "P1"]],["x", ["Q0"],["Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"68_2": [ +[[2,2,2,4,["17dec7de85eeb"],[-8.37920938533132320e-01,-5.70277199374577409e-02]],[["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,2,4,["17dec7de85eeb"],[-8.37920938533132209e-01,-5.70277199374577409e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P1"]]]] +] +,"69_2": [ +[[2,2,2,4,["1193bd92fc0fe"],[8.26700808276732563e-02,-6.12889249263151692e-01]],[["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,2,4,["1193bd92fc0fe"],[8.26700808276732563e-02,-6.12889249263151692e-01]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P1"]]]] +] +,"70_2": [ +[[2,1,2,5,["e9d20945c669"],[-5.09462921753444431e-01,-6.94631106518156793e-02]],[["add", ["P1"],["P0", "P0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,2,5,["e9d20945c669"],[-5.09462921753444431e-01,-6.94631106518156793e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]],["h", ["Q1"],["Q1"]]]] +] +,"71_2": [ +[[2,1,2,5,["14479fcdd00f2"],[-6.33379879392728329e-01,-3.28568089450425704e-01]],[["add", ["P1"],["P0", "P0"]],["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]]]] +,[[2,1,2,5,["14479fcdd00f2"],[-6.33379879392728329e-01,-3.28568089450425593e-01]],[["add", ["P1"],["P0", "P0"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"72_2": [ +[[2,1,2,5,["bfb1511b2845"],[-2.18384136228260944e-01,3.60557150472222698e-01]],[["add", ["P1"],["P0", "P0"]],["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P1"]]]] +,[[2,1,2,5,["bfb1511b2845"],[-2.18384136228260944e-01,3.60557150472222587e-01]],[["add", ["P1"],["P0", "P0"]],["rz", ["Q0"],["Q0", "P1"]],["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"73_2": [ +[[2,1,2,5,["9764fb415715"],[-3.01434639197742160e-01,-1.41325305333676737e-01]],[["add", ["P1"],["P0", "P0"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,2,5,["9764fb415715"],[-3.01434639197742160e-01,-1.41325305333676737e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]],["h", ["Q1"],["Q1"]]]] +] +,"74_2": [ +[[2,1,2,5,["10661405dc5bd"],[-4.87640608457623859e-01,-3.08402258669036367e-01]],[["add", ["P1"],["P0", "P0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,1,2,5,["10661405dc5bd"],[-4.87640608457623859e-01,-3.08402258669036367e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P1"]],["x", ["Q1"],["Q1"]]]] +] +,"75_2": [ +[[2,1,2,5,["a007fd046d39"],[-3.42470273468699071e-01,8.09716433883308079e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,2,5,["a007fd046d39"],[-3.42470273468699071e-01,8.09716433883308079e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P1"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"76_2": [ +[[2,1,2,5,["18c4ce01fc448"],[-8.70295832330430841e-01,-4.52916989873856923e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]]]] +,[[2,1,2,5,["18c4ce01fc448"],[-8.70295832330430841e-01,-4.52916989873856923e-02]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P1"]],["x", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"77_2": [ +[[2,1,2,5,["6d159ac2b352"],[-1.00910742210391702e-01,-2.17621259493809616e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,1,2,5,["6d159ac2b352"],[-1.00910742210391702e-01,-2.17621259493809616e-01]],[["add", ["P1"],["P0", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"78_2": [ +[[2,2,3,5,["11c81f2f23829"],[-5.95102040503439955e-01,1.93073929112878018e-01]],[["add", ["P2"],["P0", "P1"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["11c81f2f23829"],[-5.95102040503439955e-01,1.93073929112878018e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]],["h", ["Q1"],["Q1"]]]] +] +,"79_2": [ +[[2,2,3,5,["927eac22f33d"],[-3.17750259927077283e-01,-5.30329843346062924e-02]],[["add", ["P2"],["P0", "P1"]],["h", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]]]] +,[[2,2,3,5,["927eac22f33d"],[-3.17750259927077505e-01,-5.30329843346063201e-02]],[["add", ["P2"],["P0", "P1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"80_2": [ +[[2,2,3,5,["138a4fb763d50"],[-5.16879539388334308e-01,4.53330895242939680e-01]],[["add", ["P2"],["P0", "P1"]],["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[2,2,3,5,["138a4fb763d50"],[-5.16879539388334197e-01,4.53330895242939680e-01]],[["add", ["P2"],["P0", "P1"]],["rz", ["Q0"],["Q0", "P2"]],["h", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["h", ["Q0"],["Q0"]]]] +] +,"81_2": [ +[[2,2,3,5,["6450572c5bf9"],[-2.20589845000729756e-01,-1.07109193331078600e-03]],[["add", ["P2"],["P0", "P1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]],["h", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["6450572c5bf9"],[-2.20589845000729756e-01,-1.07109193331078600e-03]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["h", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]],["h", ["Q1"],["Q1"]]]] +] +,"82_2": [ +[[2,2,3,5,["10ce7a507e845"],[-5.90077893505632778e-01,3.84309286505906678e-02]],[["add", ["P2"],["P0", "P1"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,3,5,["10ce7a507e845"],[-5.90077893505632778e-01,3.84309286505906678e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["rz", ["Q1"],["Q1", "P2"]],["x", ["Q1"],["Q1"]]]] +] +,"83_2": [ +[[2,2,3,5,["bde687f4cf55"],[-4.17320078160656083e-01,-1.51681489094598332e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["bde687f4cf55"],[-4.17320078160656083e-01,-1.51681489094598332e-02]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"84_2": [ +[[2,2,3,5,["150b7ef280a81"],[-7.20303351382400203e-01,-1.71557410665941656e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]]]] +,[[2,2,3,5,["150b7ef280a81"],[-7.20303351382400203e-01,-1.71557410665941656e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]],["x", ["Q0"],["Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"85_2": [ +[[2,2,3,5,["12eb888c7c7f2"],[-5.49483482926825695e-01,-3.75780909684685471e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["12eb888c7c7f2"],[-5.49483482926825695e-01,-3.75780909684685471e-01]],[["add", ["P2"],["P0", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"86_2": [ +[[2,2,3,5,["5fe144714b86"],[-1.76300178602371238e-01,1.15640380757876193e-01]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["5fe144714b86"],[-1.76300178602371183e-01,1.15640380757876138e-01]],[["add", ["P2"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]]]] +] +,"87_2": [ +[[2,2,3,5,["a8eb6c2da5bf"],[6.95034542710955550e-02,-3.64897852777678444e-01]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,3,5,["a8eb6c2da5bf"],[6.95034542710956105e-02,-3.64897852777678389e-01]],[["add", ["P2"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]]]] +] +,"88_2": [ +[[2,2,3,5,["c5a4d6bcca20"],[-4.31184363134475446e-01,5.45679671823712797e-02]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["c5a4d6bcca20"],[-4.31184363134475557e-01,5.45679671823713353e-02]],[["add", ["P2"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]]]] +] +,"89_2": [ +[[2,2,3,5,["103fc9a344e83"],[1.54657964223052169e-01,-5.50400838652711166e-01]],[["add", ["P2"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,3,5,["103fc9a344e83"],[1.54657964223052086e-01,-5.50400838652711277e-01]],[["add", ["P2"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +] +,"90_2": [ +[[2,2,3,5,["5892b8ce96e6"],[-1.94694716150023317e-01,-5.57008449151208396e-03]],[["add", ["P2"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P0"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,3,5,["5892b8ce96e6"],[-1.94694716150023317e-01,-5.57008449151208396e-03]],[["add", ["P2"],["P1", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P0"]],["rz", ["Q0"],["Q0", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"91_2": [ +[[2,2,4,6,["17cd7f25e4d8b"],[8.31685679489962415e-01,9.83771067889611661e-02]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P3"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,4,6,["17cd7f25e4d8b"],[8.31685679489962415e-01,9.83771067889612078e-02]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P3"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]]]] +] +,"92_2": [ +[[2,2,4,6,["e256f182ba07"],[-2.14071514276285235e-01,4.49338014535684671e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P3"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,4,6,["e256f182ba07"],[-2.14071514276285291e-01,4.49338014535684782e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P3"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]]]] +] +,"93_2": [ +[[2,2,4,6,["3daa07b4dd16"],[1.13878785289113077e-01,-7.36155164114838390e-02]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P3"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,4,6,["3daa07b4dd16"],[1.13878785289113271e-01,-7.36155164114839222e-02]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P3"]]]] +] +,"94_2": [ +[[2,2,4,6,["233ba446ea1d"],[2.57413027802795152e-02,-7.30769889702292397e-02]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["rz", ["Q1"],["Q1", "P3"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +,[[2,2,4,6,["233ba446ea1d"],[2.57413027802796124e-02,-7.30769889702292119e-02]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P3"]]]] +] +,"95_2": [ +[[2,2,4,6,["182683a34c383"],[8.38051460450548014e-01,1.40324302792633554e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["rz", ["Q1"],["Q1", "P2"]],["rz", ["Q1"],["Q1", "P3"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,2,4,6,["182683a34c383"],[8.38051460450548014e-01,1.40324302792633554e-01]],[["add", ["P2"],["P0", "P0"]],["add", ["P3"],["P1", "P1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]],["rz", ["Q0"],["Q0", "P2"]],["rz", ["Q0"],["Q0", "P3"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"96_3": [ +[[1,2,3,2,["23a4fc68c4d2"],[3.78020004326112824e-03,-7.82918252286620708e-02]],[["add", ["P2"],["P0", "P1"]],["rz", ["Q0"],["Q0", "P2"]]]] +,[[1,2,2,2,["23a4fc68c4d2"],[3.78020004326151682e-03,-7.82918252286620153e-02]],[["rz", ["Q0"],["Q0", "P0"]],["rz", ["Q0"],["Q0", "P1"]]]] +,[[1,2,2,2,["23a4fc68c4d2"],[3.78020004326151682e-03,-7.82918252286620153e-02]],[["rz", ["Q0"],["Q0", "P1"]],["rz", ["Q0"],["Q0", "P0"]]]] +] +,"97_3": [ +[[2,0,0,2,["bf95140e9959"],[4.17872959895788709e-01,-5.35801877473238569e-02]],[["x", ["Q0"],["Q0"]],["x", ["Q1"],["Q1"]]]] +,[[2,0,0,3,["bf95140e9959"],[4.17872959895788709e-01,-5.35801877473238569e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,3,["bf95140e9959"],[4.17872959895788709e-01,-5.35801877473238569e-02]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["x", ["Q1"],["Q1"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +,"98_3": [ +[[2,0,0,2,["3b32578d572b"],[1.26512565405562966e-01,-3.06602521134137218e-02]],[["x", ["Q1"],["Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,2,["3b32578d572b"],[1.26512565405562966e-01,-3.06602521134137218e-02]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q1"],["Q1"]]]] +,[[2,0,0,3,["3b32578d572b"],[1.26512565405562966e-01,-3.06602521134137218e-02]],[["x", ["Q0"],["Q0"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]],["x", ["Q0"],["Q0"]]]] +] +,"99_7": [ +[[2,0,0,0,["639072adc5c0"],[2.18727073309198827e-01,9.74611226247737439e-03]],[]] +,[[2,0,0,2,["639072adc5c0"],[2.18727073309198827e-01,9.74611226247737439e-03]],[["h", ["Q0"],["Q0"]],["h", ["Q0"],["Q0"]]]] +,[[2,0,0,2,["639072adc5c0"],[2.18727073309198800e-01,9.74611226247740214e-03]],[["h", ["Q1"],["Q1"]],["h", ["Q1"],["Q1"]]]] +,[[2,0,0,2,["639072adc5c0"],[2.18727073309198827e-01,9.74611226247737439e-03]],[["x", ["Q0"],["Q0"]],["x", ["Q0"],["Q0"]]]] +,[[2,0,0,2,["639072adc5c0"],[2.18727073309198827e-01,9.74611226247737439e-03]],[["x", ["Q1"],["Q1"]],["x", ["Q1"],["Q1"]]]] +,[[2,0,0,2,["639072adc5c0"],[2.18727073309198827e-01,9.74611226247737439e-03]],[["cx", ["Q0", "Q1"],["Q0", "Q1"]],["cx", ["Q0", "Q1"],["Q0", "Q1"]]]] +,[[2,0,0,2,["639072adc5c0"],[2.18727073309198827e-01,9.74611226247737439e-03]],[["cx", ["Q1", "Q0"],["Q1", "Q0"]],["cx", ["Q1", "Q0"],["Q1", "Q0"]]]] +] +} +] diff --git a/tests/taso_termination.rs b/tests/taso_termination.rs new file mode 100644 index 00000000..a61534e5 --- /dev/null +++ b/tests/taso_termination.rs @@ -0,0 +1,34 @@ +#[cfg(feature = "portmatching")] +mod require_portmatching { + use hugr::Hugr; + use rstest::{fixture, rstest}; + use tket2::{ + json::TKETDecode, + optimiser::{DefaultTasoOptimiser, TasoOptimiser}, + Circuit, + }; + use tket_json_rs::circuit_json::SerialCircuit; + + #[fixture] + fn nam_4_2() -> DefaultTasoOptimiser { + // TasoOptimiser::default_with_rewriter_binary("test_files/nam_4_2.rwr").unwrap() + TasoOptimiser::default_with_eccs_json_file("test_files/Nam_4_2_complete_ECC_set.json") + .unwrap() + } + + #[fixture] + fn simple_circ() -> Hugr { + let json = r#" + {"bits": [], "commands": [{"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["0.1"], "type": "Rz"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [1]]], "op": {"params": ["0.2"], "type": "Rz"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["-0.1"], "type": "Rz"}}], "created_qubits": [], "discarded_qubits": [], "implicit_permutation": [[["q", [0]], ["q", [0]]], [["q", [1]], ["q", [1]]], [["q", [2]], ["q", [2]]]], "phase": "0.0", "qubits": [["q", [0]], ["q", [1]], ["q", [2]]]} + "#; + let ser: SerialCircuit = serde_json::from_str(json).unwrap(); + ser.decode().unwrap() + } + + #[rstest] + #[ignore = "Takes 800ms"] + fn taso_termination(simple_circ: Hugr, nam_4_2: DefaultTasoOptimiser) { + let opt_circ = nam_4_2.optimise(&simple_circ, None, 1.try_into().unwrap()); + assert_eq!(opt_circ.commands().count(), 11); + } +} From 05c495ff694b9db21d718cb51cbcfc15da474b2f Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Wed, 4 Oct 2023 14:20:47 +0200 Subject: [PATCH 09/11] Add comments --- tests/taso_termination.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/taso_termination.rs b/tests/taso_termination.rs index a61534e5..78ae87ac 100644 --- a/tests/taso_termination.rs +++ b/tests/taso_termination.rs @@ -9,24 +9,40 @@ mod require_portmatching { }; use tket_json_rs::circuit_json::SerialCircuit; + /// A set of equivalence circuit classes (ECC) + /// + /// This is the complete set of ECCs for 2-qubit circuits with up to + /// 4 gates, using the NAM gateset (CX, Rz, H). #[fixture] fn nam_4_2() -> DefaultTasoOptimiser { - // TasoOptimiser::default_with_rewriter_binary("test_files/nam_4_2.rwr").unwrap() TasoOptimiser::default_with_eccs_json_file("test_files/Nam_4_2_complete_ECC_set.json") .unwrap() } + /// The following circuit + /// ┌──────────┐ ┌───────────┐ + ///q_0: ──■──┤ Rz(π/10) ├──■─────────────────────────■────■──┤ Rz(-π/10) ├ + /// │ └──────────┘┌─┴─┐┌───┐┌─────────┐┌───┐┌─┴─┐ │ └───────────┘ + ///q_1: ──┼──────────────┤ X ├┤ H ├┤ Rz(π/5) ├┤ H ├┤ X ├──┼─────────────── + /// ┌─┴─┐ └───┘└───┘└─────────┘└───┘└───┘┌─┴─┐ + ///q_2: ┤ X ├───────────────────────────────────────────┤ X ├───────────── + /// └───┘ └───┘ #[fixture] fn simple_circ() -> Hugr { - let json = r#" - {"bits": [], "commands": [{"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["0.1"], "type": "Rz"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [1]]], "op": {"params": ["0.2"], "type": "Rz"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["-0.1"], "type": "Rz"}}], "created_qubits": [], "discarded_qubits": [], "implicit_permutation": [[["q", [0]], ["q", [0]]], [["q", [1]], ["q", [1]]], [["q", [2]], ["q", [2]]]], "phase": "0.0", "qubits": [["q", [0]], ["q", [1]], ["q", [2]]]} - "#; + // The TK1 json of the circuit + let json = r#"{ + "bits": [], + "commands": [{"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["0.1"], "type": "Rz"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [1]]], "op": {"params": ["0.2"], "type": "Rz"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["-0.1"], "type": "Rz"}}], + "created_qubits": [], + "discarded_qubits": [], + "implicit_permutation": [[["q", [0]], ["q", [0]]], [["q", [1]], ["q", [1]]], [["q", [2]], ["q", [2]]]], "phase": "0.0", "qubits": [["q", [0]], ["q", [1]], ["q", [2]]] + }"#; let ser: SerialCircuit = serde_json::from_str(json).unwrap(); ser.decode().unwrap() } #[rstest] - #[ignore = "Takes 800ms"] + // #[ignore = "Takes 800ms"] fn taso_termination(simple_circ: Hugr, nam_4_2: DefaultTasoOptimiser) { let opt_circ = nam_4_2.optimise(&simple_circ, None, 1.try_into().unwrap()); assert_eq!(opt_circ.commands().count(), 11); From 91f8d08b8b9a8737ef9309d1e9d539ca244a1d56 Mon Sep 17 00:00:00 2001 From: Luca Mondada Date: Wed, 4 Oct 2023 14:29:34 +0200 Subject: [PATCH 10/11] Further spread JSON --- tests/taso_termination.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/taso_termination.rs b/tests/taso_termination.rs index 78ae87ac..bc94dfe0 100644 --- a/tests/taso_termination.rs +++ b/tests/taso_termination.rs @@ -32,10 +32,23 @@ mod require_portmatching { // The TK1 json of the circuit let json = r#"{ "bits": [], - "commands": [{"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["0.1"], "type": "Rz"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [1]]], "op": {"params": ["0.2"], "type": "Rz"}}, {"args": [["q", [1]]], "op": {"type": "H"}}, {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, {"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, {"args": [["q", [0]]], "op": {"params": ["-0.1"], "type": "Rz"}}], + "commands": [ + {"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, + {"args": [["q", [0]]], "op": {"params": ["0.1"], "type": "Rz"}}, + {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, + {"args": [["q", [1]]], "op": {"type": "H"}}, + {"args": [["q", [1]]], "op": {"params": ["0.2"], "type": "Rz"}}, + {"args": [["q", [1]]], "op": {"type": "H"}}, + {"args": [["q", [0]], ["q", [1]]], "op": {"type": "CX"}}, + {"args": [["q", [0]], ["q", [2]]], "op": {"type": "CX"}}, + {"args": [["q", [0]]], "op": {"params": ["-0.1"], "type": "Rz"}}], "created_qubits": [], "discarded_qubits": [], - "implicit_permutation": [[["q", [0]], ["q", [0]]], [["q", [1]], ["q", [1]]], [["q", [2]], ["q", [2]]]], "phase": "0.0", "qubits": [["q", [0]], ["q", [1]], ["q", [2]]] + "implicit_permutation": [ + [["q", [0]], ["q", [0]]], [["q", [1]], ["q", [1]]], [["q", [2]], ["q", [2]]] + ], + "phase": "0.0", + "qubits": [["q", [0]], ["q", [1]], ["q", [2]]] }"#; let ser: SerialCircuit = serde_json::from_str(json).unwrap(); ser.decode().unwrap() From 6173d5a1ad074549f63517312ace02607f71f533 Mon Sep 17 00:00:00 2001 From: Agustin Borgna Date: Fri, 20 Oct 2023 09:52:53 +0100 Subject: [PATCH 11/11] Update taso API --- tests/taso_termination.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/taso_termination.rs b/tests/taso_termination.rs index bc94dfe0..65d393e0 100644 --- a/tests/taso_termination.rs +++ b/tests/taso_termination.rs @@ -55,9 +55,9 @@ mod require_portmatching { } #[rstest] - // #[ignore = "Takes 800ms"] + //#[ignore = "Takes 200ms"] fn taso_termination(simple_circ: Hugr, nam_4_2: DefaultTasoOptimiser) { - let opt_circ = nam_4_2.optimise(&simple_circ, None, 1.try_into().unwrap()); + let opt_circ = nam_4_2.optimise(&simple_circ, None, 1.try_into().unwrap(), false, 10); assert_eq!(opt_circ.commands().count(), 11); } }