pub(super) mod parser;
use std::sync::LazyLock;
use hugr::builder::{DFGBuilder, Dataflow};
use hugr::ops::Value;
use hugr::std_extensions::arithmetic::float_ops::FloatOps;
use hugr::std_extensions::arithmetic::float_types::{ConstF64, float64_type};
use hugr::types::Type;
use hugr::{Hugr, Wire};
use crate::extension::rotation::{RotationOp, rotation_type};
#[derive(Debug, derive_more::Display, Clone, Copy, Hash, PartialEq, Eq)]
pub enum ParameterType {
FloatRadians,
FloatHalfTurns,
Rotation,
}
impl ParameterType {
pub fn to_type(&self) -> &'static Type {
static FLOAT_TYPE: LazyLock<Type> = LazyLock::new(float64_type);
static ROTATION_TYPE: LazyLock<Type> = LazyLock::new(rotation_type);
match self {
ParameterType::FloatRadians => &FLOAT_TYPE,
ParameterType::FloatHalfTurns => &FLOAT_TYPE,
ParameterType::Rotation => &ROTATION_TYPE,
}
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct LoadedParameter {
typ: ParameterType,
wire: Wire,
}
impl LoadedParameter {
pub fn new(typ: ParameterType, wire: Wire) -> LoadedParameter {
LoadedParameter { typ, wire }
}
#[inline]
pub fn typ(&self) -> ParameterType {
self.typ
}
#[inline]
pub fn wire(&self) -> Wire {
self.wire
}
#[inline]
pub fn float_radians(wire: Wire) -> LoadedParameter {
LoadedParameter {
typ: ParameterType::FloatRadians,
wire,
}
}
#[inline]
pub fn float_half_turns(wire: Wire) -> LoadedParameter {
LoadedParameter {
typ: ParameterType::FloatHalfTurns,
wire,
}
}
#[inline]
pub fn rotation(wire: Wire) -> LoadedParameter {
LoadedParameter {
typ: ParameterType::Rotation,
wire,
}
}
#[inline]
pub fn wire_type(&self) -> &'static Type {
self.typ.to_type()
}
#[inline]
pub fn with_type<H: AsRef<Hugr> + AsMut<Hugr>>(
&self,
typ: ParameterType,
hugr: &mut DFGBuilder<H>,
) -> LoadedParameter {
match typ {
ParameterType::FloatRadians => self.as_float_radians(hugr),
ParameterType::FloatHalfTurns => self.as_float_half_turns(hugr),
ParameterType::Rotation => self.as_rotation(hugr),
}
}
pub fn as_float_radians<H: AsRef<Hugr> + AsMut<Hugr>>(
&self,
hugr: &mut DFGBuilder<H>,
) -> LoadedParameter {
match self.typ {
ParameterType::FloatRadians => *self,
ParameterType::FloatHalfTurns => {
let pi = hugr.add_load_const(Value::from(ConstF64::new(std::f64::consts::PI)));
let float_radians = hugr
.add_dataflow_op(FloatOps::fmul, [self.wire(), pi])
.expect("Error converting float to rotation")
.out_wire(0);
LoadedParameter::float_radians(float_radians)
}
ParameterType::Rotation => self.as_float_half_turns(hugr).as_float_radians(hugr),
}
}
pub fn as_float_half_turns<H: AsRef<Hugr> + AsMut<Hugr>>(
&self,
hugr: &mut DFGBuilder<H>,
) -> LoadedParameter {
match self.typ {
ParameterType::FloatHalfTurns => *self,
ParameterType::FloatRadians => {
let pi = hugr.add_load_const(Value::from(ConstF64::new(std::f64::consts::PI)));
let float_halfturns = hugr
.add_dataflow_op(FloatOps::fdiv, [self.wire, pi])
.expect("Error converting float to rotation")
.out_wire(0);
LoadedParameter::float_half_turns(float_halfturns)
}
ParameterType::Rotation => {
let wire = hugr
.add_dataflow_op(RotationOp::to_halfturns, [self.wire()])
.unwrap()
.out_wire(0);
LoadedParameter::float_half_turns(wire)
}
}
}
pub fn as_rotation<H: AsRef<Hugr> + AsMut<Hugr>>(
&self,
hugr: &mut DFGBuilder<H>,
) -> LoadedParameter {
match self.typ {
ParameterType::Rotation => *self,
ParameterType::FloatHalfTurns => {
let wire = hugr
.add_dataflow_op(RotationOp::from_halfturns_unchecked, [self.wire()])
.unwrap()
.out_wire(0);
LoadedParameter::rotation(wire)
}
ParameterType::FloatRadians => self.as_float_half_turns(hugr).as_rotation(hugr),
}
}
}