Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion tket-py/src/circuit/tk2circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use hugr::builder::{CircuitBuilder, DFGBuilder, Dataflow, DataflowHugr};
use hugr::envelope::{EnvelopeConfig, EnvelopeFormat, ZstdConfig};
use hugr::extension::prelude::qb_t;
use hugr::extension::{ExtensionRegistry, EMPTY_REG};
use hugr::hugr::Patch;
use hugr::ops::handle::NodeHandle;
use hugr::ops::{ExtensionOp, OpType};
use hugr::package::Package;
Expand Down Expand Up @@ -92,7 +93,9 @@ impl Tk2Circuit {

/// Apply a rewrite on the circuit.
pub fn apply_rewrite(&mut self, rw: PyCircuitRewrite) {
rw.rewrite.apply(&mut self.circ).expect("Apply error.");
rw.rewrite
.apply(self.circ.hugr_mut())
.expect("Apply error.");
}

/// Encode the circuit as a HUGR envelope.
Expand Down
8 changes: 6 additions & 2 deletions tket-py/src/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use crate::circuit::Tk2Circuit;
use crate::rewrite::PyCircuitRewrite;
use crate::utils::{create_py_exception, ConvertPyErr};

use hugr::{HugrView, Node};
use hugr::{HugrView, Node, SimpleReplacement};
use pyo3::prelude::*;
use tket::portmatching::{CircuitPattern, PatternMatch, PatternMatcher};
use tket::rewrite::CircuitRewrite;
use tket::Circuit;

/// The module definition
Expand Down Expand Up @@ -123,6 +124,9 @@ impl RuleMatcher {
) -> PyResult<PyCircuitRewrite> {
let r = self.rights.get(pmatch.pattern_id().0).unwrap().clone();
let rw = pmatch.to_rewrite(target, r).convert_pyerrs()?;
Ok(rw.into())
match rw {
CircuitRewrite::New { .. } => unimplemented!(),
CircuitRewrite::Old(rew) => Ok(SimpleReplacement::from(rew).into()),
}
}
}
45 changes: 32 additions & 13 deletions tket-py/src/rewrite.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! PyO3 wrapper for rewriters.

use derive_more::From;
use hugr::{hugr::views::SiblingSubgraph, HugrView, Node};
use hugr::{hugr::views::SiblingSubgraph, HugrView, Node, SimpleReplacement};
use itertools::Itertools;
use pyo3::prelude::*;
use std::path::PathBuf;
use tket::{
resource::ResourceScope,
rewrite::{CircuitRewrite, ECCRewriter, Rewriter},
Circuit,
};
Expand All @@ -32,7 +33,7 @@ pub fn module(py: Python<'_>) -> PyResult<Bound<'_, PyModule>> {
#[repr(transparent)]
pub struct PyCircuitRewrite {
/// Rust representation of the circuit chunks.
pub rewrite: CircuitRewrite,
pub rewrite: SimpleReplacement,
}

#[pymethods]
Expand All @@ -42,12 +43,14 @@ impl PyCircuitRewrite {
/// The difference between the new number of nodes minus the old. A positive
/// number is an increase in node count, a negative number is a decrease.
pub fn node_count_delta(&self) -> isize {
self.rewrite.node_count_delta()
let old_count = self.rewrite.subgraph().node_count() as isize;
let new_count = Circuit::new(self.rewrite.replacement()).num_operations() as isize;
new_count - old_count
}

/// The replacement subcircuit.
pub fn replacement(&self) -> Tk2Circuit {
self.rewrite.replacement().to_owned().into()
Circuit::new(self.rewrite.replacement().to_owned()).into()
}

#[new]
Expand All @@ -56,13 +59,14 @@ impl PyCircuitRewrite {
source_circ: PyRef<Tk2Circuit>,
replacement: Tk2Circuit,
) -> PyResult<Self> {
let repl = SimpleReplacement::try_new(
source_position.0,
source_circ.circ.hugr(),
replacement.circ.into_hugr(),
)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?;
Ok(Self {
rewrite: CircuitRewrite::try_new(
&source_position.0,
source_circ.circ.hugr(),
replacement.circ,
)
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?,
rewrite: repl.into(),
})
}
}
Expand All @@ -79,8 +83,20 @@ pub enum PyRewriter {
Vec(Vec<PyRewriter>),
}

impl<H: HugrView<Node = Node>> Rewriter<Circuit<H>> for PyRewriter {
fn get_rewrites(&self, circ: &Circuit<H>) -> Vec<CircuitRewrite> {
// impl<H: HugrView<Node = Node>> Rewriter<H> for PyRewriter {
// fn get_rewrites(&self, circ: &H) -> Vec<CircuitRewrite> {
// match self {
// Self::ECC(ecc) => ecc.0.get_rewrites(circ),
// Self::Vec(rewriters) => rewriters
// .iter()
// .flat_map(|r| r.get_rewrites(circ))
// .collect(),
// }
// }
// }

impl<H: HugrView<Node = Node>> Rewriter<ResourceScope<H>> for PyRewriter {
fn get_rewrites(&self, circ: &ResourceScope<H>) -> Vec<CircuitRewrite<<H>::Node>> {
match self {
Self::ECC(ecc) => ecc.0.get_rewrites(circ),
Self::Vec(rewriters) => rewriters
Expand Down Expand Up @@ -146,7 +162,10 @@ impl PyECCRewriter {
self.0
.get_rewrites(&circ.circ)
.into_iter()
.map_into()
.map(|r| match r {
CircuitRewrite::New { .. } => unimplemented!(),
CircuitRewrite::Old(rewrite) => SimpleReplacement::from(rewrite).into(),
})
.collect()
}
}
2 changes: 1 addition & 1 deletion tket/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::collections::HashSet;
use std::iter::Sum;

pub use command::{Command, CommandIterator};
pub use hash::CircuitHash;
pub use hash::{CircuitHash, HashError};
use hugr::extension::prelude::{NoopDef, TupleOpDef};
use hugr::extension::simple_op::MakeOpDef;
use hugr::hugr::views::sibling_subgraph::InvalidSubgraph;
Expand Down
38 changes: 21 additions & 17 deletions tket/src/optimiser/badger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use crate::circuit::CircuitHash;
use crate::optimiser::badger::worker::BadgerWorker;
use crate::optimiser::{pqueue_worker, BacktrackingOptimiser, Optimiser, State, StatePQWorker};
use crate::passes::CircuitChunks;
use crate::resource::ResourceScope;
use crate::rewrite::strategy::{RewriteResult, RewriteStrategy};
use crate::rewrite::Rewriter;
use crate::Circuit;
Expand Down Expand Up @@ -118,7 +119,7 @@ impl<R, S> BadgerOptimiser<R, S> {
Self { rewriter, strategy }
}

fn cost(&self, circ: &Circuit<impl HugrView<Node = Node>>) -> S::Cost
fn cost(&self, circ: &ResourceScope<impl HugrView<Node = Node>>) -> S::Cost
where
S: RewriteStrategy,
{
Expand All @@ -130,12 +131,13 @@ impl<R, S> BadgerOptimiser<R, S> {
#[derive(Clone, Debug)]
struct BadgerState<C> {
/// The current circuit
circ: Circuit,
circ: ResourceScope,
/// The circuit cost
cost: C,
}

impl<R: Rewriter, S: RewriteStrategy> State<&BadgerOptimiser<R, S>> for BadgerState<S::Cost>
impl<R: Rewriter<ResourceScope>, S: RewriteStrategy> State<&BadgerOptimiser<R, S>>
for BadgerState<S::Cost>
where
S::Cost: serde::Serialize,
{
Expand Down Expand Up @@ -164,7 +166,7 @@ where

impl<R, S> BadgerOptimiser<R, S>
where
R: Rewriter + Send + Clone + Sync + 'static,
R: Rewriter<ResourceScope> + Send + Clone + Sync + 'static,
S: RewriteStrategy + Send + Sync + Clone + 'static,
S::Cost: serde::Serialize + Send + Sync,
{
Expand All @@ -188,7 +190,7 @@ where
log_config: BadgerLogger,
options: BadgerOptions,
) -> Circuit {
match options.n_threads.get() {
let h = match options.n_threads.get() {
1 => self.badger(circ, log_config, options),
_ => {
if options.split_circuit {
Expand All @@ -199,6 +201,8 @@ where
}
}
}
.into_hugr();
Circuit::new(h)
}

/// Run the Badger optimiser on a circuit, using a single thread.
Expand All @@ -208,12 +212,11 @@ where
circ: &Circuit<impl HugrView<Node = Node>>,
logger: BadgerLogger,
opt: BadgerOptions,
) -> Circuit {
) -> ResourceScope {
let backtracking = BacktrackingOptimiser::with_badger_options(&opt);
let init_state = BadgerState {
circ: circ.to_owned(),
cost: self.cost(circ),
};
let circ = ResourceScope::from_circuit(circ.to_owned());
let cost = self.cost(&circ);
let init_state = BadgerState { circ, cost };
backtracking
.optimise_with_options(init_state, self, logger.into())
.expect("optimisation failed")
Expand All @@ -231,10 +234,10 @@ where
circ: &Circuit<impl HugrView<Node = Node>>,
mut logger: BadgerLogger,
opt: BadgerOptions,
) -> Circuit {
) -> ResourceScope {
let start_time = Instant::now();
let n_threads: usize = opt.n_threads.get();
let circ = circ.to_owned();
let circ = ResourceScope::from_circuit(circ.to_owned());

// multi-consumer priority channel for queuing circuits to be processed by the
// workers
Expand Down Expand Up @@ -372,17 +375,18 @@ where
circ: &Circuit<impl HugrView<Node = Node>>,
mut logger: BadgerLogger,
opt: BadgerOptions,
) -> Result<Circuit, HugrError> {
) -> Result<ResourceScope, HugrError> {
let start_time = Instant::now();
let circ = circ.to_owned();
let circ = ResourceScope::from_circuit(circ.to_owned());
let circ_cost = self.cost(&circ);
let max_chunk_cost = circ_cost.clone().div_cost(opt.n_threads);
logger.log(format!(
"Splitting circuit with cost {:?} into chunks of at most {max_chunk_cost:?}.",
circ_cost.clone()
));
let mut chunks =
CircuitChunks::split_with_cost(&circ, max_chunk_cost, |op| self.strategy.op_cost(op));
let mut chunks = CircuitChunks::split_with_cost(&circ.as_circuit(), max_chunk_cost, |op| {
self.strategy.op_cost(op)
});

let num_rewrites = circ.rewrite_trace().map(|rs| rs.count());
logger.log_best(circ_cost.clone(), num_rewrites);
Expand Down Expand Up @@ -421,7 +425,7 @@ where
chunks[i] = res;
}

let best_circ = chunks.reassemble()?;
let best_circ = ResourceScope::from_circuit(chunks.reassemble()?);
let best_circ_cost = self.cost(&best_circ);
if best_circ_cost.clone() < circ_cost {
let num_rewrites = best_circ.rewrite_trace().map(|rs| rs.count());
Expand Down
9 changes: 5 additions & 4 deletions tket/src/optimiser/badger/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

use std::thread::{self, JoinHandle};

use crate::circuit::cost::CircuitCost;
use crate::circuit::CircuitHash;
use crate::resource::ResourceScope;
use crate::rewrite::strategy::RewriteStrategy;
use crate::rewrite::Rewriter;
use crate::{circuit::cost::CircuitCost, Circuit};

use super::pqueue_worker::{StatePQueueChannels, Work};

Expand All @@ -15,7 +16,7 @@ pub struct BadgerWorker<R, S, P: Ord> {
#[allow(unused)]
id: usize,
/// The channel to send and receive work from.
priority_channel: StatePQueueChannels<Circuit, P>,
priority_channel: StatePQueueChannels<ResourceScope, P>,
/// The rewriter to use.
rewriter: R,
/// The rewrite strategy to use.
Expand All @@ -24,15 +25,15 @@ pub struct BadgerWorker<R, S, P: Ord> {

impl<R, S, P> BadgerWorker<R, S, P>
where
R: Rewriter + Send + 'static,
R: Rewriter<ResourceScope> + Send + 'static,
S: RewriteStrategy<Cost = P> + Send + 'static,
P: CircuitCost + Send + Sync + 'static,
{
/// Spawn a new worker thread.
#[allow(clippy::too_many_arguments)]
pub fn spawn(
id: usize,
priority_channel: StatePQueueChannels<Circuit, P>,
priority_channel: StatePQueueChannels<ResourceScope, P>,
rewriter: R,
strategy: S,
) -> JoinHandle<()> {
Expand Down
12 changes: 6 additions & 6 deletions tket/src/passes/chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use hugr::hugr::{HugrError, NodeMetadataMap};
use hugr::ops::handle::DataflowParentID;
use hugr::ops::OpType;
use hugr::types::Signature;
use hugr::{Hugr, HugrView, IncomingPort, Node, OutgoingPort, PortIndex, Wire};
use hugr_core::hugr::internal::{HugrInternals, HugrMutInternals as _};
use hugr::{HugrView, IncomingPort, Node, OutgoingPort, PortIndex, Wire};
use hugr_core::hugr::internal::HugrMutInternals as _;
use itertools::Itertools;
use rayon::iter::{IntoParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
use rayon::slice::ParallelSliceMut;
Expand Down Expand Up @@ -49,10 +49,10 @@ impl Chunk {
/// Extract a chunk from a circuit.
///
/// The chunk is extracted from the input wires to the output wires.
pub(self) fn extract(
circ: &Circuit,
pub(self) fn extract<H: HugrView<Node = Node>>(
circ: &Circuit<H>,
nodes: impl IntoIterator<Item = Node>,
checker: &TopoConvexChecker<'_, Hugr>,
checker: &TopoConvexChecker<'_, H>,
) -> Self {
let subgraph = SiblingSubgraph::try_from_nodes_with_checker(
nodes.into_iter().collect_vec(),
Expand Down Expand Up @@ -260,7 +260,7 @@ impl CircuitChunks {
///
/// The circuit is split into chunks of at most `max_cost`, using the provided cost function.
pub fn split_with_cost<C: CircuitCost>(
circ: &Circuit,
circ: &Circuit<impl HugrView<Node = Node>>,
max_cost: C,
op_cost: impl Fn(&OpType) -> C,
) -> Self {
Expand Down
3 changes: 2 additions & 1 deletion tket/src/passes/pytket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//! This is a best-effort attempt, and may not always succeed.

use derive_more::{Display, Error, From};
use hugr::hugr::Patch;
use hugr::{HugrView, Node};
use itertools::Itertools;

Expand All @@ -24,7 +25,7 @@ pub fn lower_to_pytket<T: HugrView<Node = Node>>(
// typically generated by guppy.
let rewrites = find_tuple_unpack_rewrites(&circ).collect_vec();
for rewrite in rewrites {
rewrite.apply(&mut circ).unwrap();
rewrite.apply(circ.hugr_mut()).unwrap();
}

Ok(circ)
Expand Down
Loading
Loading