use std::fmt::{self, Debug, Display};
use itertools::Itertools;
use crate::{ops::Value, Hugr, HugrView, IncomingPort, Node};
pub fn display_list<T>(ts: impl IntoIterator<Item = T>, f: &mut fmt::Formatter) -> fmt::Result
where
T: Display,
{
display_list_with_separator(ts, f, ", ")
}
pub fn display_list_with_separator<T>(
ts: impl IntoIterator<Item = T>,
f: &mut fmt::Formatter,
sep: &str,
) -> fmt::Result
where
T: Display,
{
let mut first = true;
for t in ts.into_iter() {
if !first {
f.write_str(sep)?;
}
t.fmt(f)?;
if first {
first = false;
}
}
Ok(())
}
#[inline]
pub fn collect_array<const N: usize, T: Debug>(arr: impl IntoIterator<Item = T>) -> [T; N] {
try_collect_array(arr).unwrap_or_else(|v| panic!("Expected {} elements, got {:?}", N, v))
}
#[inline]
pub fn try_collect_array<const N: usize, T>(
arr: impl IntoIterator<Item = T>,
) -> Result<[T; N], Vec<T>> {
arr.into_iter().collect_vec().try_into()
}
#[allow(dead_code)]
pub(crate) fn is_default<T: Default + PartialEq>(t: &T) -> bool {
*t == Default::default()
}
#[cfg(test)]
pub(crate) mod test_quantum_extension {
use crate::ops::{OpName, OpNameRef};
use crate::types::FuncValueType;
use crate::{
extension::{
prelude::{BOOL_T, QB_T},
ExtensionId, ExtensionRegistry, PRELUDE,
},
ops::ExtensionOp,
std_extensions::arithmetic::float_types,
type_row,
types::{PolyFuncTypeRV, Signature},
Extension,
};
use lazy_static::lazy_static;
fn one_qb_func() -> PolyFuncTypeRV {
FuncValueType::new_endo(QB_T).into()
}
fn two_qb_func() -> PolyFuncTypeRV {
FuncValueType::new_endo(type_row![QB_T, QB_T]).into()
}
pub const EXTENSION_ID: ExtensionId = ExtensionId::new_unchecked("test.quantum");
fn extension() -> Extension {
let mut extension = Extension::new_test(EXTENSION_ID);
extension
.add_op(OpName::new_inline("H"), "Hadamard".into(), one_qb_func())
.unwrap();
extension
.add_op(
OpName::new_inline("RzF64"),
"Rotation specified by float".into(),
Signature::new(type_row![QB_T, float_types::FLOAT64_TYPE], type_row![QB_T]),
)
.unwrap();
extension
.add_op(OpName::new_inline("CX"), "CX".into(), two_qb_func())
.unwrap();
extension
.add_op(
OpName::new_inline("Measure"),
"Measure a qubit, returning the qubit and the measurement result.".into(),
Signature::new(type_row![QB_T], type_row![QB_T, BOOL_T]),
)
.unwrap();
extension
.add_op(
OpName::new_inline("QAlloc"),
"Allocate a new qubit.".into(),
Signature::new(type_row![], type_row![QB_T]),
)
.unwrap();
extension
.add_op(
OpName::new_inline("QDiscard"),
"Discard a qubit.".into(),
Signature::new(type_row![QB_T], type_row![]),
)
.unwrap();
extension
}
lazy_static! {
pub static ref EXTENSION: Extension = extension();
static ref REG: ExtensionRegistry = ExtensionRegistry::try_new([EXTENSION.to_owned(), PRELUDE.to_owned(), float_types::EXTENSION.to_owned()]).unwrap();
}
fn get_gate(gate_name: &OpNameRef) -> ExtensionOp {
EXTENSION
.instantiate_extension_op(gate_name, [], ®)
.unwrap()
}
pub(crate) fn h_gate() -> ExtensionOp {
get_gate("H")
}
pub(crate) fn cx_gate() -> ExtensionOp {
get_gate("CX")
}
pub(crate) fn measure() -> ExtensionOp {
get_gate("Measure")
}
pub(crate) fn rz_f64() -> ExtensionOp {
get_gate("RzF64")
}
pub(crate) fn q_alloc() -> ExtensionOp {
get_gate("QAlloc")
}
pub(crate) fn q_discard() -> ExtensionOp {
get_gate("QDiscard")
}
}
fn sort_by_in_port(consts: &[(IncomingPort, Value)]) -> Vec<&(IncomingPort, Value)> {
let mut v: Vec<_> = consts.iter().collect();
v.sort_by_key(|(i, _)| i);
v
}
pub fn sorted_consts(consts: &[(IncomingPort, Value)]) -> Vec<&Value> {
sort_by_in_port(consts)
.into_iter()
.map(|(_, c)| c)
.collect()
}
pub fn depth(h: &Hugr, n: Node) -> u32 {
match h.get_parent(n) {
Some(p) => 1 + depth(h, p),
None => 0,
}
}
#[allow(dead_code)]
#[cfg(test)]
pub(crate) mod test {
#[allow(unused_imports)]
use crate::HugrView;
use crate::{
ops::{OpType, Value},
Hugr,
};
#[cfg(not(ci_run))]
pub(crate) fn viz_dotstr(dotstr: impl AsRef<str>) {
let mut base: String = "https://dreampuf.github.io/GraphvizOnline/#".into();
base.push_str(&urlencoding::encode(dotstr.as_ref()));
webbrowser::open(&base).unwrap();
}
#[cfg(not(ci_run))]
pub(crate) fn viz_hugr(hugr: &impl HugrView) {
viz_dotstr(hugr.dot_string());
}
pub(crate) fn assert_fully_folded(h: &Hugr, expected_value: &Value) {
assert_fully_folded_with(h, |v| v == expected_value)
}
pub(crate) fn assert_fully_folded_with(h: &Hugr, check_value: impl Fn(&Value) -> bool) {
let mut node_count = 0;
for node in h.children(h.root()) {
let op = h.get_optype(node);
match op {
OpType::Input(_) | OpType::Output(_) | OpType::LoadConstant(_) => node_count += 1,
OpType::Const(c) if check_value(c.value()) => node_count += 1,
_ => panic!("unexpected op: {}\n{}", op, h.mermaid_string()),
}
}
assert_eq!(node_count, 4);
}
}