Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feat/taso-split
Browse files Browse the repository at this point in the history
  • Loading branch information
aborgna-q committed Oct 3, 2023
2 parents 9a40ac9 + 0dcf5e0 commit d31339c
Show file tree
Hide file tree
Showing 9 changed files with 487 additions and 155 deletions.
24 changes: 24 additions & 0 deletions src/circuit.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Quantum circuit representation and operations.
pub mod command;
pub mod cost;
mod hash;
pub mod units;

Expand All @@ -22,6 +23,7 @@ use itertools::Itertools;
use portgraph::Direction;
use thiserror::Error;

use self::cost::CircuitCost;
use self::units::{filter, FilteredUnits, Units};

/// An object behaving like a quantum circuit.
Expand Down Expand Up @@ -126,6 +128,28 @@ pub trait Circuit: HugrView {
// Traverse the circuit in topological order.
CommandIterator::new(self)
}

/// Compute the cost of the circuit based on a per-operation cost function.
#[inline]
fn circuit_cost<F, C>(&self, op_cost: F) -> C
where
Self: Sized,
C: CircuitCost,
F: Fn(&OpType) -> C,
{
self.commands().map(|cmd| op_cost(cmd.optype())).sum()
}

/// Compute the cost of a group of nodes in a circuit based on a
/// per-operation cost function.
#[inline]
fn nodes_cost<F, C>(&self, nodes: impl IntoIterator<Item = Node>, op_cost: F) -> C
where
C: CircuitCost,
F: Fn(&OpType) -> C,
{
nodes.into_iter().map(|n| op_cost(self.get_optype(n))).sum()
}
}

/// Remove an empty wire in a dataflow HUGR.
Expand Down
102 changes: 102 additions & 0 deletions src/circuit/cost.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! Cost definitions for a circuit.
use derive_more::From;
use hugr::ops::OpType;
use std::fmt::Debug;
use std::iter::Sum;
use std::num::NonZeroUsize;
use std::ops::Add;

use crate::ops::op_matches;
use crate::T2Op;

/// The cost for a group of operations in a circuit, each with cost `OpCost`.
pub trait CircuitCost: Add<Output = Self> + Sum<Self> + Debug + Default + Clone + Ord {
/// Returns true if the cost is above the threshold.
fn check_threshold(self, threshold: Self) -> bool;

/// Divide the cost, rounded up.
fn div_cost(self, n: NonZeroUsize) -> Self;
}

/// 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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 Add<MajorMinorCost> for MajorMinorCost {
type Output = MajorMinorCost;

fn add(self, rhs: MajorMinorCost) -> Self::Output {
(self.major + rhs.major, self.minor + rhs.minor).into()
}
}

impl Sum for MajorMinorCost {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(|a, b| (a.major + b.major, a.minor + b.minor).into())
.unwrap_or_default()
}
}

impl CircuitCost for MajorMinorCost {
#[inline]
fn check_threshold(self, threshold: Self) -> bool {
self.major > threshold.major
}

#[inline]
fn div_cost(mut self, n: NonZeroUsize) -> Self {
self.major = (self.major.saturating_sub(1)) / n.get() + 1;
self.minor = (self.minor.saturating_sub(1)) / n.get() + 1;
self
}
}

impl CircuitCost for usize {
#[inline]
fn check_threshold(self, threshold: Self) -> bool {
self > threshold
}

#[inline]
fn div_cost(self, n: NonZeroUsize) -> Self {
(self.saturating_sub(1)) / n.get() + 1
}
}

/// Returns true if the operation is a controlled X operation.
pub fn is_cx(op: &OpType) -> bool {
op_matches(op, T2Op::CX)
}

/// Returns true if the operation is a quantum operation.
pub fn is_quantum(op: &OpType) -> bool {
let Ok(op): Result<T2Op, _> = op.try_into() else {
return false;
};
op.is_quantum()
}
10 changes: 10 additions & 0 deletions src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit d31339c

Please sign in to comment.