diff --git a/test_files/barenco_tof_10.json b/test_files/barenco_tof_10.json index ebb40575..a80d9d90 100644 --- a/test_files/barenco_tof_10.json +++ b/test_files/barenco_tof_10.json @@ -47,7 +47,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -183,7 +183,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -288,7 +288,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -424,7 +424,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -529,7 +529,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -665,7 +665,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -770,7 +770,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -906,7 +906,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1011,7 +1011,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1147,7 +1147,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1252,7 +1252,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1388,7 +1388,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1493,7 +1493,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1629,7 +1629,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1734,7 +1734,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1870,7 +1870,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -1975,7 +1975,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -2063,7 +2063,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -2212,7 +2212,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -2365,7 +2365,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -2518,7 +2518,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -2671,7 +2671,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -2824,7 +2824,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -2977,7 +2977,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -3130,7 +3130,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -3283,7 +3283,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -3436,7 +3436,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -3545,7 +3545,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -3794,7 +3794,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -4043,7 +4043,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -4292,7 +4292,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -4541,7 +4541,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -4790,7 +4790,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -5039,7 +5039,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -5332,7 +5332,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -5420,7 +5420,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -5525,7 +5525,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -5678,7 +5678,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -5831,7 +5831,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -5984,7 +5984,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6137,7 +6137,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6290,7 +6290,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6443,7 +6443,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6596,7 +6596,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6684,7 +6684,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6772,7 +6772,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6860,7 +6860,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -6948,7 +6948,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -7036,7 +7036,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" @@ -7124,7 +7124,7 @@ "type": "Rz", "n_qb": 1, "params": [ - "-0.25" + "1.75" ], "signature": [ "Q" diff --git a/test_files/eccs/nam_4_2.rwr b/test_files/eccs/nam_4_2.rwr index 97649f54..cb2a24c0 100644 Binary files a/test_files/eccs/nam_4_2.rwr and b/test_files/eccs/nam_4_2.rwr differ diff --git a/test_files/eccs/nam_6_3.rwr b/test_files/eccs/nam_6_3.rwr index 447fc018..83c9f249 100644 Binary files a/test_files/eccs/nam_6_3.rwr and b/test_files/eccs/nam_6_3.rwr differ diff --git a/test_files/eccs/small_eccs.rwr b/test_files/eccs/small_eccs.rwr index 828e8828..a9ebc2d9 100644 Binary files a/test_files/eccs/small_eccs.rwr and b/test_files/eccs/small_eccs.rwr differ diff --git a/tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr b/tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr index 447fc018..83c9f249 100644 Binary files a/tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr and b/tket2-eccs/src/tket2_eccs/data/nam_6_3.rwr differ diff --git a/tket2-hseries/src/lib.rs b/tket2-hseries/src/lib.rs index c463c9ed..1bafbcf4 100644 --- a/tket2-hseries/src/lib.rs +++ b/tket2-hseries/src/lib.rs @@ -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}; @@ -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 @@ -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() diff --git a/tket2-py/tket2/circuit/build.py b/tket2-py/tket2/circuit/build.py index 811e0694..3e328d17 100644 --- a/tket2-py/tket2/circuit/build.py +++ b/tket2-py/tket2/circuit/build.py @@ -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]) diff --git a/tket2/src/circuit.rs b/tket2/src/circuit.rs index 120edd40..d54ef645 100644 --- a/tket2/src/circuit.rs +++ b/tket2/src/circuit.rs @@ -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}; @@ -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; @@ -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)], diff --git a/tket2/src/circuit/command.rs b/tket2/src/circuit/command.rs index 4a0597ea..6fc68f11 100644 --- a/tket2/src/circuit/command.rs +++ b/tket2/src/circuit/command.rs @@ -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; @@ -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(), ®ISTRY) .unwrap() .into(); @@ -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), diff --git a/tket2/src/extension.rs b/tket2/src/extension.rs index fdecbd6a..3f2045d3 100644 --- a/tket2/src/extension.rs +++ b/tket2/src/extension.rs @@ -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}; @@ -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(); @@ -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); @@ -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(); diff --git a/tket2/src/extension/angle.rs b/tket2/src/extension/angle.rs index 49c0666f..74668e21 100644 --- a/tket2/src/extension/angle.rs +++ b/tket2/src/extension/angle.rs @@ -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 { if !is_valid_log_denom(log_denom) { @@ -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::from_radians_rounding(LOG_DENOM_MAX, theta) + } + /// Returns the value of the constant pub fn value(&self) -> u64 { self.value @@ -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] diff --git a/tket2/src/ops.rs b/tket2/src/ops.rs index e9bdda6a..644dc04d 100644 --- a/tket2/src/ops.rs +++ b/tket2/src/ops.rs @@ -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, }; @@ -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}, }; @@ -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![]), } diff --git a/tket2/src/optimiser/badger.rs b/tket2/src/optimiser/badger.rs index 0bb0862a..0c64fd9e 100644 --- a/tket2/src/optimiser/badger.rs +++ b/tket2/src/optimiser/badger.rs @@ -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(); @@ -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, @@ -642,7 +641,7 @@ mod tests { .unwrap(); // Rzs combined into a single one. - assert_eq!(op1.cast::(), Some(FloatOps::fadd)); + assert_eq!(op1.cast(), Some(AngleOp::aadd)); assert!(op_matches(op2, Tk2Op::Rz)); } diff --git a/tket2/src/optimiser/badger/qtz_circuit.rs b/tket2/src/optimiser/badger/qtz_circuit.rs index aa46c69f..212328b6 100644 --- a/tket2/src/optimiser/badger/qtz_circuit.rs +++ b/tket2/src/optimiser/badger/qtz_circuit.rs @@ -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)] @@ -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 { @@ -64,7 +64,7 @@ fn map_op(opstr: &str) -> Op { impl From for Circuit { fn from(RepCircData { circ: rc, meta }: RepCircData) -> Self { let qb_types: Vec = vec![QB_T; meta.n_qb]; - let param_types: Vec = vec![FLOAT64_TYPE; meta.n_input_param]; + let param_types: Vec = vec![ANGLE_TYPE; meta.n_input_param]; let mut builder = DFGBuilder::new(Signature::new( [qb_types.clone(), param_types].concat(), qb_types, diff --git a/tket2/src/passes/commutation.rs b/tket2/src/passes/commutation.rs index 1834bf7f..bc4732d0 100644 --- a/tket2/src/passes/commutation.rs +++ b/tket2/src/passes/commutation.rs @@ -326,11 +326,14 @@ pub fn apply_greedy_commutation(circ: &mut Circuit) -> Result 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], ))?; diff --git a/tket2/src/portmatching/pattern.rs b/tket2/src/portmatching/pattern.rs index 36be1870..97d95533 100644 --- a/tket2/src/portmatching/pattern.rs +++ b/tket2/src/portmatching/pattern.rs @@ -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; @@ -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(); @@ -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(); diff --git a/tket2/src/serialize/pytket.rs b/tket2/src/serialize/pytket.rs index 1bb3bb8a..e3afd379 100644 --- a/tket2/src/serialize/pytket.rs +++ b/tket2/src/serialize/pytket.rs @@ -20,13 +20,13 @@ use std::path::Path; use std::{fs, io}; use hugr::ops::{NamedOp, OpType, Value}; -use hugr::std_extensions::arithmetic::float_types::ConstF64; use thiserror::Error; use tket_json_rs::circuit_json::{self, SerialCircuit}; use tket_json_rs::optype::OpType as SerialOpType; use crate::circuit::Circuit; +use crate::extension::angle::ConstAngle; use self::decoder::Tk1Decoder; use self::encoder::Tk1Encoder; @@ -298,7 +298,9 @@ fn try_param_to_constant(param: &str) -> Option { }; let radians = half_turns * std::f64::consts::PI; - Some(ConstF64::new(radians).into()) + ConstAngle::from_radians_rounding_max(radians) + .ok() + .map(Into::into) } /// Convert a HUGR angle constant to a TKET1 parameter. @@ -307,9 +309,8 @@ fn try_param_to_constant(param: &str) -> Option { /// whereas HUGR uses radians. #[inline] fn try_constant_to_param(val: &Value) -> Option { - let const_float = val.get_custom_value::()?; - let radians: f64 = **const_float; - let half_turns = radians / std::f64::consts::PI; + let const_angle = val.get_custom_value::()?; + let half_turns = const_angle.to_turns() * 2.0; Some(half_turns.to_string()) } diff --git a/tket2/src/serialize/pytket/encoder.rs b/tket2/src/serialize/pytket/encoder.rs index 6d2ffc43..63a11222 100644 --- a/tket2/src/serialize/pytket/encoder.rs +++ b/tket2/src/serialize/pytket/encoder.rs @@ -5,8 +5,6 @@ use std::collections::{HashMap, HashSet, VecDeque}; use hugr::extension::prelude::{BOOL_T, QB_T}; use hugr::ops::{OpTrait, OpType}; -use hugr::std_extensions::arithmetic::float_ops::FloatOps; -use hugr::std_extensions::arithmetic::float_types::FLOAT64_TYPE; use hugr::{HugrView, Wire}; use itertools::Itertools; use tket_json_rs::circuit_json::Register as RegisterUnit; @@ -14,6 +12,7 @@ use tket_json_rs::circuit_json::{self, SerialCircuit}; use crate::circuit::command::{CircuitUnit, Command}; use crate::circuit::Circuit; +use crate::extension::angle::{AngleOp, ANGLE_TYPE}; use crate::ops::match_symb_const_op; use crate::serialize::pytket::RegisterHash; use crate::Tk2Op; @@ -50,7 +49,7 @@ impl Tk1Encoder { // Check for unsupported input types. for (_, _, typ) in circ.units() { - if ![FLOAT64_TYPE, QB_T, BOOL_T].contains(&typ) { + if ![ANGLE_TYPE, QB_T, BOOL_T].contains(&typ) { return Err(TK1ConvertError::NonSerializableInputs { typ }); } } @@ -126,9 +125,9 @@ impl Tk1Encoder { ) }); bit_args.push(reg); - } else if ty == FLOAT64_TYPE { + } else if ty == ANGLE_TYPE { let CircuitUnit::Wire(param_wire) = unit else { - unreachable!("Float types are not linear.") + unreachable!("Angle types are not linear.") }; params.push(param_wire); } else { @@ -553,12 +552,12 @@ impl ParameterTracker { fn new(circ: &Circuit) -> Self { let mut tracker = ParameterTracker::default(); - let float_input_wires = circ.units().filter_map(|u| match u { - (CircuitUnit::Wire(w), _, ty) if ty == FLOAT64_TYPE => Some(w), + let angle_input_wires = circ.units().filter_map(|u| match u { + (CircuitUnit::Wire(w), _, ty) if ty == ANGLE_TYPE => Some(w), _ => None, }); - for (i, wire) in float_input_wires.enumerate() { + for (i, wire) in angle_input_wires.enumerate() { tracker.add_parameter(wire, format!("f{i}")); } @@ -576,8 +575,8 @@ impl ParameterTracker { let input_count = if let Some(signature) = optype.dataflow_signature() { // Only consider commands where all inputs are parameters, // and some outputs are also parameters. - let all_inputs = signature.input().iter().all(|ty| ty == &FLOAT64_TYPE); - let some_output = signature.output().iter().any(|ty| ty == &FLOAT64_TYPE); + let all_inputs = signature.input().iter().all(|ty| ty == &ANGLE_TYPE); + let some_output = signature.output().iter().any(|ty| ty == &ANGLE_TYPE); if !all_inputs || !some_output { return Ok(false); } @@ -595,10 +594,10 @@ impl ParameterTracker { let mut inputs = Vec::with_capacity(input_count); for (unit, _, _) in command.inputs() { let CircuitUnit::Wire(wire) = unit else { - panic!("Float types are not linear") + panic!("Angle types are not linear") }; let Some(param) = self.parameters.get(&wire) else { - let typ = FLOAT64_TYPE; + let typ = ANGLE_TYPE; return Err(OpConvertError::UnresolvedParamInput { typ, optype: optype.clone(), @@ -620,7 +619,7 @@ impl ParameterTracker { // Re-use the parameter from the input. inputs[0].clone() } - OpType::ExtensionOp(_) if optype.cast::() == Some(FloatOps::fadd) => { + OpType::ExtensionOp(_) if optype.cast() == Some(AngleOp::aadd) => { format!("{} + {}", inputs[0], inputs[1]) } _ => { diff --git a/tket2/src/serialize/pytket/op/native.rs b/tket2/src/serialize/pytket/op/native.rs index c003e491..552c1449 100644 --- a/tket2/src/serialize/pytket/op/native.rs +++ b/tket2/src/serialize/pytket/op/native.rs @@ -3,13 +3,13 @@ use hugr::extension::prelude::{Noop, BOOL_T, QB_T}; use hugr::ops::{OpTrait, OpType}; -use hugr::std_extensions::arithmetic::float_types::FLOAT64_TYPE; use hugr::types::Signature; use hugr::IncomingPort; use tket_json_rs::circuit_json; use tket_json_rs::optype::OpType as Tk1OpType; +use crate::extension::angle::ANGLE_TYPE; use crate::Tk2Op; /// An operation with a native TKET2 counterpart. @@ -159,7 +159,7 @@ impl NativeOp { let types = sig.input_types().to_owned(); sig.input_ports() .zip(types) - .filter(|(_, ty)| ty == &FLOAT64_TYPE) + .filter(|(_, ty)| ty == &ANGLE_TYPE) .map(|(port, _)| port) }) } @@ -179,7 +179,7 @@ impl NativeOp { self.input_qubits += 1; } else if ty == &BOOL_T { self.input_bits += 1; - } else if ty == &FLOAT64_TYPE { + } else if ty == &ANGLE_TYPE { self.num_params += 1; } } diff --git a/tket2/src/serialize/pytket/op/serialised.rs b/tket2/src/serialize/pytket/op/serialised.rs index f6d5bf31..35c0d7a3 100644 --- a/tket2/src/serialize/pytket/op/serialised.rs +++ b/tket2/src/serialize/pytket/op/serialised.rs @@ -4,13 +4,13 @@ use hugr::extension::prelude::{BOOL_T, QB_T}; use hugr::ops::custom::ExtensionOp; use hugr::ops::{NamedOp, OpType}; -use hugr::std_extensions::arithmetic::float_types::FLOAT64_TYPE; use hugr::types::{Signature, TypeArg}; use hugr::IncomingPort; use serde::de::Error; use tket_json_rs::circuit_json; +use crate::extension::angle::ANGLE_TYPE; use crate::extension::{REGISTRY, TKET1_EXTENSION, TKET1_EXTENSION_ID, TKET1_OP_NAME}; use crate::serialize::pytket::OpConvertError; @@ -38,7 +38,7 @@ pub struct OpaqueTk1Op { /// instead stored purely as metadata for the `Operation`. param_inputs: Vec>, /// The number of non-None inputs in `param_inputs`, corresponding to the - /// FLOAT64_TYPE inputs to the Hugr operation. + /// ANGLE_TYPE inputs to the Hugr operation. pub num_params: usize, } @@ -112,7 +112,7 @@ impl OpaqueTk1Op { vec![BOOL_T.clone(); self.num_bits], ] .concat(); - let params = vec![FLOAT64_TYPE; self.num_params]; + let params = vec![ANGLE_TYPE; self.num_params]; Signature::new([linear.clone(), params].concat(), linear) .with_extension_delta(TKET1_EXTENSION_ID) } diff --git a/tket2/src/serialize/pytket/tests.rs b/tket2/src/serialize/pytket/tests.rs index 288b2531..abc776f3 100644 --- a/tket2/src/serialize/pytket/tests.rs +++ b/tket2/src/serialize/pytket/tests.rs @@ -7,10 +7,6 @@ use hugr::builder::{DFGBuilder, Dataflow, DataflowHugr}; use hugr::extension::prelude::{BOOL_T, QB_T}; use hugr::hugr::hugrmut::HugrMut; -use hugr::std_extensions::arithmetic::{ - float_ops::FloatOps, - float_types::{ConstF64, FLOAT64_TYPE}, -}; use hugr::types::Signature; use hugr::HugrView; use rstest::{fixture, rstest}; @@ -19,6 +15,7 @@ use tket_json_rs::optype; use super::{TKETDecode, METADATA_Q_OUTPUT_REGISTERS}; use crate::circuit::Circuit; +use crate::extension::angle::{AngleOp, ConstAngle, ANGLE_TYPE}; use crate::extension::REGISTRY; use crate::Tk2Op; @@ -64,8 +61,8 @@ const PARAMETERIZED: &str = r#"{ "commands": [ {"args":[["q",[0]]],"op":{"type":"H"}}, {"args":[["q",[1]],["q",[0]]],"op":{"type":"CX"}}, - {"args":[["q",[0]]],"op":{"params":["0.1"],"type":"Rz"}}, - {"args": [["q", [0]]], "op": {"params": ["3.141596/pi", "alpha", "0.3"], "type": "TK1"}} + {"args":[["q",[0]]],"op":{"params":["1.5707963267948966/pi"],"type":"Rz"}}, + {"args": [["q", [0]]], "op": {"params": ["3.141596/pi", "alpha", "0.7853981633974483/pi"], "type": "TK1"}} ], "created_qubits": [], "discarded_qubits": [], @@ -191,13 +188,13 @@ fn circ_measure_ancilla() -> Circuit { #[fixture] fn circ_add_angles_symbolic() -> 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(); let [qb, f1, f2] = h.input_wires_arr(); let [f12] = h - .add_dataflow_op(FloatOps::fadd, [f1, f2]) + .add_dataflow_op(AngleOp::aadd, [f1, f2]) .unwrap() .outputs_arr(); let [qb] = h @@ -215,10 +212,10 @@ fn circ_add_angles_constants() -> Circuit { let qb = h.input_wires().next().unwrap(); - let point2 = h.add_load_value(ConstF64::new(0.2 * std::f64::consts::PI)); - let point3 = h.add_load_value(ConstF64::new(0.3 * std::f64::consts::PI)); + let point2 = h.add_load_value(ConstAngle::new(2, 3).unwrap()); + let point3 = h.add_load_value(ConstAngle::new(4, 5).unwrap()); let point5 = h - .add_dataflow_op(FloatOps::fadd, [point2, point3]) + .add_dataflow_op(AngleOp::aadd, [point2, point3]) .unwrap() .out_wire(0); @@ -293,7 +290,7 @@ fn circuit_roundtrip(#[case] circ: Circuit, #[case] decoded_sig: Signature) { /// expressions. #[rstest] #[case::symbolic(circ_add_angles_symbolic(), "f0 + f1")] -#[case::constants(circ_add_angles_constants(), "0.2 + 0.3")] +#[case::constants(circ_add_angles_constants(), "1.5 + 0.625")] fn test_add_angle_serialise(#[case] circ_add_angles: Circuit, #[case] param_str: &str) { let ser: SerialCircuit = SerialCircuit::encode(&circ_add_angles).unwrap(); assert_eq!(ser.commands.len(), 1); diff --git a/tket2/src/utils.rs b/tket2/src/utils.rs index 52876871..a0279329 100644 --- a/tket2/src/utils.rs +++ b/tket2/src/utils.rs @@ -3,8 +3,6 @@ use hugr::builder::{Container, DataflowSubContainer, FunctionBuilder, HugrBuilder, ModuleBuilder}; use hugr::extension::PRELUDE_REGISTRY; use hugr::ops::handle::NodeHandle; -use hugr::std_extensions::arithmetic::float_ops::FLOAT_OPS_REGISTRY; -use hugr::std_extensions::arithmetic::float_types; use hugr::types::{Type, TypeBound}; use hugr::Hugr; use hugr::{ @@ -14,6 +12,7 @@ use hugr::{ }; use crate::circuit::Circuit; +use crate::extension::{REGISTRY, TKET2_EXTENSION_ID}; pub(crate) fn type_is_linear(typ: &Type) -> bool { !TypeBound::Copyable.contains(typ.least_upper_bound()) @@ -26,8 +25,7 @@ where F: FnOnce(&mut CircuitBuilder>) -> Result<(), BuildError>, { let qb_row = vec![QB_T; num_qubits]; - let signature = - Signature::new(qb_row.clone(), qb_row).with_extension_delta(float_types::EXTENSION_ID); + let signature = Signature::new(qb_row.clone(), qb_row).with_extension_delta(TKET2_EXTENSION_ID); let mut h = FunctionBuilder::new("main", signature)?; let qbs = h.input_wires(); @@ -38,8 +36,7 @@ where let qbs = circ.finish(); - // The float ops registry is required to define constant float values. - let hugr = h.finish_hugr_with_outputs(qbs, &FLOAT_OPS_REGISTRY)?; + let hugr = h.finish_hugr_with_outputs(qbs, ®ISTRY)?; Ok(hugr.into()) }