diff --git a/src/optimiser/taso/_tests.rs b/src/optimiser/taso/_tests.rs deleted file mode 100644 index 66a8ee72..00000000 --- a/src/optimiser/taso/_tests.rs +++ /dev/null @@ -1,157 +0,0 @@ -use crate::circuit::{ - circuit::UnitID, - operation::{ConstValue, WireType}, -}; - -use super::*; -#[test] -fn test_simple_hash() { - let mut circ1 = Circuit::new(); - let [input, output] = circ1.boundary(); - - let point5 = circ1.add_vertex(Op::Const(ConstValue::f64_angle(0.5))); - let rx = circ1.add_vertex(Op::RzF64); - circ1 - .add_insert_edge((input, 0), (rx, 0), WireType::Qubit) - .unwrap(); - circ1 - .add_insert_edge((point5, 0), (rx, 1), WireType::Angle) - .unwrap(); - circ1 - .add_insert_edge((rx, 0), (output, 0), WireType::Qubit) - .unwrap(); - - let mut circ = Circuit::new(); - let [input, output] = circ.boundary(); - - // permute addition operations - let rx = circ.add_vertex(Op::RzF64); - let point5 = circ.add_vertex(Op::Const(ConstValue::f64_angle(0.5))); - circ.add_insert_edge((rx, 0), (output, 0), WireType::Qubit) - .unwrap(); - circ.add_insert_edge((input, 0), (rx, 0), WireType::Qubit) - .unwrap(); - circ.add_insert_edge((point5, 0), (rx, 1), WireType::Angle) - .unwrap(); - - assert_eq!(circuit_hash(&circ), circuit_hash(&circ1)); - - let mut circ = Circuit::new(); - let [input, output] = circ.boundary(); - - let point5 = circ.add_vertex(Op::Const(ConstValue::f64_angle(0.5))); - let rx = circ.add_vertex(Op::RxF64); // rx rather than rz - circ.add_insert_edge((input, 0), (rx, 0), WireType::Qubit) - .unwrap(); - circ.add_insert_edge((point5, 0), (rx, 1), WireType::Angle) - .unwrap(); - circ.add_insert_edge((rx, 0), (output, 0), WireType::Qubit) - .unwrap(); - - assert_ne!(circuit_hash(&circ), circuit_hash(&circ1)); -} - -// TODO test that takes a list of circuits (some of them very related to -// each other but distinct) and checks for no hash collisions - -#[test] -fn test_taso_small() { - // Figure 6 from Quartz paper https://arxiv.org/pdf/2204.09033.pdf - - let repsets = small_repset(); - - test_taso(repsets); -} - -fn test_taso(repsets: Vec) { - let circ = sample_circ(); - let mut correct = Circuit::with_uids(n_qbs(4)); - correct.append_op(Op::H, &[0]).unwrap(); - correct.append_op(Op::H, &[3]).unwrap(); - correct.append_op(Op::CX, &[3, 2]).unwrap(); - correct.append_op(Op::CX, &[2, 1]).unwrap(); - correct.append_op(Op::CX, &[1, 0]).unwrap(); - for f in [taso, |c, ps, g, cst, tmo| taso_mpsc(c, ps, g, cst, tmo, 4)] { - let cout = f(circ.clone(), repsets.clone(), 1.2, Circuit::node_count, 10); - - assert_ne!(circuit_hash(&circ), circuit_hash(&cout)); - assert_eq!(circuit_hash(&correct), circuit_hash(&cout)); - } -} - -fn small_repset() -> Vec { - let mut two_h = Circuit::with_uids(n_qbs(1)); - two_h.append_op(Op::H, &[0]).unwrap(); - two_h.append_op(Op::H, &[0]).unwrap(); - - let oneqb_id = Circuit::with_uids(n_qbs(1)); - - let mut cx_left = Circuit::with_uids(vec![ - UnitID::Qubit { - reg_name: "q".into(), - index: vec![0], - }, - UnitID::Qubit { - reg_name: "q".into(), - index: vec![1], - }, - ]); - cx_left.append_op(Op::CX, &[0, 1]).unwrap(); - cx_left.append_op(Op::H, &[0]).unwrap(); - cx_left.append_op(Op::H, &[1]).unwrap(); - - let mut cx_right = Circuit::with_uids(vec![ - UnitID::Qubit { - reg_name: "q".into(), - index: vec![0], - }, - UnitID::Qubit { - reg_name: "q".into(), - index: vec![1], - }, - ]); - cx_right.append_op(Op::H, &[0]).unwrap(); - cx_right.append_op(Op::H, &[1]).unwrap(); - cx_right.append_op(Op::CX, &[1, 0]).unwrap(); - - let repsets = vec![ - RepCircSet { - rep_circ: oneqb_id, - others: vec![two_h], - }, - RepCircSet { - rep_circ: cx_left, - others: vec![cx_right], - }, - ]; - repsets -} - -fn n_qbs(n: u32) -> Vec { - (0..n) - .map(|i| UnitID::Qubit { - reg_name: "q".into(), - index: vec![i], - }) - .collect() -} - -fn sample_circ() -> Circuit { - let mut circ = Circuit::with_uids(n_qbs(4)); - circ.append_op(Op::H, &[1]).unwrap(); - circ.append_op(Op::H, &[2]).unwrap(); - circ.append_op(Op::CX, &[2, 3]).unwrap(); - circ.append_op(Op::H, &[3]).unwrap(); - circ.append_op(Op::CX, &[1, 2]).unwrap(); - circ.append_op(Op::H, &[2]).unwrap(); - circ.append_op(Op::CX, &[0, 1]).unwrap(); - circ.append_op(Op::H, &[1]).unwrap(); - circ.append_op(Op::H, &[0]).unwrap(); - circ -} - -#[test] -fn test_taso_big() { - let repsets = rep_sets_from_path("test_files/h_rz_cxcomplete_ECC_set.json"); - test_taso(repsets); -} diff --git a/src/passes/_apply.rs b/src/passes/_apply.rs deleted file mode 100644 index ea87da04..00000000 --- a/src/passes/_apply.rs +++ /dev/null @@ -1,138 +0,0 @@ - -use self::pattern::{FixedStructPattern, Match, NodeCompClosure, PatternMatcher}; -use portgraph::{ - graph::{NodeIndex, DIRECTIONS}, - substitute::{BoundedSubgraph, RewriteError, SubgraphRef}, -}; - -pub trait RewriteGenerator<'s, T: Iterator + 's> { - fn rewrites<'a: 's>(&'s self, base_circ: &'a Circuit) -> T; - fn into_rewrites(self, base_circ: &'s Circuit) -> T; -} - -/// Repeatedly apply all available rewrites reported by finder closure until no more are found. -/// -/// # Errors -/// -/// This function will return an error if rewrite application fails. -pub fn apply_exhaustive(mut circ: Circuit, finder: F) -> Result<(Circuit, bool), RewriteError> -where - F: Fn(&Circuit) -> Vec, -{ - let mut success = false; - loop { - // assuming all the returned rewrites are non-overlapping - // or filter to make them non-overlapping - // then in theory, they can all be applied in parallel - let rewrites = finder(&circ); - if rewrites.is_empty() { - break; - } - success = true; - for rewrite in rewrites { - circ.apply_rewrite(rewrite)?; - } - } - - Ok((circ, success)) -} - -/// Repeatedly apply first reported rewrite -/// -/// # Errors -/// -/// This function will return an error if rewrite application fails. -pub fn apply_greedy(mut circ: Circuit, finder: F) -> Result<(Circuit, bool), RewriteError> -where - F: Fn(&Circuit) -> Option, -{ - let mut success = false; - while let Some(rewrite) = finder(&circ) { - success |= true; - circ.apply_rewrite(rewrite)?; - } - - Ok((circ, success)) -} - -pub type CircFixedStructPattern = FixedStructPattern; - -impl CircFixedStructPattern { - pub fn from_circ(pattern_circ: Circuit, node_comp_closure: F) -> Self { - Self { - boundary: pattern_circ.boundary(), - graph: pattern_circ.dag, - node_comp_closure, - } - } -} - -pub struct PatternRewriter { - pattern: CircFixedStructPattern, - rewrite_closure: G, -} - -impl PatternRewriter { - pub fn new(pattern: CircFixedStructPattern, rewrite_closure: G) -> Self { - Self { - pattern, - rewrite_closure, - } - } -} - -impl<'s, 'f: 's, F, G> RewriteGenerator<'s, CircRewriteIter<'s, F, G>> for PatternRewriter -where - F: NodeCompClosure + Clone + Send + Sync + 'f, - G: Fn(Match) -> (Circuit, Param) + 's + Clone, -{ - fn into_rewrites(self, base_circ: &'s Circuit) -> CircRewriteIter<'s, F, G> { - let ports = pattern_ports(&self.pattern); - let matcher = PatternMatcher::new(self.pattern, base_circ.dag_ref()); - - RewriteIter { - match_iter: matcher.into_iter(), - ports, - rewrite_closure: self.rewrite_closure, - circ: base_circ, - } - } - - fn rewrites<'a: 's>(&'s self, base_circ: &'a Circuit) -> CircRewriteIter<'s, F, G> { - let ports = pattern_ports(&self.pattern); - let matcher = PatternMatcher::new(self.pattern.clone(), base_circ.dag_ref()); - - RewriteIter { - match_iter: matcher.into_iter(), - ports, - rewrite_closure: self.rewrite_closure.clone(), - circ: base_circ, - } - } -} - -pub type CircRewriteIter<'a, F, G> = RewriteIter<'a, VertexProperties, EdgeProperties, F, G>; - -pub fn decompose_custom(circ: &Circuit) -> impl Iterator + '_ { - circ.dag.node_indices().filter_map(|n| { - let op = &circ.dag.node_weight(n).unwrap().op; - if let Op::Custom(x) = op { - Some(CircuitRewrite::new( - BoundedSubgraph::from_node(&circ.dag, n), - x.to_circuit().expect("Circuit generation failed.").into(), - 0.0, - )) - } else { - None - } - }) -} - -#[cfg(feature = "pyo3")] -use pyo3::prelude::pyfunction; - -#[cfg_attr(feature = "pyo3", pyfunction)] -pub fn decompose_custom_pass(circ: Circuit) -> (Circuit, bool) { - let (circ, suc) = apply_exhaustive(circ, |c| decompose_custom(c).collect()).unwrap(); - (circ, suc) -} \ No newline at end of file diff --git a/src/passes/_multi_search.rs b/src/passes/_multi_search.rs deleted file mode 100644 index 46f0f21c..00000000 --- a/src/passes/_multi_search.rs +++ /dev/null @@ -1,100 +0,0 @@ -// use crate::circuit::{ -// circuit::Circuit, -// dag::{EdgeProperties, VertexProperties}, -// operation::Param, -// }; - -// use super::{ -// pattern::{Match, NodeCompClosure}, -// CircRewriteIter, RewriteGenerator, -// }; -// use std::{ -// sync::{ -// mpsc::{channel, Receiver, Sender}, -// Arc, -// }, -// thread::{self, JoinHandle}, -// }; -// pub struct MultiSearcher { -// max_threads: u32, -// r_main: Receiver>, -// thread_ts: Vec>>>, -// joins: Vec>, -// // input_channel: (Sender>, Receiver>), -// // return_channel: (Sender, Receiver), -// } - -// pub fn searcher(max_threads: u32, rewrite_gens: Vec) -> MultiSearcher -// where -// F: NodeCompClosure + Clone + Send + Sync + 'static, -// G: Fn(Match) -> (Circuit, Param) + Clone + 'static, -// T: RewriteGenerator<'static, CircRewriteIter<'static, F, G>> + Send + Sync + Clone + 'static, -// { -// let n_threads = std::cmp::min(max_threads as usize, rewrite_gens.len()); - -// let (t_main, r_main) = channel(); - -// let mut chunks: Vec> = (0..n_threads).map(|_| vec![]).collect(); - -// for (count, p) in rewrite_gens.into_iter().enumerate() { -// chunks[count % n_threads].push((count, p)); -// } - -// let (joins, thread_ts): (Vec<_>, Vec<_>) = chunks -// .into_iter() -// .enumerate() -// .map(|(i, repsets)| { -// // channel for sending circuits to each thread -// let (t_this, r_this) = channel(); -// let tn = t_main.clone(); -// let jn = thread::spawn(move || { -// for received in r_this { -// let sent_circ: Arc = if let Some(hc) = received { -// hc -// } else { -// // main has signalled no more circuits will be sent -// return; -// }; -// println!("thread {i} got one"); -// for (set_i, rcs) in repsets.iter() { -// for rewrite in rcs.rewrites(&sent_circ) { -// // TODO here is where a optimal data-sharing copy would be handy -// let mut newc = sent_circ.as_ref().clone(); -// newc.apply_rewrite(rewrite).expect("rewrite failure"); - -// tn.send(Some(newc)).unwrap(); -// println!("thread {i} sent one back from set {set_i}"); -// } -// } -// // no more circuits will be generated, tell main this thread is -// // done with this circuit -// tn.send(None).unwrap(); -// } -// }); - -// (jn, t_this) -// }) -// .unzip(); - -// MultiSearcher { -// max_threads, -// r_main, -// thread_ts, -// joins, -// } -// } -// impl MultiSearcher { -// pub fn send_circ(&self, circ: Arc) { -// for thread_t in &self.thread_ts { -// thread_t.send(Some(circ.clone())).unwrap(); -// } -// } - -// pub fn stop(self) { -// for (join, tx) in self.joins.into_iter().zip(self.thread_ts.into_iter()) { -// // tell all the threads we're done and join the threads -// tx.send(None).unwrap(); -// join.join().unwrap(); -// } -// } -// } diff --git a/src/passes/_redundancy.rs b/src/passes/_redundancy.rs deleted file mode 100644 index 26fd676e..00000000 --- a/src/passes/_redundancy.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::collections::HashSet; - -use crate::circuit::circuit::{Circuit, CircuitRewrite}; -use crate::circuit::dag::{Edge, EdgeProperties, Vertex, VertexProperties, DAG}; -use crate::circuit::operation::{Op, Param}; -use portgraph::graph::{Direction, EdgeIndex}; -use portgraph::substitute::BoundedSubgraph; - -fn get_boundary(dag: &DAG, node: Vertex, direction: Direction) -> Vec { - dag.node_edges(node, direction).cloned().collect() -} -fn get_weights(dag: &DAG, edges: &Vec) -> Vec { - edges - .iter() - .map(|e| dag.edge_weight(*e).unwrap().clone()) - .collect() -} - -fn add_neighbours(dag: &DAG, preds: &Vec, succs: &Vec, set: &mut HashSet) { - for (it, i) in [(preds.iter(), 0), (succs.iter(), 1)] { - for e in it { - set.insert(dag.edge_endpoints(*e).unwrap()[i].node); - } - } -} - -// assumes no wire swaps -fn identity(edge_weights: Vec) -> Circuit { - let mut circ = Circuit::new(); - let [i, o] = circ.boundary(); - for (p, w) in edge_weights.into_iter().enumerate() { - let noop = circ.add_vertex(Op::Noop); - circ.add_edge((i, p as u8), (o, p as u8), w.edge_type); - } - - circ -} - -// A version of the redundancy removal in TKET but with only identity and dagger removal -pub fn remove_redundancies(mut circ: Circuit) -> Circuit { - let mut candidate_nodes: HashSet<_> = circ.dag.nodes().collect(); - - while !candidate_nodes.is_empty() { - let candidate = candidate_nodes - .take(&candidate_nodes.iter().next().cloned().unwrap()) - .unwrap(); - let op = match circ.dag.node_weight(candidate) { - None => continue, - Some(VertexProperties { op }) => match op { - Op::Input | Op::Output => continue, - _ => op, - }, - }; - - if !matches!(op, Op::Noop) { - if let Some(phase) = op.identity_up_to_phase() { - let preds: Vec<_> = get_boundary(&circ.dag, candidate, Direction::Incoming); - let succs: Vec<_> = get_boundary(&circ.dag, candidate, Direction::Outgoing); - - add_neighbours(&circ.dag, &preds, &succs, &mut candidate_nodes); - - let new_weights = get_weights(&circ.dag, &preds); - circ.apply_rewrite(CircuitRewrite::new( - BoundedSubgraph::from_node(&circ.dag, candidate), - identity(new_weights).into(), - Param::from(phase), - )) - .unwrap(); - continue; - } - } - - let kids: HashSet<_> = circ - .dag - .node_edges(candidate, Direction::Outgoing) - .filter_map(|e| { - let [start, end] = circ.dag.edge_endpoints(*e).unwrap(); - if start.port == end.port { - Some(end.node) - } else { - None - } - }) - .collect(); - - if kids.len() != 1 { - continue; - } - - let kid = *kids.iter().next().unwrap(); - - if let Some(dagged) = circ.dag.node_weight(kid).unwrap().op.dagger() { - if op != &dagged { - continue; - } - - let preds: Vec<_> = get_boundary(&circ.dag, candidate, Direction::Incoming); - let succs: Vec<_> = get_boundary(&circ.dag, kid, Direction::Outgoing); - - let new_weights = get_weights(&circ.dag, &preds); - add_neighbours(&circ.dag, &preds, &succs, &mut candidate_nodes); - circ.apply_rewrite(CircuitRewrite::new( - BoundedSubgraph::new([candidate, kid].into_iter().into(), [preds, succs]), - identity(new_weights).into(), - Param::from(0.0), - )) - .unwrap(); - continue; - } - } -}