Skip to content

Commit

Permalink
feat!: replace f64 with angle type for tk2 ops (#578)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Parametric Tk2Ops take angle type rather than float.
  • Loading branch information
ss2165 committed Sep 4, 2024
1 parent e6acc88 commit d14631f
Show file tree
Hide file tree
Showing 22 changed files with 154 additions and 131 deletions.
100 changes: 50 additions & 50 deletions test_files/barenco_tof_10.json

Large diffs are not rendered by default.

Binary file modified test_files/eccs/nam_4_2.rwr
Binary file not shown.
Binary file modified test_files/eccs/nam_6_3.rwr
Binary file not shown.
Binary file modified test_files/eccs/small_eccs.rwr
Binary file not shown.
Binary file modified tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr
Binary file not shown.
7 changes: 3 additions & 4 deletions tket2-hseries/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,13 @@ mod test {
builder::{Container, DFGBuilder, Dataflow, DataflowHugr, DataflowSubContainer},
extension::prelude::{BOOL_T, QB_T},
ops::handle::NodeHandle,
std_extensions::arithmetic::float_types::ConstF64,
type_row,
types::Signature,
HugrView as _,
};
use itertools::Itertools as _;
use petgraph::visit::{Topo, Walker as _};
use tket2::Tk2Op;
use tket2::{extension::angle::ConstAngle, Tk2Op};

use crate::{extension::futures::FutureOpDef, HSeriesPass};

Expand All @@ -120,7 +119,7 @@ mod test {
.node();

// this LoadConstant should be pushed below the quantum ops where possible
let angle = builder.add_load_value(ConstF64::new(1.0));
let angle = builder.add_load_value(ConstAngle::PI);
let f_node = angle.node();

// with no dependencies, this H should be lifted to the start
Expand All @@ -130,7 +129,7 @@ mod test {
.outputs_arr();
let h_node = qb.node();

// depending on the angle means this op can't be lifted above the float ops
// depending on the angle means this op can't be lifted above the angle ops
let [qb] = builder
.add_dataflow_op(Tk2Op::Rx, [qb, angle])
.unwrap()
Expand Down
2 changes: 1 addition & 1 deletion tket2-py/tket2/circuit/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def __call__(self, q: ComWire) -> Command:

Measure = MeasureDef()


# TODO use angle type once extension is serialised.
_RzSig = tys.FunctionType([tys.Qubit, FLOAT_T], [tys.Qubit])


Expand Down
4 changes: 2 additions & 2 deletions tket2/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,6 @@ fn update_signature(
#[cfg(test)]
mod tests {
use cool_asserts::assert_matches;
use hugr::std_extensions::arithmetic::float_types::ConstF64;
use hugr::CircuitUnit;
use rstest::{fixture, rstest};

Expand All @@ -632,6 +631,7 @@ mod tests {
};

use super::*;
use crate::extension::angle::ConstAngle;
use crate::serialize::load_tk1_json_str;
use crate::utils::{build_module_with_circuit, build_simple_circuit};
use crate::Tk2Op;
Expand Down Expand Up @@ -661,7 +661,7 @@ mod tests {
build_simple_circuit(2, |circ| {
circ.append(Tk2Op::H, [0])?;
circ.append(Tk2Op::CX, [0, 1])?;
let angle = circ.add_constant(ConstF64::new(0.5));
let angle = circ.add_constant(ConstAngle::PI_2);
circ.append_and_consume(
Tk2Op::Rz,
[CircuitUnit::Linear(1), CircuitUnit::Wire(angle)],
Expand Down
12 changes: 7 additions & 5 deletions tket2/src/circuit/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,14 +479,13 @@ mod test {
use hugr::hugr::hugrmut::HugrMut;
use hugr::ops::handle::NodeHandle;
use hugr::ops::{NamedOp, Value};
use hugr::std_extensions::arithmetic::float_ops::FLOAT_OPS_REGISTRY;
use hugr::std_extensions::arithmetic::float_types::ConstF64;
use hugr::types::Signature;
use itertools::Itertools;
use rstest::{fixture, rstest};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

use crate::extension::angle::ConstAngle;
use crate::extension::REGISTRY;
use crate::utils::{build_module_with_circuit, build_simple_circuit};
use crate::Tk2Op;
Expand Down Expand Up @@ -591,12 +590,12 @@ mod test {
let mut h = DFGBuilder::new(Signature::new(qb_row.clone(), qb_row)).unwrap();
let [q_in] = h.input_wires_arr();

let constant = h.add_constant(Value::extension(ConstF64::new(0.5)));
let constant = h.add_constant(Value::extension(ConstAngle::PI_2));
let loaded_const = h.load_const(&constant);
let rz = h.add_dataflow_op(Tk2Op::Rz, [q_in, loaded_const]).unwrap();

let circ: Circuit = h
.finish_hugr_with_outputs(rz.outputs(), &FLOAT_OPS_REGISTRY)
.finish_hugr_with_outputs(rz.outputs(), &REGISTRY)
.unwrap()
.into();

Expand All @@ -606,7 +605,10 @@ mod test {
// First command is the constant definition.
// It has a single output.
let const_cmd = commands.next().unwrap();
assert_eq!(const_cmd.optype().name().as_str(), "const:custom:f64(0.5)");
assert_eq!(
const_cmd.optype().name().as_str(),
"const:custom:a(2π*1/2^2)"
);
assert_eq_iter!(const_cmd.inputs().map(|(u, _, _)| u), [],);
assert_eq_iter!(
const_cmd.outputs().map(|(u, _, _)| u),
Expand Down
13 changes: 4 additions & 9 deletions tket2/src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

use crate::serialize::pytket::OpaqueTk1Op;
use crate::Tk2Op;
use angle::ANGLE_TYPE;
use hugr::extension::prelude::PRELUDE;
use hugr::extension::simple_op::MakeOpDef;
use hugr::extension::{
CustomSignatureFunc, ExtensionId, ExtensionRegistry, SignatureError, Version,
};
use hugr::hugr::IdentList;
use hugr::std_extensions::arithmetic::{
float_ops::EXTENSION as FLOAT_OPS_EXTENSION,
float_types::{EXTENSION as FLOAT_TYPES_EXTENSION, FLOAT64_TYPE},
};
use hugr::types::type_param::{TypeArg, TypeParam};
use hugr::types::{CustomType, PolyFuncType, PolyFuncTypeRV, Signature};
use hugr::{type_row, Extension};
Expand Down Expand Up @@ -59,8 +56,6 @@ pub static ref REGISTRY: ExtensionRegistry = ExtensionRegistry::try_new([
TKET1_EXTENSION.to_owned(),
PRELUDE.to_owned(),
TKET2_EXTENSION.to_owned(),
FLOAT_TYPES_EXTENSION.to_owned(),
FLOAT_OPS_EXTENSION.to_owned(),
]).unwrap();


Expand Down Expand Up @@ -96,7 +91,7 @@ pub const TKET2_EXTENSION_ID: ExtensionId = ExtensionId::new_unchecked("quantum.
pub const SYM_EXPR_NAME: SmolStr = SmolStr::new_inline("SymExpr");

/// The name of the symbolic expression opaque type arg.
pub const SYM_OP_ID: SmolStr = SmolStr::new_inline("symbolic_float");
pub const SYM_OP_ID: SmolStr = SmolStr::new_inline("symbolic_angle");

/// Current version of the TKET 2 extension
pub const TKET2_EXTENSION_VERSION: Version = Version::new(0, 1, 0);
Expand All @@ -113,8 +108,8 @@ pub static ref TKET2_EXTENSION: Extension = {

e.add_op(
SYM_OP_ID,
"Store a sympy expression that can be evaluated to a float.".to_string(),
PolyFuncType::new(vec![TypeParam::String], Signature::new(type_row![], type_row![FLOAT64_TYPE])),
"Store a sympy expression that can be evaluated to an angle.".to_string(),
PolyFuncType::new(vec![TypeParam::String], Signature::new(type_row![], type_row![ANGLE_TYPE])),
)
.unwrap();

Expand Down
31 changes: 31 additions & 0 deletions tket2/src/extension/angle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ pub struct ConstAngle {
}

impl ConstAngle {
/// The constant π
pub const PI: Self = Self::new_unchecked(1, 1);
/// The constant 2π
pub const TAU: Self = Self::new_unchecked(0, 1);
/// The constant π/2
pub const PI_2: Self = Self::new_unchecked(2, 1);
/// The constant π/4
pub const PI_4: Self = Self::new_unchecked(3, 1);

/// Create a new [`ConstAngle`] from a log-denominator and a numerator without
/// checking for validity.
const fn new_unchecked(log_denom: u8, value: u64) -> Self {
Self { log_denom, value }
}
/// Create a new [`ConstAngle`] from a log-denominator and a numerator
pub fn new(log_denom: u8, value: u64) -> Result<Self, ConstTypeError> {
if !is_valid_log_denom(log_denom) {
Expand Down Expand Up @@ -73,6 +87,13 @@ impl ConstAngle {
})
}

/// Create a new [`ConstAngle`] from a floating-point value in radians,
/// using the highest possible log-denominator and
/// rounding to the nearest corresponding value. (Ties round away from zero.)
pub fn from_radians_rounding_max(theta: f64) -> Result<Self, ConstTypeError> {
Self::from_radians_rounding(LOG_DENOM_MAX, theta)
}

/// Returns the value of the constant
pub fn value(&self) -> u64 {
self.value
Expand All @@ -82,6 +103,16 @@ impl ConstAngle {
pub fn log_denom(&self) -> u8 {
self.log_denom
}

/// Returns the value of the constant in radians
pub fn to_radians(&self) -> f64 {
self.to_turns() * TAU
}

/// Returns the value of the constant divided by 2π
pub fn to_turns(&self) -> f64 {
(self.value as f64) / (1u64 << self.log_denom) as f64
}
}

#[typetag::serde]
Expand Down
6 changes: 3 additions & 3 deletions tket2/src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::extension::angle::ANGLE_TYPE;
use crate::extension::{
SYM_OP_ID, TKET2_EXTENSION as EXTENSION, TKET2_EXTENSION_ID as EXTENSION_ID,
};
Expand All @@ -10,7 +11,6 @@ use hugr::{
ExtensionId, OpDef, SignatureFunc,
},
ops::OpType,
std_extensions::arithmetic::float_types::FLOAT64_TYPE,
type_row,
types::{type_param::TypeArg, Signature},
};
Expand Down Expand Up @@ -115,8 +115,8 @@ impl MakeOpDef for Tk2Op {
CX | CZ | CY => Signature::new_endo(type_row![QB_T; 2]),
Toffoli => Signature::new_endo(type_row![QB_T; 3]),
Measure => Signature::new(one_qb_row, type_row![QB_T, BOOL_T]),
Rz | Rx | Ry => Signature::new(type_row![QB_T, FLOAT64_TYPE], one_qb_row),
CRz => Signature::new(type_row![QB_T, QB_T, FLOAT64_TYPE], type_row![QB_T; 2]),
Rz | Rx | Ry => Signature::new(type_row![QB_T, ANGLE_TYPE], one_qb_row),
CRz => Signature::new(type_row![QB_T, QB_T, ANGLE_TYPE], type_row![QB_T; 2]),
QAlloc => Signature::new(type_row![], one_qb_row),
QFree => Signature::new(one_qb_row, type_row![]),
}
Expand Down
11 changes: 5 additions & 6 deletions tket2/src/optimiser/badger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,20 +544,19 @@ mod tests {
use hugr::{
builder::{DFGBuilder, Dataflow, DataflowHugr},
extension::prelude::QB_T,
std_extensions::arithmetic::float_types::FLOAT64_TYPE,
types::Signature,
};
use rstest::{fixture, rstest};

use crate::optimiser::badger::BadgerOptions;
use crate::serialize::load_tk1_json_str;
use crate::{extension::angle::ANGLE_TYPE, optimiser::badger::BadgerOptions};
use crate::{extension::REGISTRY, Circuit, Tk2Op};

use super::{BadgerOptimiser, DefaultBadgerOptimiser};

#[fixture]
fn rz_rz() -> Circuit {
let input_t = vec![QB_T, FLOAT64_TYPE, FLOAT64_TYPE];
let input_t = vec![QB_T, ANGLE_TYPE, ANGLE_TYPE];
let output_t = vec![QB_T];
let mut h = DFGBuilder::new(Signature::new(input_t, output_t)).unwrap();

Expand Down Expand Up @@ -623,9 +622,9 @@ mod tests {
#[case::compiled(badger_opt_compiled())]
#[case::json(badger_opt_json())]
fn rz_rz_cancellation(rz_rz: Circuit, #[case] badger_opt: DefaultBadgerOptimiser) {
use hugr::{ops::OpType, std_extensions::arithmetic::float_ops::FloatOps};
use hugr::ops::OpType;

use crate::op_matches;
use crate::{extension::angle::AngleOp, op_matches};

let opt_rz = badger_opt.optimise(
&rz_rz,
Expand All @@ -642,7 +641,7 @@ mod tests {
.unwrap();

// Rzs combined into a single one.
assert_eq!(op1.cast::<FloatOps>(), Some(FloatOps::fadd));
assert_eq!(op1.cast(), Some(AngleOp::aadd));
assert!(op_matches(op2, Tk2Op::Rz));
}

Expand Down
6 changes: 3 additions & 3 deletions tket2/src/optimiser/badger/qtz_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use std::path::Path;
use hugr::builder::{DFGBuilder, Dataflow, DataflowHugr};
use hugr::extension::prelude::QB_T;
use hugr::ops::OpType as Op;
use hugr::std_extensions::arithmetic::float_types::FLOAT64_TYPE;
use hugr::types::{Signature, Type};
use hugr::{CircuitUnit, Hugr};
use itertools::Itertools;
use serde::{Deserialize, Serialize};

use crate::extension::angle::{AngleOp, ANGLE_TYPE};
use crate::{Circuit, Tk2Op};

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -41,7 +41,7 @@ struct RepCircData {

fn map_op(opstr: &str) -> Op {
if opstr == "add" {
return hugr::std_extensions::arithmetic::float_ops::FloatOps::fadd.into();
return AngleOp::aadd.into();
}
// TODO, more
match opstr {
Expand All @@ -64,7 +64,7 @@ fn map_op(opstr: &str) -> Op {
impl From<RepCircData> for Circuit<Hugr> {
fn from(RepCircData { circ: rc, meta }: RepCircData) -> Self {
let qb_types: Vec<Type> = vec![QB_T; meta.n_qb];
let param_types: Vec<Type> = vec![FLOAT64_TYPE; meta.n_input_param];
let param_types: Vec<Type> = vec![ANGLE_TYPE; meta.n_input_param];
let mut builder = DFGBuilder::new(Signature::new(
[qb_types.clone(), param_types].concat(),
qb_types,
Expand Down
9 changes: 6 additions & 3 deletions tket2/src/passes/commutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,14 @@ pub fn apply_greedy_commutation(circ: &mut Circuit) -> Result<u32, PullForwardEr
#[cfg(test)]
mod test {

use crate::{extension::REGISTRY, ops::test::t2_bell_circuit, utils::build_simple_circuit};
use crate::{
extension::{angle::ANGLE_TYPE, REGISTRY},
ops::test::t2_bell_circuit,
utils::build_simple_circuit,
};
use hugr::{
builder::{DFGBuilder, Dataflow, DataflowHugr},
extension::prelude::{BOOL_T, QB_T},
std_extensions::arithmetic::float_types::FLOAT64_TYPE,
type_row,
types::Signature,
};
Expand Down Expand Up @@ -436,7 +439,7 @@ mod test {
fn non_linear_inputs() -> Circuit {
let build = || {
let mut dfg = DFGBuilder::new(Signature::new(
type_row![QB_T, QB_T, FLOAT64_TYPE],
type_row![QB_T, QB_T, ANGLE_TYPE],
type_row![QB_T, QB_T],
))?;

Expand Down
6 changes: 3 additions & 3 deletions tket2/src/portmatching/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ mod tests {
use hugr::builder::{DFGBuilder, Dataflow, DataflowHugr};
use hugr::extension::prelude::QB_T;
use hugr::ops::OpType;
use hugr::std_extensions::arithmetic::float_types::FLOAT64_TYPE;
use hugr::types::Signature;

use crate::extension::angle::ANGLE_TYPE;
use crate::extension::REGISTRY;
use crate::utils::build_simple_circuit;
use crate::Tk2Op;
Expand All @@ -188,7 +188,7 @@ mod tests {

/// A circuit with two rotation gates in sequence, sharing a param
fn circ_with_copy() -> Circuit {
let input_t = vec![QB_T, FLOAT64_TYPE];
let input_t = vec![QB_T, ANGLE_TYPE];
let output_t = vec![QB_T];
let mut h = DFGBuilder::new(Signature::new(input_t, output_t)).unwrap();

Expand All @@ -206,7 +206,7 @@ mod tests {

/// A circuit with two rotation gates in parallel, sharing a param
fn circ_with_copy_disconnected() -> Circuit {
let input_t = vec![QB_T, QB_T, FLOAT64_TYPE];
let input_t = vec![QB_T, QB_T, ANGLE_TYPE];
let output_t = vec![QB_T, QB_T];
let mut h = DFGBuilder::new(Signature::new(input_t, output_t)).unwrap();

Expand Down
Loading

0 comments on commit d14631f

Please sign in to comment.