Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Unify the serialisation tests #730

Merged
merged 2 commits into from
Dec 1, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 44 additions & 68 deletions src/hugr/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ pub mod test {
use crate::types::{FunctionType, Type};
use crate::OutgoingPort;
use itertools::Itertools;
use portgraph::LinkView;
use portgraph::{
multiportgraph::MultiPortGraph, Hierarchy, LinkMut, PortMut, PortView, UnmanagedDenseMap,
};
Expand All @@ -277,11 +278,47 @@ pub mod test {
assert_eq!(ser_roundtrip(&hg), hg);
}

/// Serialize and deserialize a value.
pub fn ser_roundtrip<T: Serialize + serde::de::DeserializeOwned>(g: &T) -> T {
let v = rmp_serde::to_vec_named(g).unwrap();
rmp_serde::from_slice(&v[..]).unwrap()
}

/// Serialize and deserialize a HUGR, and check that the result is the same as the original.
///
/// Returns the deserialized HUGR.
pub fn check_hugr_roundtrip(hugr: &Hugr) -> Hugr {
let new_hugr: Hugr = ser_roundtrip(hugr);

// Original HUGR, with canonicalized node indices
//
// The internal port indices may still be different.
let mut h_canon = hugr.clone();
h_canon.canonicalize_nodes(|_, _| {});

assert_eq!(new_hugr.root, h_canon.root);
assert_eq!(new_hugr.hierarchy, h_canon.hierarchy);
assert_eq!(new_hugr.op_types, h_canon.op_types);
assert_eq!(new_hugr.metadata, h_canon.metadata);

// Check that the graphs are equivalent up to port renumbering.
let new_graph = &new_hugr.graph;
let old_graph = &h_canon.graph;
assert_eq!(new_graph.node_count(), old_graph.node_count());
assert_eq!(new_graph.port_count(), old_graph.port_count());
assert_eq!(new_graph.link_count(), old_graph.link_count());
for n in old_graph.nodes_iter() {
assert_eq!(new_graph.num_inputs(n), old_graph.num_inputs(n));
assert_eq!(new_graph.num_outputs(n), old_graph.num_outputs(n));
assert_eq!(
new_graph.output_neighbours(n).collect_vec(),
old_graph.output_neighbours(n).collect_vec()
);
}

new_hugr
}

/// Generate an optype for a node with a matching amount of inputs and outputs.
fn gen_optype(g: &MultiPortGraph, node: portgraph::NodeIndex) -> OpType {
let inputs = g.num_inputs(node);
Expand Down Expand Up @@ -323,18 +360,15 @@ pub mod test {
op_types[n] = NodeType::new_pure(gen_optype(&g, n));
}

let hg = Hugr {
let hugr = Hugr {
graph: g,
hierarchy: h,
root,
op_types,
metadata: Default::default(),
};

let v = rmp_serde::to_vec_named(&hg).unwrap();

let newhg = rmp_serde::from_slice(&v[..]).unwrap();
assert_eq!(hg, newhg);
check_hugr_roundtrip(&hugr);
}

#[test]
Expand Down Expand Up @@ -368,44 +402,7 @@ pub mod test {
module_builder.finish_prelude_hugr().unwrap()
};

let ser_hugr: SerHugrV0 = (&hugr).try_into().unwrap();
// HUGR internal structures are not preserved across serialization, so
// test equality on SerHugrV0 instead.
assert_eq!(ser_roundtrip(&ser_hugr), ser_hugr);
}

#[test]
fn metadata_hugr_ser() {
let hugr = {
let mut module_builder = ModuleBuilder::new();
let t_row = vec![Type::new_sum(vec![NAT, QB])];
let mut f_build = module_builder
.define_function("main", FunctionType::new(t_row.clone(), t_row).into())
.unwrap();

let outputs = f_build
.input_wires()
.map(|in_wire| {
f_build
.add_dataflow_op(
LeafOp::Noop {
ty: f_build.get_wire_type(in_wire).unwrap(),
},
[in_wire],
)
.unwrap()
.out_wire(0)
})
.collect_vec();

f_build.finish_with_outputs(outputs).unwrap();
module_builder.finish_prelude_hugr().unwrap()
};

let ser_hugr: SerHugrV0 = (&hugr).try_into().unwrap();
// HUGR internal structures are not preserved across serialization, so
// test equality on SerHugrV0 instead.
assert_eq!(ser_roundtrip(&ser_hugr), ser_hugr);
check_hugr_roundtrip(&hugr);
}

#[test]
Expand All @@ -419,25 +416,14 @@ pub mod test {
.unwrap()
.out_wire(0);
}
let h = dfg.finish_hugr_with_outputs(params, &EMPTY_REG)?;

let ser = serde_json::to_string(&h)?;
let h_deser: Hugr = serde_json::from_str(&ser)?;

// Check the canonicalization works
let mut h_canon = h;
h_canon.canonicalize_nodes(|_, _| {});

for node in h_deser.nodes() {
assert_eq!(h_deser.get_optype(node), h_canon.get_optype(node));
assert_eq!(h_deser.get_parent(node), h_canon.get_parent(node));
}
let hugr = dfg.finish_hugr_with_outputs(params, &EMPTY_REG)?;

check_hugr_roundtrip(&hugr);
Ok(())
}

#[test]
fn hierarchy_order() {
fn canonicalisation() {
let mut hugr = closed_dfg_root_hugr(FunctionType::new(vec![QB], vec![QB]));
let [old_in, out] = hugr.get_io(hugr.root()).unwrap();
hugr.connect(old_in, 0, out, 0).unwrap();
Expand All @@ -450,18 +436,8 @@ pub mod test {
hugr.remove_node(old_in).unwrap();
hugr.update_validate(&PRELUDE_REGISTRY).unwrap();

let ser = serde_json::to_vec(&hugr).unwrap();
let new_hugr: Hugr = serde_json::from_slice(&ser).unwrap();
let new_hugr: Hugr = check_hugr_roundtrip(&hugr);
new_hugr.validate(&EMPTY_REG).unwrap_err();
new_hugr.validate(&PRELUDE_REGISTRY).unwrap();

// Check the canonicalization works
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test is just unit testing the canonicalize, without serialisation so I think it should be left as is

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uhm, the code here was doing the same as the new function; checking that the canonicalization matches with the serialisation roundtrip.

It seems I didn't delete the serialisation code above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ok 👍

let mut h_canon = hugr.clone();
h_canon.canonicalize_nodes(|_, _| {});

for node in new_hugr.nodes() {
assert_eq!(new_hugr.get_optype(node), h_canon.get_optype(node));
assert_eq!(new_hugr.get_parent(node), h_canon.get_parent(node));
}
}
}