diff --git a/Cargo.lock b/Cargo.lock index 7198a4ea5b..085d2d6a5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "serde", "version_check", @@ -301,9 +301,9 @@ checksum = "38c99613cb3cd7429889a08dfcf651721ca971c86afa30798461f8eee994de47" [[package]] name = "bstr" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -351,9 +351,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.18" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "jobserver", "libc", @@ -936,9 +936,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1483,14 +1483,12 @@ dependencies = [ [[package]] name = "insta" -version = "1.42.2" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50259abbaa67d11d2bcafc7ba1d094ed7a0c70e3ce893f0d0997f73558cb3084" +checksum = "ab2d11b2f17a45095b8c3603928ba29d7d918d7129d0d0641a36ba73cf07daa6" dependencies = [ "console", - "linked-hash-map", "once_cell", - "pin-project", "serde", "similar", ] @@ -1622,21 +1620,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "linux-raw-sys" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -1696,9 +1688,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ "adler2", ] @@ -1937,26 +1929,6 @@ dependencies = [ "serde", ] -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -2011,9 +1983,9 @@ checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "portgraph" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9ea69cfb011d5f17af28813ec37a0a9668a063090e14ad75dc5fc07ba01b47" +checksum = "5fdce52d51ec359351ff3c209fafb6f133562abf52d951ce5821c0184798d979" dependencies = [ "bitvec", "delegate", @@ -2029,7 +2001,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy 0.8.25", ] [[package]] @@ -2094,9 +2066,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -2259,7 +2231,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2694,9 +2666,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -2830,15 +2802,15 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" dependencies = [ "indexmap", "toml_datetime", @@ -3418,9 +3390,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] @@ -3496,11 +3468,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive 0.8.25", ] [[package]] @@ -3516,9 +3488,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c72326a337..97dad7dea6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ regex = "1.10.6" regex-syntax = "0.8.3" rstest = "0.24.0" semver = "1.0.26" -serde = "1.0.195" +serde = "1.0.219" serde_json = "1.0.140" serde_yaml = "0.9.34" smol_str = "0.3.1" @@ -87,8 +87,8 @@ zstd = "0.13.2" # These public dependencies usually require breaking changes downstream, so we # try to be as permissive as possible. pyo3 = ">= 0.23.4, < 0.25" -portgraph = { version = ">= 0.13.3, < 0.15" } -petgraph = { version = ">= 0.7.1, < 0.9", default-features = false } +portgraph = { version = "0.14.1" } +petgraph = { version = ">= 0.8.1, < 0.9", default-features = false } [profile.dev.package] insta.opt-level = 3 diff --git a/hugr-core/src/builder/dataflow.rs b/hugr-core/src/builder/dataflow.rs index 64c5f5c843..b84f3a05a4 100644 --- a/hugr-core/src/builder/dataflow.rs +++ b/hugr-core/src/builder/dataflow.rs @@ -506,8 +506,8 @@ pub(crate) mod test { #[rstest] fn dfg_hugr(simple_dfg_hugr: Hugr) { - assert_eq!(simple_dfg_hugr.node_count(), 3); - assert_matches!(simple_dfg_hugr.root_type().tag(), OpTag::Dfg); + assert_eq!(simple_dfg_hugr.num_nodes(), 3); + assert_matches!(simple_dfg_hugr.root_optype().tag(), OpTag::Dfg); } #[test] @@ -533,7 +533,7 @@ pub(crate) mod test { }; let hugr = module_builder.finish_hugr()?; - assert_eq!(hugr.node_count(), 7); + assert_eq!(hugr.num_nodes(), 7); assert_eq!(hugr.get_metadata(hugr.root(), "x"), None); assert_eq!(hugr.get_metadata(dfg_node, "x").cloned(), Some(json!(42))); diff --git a/hugr-core/src/core.rs b/hugr-core/src/core.rs index 03e009bef8..cc9da77ab3 100644 --- a/hugr-core/src/core.rs +++ b/hugr-core/src/core.rs @@ -83,7 +83,7 @@ pub struct Wire(N, OutgoingPort); impl Node { /// Returns the node as a portgraph `NodeIndex`. #[inline] - pub(crate) fn pg_index(self) -> portgraph::NodeIndex { + pub(crate) fn into_portgraph(self) -> portgraph::NodeIndex { self.index } } diff --git a/hugr-core/src/export.rs b/hugr-core/src/export.rs index 09ccf944ca..078fe3c27e 100644 --- a/hugr-core/src/export.rs +++ b/hugr-core/src/export.rs @@ -1,4 +1,5 @@ //! Exporting HUGR graphs to their `hugr-model` representation. +use crate::hugr::internal::HugrInternals; use crate::{ extension::{ExtensionId, OpDef, SignatureFunc}, hugr::IdentList, @@ -94,7 +95,7 @@ struct Context<'a> { impl<'a> Context<'a> { pub fn new(hugr: &'a Hugr, bump: &'a Bump) -> Self { let mut module = table::Module::default(); - module.nodes.reserve(hugr.node_count()); + module.nodes.reserve(hugr.num_nodes()); let links = Links::new(hugr); Self { @@ -999,7 +1000,7 @@ impl<'a> Context<'a> { let outer_hugr = std::mem::replace(&mut self.hugr, hugr); let outer_node_to_id = std::mem::take(&mut self.node_to_id); - let region = match hugr.root_type() { + let region = match hugr.root_optype() { OpType::DFG(_) => self.export_dfg(hugr.root(), model::ScopeClosure::Closed), _ => panic!("Value::Function root must be a DFG"), }; @@ -1031,7 +1032,7 @@ impl<'a> Context<'a> { } pub fn export_node_metadata(&mut self, node: Node) -> &'a [table::TermId] { - let metadata_map = self.hugr.get_node_metadata(node); + let metadata_map = self.hugr.node_metadata_map(node); let has_order_edges = { fn is_relevant_node(hugr: &Hugr, node: Node) -> bool { @@ -1049,13 +1050,11 @@ impl<'a> Context<'a> { .any(|(other, _)| is_relevant_node(self.hugr, other)) }; - let meta_capacity = metadata_map.map_or(0, |map| map.len()) + has_order_edges as usize; + let meta_capacity = metadata_map.len() + has_order_edges as usize; let mut meta = BumpVec::with_capacity_in(meta_capacity, self.bump); - if let Some(metadata_map) = metadata_map { - for (name, value) in metadata_map { - meta.push(self.export_json_meta(name, value)); - } + for (name, value) in metadata_map { + meta.push(self.export_json_meta(name, value)); } if has_order_edges { diff --git a/hugr-core/src/hugr.rs b/hugr-core/src/hugr.rs index 7a74b40703..93250b8e37 100644 --- a/hugr-core/src/hugr.rs +++ b/hugr-core/src/hugr.rs @@ -89,6 +89,25 @@ impl Hugr { Self::with_capacity(root_node.into(), 0, 0) } + /// Create a new Hugr, with a single root node and preallocated capacity. + pub fn with_capacity(root_node: OpType, nodes: usize, ports: usize) -> Self { + let mut graph = MultiPortGraph::with_capacity(nodes, ports); + let hierarchy = Hierarchy::new(); + let mut op_types = UnmanagedDenseMap::with_capacity(nodes); + let root = graph.add_node(root_node.input_count(), root_node.output_count()); + let extensions = root_node.used_extensions(); + op_types[root] = root_node; + + Self { + graph, + hierarchy, + root, + op_types, + metadata: UnmanagedDenseMap::with_capacity(nodes), + extensions: extensions.unwrap_or_default(), + } + } + /// Load a Hugr from a json reader. /// /// Validates the Hugr against the provided extension registry, ensuring all @@ -154,7 +173,7 @@ impl Hugr { .map(|ch| Ok((ch, infer(h, ch, remove)?))) .collect::, _>>()?; - let Some(es) = delta_mut(h.op_types.get_mut(node.pg_index())) else { + let Some(es) = delta_mut(h.op_types.get_mut(node.into_portgraph())) else { return Ok(h.get_optype(node).extension_delta()); }; if es.contains(&TO_BE_INFERRED) { @@ -260,31 +279,6 @@ impl Hugr { /// Internal API for HUGRs, not intended for use by users. impl Hugr { - /// Create a new Hugr, with a single root node and preallocated capacity. - pub(crate) fn with_capacity(root_node: OpType, nodes: usize, ports: usize) -> Self { - let mut graph = MultiPortGraph::with_capacity(nodes, ports); - let hierarchy = Hierarchy::new(); - let mut op_types = UnmanagedDenseMap::with_capacity(nodes); - let root = graph.add_node(root_node.input_count(), root_node.output_count()); - let extensions = root_node.used_extensions(); - op_types[root] = root_node; - - Self { - graph, - hierarchy, - root, - op_types, - metadata: UnmanagedDenseMap::with_capacity(nodes), - extensions: extensions.unwrap_or_default(), - } - } - - /// Set the root node of the hugr. - pub(crate) fn set_root(&mut self, root: Node) { - self.hierarchy.detach(self.root); - self.root = root.pg_index(); - } - /// Add a node to the graph. pub(crate) fn add_node(&mut self, nodetype: OpType) -> Node { let node = self @@ -322,7 +316,7 @@ impl Hugr { /// preserve the indices. pub fn canonicalize_nodes(&mut self, mut rekey: impl FnMut(Node, Node)) { // Generate the ordered list of nodes - let mut ordered = Vec::with_capacity(self.node_count()); + let mut ordered = Vec::with_capacity(self.num_nodes()); let root = self.root(); ordered.extend(self.as_mut().canonical_order(root)); @@ -339,8 +333,8 @@ impl Hugr { let target: Node = portgraph::NodeIndex::new(position).into(); if target != source { - let pg_target = target.pg_index(); - let pg_source = source.pg_index(); + let pg_target = target.into_portgraph(); + let pg_source = source.into_portgraph(); self.graph.swap_nodes(pg_target, pg_source); self.op_types.swap(pg_target, pg_source); self.hierarchy.swap_nodes(pg_target, pg_source); diff --git a/hugr-core/src/hugr/hugrmut.rs b/hugr-core/src/hugr/hugrmut.rs index c58ccbdbc6..6353820f47 100644 --- a/hugr-core/src/hugr/hugrmut.rs +++ b/hugr-core/src/hugr/hugrmut.rs @@ -18,6 +18,7 @@ use crate::types::Substitution; use crate::{Extension, Hugr, IncomingPort, OutgoingPort, Port, PortIndex}; use super::internal::HugrMutInternals; +use super::views::{panic_invalid_node, panic_invalid_non_root, panic_invalid_port}; /// Functions for low-level building of a HUGR. pub trait HugrMut: HugrMutInternals { @@ -26,12 +27,7 @@ pub trait HugrMut: HugrMutInternals { /// # Panics /// /// If the node is not in the graph. - fn get_metadata_mut(&mut self, node: Self::Node, key: impl AsRef) -> &mut NodeMetadata { - panic_invalid_node(self, node); - self.node_metadata_map_mut(node) - .entry(key.as_ref()) - .or_insert(serde_json::Value::Null) - } + fn get_metadata_mut(&mut self, node: Self::Node, key: impl AsRef) -> &mut NodeMetadata; /// Sets a metadata value associated with a node. /// @@ -43,21 +39,14 @@ pub trait HugrMut: HugrMutInternals { node: Self::Node, key: impl AsRef, metadata: impl Into, - ) { - let entry = self.get_metadata_mut(node, key); - *entry = metadata.into(); - } + ); /// Remove a metadata entry associated with a node. /// /// # Panics /// /// If the node is not in the graph. - fn remove_metadata(&mut self, node: Self::Node, key: impl AsRef) { - panic_invalid_node(self, node); - let node_meta = self.node_metadata_map_mut(node); - node_meta.remove(key.as_ref()); - } + fn remove_metadata(&mut self, node: Self::Node, key: impl AsRef); /// Add a node to the graph with a parent in the hierarchy. /// @@ -209,9 +198,7 @@ pub trait HugrMut: HugrMutInternals { /// These can be queried using [`HugrView::extensions`]. /// /// See [`ExtensionRegistry::register_updated`] for more information. - fn use_extension(&mut self, extension: impl Into>) { - self.extensions_mut().register_updated(extension); - } + fn use_extension(&mut self, extension: impl Into>); /// Extend the set of extensions used by the hugr with the extensions in the /// registry. @@ -224,10 +211,7 @@ pub trait HugrMut: HugrMutInternals { /// See [`ExtensionRegistry::register_updated`] for more information. fn use_extensions(&mut self, registry: impl IntoIterator) where - ExtensionRegistry: Extend, - { - self.extensions_mut().extend(registry); - } + ExtensionRegistry: Extend; } /// Records the result of inserting a Hugr or view @@ -262,10 +246,33 @@ fn translate_indices( /// Impl for non-wrapped Hugrs. Overwrites the recursive default-impls to directly use the hugr. impl HugrMut for Hugr { + fn get_metadata_mut(&mut self, node: Self::Node, key: impl AsRef) -> &mut NodeMetadata { + panic_invalid_node(self, node); + self.node_metadata_map_mut(node) + .entry(key.as_ref()) + .or_insert(serde_json::Value::Null) + } + + fn set_metadata( + &mut self, + node: Self::Node, + key: impl AsRef, + metadata: impl Into, + ) { + let entry = self.get_metadata_mut(node, key); + *entry = metadata.into(); + } + + fn remove_metadata(&mut self, node: Self::Node, key: impl AsRef) { + panic_invalid_node(self, node); + let node_meta = self.node_metadata_map_mut(node); + node_meta.remove(key.as_ref()); + } + fn add_node_with_parent(&mut self, parent: Node, node: impl Into) -> Node { let node = self.as_mut().add_node(node.into()); self.hierarchy - .push_child(node.pg_index(), parent.pg_index()) + .push_child(node.into_portgraph(), parent.into_portgraph()) .expect("Inserting a newly-created node into the hierarchy should never fail."); node } @@ -273,7 +280,7 @@ impl HugrMut for Hugr { fn add_node_before(&mut self, sibling: Node, nodetype: impl Into) -> Node { let node = self.as_mut().add_node(nodetype.into()); self.hierarchy - .insert_before(node.pg_index(), sibling.pg_index()) + .insert_before(node.into_portgraph(), sibling.into_portgraph()) .expect("Inserting a newly-created node into the hierarchy should never fail."); node } @@ -281,16 +288,16 @@ impl HugrMut for Hugr { fn add_node_after(&mut self, sibling: Node, op: impl Into) -> Node { let node = self.as_mut().add_node(op.into()); self.hierarchy - .insert_after(node.pg_index(), sibling.pg_index()) + .insert_after(node.into_portgraph(), sibling.into_portgraph()) .expect("Inserting a newly-created node into the hierarchy should never fail."); node } fn remove_node(&mut self, node: Node) -> OpType { panic_invalid_non_root(self, node); - self.hierarchy.remove(node.pg_index()); - self.graph.remove_node(node.pg_index()); - self.op_types.take(node.pg_index()) + self.hierarchy.remove(node.into_portgraph()); + self.graph.remove_node(node.into_portgraph()); + self.op_types.take(node.into_portgraph()) } fn remove_subtree(&mut self, node: Node) { @@ -316,9 +323,9 @@ impl HugrMut for Hugr { panic_invalid_port(self, dst, dst_port); self.graph .link_nodes( - src.pg_index(), + src.into_portgraph(), src_port.index(), - dst.pg_index(), + dst.into_portgraph(), dst_port.index(), ) .expect("The ports should exist at this point."); @@ -330,7 +337,7 @@ impl HugrMut for Hugr { panic_invalid_port(self, node, port); let port = self .graph - .port_index(node.pg_index(), offset) + .port_index(node.into_portgraph(), offset) .expect("The port should exist at this point."); self.graph.unlink_port(port); } @@ -364,13 +371,17 @@ impl HugrMut for Hugr { self.metadata.set(new_node, meta); } debug_assert_eq!( - Some(&new_root.pg_index()), - node_map.get(&other.root().pg_index()) + Some(&new_root.into_portgraph()), + node_map.get(&other.root().into_portgraph()) ); InsertionResult { new_root, - node_map: translate_indices(|n| other.get_node(n), |n| self.get_node(n), node_map) - .collect(), + node_map: translate_indices( + |n| other.from_portgraph_node(n), + |n| self.from_portgraph_node(n), + node_map, + ) + .collect(), } } @@ -384,19 +395,26 @@ impl HugrMut for Hugr { // // No need to compute each node's extensions here, as we merge `other.extensions` directly. for (&node, &new_node) in node_map.iter() { - let nodetype = other.get_optype(other.get_node(node)); + let node = other.from_portgraph_node(node); + let nodetype = other.get_optype(node); self.op_types.set(new_node, nodetype.clone()); - let meta = other.base_hugr().metadata.get(node); - self.metadata.set(new_node, meta.clone()); + let meta = other.node_metadata_map(node); + if !meta.is_empty() { + self.metadata.set(new_node, Some(meta.clone())); + } } debug_assert_eq!( - Some(&new_root.pg_index()), - node_map.get(&other.get_pg_index(other.root())) + Some(&new_root.into_portgraph()), + node_map.get(&other.to_portgraph_node(other.root())) ); InsertionResult { new_root, - node_map: translate_indices(|n| other.get_node(n), |n| self.get_node(n), node_map) - .collect(), + node_map: translate_indices( + |n| other.from_portgraph_node(n), + |n| self.from_portgraph_node(n), + node_map, + ) + .collect(), } } @@ -410,7 +428,7 @@ impl HugrMut for Hugr { let context: HashSet = subgraph .nodes() .iter() - .map(|&n| other.get_pg_index(n)) + .map(|&n| other.to_portgraph_node(n)) .collect(); let portgraph: NodeFiltered<_, NodeFilter>, _> = NodeFiltered::new_node_filtered( @@ -421,16 +439,24 @@ impl HugrMut for Hugr { let node_map = insert_subgraph_internal(self, root, other, &portgraph); // Update the optypes and metadata, copying them from the other graph. for (&node, &new_node) in node_map.iter() { - let nodetype = other.get_optype(other.get_node(node)); + let node = other.from_portgraph_node(node); + let nodetype = other.get_optype(node); self.op_types.set(new_node, nodetype.clone()); - let meta = other.base_hugr().metadata.get(node); - self.metadata.set(new_node, meta.clone()); + let meta = other.node_metadata_map(node); + if !meta.is_empty() { + self.metadata.set(new_node, Some(meta.clone())); + } // Add the required extensions to the registry. if let Ok(exts) = nodetype.used_extensions() { self.use_extensions(exts); } } - translate_indices(|n| other.get_node(n), |n| self.get_node(n), node_map).collect() + translate_indices( + |n| other.from_portgraph_node(n), + |n| self.from_portgraph_node(n), + node_map, + ) + .collect() } fn copy_descendants( @@ -439,15 +465,19 @@ impl HugrMut for Hugr { new_parent: Self::Node, subst: Option, ) -> BTreeMap { - let mut descendants = self.base_hugr().hierarchy.descendants(root.pg_index()); + let mut descendants = self.hierarchy.descendants(root.into_portgraph()); let root2 = descendants.next(); - debug_assert_eq!(root2, Some(root.pg_index())); + debug_assert_eq!(root2, Some(root.into_portgraph())); let nodes = Vec::from_iter(descendants); let node_map = portgraph::view::Subgraph::with_nodes(&mut self.graph, nodes) .copy_in_parent() .expect("Is a MultiPortGraph"); - let node_map = translate_indices(|n| self.get_node(n), |n| self.get_node(n), node_map) - .collect::>(); + let node_map = translate_indices( + |n| self.from_portgraph_node(n), + |n| self.from_portgraph_node(n), + node_map, + ) + .collect::>(); for node in self.children(root).collect::>() { self.set_parent(*node_map.get(&node).unwrap(), new_parent); @@ -462,12 +492,25 @@ impl HugrMut for Hugr { (None, op) => op.clone(), (Some(subst), op) => op.substitute(subst), }; - self.op_types.set(new_node.pg_index(), new_optype); - let meta = self.base_hugr().metadata.get(node.pg_index()).clone(); - self.metadata.set(new_node.pg_index(), meta); + self.op_types.set(new_node.into_portgraph(), new_optype); + let meta = self.metadata.get(node.into_portgraph()).clone(); + self.metadata.set(new_node.into_portgraph(), meta); } node_map } + + #[inline] + fn use_extension(&mut self, extension: impl Into>) { + self.extensions_mut().register_updated(extension); + } + + #[inline] + fn use_extensions(&mut self, registry: impl IntoIterator) + where + ExtensionRegistry: Extend, + { + self.extensions_mut().extend(registry); + } } /// Internal implementation of `insert_hugr` and `insert_view` methods for @@ -487,18 +530,20 @@ fn insert_hugr_internal( .graph .insert_graph(&other.portgraph()) .unwrap_or_else(|e| panic!("Internal error while inserting a hugr into another: {e}")); - let other_root = node_map[&other.get_pg_index(other.root())]; + let other_root = node_map[&other.to_portgraph_node(other.root())]; // Update hierarchy and optypes hugr.hierarchy - .push_child(other_root, root.pg_index()) + .push_child(other_root, root.into_portgraph()) .expect("Inserting a newly-created node into the hierarchy should never fail."); for (&node, &new_node) in node_map.iter() { - other.children(other.get_node(node)).for_each(|child| { - hugr.hierarchy - .push_child(node_map[&other.get_pg_index(child)], new_node) - .expect("Inserting a newly-created node into the hierarchy should never fail."); - }); + other + .children(other.from_portgraph_node(node)) + .for_each(|child| { + hugr.hierarchy + .push_child(node_map[&other.to_portgraph_node(child)], new_node) + .expect("Inserting a newly-created node into the hierarchy should never fail."); + }); } // Merge the extension sets. @@ -534,9 +579,9 @@ fn insert_subgraph_internal( // update the hierarchy with their new id. for (&node, &new_node) in node_map.iter() { let new_parent = other - .get_parent(other.get_node(node)) - .and_then(|parent| node_map.get(&other.get_pg_index(parent)).copied()) - .unwrap_or(root.pg_index()); + .get_parent(other.from_portgraph_node(node)) + .and_then(|parent| node_map.get(&other.to_portgraph_node(parent)).copied()) + .unwrap_or(root.into_portgraph()); hugr.hierarchy .push_child(new_node, new_parent) .expect("Inserting a newly-created node into the hierarchy should never fail."); @@ -545,45 +590,6 @@ fn insert_subgraph_internal( node_map } -/// Panic if [`HugrView::valid_node`] fails. -#[track_caller] -pub(super) fn panic_invalid_node(hugr: &H, node: H::Node) { - // TODO: When stacking hugr wrappers, this gets called for every layer. - // Should we `cfg!(debug_assertions)` this? Benchmark and see if it matters. - if !hugr.valid_node(node) { - panic!("Received an invalid node {node} while mutating a HUGR.",); - } -} - -/// Panic if [`HugrView::valid_non_root`] fails. -#[track_caller] -pub(super) fn panic_invalid_non_root(hugr: &H, node: H::Node) { - // TODO: When stacking hugr wrappers, this gets called for every layer. - // Should we `cfg!(debug_assertions)` this? Benchmark and see if it matters. - if !hugr.valid_non_root(node) { - panic!("Received an invalid non-root node {node} while mutating a HUGR.",); - } -} - -/// Panic if [`HugrView::valid_node`] fails. -#[track_caller] -pub(super) fn panic_invalid_port( - hugr: &H, - node: Node, - port: impl Into, -) { - let port = port.into(); - // TODO: When stacking hugr wrappers, this gets called for every layer. - // Should we `cfg!(debug_assertions)` this? Benchmark and see if it matters. - if hugr - .portgraph() - .port_index(node.pg_index(), port.pg_offset()) - .is_none() - { - panic!("Received an invalid port {port} for node {node} while mutating a HUGR"); - } -} - #[cfg(test)] mod test { use crate::extension::PRELUDE; @@ -667,14 +673,14 @@ mod test { fd }); hugr.validate().unwrap(); - assert_eq!(hugr.node_count(), 7); + assert_eq!(hugr.num_nodes(), 7); hugr.remove_subtree(foo); hugr.validate().unwrap(); - assert_eq!(hugr.node_count(), 4); + assert_eq!(hugr.num_nodes(), 4); hugr.remove_subtree(bar); hugr.validate().unwrap(); - assert_eq!(hugr.node_count(), 1); + assert_eq!(hugr.num_nodes(), 1); } } diff --git a/hugr-core/src/hugr/internal.rs b/hugr-core/src/hugr/internal.rs index 58ce066c05..f69d2ad399 100644 --- a/hugr-core/src/hugr/internal.rs +++ b/hugr-core/src/hugr/internal.rs @@ -1,6 +1,5 @@ //! Internal traits, not exposed in the public `hugr` API. -use std::borrow::Cow; use std::ops::Range; use std::sync::OnceLock; @@ -8,11 +7,12 @@ use itertools::Itertools; use portgraph::{LinkMut, LinkView, MultiPortGraph, PortMut, PortOffset, PortView}; use crate::extension::ExtensionRegistry; -use crate::ops::handle::NodeHandle; use crate::{Direction, Hugr, Node}; -use super::hugrmut::{panic_invalid_node, panic_invalid_non_root}; -use super::{HugrView, NodeMetadataMap, OpType}; +use super::views::{panic_invalid_node, panic_invalid_non_root}; +use super::HugrView; +use super::{NodeMetadataMap, OpType}; +use crate::ops::handle::NodeHandle; /// Trait for accessing the internals of a Hugr(View). /// @@ -20,7 +20,7 @@ use super::{HugrView, NodeMetadataMap, OpType}; /// view. pub trait HugrInternals { /// The underlying portgraph view type. - type Portgraph<'p>: LinkView + Clone + 'p + type Portgraph<'p>: LinkView + Clone + 'p where Self: 'p; @@ -30,24 +30,24 @@ pub trait HugrInternals { /// Returns a reference to the underlying portgraph. fn portgraph(&self) -> Self::Portgraph<'_>; + /// Returns a flat portgraph view of a region in the HUGR. + /// + /// This is a subgraph of [`HugrInternals::portgraph`], with a flat hierarchy. + fn region_portgraph( + &self, + parent: Self::Node, + ) -> portgraph::view::FlatRegion<'_, impl LinkView + Clone + '_>; + /// Returns the portgraph [Hierarchy](portgraph::Hierarchy) of the graph /// returned by [`HugrInternals::portgraph`]. - #[inline] - fn hierarchy(&self) -> Cow<'_, portgraph::Hierarchy> { - Cow::Borrowed(&self.base_hugr().hierarchy) - } - - /// Returns the Hugr at the base of a chain of views. - fn base_hugr(&self) -> &Hugr; - - /// Return the root node of this view. - fn root_node(&self) -> Self::Node; + fn hierarchy(&self) -> &portgraph::Hierarchy; /// Convert a node to a portgraph node index. - fn get_pg_index(&self, node: impl NodeHandle) -> portgraph::NodeIndex; + fn to_portgraph_node(&self, node: impl NodeHandle) -> portgraph::NodeIndex; /// Convert a portgraph node index to a node. - fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node; + #[allow(clippy::wrong_self_convention)] + fn from_portgraph_node(&self, index: portgraph::NodeIndex) -> Self::Node; /// Returns a metadata entry associated with a node. /// @@ -55,6 +55,14 @@ pub trait HugrInternals { /// /// If the node is not in the graph. fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap; + + /// Returns the Hugr at the base of a chain of views. + // TODO: This will be removed in a future PR. + #[deprecated( + since = "0.16.0", + note = "This method will be removed in a future PR. Use the individual HugrInternals methods instead." + )] + fn base_hugr(&self) -> &Hugr; } impl HugrInternals for Hugr { @@ -71,34 +79,40 @@ impl HugrInternals for Hugr { } #[inline] - fn hierarchy(&self) -> Cow<'_, portgraph::Hierarchy> { - Cow::Borrowed(&self.hierarchy) + fn region_portgraph( + &self, + parent: Self::Node, + ) -> portgraph::view::FlatRegion<'_, impl LinkView + Clone + '_> { + let pg = self.portgraph(); + let root = self.to_portgraph_node(parent); + portgraph::view::FlatRegion::new_without_root(pg, &self.hierarchy, root) } #[inline] - fn base_hugr(&self) -> &Hugr { - self + fn hierarchy(&self) -> &portgraph::Hierarchy { + &self.hierarchy } #[inline] - fn root_node(&self) -> Self::Node { - self.root.into() + fn base_hugr(&self) -> &Hugr { + self } #[inline] - fn get_pg_index(&self, node: impl NodeHandle) -> portgraph::NodeIndex { - node.node().pg_index() + fn to_portgraph_node(&self, node: impl NodeHandle) -> portgraph::NodeIndex { + node.node().into_portgraph() } #[inline] - fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node { + fn from_portgraph_node(&self, index: portgraph::NodeIndex) -> Self::Node { index.into() } + #[inline] fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap { static EMPTY: OnceLock = OnceLock::new(); panic_invalid_node(self, node); - let map = self.metadata.get(node.pg_index()).as_ref(); + let map = self.metadata.get(node.into_portgraph()).as_ref(); map.unwrap_or(EMPTY.get_or_init(Default::default)) } } @@ -108,10 +122,14 @@ impl HugrInternals for Hugr { /// Specifically, this trait lets you apply arbitrary modifications that may /// invalidate the HUGR. pub trait HugrMutInternals: HugrView { - /// Set root node of the HUGR. + /// Set the node at the root of the HUGR hierarchy. /// - /// This should be an existing node in the HUGR. Most operations use the - /// root node as a starting point for traversal. + /// Any node not reachable from this root should be deleted from the HUGR + /// after this call. + /// + /// # Panics + /// + /// If the node is not in the graph. fn set_root(&mut self, root: Self::Node); /// Set the number of ports on a node. This may invalidate the node's `PortIndex`. @@ -225,21 +243,21 @@ pub trait HugrMutInternals: HugrView { /// Impl for non-wrapped Hugrs. Overwrites the recursive default-impls to directly use the hugr. impl HugrMutInternals for Hugr { fn set_root(&mut self, root: Node) { - panic_invalid_node(self, root); - self.root = self.get_pg_index(root); + self.hierarchy.detach(self.root); + self.root = root.into_portgraph(); } #[inline] fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) { panic_invalid_node(self, node); self.graph - .set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {}) + .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {}) } fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range { panic_invalid_node(self, node); - let mut incoming = self.graph.num_inputs(node.pg_index()); - let mut outgoing = self.graph.num_outputs(node.pg_index()); + let mut incoming = self.graph.num_inputs(node.into_portgraph()); + let mut outgoing = self.graph.num_outputs(node.into_portgraph()); let increment = |num: &mut usize| { let new = num.saturating_add_signed(amount); let range = *num..new; @@ -251,7 +269,7 @@ impl HugrMutInternals for Hugr { Direction::Outgoing => increment(&mut outgoing), }; self.graph - .set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {}); + .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {}); range } @@ -263,20 +281,18 @@ impl HugrMutInternals for Hugr { amount: usize, ) -> Range { panic_invalid_node(self, node); - let old_num_ports = self.base_hugr().graph.num_ports(node.pg_index(), direction); + let old_num_ports = self.graph.num_ports(node.into_portgraph(), direction); self.add_ports(node, direction, amount as isize); for swap_from_port in (index..old_num_ports).rev() { let swap_to_port = swap_from_port + amount; let [from_port_index, to_port_index] = [swap_from_port, swap_to_port].map(|p| { - self.base_hugr() - .graph - .port_index(node.pg_index(), PortOffset::new(direction, p)) + self.graph + .port_index(node.into_portgraph(), PortOffset::new(direction, p)) .unwrap() }); let linked_ports = self - .base_hugr() .graph .port_links(from_port_index) .map(|(_, to_subport)| to_subport.port()) @@ -295,27 +311,27 @@ impl HugrMutInternals for Hugr { fn set_parent(&mut self, node: Node, parent: Node) { panic_invalid_node(self, parent); panic_invalid_node(self, node); - self.hierarchy.detach(node.pg_index()); + self.hierarchy.detach(node.into_portgraph()); self.hierarchy - .push_child(node.pg_index(), parent.pg_index()) + .push_child(node.into_portgraph(), parent.into_portgraph()) .expect("Inserting a newly-created node into the hierarchy should never fail."); } fn move_after_sibling(&mut self, node: Node, after: Node) { panic_invalid_non_root(self, node); panic_invalid_non_root(self, after); - self.hierarchy.detach(node.pg_index()); + self.hierarchy.detach(node.into_portgraph()); self.hierarchy - .insert_after(node.pg_index(), after.pg_index()) + .insert_after(node.into_portgraph(), after.into_portgraph()) .expect("Inserting a newly-created node into the hierarchy should never fail."); } fn move_before_sibling(&mut self, node: Node, before: Node) { panic_invalid_non_root(self, node); panic_invalid_non_root(self, before); - self.hierarchy.detach(node.pg_index()); + self.hierarchy.detach(node.into_portgraph()); self.hierarchy - .insert_before(node.pg_index(), before.pg_index()) + .insert_before(node.into_portgraph(), before.into_portgraph()) .expect("Inserting a newly-created node into the hierarchy should never fail."); } @@ -326,14 +342,14 @@ impl HugrMutInternals for Hugr { fn optype_mut(&mut self, node: Self::Node) -> &mut OpType { panic_invalid_node(self, node); - let node = self.get_pg_index(node); + let node = self.to_portgraph_node(node); self.op_types.get_mut(node) } fn node_metadata_map_mut(&mut self, node: Self::Node) -> &mut NodeMetadataMap { panic_invalid_node(self, node); self.metadata - .get_mut(node.pg_index()) + .get_mut(node.into_portgraph()) .get_or_insert_with(Default::default) } diff --git a/hugr-core/src/hugr/patch.rs b/hugr-core/src/hugr/patch.rs index bc6195ebad..1744ce7607 100644 --- a/hugr-core/src/hugr/patch.rs +++ b/hugr-core/src/hugr/patch.rs @@ -153,12 +153,12 @@ impl PatchHugrMut for Transactional { return self.underlying.apply_hugr_mut(h); } // Try to backup just the contents of this HugrMut. - let mut backup = Hugr::new(h.root_type().clone()); + let mut backup = Hugr::new(h.root_optype().clone()); backup.insert_from_view(backup.root(), h); let r = self.underlying.apply_hugr_mut(h); if r.is_err() { // Try to restore backup. - h.replace_op(h.root(), backup.root_type().clone()); + h.replace_op(h.root(), backup.root_optype().clone()); while let Some(child) = h.first_child(h.root()) { h.remove_node(child); } diff --git a/hugr-core/src/hugr/patch/consts.rs b/hugr-core/src/hugr/patch/consts.rs index 6d0c011fe6..eb9142f85c 100644 --- a/hugr-core/src/hugr/patch/consts.rs +++ b/hugr-core/src/hugr/patch/consts.rs @@ -144,7 +144,7 @@ mod test { let mut h = build.finish_hugr()?; // nodes are Module, Function, Input, Output, Const, LoadConstant*2, MakeTuple - assert_eq!(h.node_count(), 8); + assert_eq!(h.num_nodes(), 8); let tup_node = tup.node(); // can't remove invalid node assert_eq!( @@ -199,7 +199,7 @@ mod test { // remove const assert_eq!(h.apply_patch(remove_con)?, h.root()); - assert_eq!(h.node_count(), 4); + assert_eq!(h.num_nodes(), 4); assert!(h.validate().is_ok()); Ok(()) } diff --git a/hugr-core/src/hugr/patch/insert_identity.rs b/hugr-core/src/hugr/patch/insert_identity.rs index 98ab0ff021..c1f959ccda 100644 --- a/hugr-core/src/hugr/patch/insert_identity.rs +++ b/hugr-core/src/hugr/patch/insert_identity.rs @@ -118,7 +118,7 @@ mod tests { fn correct_insertion(dfg_hugr: Hugr) { let mut h = dfg_hugr; - assert_eq!(h.node_count(), 6); + assert_eq!(h.num_nodes(), 6); let final_node = h .input_neighbours(h.get_io(h.root()).unwrap()[1]) @@ -131,7 +131,7 @@ mod tests { let noop_node = h.apply_patch(rw).unwrap(); - assert_eq!(h.node_count(), 7); + assert_eq!(h.num_nodes(), 7); let noop: Noop = h.get_optype(noop_node).cast().unwrap(); diff --git a/hugr-core/src/hugr/patch/outline_cfg.rs b/hugr-core/src/hugr/patch/outline_cfg.rs index 0f40615a9c..b43b6b4e34 100644 --- a/hugr-core/src/hugr/patch/outline_cfg.rs +++ b/hugr-core/src/hugr/patch/outline_cfg.rs @@ -202,11 +202,11 @@ impl PatchHugrMut for OutlineCfg { // https://github.com/CQCL/hugr/issues/2029 let hierarchy = h.hierarchy(); let inner_exit = hierarchy - .children(h.get_pg_index(cfg_node)) + .children(h.to_portgraph_node(cfg_node)) .exactly_one() .ok() .unwrap(); - let inner_exit = h.get_node(inner_exit); + let inner_exit = h.from_portgraph_node(inner_exit); //let inner_exit = h.children(cfg_node).exactly_one().ok().unwrap(); // Entry node must be first @@ -512,6 +512,7 @@ mod test { } assert_eq!(h.get_parent(new_block), Some(cfg)); assert!(h.get_optype(new_block).is_dataflow_block()); + #[allow(deprecated)] let b = h.base_hugr(); // To cope with `h` potentially being a SiblingMut assert_eq!(b.get_parent(new_cfg), Some(new_block)); for n in blocks { diff --git a/hugr-core/src/hugr/patch/replace.rs b/hugr-core/src/hugr/patch/replace.rs index 6f0b0ed65a..183200751c 100644 --- a/hugr-core/src/hugr/patch/replace.rs +++ b/hugr-core/src/hugr/patch/replace.rs @@ -7,6 +7,7 @@ use thiserror::Error; use crate::core::HugrNode; use crate::hugr::hugrmut::InsertionResult; +use crate::hugr::views::check_valid_non_root; use crate::hugr::HugrMut; use crate::ops::{OpTag, OpTrait}; use crate::types::EdgeKind; @@ -188,7 +189,7 @@ impl Replacement { // equality of OpType/Signature, e.g. to ease changing of Input/Output // node signatures too. let removed = h.get_optype(parent).tag(); - let replacement = self.replacement.root_type().tag(); + let replacement = self.replacement.root_optype().tag(); if removed != replacement { return Err(ReplaceError::WrongRootNodeTag { removed, @@ -265,25 +266,25 @@ impl PatchVerification for Replacement { } e.check_src(h, WhichEdgeSpec::HostToHost)?; } - self.mu_out - .iter() - .try_for_each(|e| match self.replacement.valid_non_root(e.src) { + self.mu_out.iter().try_for_each(|e| { + match check_valid_non_root(&self.replacement, e.src) { true => e.check_src(&self.replacement, WhichEdgeSpec::ReplToHost), false => Err(ReplaceError::BadEdgeSpec( Direction::Outgoing, WhichEdgeSpec::ReplToHost(e.clone()), )), - })?; + } + })?; // Edge targets... - self.mu_inp - .iter() - .try_for_each(|e| match self.replacement.valid_non_root(e.tgt) { + self.mu_inp.iter().try_for_each(|e| { + match check_valid_non_root(&self.replacement, e.tgt) { true => e.check_tgt(&self.replacement, WhichEdgeSpec::HostToRepl), false => Err(ReplaceError::BadEdgeSpec( Direction::Incoming, WhichEdgeSpec::HostToRepl(e.clone()), )), - })?; + } + })?; for e in self.mu_out.iter() { if !h.contains_node(e.tgt) || removed.contains(&e.tgt) { return Err(ReplaceError::BadEdgeSpec( @@ -430,13 +431,13 @@ where .ok_or_else(|| ReplaceError::BadEdgeSpec(Direction::Incoming, err_spec.clone()))?, kind: oe.kind, }; - if !h.valid_node(e.src) { + if !h.contains_node(e.src) { return Err(ReplaceError::BadEdgeSpec( Direction::Outgoing, err_spec.clone(), )); } - if !h.valid_node(e.tgt) { + if !h.contains_node(e.tgt) { return Err(ReplaceError::BadEdgeSpec( Direction::Incoming, err_spec.clone(), @@ -810,7 +811,7 @@ mod test { // Root node type needs to be that of common parent of the removed nodes: let mut rep2 = rep.clone(); rep2.replacement - .replace_op(rep2.replacement.root(), h.root_type().clone()); + .replace_op(rep2.replacement.root(), h.root_optype().clone()); assert_eq!( check_same_errors(rep2), ReplaceError::WrongRootNodeTag { diff --git a/hugr-core/src/hugr/patch/simple_replace.rs b/hugr-core/src/hugr/patch/simple_replace.rs index e9283644db..3908ba58ef 100644 --- a/hugr-core/src/hugr/patch/simple_replace.rs +++ b/hugr-core/src/hugr/patch/simple_replace.rs @@ -766,7 +766,7 @@ pub(in crate::hugr::patch) mod test { .unwrap(); // They should be the same, up to node indices - assert_eq!(h.edge_count(), orig.edge_count()); + assert_eq!(h.num_edges(), orig.num_edges()); } #[test] @@ -818,7 +818,7 @@ pub(in crate::hugr::patch) mod test { .unwrap(); // Nothing changed - assert_eq!(h.node_count(), orig.node_count()); + assert_eq!(h.num_nodes(), orig.num_nodes()); } /// Remove all the NOT gates in [`dfg_hugr_copy_bools`] by connecting the @@ -876,7 +876,7 @@ pub(in crate::hugr::patch) mod test { rewrite.apply(&mut hugr).unwrap_or_else(|e| panic!("{e}")); assert_eq!(hugr.validate(), Ok(())); - assert_eq!(hugr.node_count(), 3); + assert_eq!(hugr.num_nodes(), 3); } /// Remove one of the NOT ops in [`dfg_hugr_half_not_bools`] by connecting @@ -935,7 +935,7 @@ pub(in crate::hugr::patch) mod test { rewrite.apply(&mut hugr).unwrap_or_else(|e| panic!("{e}")); assert_eq!(hugr.validate(), Ok(())); - assert_eq!(hugr.node_count(), 4); + assert_eq!(hugr.num_nodes(), 4); } #[rstest] @@ -974,12 +974,12 @@ pub(in crate::hugr::patch) mod test { let rewrite = SimpleReplacement::new(subgraph, replacement, nu_inp, nu_out); - assert_eq!(h.node_count(), 4); + assert_eq!(h.num_nodes(), 4); rewrite.apply(&mut h).unwrap_or_else(|e| panic!("{e}")); h.validate().unwrap_or_else(|e| panic!("{e}")); - assert_eq!(h.node_count(), 6); + assert_eq!(h.num_nodes(), 6); } use crate::hugr::patch::replace::Replacement; diff --git a/hugr-core/src/hugr/rewrite.rs b/hugr-core/src/hugr/rewrite.rs index e220864a73..76dc93ab10 100644 --- a/hugr-core/src/hugr/rewrite.rs +++ b/hugr-core/src/hugr/rewrite.rs @@ -77,12 +77,12 @@ impl Rewrite for Transactional { return self.underlying.apply(h); } // Try to backup just the contents of this HugrMut. - let mut backup = Hugr::new(h.root_type().clone()); + let mut backup = Hugr::new(h.root_optype().clone()); backup.insert_from_view(backup.root(), h); let r = self.underlying.apply(h); if r.is_err() { // Try to restore backup. - h.replace_op(h.root(), backup.root_type().clone()); + h.replace_op(h.root(), backup.root_optype().clone()); while let Some(child) = h.first_child(h.root()) { h.remove_node(child); } diff --git a/hugr-core/src/hugr/serialize.rs b/hugr-core/src/hugr/serialize.rs index 906084d557..5e4922157f 100644 --- a/hugr-core/src/hugr/serialize.rs +++ b/hugr-core/src/hugr/serialize.rs @@ -157,13 +157,13 @@ impl TryFrom<&Hugr> for SerHugrLatest { fn try_from(hugr: &Hugr) -> Result { // We compact the operation nodes during the serialization process, // and ignore the copy nodes. - let mut node_rekey: HashMap = HashMap::with_capacity(hugr.node_count()); + let mut node_rekey: HashMap = HashMap::with_capacity(hugr.num_nodes()); for (order, node) in hugr.canonical_order(hugr.root()).enumerate() { node_rekey.insert(node, portgraph::NodeIndex::new(order).into()); } - let mut nodes = vec![None; hugr.node_count()]; - let mut metadata = vec![None; hugr.node_count()]; + let mut nodes = vec![None; hugr.num_nodes()]; + let mut metadata = vec![None; hugr.num_nodes()]; for n in hugr.nodes() { let parent = node_rekey[&hugr.get_parent(n).unwrap_or(n)]; let opt = hugr.get_optype(n); @@ -172,7 +172,7 @@ impl TryFrom<&Hugr> for SerHugrLatest { parent, op: opt.clone(), }); - metadata[new_node].clone_from(hugr.metadata.get(n.pg_index())); + metadata[new_node].clone_from(hugr.metadata.get(n.into_portgraph())); } let nodes = nodes .into_iter() @@ -251,7 +251,7 @@ impl TryFrom for Hugr { } let unwrap_offset = |node: Node, offset, dir, hugr: &Hugr| -> Result { - if !hugr.graph.contains_node(node.pg_index()) { + if !hugr.graph.contains_node(node.into_portgraph()) { return Err(HUGRSerializationError::UnknownEdgeNode { node }); } let offset = match offset { diff --git a/hugr-core/src/hugr/validate.rs b/hugr-core/src/hugr/validate.rs index 3b04ccd867..3690ec947b 100644 --- a/hugr-core/src/hugr/validate.rs +++ b/hugr-core/src/hugr/validate.rs @@ -20,7 +20,7 @@ use crate::types::EdgeKind; use crate::{Direction, Hugr, Node, Port}; use super::internal::HugrInternals; -use super::views::{HierarchyView, HugrView, SiblingGraph}; +use super::views::HugrView; use super::ExtensionError; /// Structure keeping track of pre-computed information used in the validation @@ -31,7 +31,7 @@ use super::ExtensionError; struct ValidationContext<'a> { hugr: &'a Hugr, /// Dominator tree for each CFG region, using the container node as index. - dominators: HashMap>, + dominators: HashMap>, } impl Hugr { @@ -138,10 +138,10 @@ impl<'a> ValidationContext<'a> { /// /// The results of this computation should be cached in `self.dominators`. /// We don't do it here to avoid mutable borrows. - fn compute_dominator(&self, parent: Node) -> Dominators { - let region: SiblingGraph = SiblingGraph::try_new(self.hugr, parent).unwrap(); + fn compute_dominator(&self, parent: Node) -> Dominators { + let region = self.hugr.region_portgraph(parent); let entry_node = self.hugr.children(parent).next().unwrap(); - dominators::simple_fast(®ion.as_petgraph(), entry_node) + dominators::simple_fast(®ion, entry_node.into_portgraph()) } /// Check the constraints on a single node. @@ -163,7 +163,7 @@ impl<'a> ValidationContext<'a> { for dir in Direction::BOTH { // Check that we have the correct amount of ports and edges. - let num_ports = self.hugr.graph.num_ports(node.pg_index(), dir); + let num_ports = self.hugr.graph.num_ports(node.into_portgraph(), dir); if num_ports != op_type.port_count(dir) { return Err(ValidationError::WrongNumberOfPorts { node, @@ -316,7 +316,7 @@ impl<'a> ValidationContext<'a> { fn validate_children(&self, node: Node, op_type: &OpType) -> Result<(), ValidationError> { let flags = op_type.validity_flags(); - if self.hugr.hierarchy().child_count(node.pg_index()) > 0 { + if self.hugr.hierarchy().child_count(node.into_portgraph()) > 0 { if flags.allowed_children.is_empty() { return Err(ValidationError::NonContainerWithChildren { node, @@ -352,7 +352,8 @@ impl<'a> ValidationContext<'a> { } } // Additional validations running over the full list of children optypes - let children_optypes = all_children.map(|c| (c.pg_index(), self.hugr.get_optype(c))); + let children_optypes = + all_children.map(|c| (c.into_portgraph(), self.hugr.get_optype(c))); if let Err(source) = op_type.validate_op_children(children_optypes) { return Err(ValidationError::InvalidChildren { parent: node, @@ -363,9 +364,9 @@ impl<'a> ValidationContext<'a> { // Additional validations running over the edges of the contained graph if let Some(edge_check) = flags.edge_check { - for source in self.hugr.hierarchy().children(node.pg_index()) { + for source in self.hugr.hierarchy().children(node.into_portgraph()) { for target in self.hugr.graph.output_neighbours(source) { - if self.hugr.hierarchy.parent(target) != Some(node.pg_index()) { + if self.hugr.hierarchy.parent(target) != Some(node.into_portgraph()) { continue; } let source_op = self.hugr.get_optype(source.into()); @@ -411,16 +412,16 @@ impl<'a> ValidationContext<'a> { /// Inter-graph edges are ignored. Only internal dataflow, constant, or /// state order edges are considered. fn validate_children_dag(&self, parent: Node, op_type: &OpType) -> Result<(), ValidationError> { - if !self.hugr.hierarchy.has_children(parent.pg_index()) { + if !self.hugr.hierarchy.has_children(parent.into_portgraph()) { // No children, nothing to do return Ok(()); }; - let region: SiblingGraph = SiblingGraph::try_new(self.hugr, parent).unwrap(); - let postorder = Topo::new(®ion.as_petgraph()); + let region = self.hugr.region_portgraph(parent); + let postorder = Topo::new(®ion); let nodes_visited = postorder - .iter(®ion.as_petgraph()) - .filter(|n| *n != parent) + .iter(®ion) + .filter(|n| *n != parent.into_portgraph()) .count(); let node_count = self.hugr.children(parent).count(); if nodes_visited != node_count { @@ -500,7 +501,7 @@ impl<'a> ValidationContext<'a> { // Must have an order edge. self.hugr .graph - .get_connections(from.pg_index(), ancestor.pg_index()) + .get_connections(from.into_portgraph(), ancestor.into_portgraph()) .find(|&(p, _)| { let offset = self.hugr.graph.port_offset(p).unwrap(); from_optype.port_kind(offset) == Some(EdgeKind::StateOrder) @@ -537,8 +538,8 @@ impl<'a> ValidationContext<'a> { } }; if !dominator_tree - .dominators(ancestor) - .is_some_and(|mut ds| ds.any(|n| n == from_parent)) + .dominators(ancestor.into_portgraph()) + .is_some_and(|mut ds| ds.any(|n| n == from_parent.into_portgraph())) { return Err(InterGraphEdgeError::NonDominatedAncestor { from, @@ -616,7 +617,12 @@ impl<'a> ValidationContext<'a> { // Root nodes are ignored, as they cannot have connected edges. if node != self.hugr.root() { for dir in Direction::BOTH { - for (i, port_index) in self.hugr.graph.ports(node.pg_index(), dir).enumerate() { + for (i, port_index) in self + .hugr + .graph + .ports(node.into_portgraph(), dir) + .enumerate() + { let port = Port::new(dir, i); self.validate_port(node, port, port_index, op_type, var_decls)?; } diff --git a/hugr-core/src/hugr/validate/test.rs b/hugr-core/src/hugr/validate/test.rs index a66296c359..236f40e3f8 100644 --- a/hugr-core/src/hugr/validate/test.rs +++ b/hugr-core/src/hugr/validate/test.rs @@ -103,7 +103,7 @@ fn invalid_root() { ); // Fix the root - b.root = module.pg_index(); + b.root = module.into_portgraph(); b.remove_node(root); assert_eq!(b.validate(), Ok(())); } @@ -142,7 +142,7 @@ fn children_restrictions() { let root = b.root(); let (_input, copy, _output) = b .hierarchy - .children(def.pg_index()) + .children(def.into_portgraph()) .map_into() .collect_tuple() .unwrap(); @@ -185,7 +185,7 @@ fn df_children_restrictions() { let (mut b, def) = make_simple_hugr(2); let (_input, output, copy) = b .hierarchy - .children(def.pg_index()) + .children(def.into_portgraph()) .map_into() .collect_tuple() .unwrap(); @@ -202,7 +202,7 @@ fn df_children_restrictions() { assert_matches!( b.validate(), Err(ValidationError::InvalidChildren { parent, source: ChildrenValidationError::IOSignatureMismatch { child, .. }, .. }) - => {assert_eq!(parent, def); assert_eq!(child, output.pg_index())} + => {assert_eq!(parent, def); assert_eq!(child, output.into_portgraph())} ); b.replace_op(output, ops::Output::new(vec![bool_t(), bool_t()])); @@ -211,7 +211,7 @@ fn df_children_restrictions() { assert_matches!( b.validate(), Err(ValidationError::InvalidChildren { parent, source: ChildrenValidationError::InternalIOChildren { child, .. }, .. }) - => {assert_eq!(parent, def); assert_eq!(child, copy.pg_index())} + => {assert_eq!(parent, def); assert_eq!(child, copy.into_portgraph())} ); } @@ -791,7 +791,7 @@ fn cfg_children_restrictions() { let (mut b, def) = make_simple_hugr(1); let (_input, _output, copy) = b .hierarchy - .children(def.pg_index()) + .children(def.into_portgraph()) .map_into() .collect_tuple() .unwrap(); @@ -855,7 +855,7 @@ fn cfg_children_restrictions() { assert_matches!( b.validate(), Err(ValidationError::InvalidChildren { parent, source: ChildrenValidationError::InternalExitChildren { child, .. }, .. }) - => {assert_eq!(parent, cfg); assert_eq!(child, exit2.pg_index())} + => {assert_eq!(parent, cfg); assert_eq!(child, exit2.into_portgraph())} ); b.remove_node(exit2); @@ -875,7 +875,7 @@ fn cfg_children_restrictions() { extension_delta: ExtensionSet::new(), }, ); - let mut block_children = b.hierarchy.children(block.pg_index()); + let mut block_children = b.hierarchy.children(block.into_portgraph()); let block_input = block_children.next().unwrap().into(); let block_output = block_children.next_back().unwrap().into(); b.replace_op(block_input, ops::Input::new(vec![qb_t()])); diff --git a/hugr-core/src/hugr/views.rs b/hugr-core/src/hugr/views.rs index a154a956f4..f9eedd548b 100644 --- a/hugr-core/src/hugr/views.rs +++ b/hugr-core/src/hugr/views.rs @@ -24,10 +24,8 @@ use itertools::Itertools; use portgraph::render::{DotFormat, MermaidFormat}; use portgraph::{LinkView, PortView}; -use super::internal::HugrInternals; -use super::{ - Hugr, HugrError, HugrMut, Node, NodeMetadata, NodeMetadataMap, ValidationError, DEFAULT_OPTYPE, -}; +use super::internal::{HugrInternals, HugrMutInternals}; +use super::{Hugr, HugrError, HugrMut, Node, NodeMetadata, ValidationError}; use crate::extension::ExtensionRegistry; use crate::ops::{OpParent, OpTag, OpTrait, OpType}; @@ -40,85 +38,67 @@ use itertools::Either; /// For end users we intend this to be superseded by region-specific APIs. pub trait HugrView: HugrInternals { /// Return the root node of this view. - #[inline] - fn root(&self) -> Self::Node { - self.root_node() - } + fn root(&self) -> Self::Node; - /// Return the type of the HUGR root node. + /// Return the optype of the HUGR root node. #[inline] - fn root_type(&self) -> &OpType { + fn root_optype(&self) -> &OpType { let node_type = self.get_optype(self.root()); - // Sadly no way to do this at present - // debug_assert!(Self::RootHandle::can_hold(node_type.tag())); node_type } - /// Returns whether the node exists. + /// Returns `true` if the node exists in the HUGR. fn contains_node(&self, node: Self::Node) -> bool; - /// Validates that a node is valid in the graph. - #[inline] - fn valid_node(&self, node: Self::Node) -> bool { - self.contains_node(node) - } - - /// Validates that a node is a valid root descendant in the graph. - /// - /// To include the root node use [`HugrView::valid_node`] instead. - #[inline] - fn valid_non_root(&self, node: Self::Node) -> bool { - self.root() != node && self.valid_node(node) - } - /// Returns the parent of a node. - #[inline] - fn get_parent(&self, node: Self::Node) -> Option { - if !self.valid_non_root(node) { - return None; - }; - self.base_hugr() - .hierarchy - .parent(self.get_pg_index(node)) - .map(|index| self.get_node(index)) - } - - /// Returns the operation type of a node. - #[inline] - fn get_optype(&self, node: Self::Node) -> &OpType { - match self.contains_node(node) { - true => self.base_hugr().op_types.get(self.get_pg_index(node)), - false => &DEFAULT_OPTYPE, - } - } + fn get_parent(&self, node: Self::Node) -> Option; /// Returns the metadata associated with a node. #[inline] fn get_metadata(&self, node: Self::Node, key: impl AsRef) -> Option<&NodeMetadata> { match self.contains_node(node) { - true => self.get_node_metadata(node)?.get(key.as_ref()), + true => self.node_metadata_map(node).get(key.as_ref()), false => None, } } - /// Retrieve the complete metadata map for a node. - fn get_node_metadata(&self, node: Self::Node) -> Option<&NodeMetadataMap> { - if !self.valid_node(node) { - return None; - } - self.base_hugr() - .metadata - .get(self.get_pg_index(node)) - .as_ref() - } + /// Returns the operation type of a node. + /// + /// # Panics + /// + /// If the node is not in the graph. + fn get_optype(&self, node: Self::Node) -> &OpType; + + /// Returns the number of nodes in the HUGR. + fn num_nodes(&self) -> usize; - /// Returns the number of nodes in the hugr. - fn node_count(&self) -> usize; + /// Returns the number of edges in the HUGR. + fn num_edges(&self) -> usize; + + /// Number of ports in node for a given direction. + fn num_ports(&self, node: Self::Node, dir: Direction) -> usize; - /// Returns the number of edges in the hugr. - fn edge_count(&self) -> usize; + /// Number of inputs to a node. + /// Shorthand for [`num_ports`][HugrView::num_ports]`(node, Direction::Incoming)`. + #[inline] + fn num_inputs(&self, node: Self::Node) -> usize { + self.num_ports(node, Direction::Incoming) + } - /// Iterates over the nodes in the port graph. + /// Number of outputs from a node. + /// Shorthand for [`num_ports`][HugrView::num_ports]`(node, Direction::Outgoing)`. + #[inline] + fn num_outputs(&self, node: Self::Node) -> usize { + self.num_ports(node, Direction::Outgoing) + } + + /// Iterates over the all the nodes in the HUGR. + /// + /// This iterator returns every node in the HUGR, including those that are + /// not descendants from the root node. + /// + /// See [`HugrView::descendants`] and [`HugrView::children`] for more specific + /// iterators. fn nodes(&self) -> impl Iterator + Clone; /// Iterator over ports of node in a given direction. @@ -260,26 +240,15 @@ pub trait HugrView: HugrInternals { self.linked_ports(node, port).next().is_some() } - /// Number of ports in node for a given direction. - fn num_ports(&self, node: Self::Node, dir: Direction) -> usize; - - /// Number of inputs to a node. - /// Shorthand for [`num_ports`][HugrView::num_ports]`(node, Direction::Incoming)`. - #[inline] - fn num_inputs(&self, node: Self::Node) -> usize { - self.num_ports(node, Direction::Incoming) - } - - /// Number of outputs from a node. - /// Shorthand for [`num_ports`][HugrView::num_ports]`(node, Direction::Outgoing)`. - #[inline] - fn num_outputs(&self, node: Self::Node) -> usize { - self.num_ports(node, Direction::Outgoing) - } - - /// Return iterator over the direct children of node. + /// Returns an iterator over the direct children of node. fn children(&self, node: Self::Node) -> impl DoubleEndedIterator + Clone; + /// Returns an iterator over all the descendants of a node, + /// including the node itself. + /// + /// Yields the node itself first, followed by its children in breath-first order. + fn descendants(&self, node: Self::Node) -> impl Iterator + Clone; + /// Returns the first child of the specified node (if it is a parent). /// Useful because `x.children().next()` leaves x borrowed. fn first_child(&self, node: Self::Node) -> Option { @@ -334,13 +303,13 @@ pub trait HugrView: HugrInternals { /// In contrast to [`poly_func_type`][HugrView::poly_func_type], this /// method always return a concrete [`Signature`]. fn inner_function_type(&self) -> Option> { - self.root_type().inner_function_type() + self.root_optype().inner_function_type() } /// Returns the function type defined by this HUGR, i.e. `Some` iff the root is /// a [`FuncDecl`][crate::ops::FuncDecl] or [`FuncDefn`][crate::ops::FuncDefn]. fn poly_func_type(&self) -> Option { - match self.root_type() { + match self.root_optype() { OpType::FuncDecl(decl) => Some(decl.signature.clone()), OpType::FuncDefn(defn) => Some(defn.signature.clone()), _ => None, @@ -363,13 +332,7 @@ pub trait HugrView: HugrInternals { /// /// For a more detailed representation, use the [`HugrView::dot_string`] /// format instead. - fn mermaid_string(&self) -> String { - self.mermaid_string_with_config(RenderConfig { - node_indices: true, - port_offsets_in_edges: true, - type_labels_in_edges: true, - }) - } + fn mermaid_string(&self) -> String; /// Return the mermaid representation of the underlying hierarchical graph. /// @@ -378,35 +341,14 @@ pub trait HugrView: HugrInternals { /// /// For a more detailed representation, use the [`HugrView::dot_string`] /// format instead. - fn mermaid_string_with_config(&self, config: RenderConfig) -> String { - let hugr = self.base_hugr(); - let graph = self.portgraph(); - graph - .mermaid_format() - .with_hierarchy(&hugr.hierarchy) - .with_node_style(render::node_style(self, config)) - .with_edge_style(render::edge_style(self, config)) - .finish() - } + fn mermaid_string_with_config(&self, config: RenderConfig) -> String; /// Return the graphviz representation of the underlying graph and hierarchy side by side. /// /// For a simpler representation, use the [`HugrView::mermaid_string`] format instead. fn dot_string(&self) -> String where - Self: Sized, - { - let hugr = self.base_hugr(); - let graph = self.portgraph(); - let config = RenderConfig::default(); - graph - .dot_format() - .with_hierarchy(&hugr.hierarchy) - .with_node_style(render::node_style(self, config)) - .with_port_style(render::port_style(self, config)) - .with_edge_style(render::edge_style(self, config)) - .finish() - } + Self: Sized; /// If a node has a static input, return the source node. fn static_source(&self, node: Self::Node) -> Option { @@ -453,10 +395,9 @@ pub trait HugrView: HugrInternals { /// Returns the set of extensions used by the HUGR. /// - /// This set may contain extensions that are no longer required by the HUGR. - fn extensions(&self) -> &ExtensionRegistry { - &self.base_hugr().extensions - } + /// This set contains all extensions required to define the operations and + /// types in the HUGR. + fn extensions(&self) -> &ExtensionRegistry; /// Check the validity of the underlying HUGR. /// @@ -465,6 +406,7 @@ pub trait HugrView: HugrInternals { /// See [`HugrView::validate_no_extensions`] for a version that doesn't check /// extension requirements. fn validate(&self) -> Result<(), ValidationError> { + #[allow(deprecated)] self.base_hugr().validate() } @@ -474,6 +416,7 @@ pub trait HugrView: HugrInternals { /// /// For a more thorough check, use [`HugrView::validate`]. fn validate_no_extensions(&self) -> Result<(), ValidationError> { + #[allow(deprecated)] self.base_hugr().validate_no_extensions() } } @@ -526,18 +469,48 @@ impl ExtractHugr for &mut Hugr { impl HugrView for Hugr { #[inline] - fn contains_node(&self, node: Node) -> bool { - self.graph.contains_node(node.pg_index()) + fn root(&self) -> Self::Node { + self.root.into() + } + + #[inline] + fn contains_node(&self, node: Self::Node) -> bool { + self.graph.contains_node(node.into_portgraph()) + } + + #[inline] + fn get_parent(&self, node: Self::Node) -> Option { + if !check_valid_non_root(self, node) { + return None; + }; + self.hierarchy + .parent(self.to_portgraph_node(node)) + .map(|index| self.from_portgraph_node(index)) + } + + #[inline] + fn get_optype(&self, node: Node) -> &OpType { + // TODO: This currently fails because some methods get the optype of + // e.g. a parent outside a region view. We should be able to re-enable + // this once we add hugr entrypoints. + //panic_invalid_node(self, node); + self.op_types.get(self.to_portgraph_node(node)) + } + + #[inline] + fn num_nodes(&self) -> usize { + self.portgraph().node_count() } #[inline] - fn node_count(&self) -> usize { - self.graph.node_count() + fn num_edges(&self) -> usize { + self.portgraph().link_count() } #[inline] - fn edge_count(&self) -> usize { - self.graph.link_count() + fn num_ports(&self, node: Self::Node, dir: Direction) -> usize { + self.portgraph() + .num_ports(self.to_portgraph_node(node), dir) } #[inline] @@ -547,12 +520,16 @@ impl HugrView for Hugr { #[inline] fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator + Clone { - self.graph.port_offsets(node.pg_index(), dir).map_into() + self.graph + .port_offsets(node.into_portgraph(), dir) + .map_into() } #[inline] fn all_node_ports(&self, node: Node) -> impl Iterator + Clone { - self.graph.all_port_offsets(node.pg_index()).map_into() + self.graph + .all_port_offsets(node.into_portgraph()) + .map_into() } #[inline] @@ -565,7 +542,7 @@ impl HugrView for Hugr { let port = self .graph - .port_index(node.pg_index(), port.pg_offset()) + .port_index(node.into_portgraph(), port.pg_offset()) .unwrap(); self.graph.port_links(port).map(|(_, link)| { let port = link.port(); @@ -578,30 +555,72 @@ impl HugrView for Hugr { #[inline] fn node_connections(&self, node: Node, other: Node) -> impl Iterator + Clone { self.graph - .get_connections(node.pg_index(), other.pg_index()) + .get_connections(node.into_portgraph(), other.into_portgraph()) .map(|(p1, p2)| { [p1, p2].map(|link| self.graph.port_offset(link.port()).unwrap().into()) }) } #[inline] - fn num_ports(&self, node: Node, dir: Direction) -> usize { - self.graph.num_ports(node.pg_index(), dir) + fn children(&self, node: Self::Node) -> impl DoubleEndedIterator + Clone { + self.hierarchy + .children(self.to_portgraph_node(node)) + .map(|n| self.from_portgraph_node(n)) } #[inline] - fn children(&self, node: Node) -> impl DoubleEndedIterator + Clone { - self.hierarchy.children(node.pg_index()).map_into() + fn descendants(&self, node: Self::Node) -> impl Iterator + Clone { + self.hierarchy + .descendants(self.to_portgraph_node(node)) + .map(|n| self.from_portgraph_node(n)) } #[inline] fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator + Clone { - self.graph.neighbours(node.pg_index(), dir).map_into() + self.graph.neighbours(node.into_portgraph(), dir).map_into() } #[inline] fn all_neighbours(&self, node: Node) -> impl Iterator + Clone { - self.graph.all_neighbours(node.pg_index()).map_into() + self.graph.all_neighbours(node.into_portgraph()).map_into() + } + + fn mermaid_string(&self) -> String { + self.mermaid_string_with_config(RenderConfig { + node_indices: true, + port_offsets_in_edges: true, + type_labels_in_edges: true, + }) + } + + fn mermaid_string_with_config(&self, config: RenderConfig) -> String { + let graph = self.portgraph(); + graph + .mermaid_format() + .with_hierarchy(&self.hierarchy) + .with_node_style(render::node_style(self, config)) + .with_edge_style(render::edge_style(self, config)) + .finish() + } + + fn dot_string(&self) -> String + where + Self: Sized, + { + let graph = self.portgraph(); + let config = RenderConfig::default(); + graph + .dot_format() + .with_hierarchy(&self.hierarchy) + .with_node_style(render::node_style(self, config)) + .with_port_style(render::port_style(self, config)) + .with_edge_style(render::edge_style(self, config)) + .finish() + } + + #[inline] + fn extensions(&self) -> &ExtensionRegistry { + &self.extensions } } @@ -630,7 +649,7 @@ where hugr: &impl HugrView, ) -> impl Iterator { self.filter(move |(n, p)| { - let kind = hugr.get_optype(*n).port_kind(*p); + let kind = HugrView::get_optype(hugr, *n).port_kind(*p); predicate(kind) }) } @@ -642,3 +661,47 @@ where P: Into + Copy, { } + +/// Returns `true` if the node exists in the graph and is not the module at the hierarchy root. +pub(super) fn check_valid_non_root(hugr: &H, node: H::Node) -> bool { + hugr.contains_node(node) && node != hugr.root() +} + +/// Panic if [`HugrView::contains_node`] fails. +#[track_caller] +pub(super) fn panic_invalid_node(hugr: &H, node: H::Node) { + // TODO: When stacking hugr wrappers, this gets called for every layer. + // Should we `cfg!(debug_assertions)` this? Benchmark and see if it matters. + if !hugr.contains_node(node) { + panic!("Received an invalid node {node}.",); + } +} + +/// Panic if [`check_valid_non_root`] fails. +#[track_caller] +pub(super) fn panic_invalid_non_root(hugr: &H, node: H::Node) { + // TODO: When stacking hugr wrappers, this gets called for every layer. + // Should we `cfg!(debug_assertions)` this? Benchmark and see if it matters. + if !check_valid_non_root(hugr, node) { + panic!("Received an invalid non-root node {node}.",); + } +} + +/// Panic if [`HugrView::valid_node`] fails. +#[track_caller] +pub(super) fn panic_invalid_port( + hugr: &H, + node: Node, + port: impl Into, +) { + let port = port.into(); + // TODO: When stacking hugr wrappers, this gets called for every layer. + // Should we `cfg!(debug_assertions)` this? Benchmark and see if it matters. + if hugr + .portgraph() + .port_index(node.into_portgraph(), port.pg_offset()) + .is_none() + { + panic!("Received an invalid port {port} for node {node} while mutating a HUGR"); + } +} diff --git a/hugr-core/src/hugr/views/descendants.rs b/hugr-core/src/hugr/views/descendants.rs index 906dea3e45..e3ba29e2c3 100644 --- a/hugr-core/src/hugr/views/descendants.rs +++ b/hugr-core/src/hugr/views/descendants.rs @@ -41,37 +41,44 @@ pub struct DescendantsGraph<'g, Root = Node> { _phantom: std::marker::PhantomData, } impl HugrView for DescendantsGraph<'_, Root> { + #[inline] + fn root(&self) -> Self::Node { + self.root + } + #[inline] fn contains_node(&self, node: Node) -> bool { - self.graph.contains_node(self.get_pg_index(node)) + self.graph.contains_node(self.to_portgraph_node(node)) } #[inline] - fn node_count(&self) -> usize { + fn num_nodes(&self) -> usize { self.graph.node_count() } #[inline] - fn edge_count(&self) -> usize { + fn num_edges(&self) -> usize { self.graph.link_count() } #[inline] fn nodes(&self) -> impl Iterator + Clone { - self.graph.nodes_iter().map(|index| self.get_node(index)) + self.graph + .nodes_iter() + .map(|index| self.from_portgraph_node(index)) } #[inline] fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator + Clone { self.graph - .port_offsets(self.get_pg_index(node), dir) + .port_offsets(self.to_portgraph_node(node), dir) .map_into() } #[inline] fn all_node_ports(&self, node: Node) -> impl Iterator + Clone { self.graph - .all_port_offsets(self.get_pg_index(node)) + .all_port_offsets(self.to_portgraph_node(node)) .map_into() } @@ -82,19 +89,19 @@ impl HugrView for DescendantsGraph<'_, Root> { ) -> impl Iterator + Clone { let port = self .graph - .port_index(self.get_pg_index(node), port.into().pg_offset()) + .port_index(self.to_portgraph_node(node), port.into().pg_offset()) .unwrap(); self.graph.port_links(port).map(|(_, link)| { let port: PortIndex = link.into(); let node = self.graph.port_node(port).unwrap(); let offset = self.graph.port_offset(port).unwrap(); - (self.get_node(node), offset.into()) + (self.from_portgraph_node(node), offset.into()) }) } fn node_connections(&self, node: Node, other: Node) -> impl Iterator + Clone { self.graph - .get_connections(self.get_pg_index(node), self.get_pg_index(other)) + .get_connections(self.to_portgraph_node(node), self.to_portgraph_node(other)) .map(|(p1, p2)| { [p1, p2].map(|link| { let offset = self.graph.port_offset(link).unwrap(); @@ -105,30 +112,46 @@ impl HugrView for DescendantsGraph<'_, Root> { #[inline] fn num_ports(&self, node: Node, dir: Direction) -> usize { - self.graph.num_ports(self.get_pg_index(node), dir) + self.graph.num_ports(self.to_portgraph_node(node), dir) } #[inline] fn children(&self, node: Node) -> impl DoubleEndedIterator + Clone { - let children = match self.graph.contains_node(self.get_pg_index(node)) { - true => self.base_hugr().hierarchy.children(self.get_pg_index(node)), + let hierarchy = self.hierarchy(); + let children = match self.graph.contains_node(self.to_portgraph_node(node)) { + true => hierarchy.children(self.to_portgraph_node(node)), false => portgraph::hierarchy::Children::default(), }; - children.map(|index| self.get_node(index)) + children.map(move |index| { + let _ = hierarchy; + self.from_portgraph_node(index) + }) } #[inline] fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator + Clone { self.graph - .neighbours(self.get_pg_index(node), dir) - .map(|index| self.get_node(index)) + .neighbours(self.to_portgraph_node(node), dir) + .map(|index| self.from_portgraph_node(index)) } #[inline] fn all_neighbours(&self, node: Node) -> impl Iterator + Clone { self.graph - .all_neighbours(self.get_pg_index(node)) - .map(|index| self.get_node(index)) + .all_neighbours(self.to_portgraph_node(node)) + .map(|index| self.from_portgraph_node(index)) + } + + delegate::delegate! { + to (&self.hugr) { + fn get_parent(&self, node: Self::Node) -> Option; + fn get_optype(&self, node: Self::Node) -> &crate::ops::OpType; + fn descendants(&self, node: Self::Node) -> impl Iterator + Clone; + fn mermaid_string(&self) -> String; + fn mermaid_string_with_config(&self, config: crate::hugr::views::render::RenderConfig) -> String; + fn dot_string(&self) -> String; + fn extensions(&self) -> &crate::extension::ExtensionRegistry; + } } } @@ -138,10 +161,11 @@ where { fn try_new(hugr: &'a impl HugrView, root: Node) -> Result { check_tag::(hugr, root)?; + #[allow(deprecated)] let hugr = hugr.base_hugr(); Ok(Self { root, - graph: RegionGraph::new(&hugr.graph, &hugr.hierarchy, hugr.get_pg_index(root)), + graph: RegionGraph::new(&hugr.graph, &hugr.hierarchy, hugr.to_portgraph_node(root)), hugr, _phantom: std::marker::PhantomData, }) @@ -166,28 +190,39 @@ where &self.graph } - fn base_hugr(&self) -> &Hugr { - self.hugr + #[inline] + fn region_portgraph( + &self, + parent: Self::Node, + ) -> portgraph::view::FlatRegion< + '_, + impl portgraph::view::LinkView + Clone + '_, + > { + self.hugr.region_portgraph(parent) } #[inline] - fn root_node(&self) -> Node { - self.root + fn hierarchy(&self) -> &portgraph::Hierarchy { + self.hugr.hierarchy() } #[inline] - fn get_pg_index(&self, node: impl NodeHandle) -> portgraph::NodeIndex { - self.hugr.get_pg_index(node) + fn to_portgraph_node(&self, node: impl NodeHandle) -> portgraph::NodeIndex { + self.hugr.to_portgraph_node(node) } #[inline] - fn get_node(&self, index: portgraph::NodeIndex) -> Node { - self.hugr.get_node(index) + fn from_portgraph_node(&self, index: portgraph::NodeIndex) -> Node { + self.hugr.from_portgraph_node(index) } fn node_metadata_map(&self, node: Self::Node) -> &crate::hugr::NodeMetadataMap { self.hugr.node_metadata_map(node) } + + fn base_hugr(&self) -> &Hugr { + self.hugr + } } #[cfg(test)] @@ -245,7 +280,7 @@ pub(super) mod test { let region: DescendantsGraph = DescendantsGraph::try_new(&hugr, def)?; let def_io = region.get_io(def).unwrap(); - assert_eq!(region.node_count(), 7); + assert_eq!(region.num_nodes(), 7); assert!(region.nodes().all(|n| n == def || hugr.get_parent(n) == Some(def) || hugr.get_parent(n) == Some(inner))); @@ -265,8 +300,8 @@ pub(super) mod test { inner_region.inner_function_type().map(Cow::into_owned), Some(Signature::new(vec![usize_t()], vec![usize_t()])) ); - assert_eq!(inner_region.node_count(), 3); - assert_eq!(inner_region.edge_count(), 1); + assert_eq!(inner_region.num_nodes(), 3); + assert_eq!(inner_region.num_edges(), 1); assert_eq!(inner_region.children(inner).count(), 2); assert_eq!(inner_region.children(hugr.root()).count(), 0); assert_eq!( @@ -315,8 +350,8 @@ pub(super) mod test { let region: DescendantsGraph = DescendantsGraph::try_new(&hugr, def)?; - assert_eq!(region.node_count(), extracted.node_count()); - assert_eq!(region.root_type(), extracted.root_type()); + assert_eq!(region.num_nodes(), extracted.num_nodes()); + assert_eq!(region.root_optype(), extracted.root_optype()); Ok(()) } diff --git a/hugr-core/src/hugr/views/impls.rs b/hugr-core/src/hugr/views/impls.rs index 440df94808..6cd1d76312 100644 --- a/hugr-core/src/hugr/views/impls.rs +++ b/hugr-core/src/hugr/views/impls.rs @@ -12,12 +12,13 @@ macro_rules! hugr_internal_methods { delegate::delegate! { to ({let $arg=self; $e}) { fn portgraph(&self) -> Self::Portgraph<'_>; - fn hierarchy(&self) -> Cow<'_, portgraph::Hierarchy>; - fn base_hugr(&self) -> &crate::Hugr; - fn root_node(&self) -> Self::Node; - fn get_pg_index(&self, node: impl crate::ops::handle::NodeHandle) -> portgraph::NodeIndex; - fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node; + fn region_portgraph(&self, parent: Self::Node) -> portgraph::view::FlatRegion<'_, impl portgraph::view::LinkView + Clone + '_>; + fn hierarchy(&self) -> &portgraph::Hierarchy; + fn to_portgraph_node(&self, node: impl crate::ops::handle::NodeHandle) -> portgraph::NodeIndex; + fn from_portgraph_node(&self, index: portgraph::NodeIndex) -> Self::Node; fn node_metadata_map(&self, node: Self::Node) -> &crate::hugr::NodeMetadataMap; + #[allow(deprecated)] + fn base_hugr(&self) -> &crate::Hugr; } } }; @@ -30,34 +31,23 @@ macro_rules! hugr_view_methods { delegate::delegate! { to ({let $arg=self; $e}) { fn root(&self) -> Self::Node; - fn root_type(&self) -> &crate::ops::OpType; + fn root_optype(&self) -> &crate::ops::OpType; fn contains_node(&self, node: Self::Node) -> bool; - fn valid_node(&self, node: Self::Node) -> bool; - fn valid_non_root(&self, node: Self::Node) -> bool; fn get_parent(&self, node: Self::Node) -> Option; - fn get_optype(&self, node: Self::Node) -> &crate::ops::OpType; fn get_metadata(&self, node: Self::Node, key: impl AsRef) -> Option<&crate::hugr::NodeMetadata>; - fn get_node_metadata(&self, node: Self::Node) -> Option<&crate::hugr::NodeMetadataMap>; - fn node_count(&self) -> usize; - fn edge_count(&self) -> usize; + fn get_optype(&self, node: Self::Node) -> &crate::ops::OpType; + fn num_nodes(&self) -> usize; + fn num_edges(&self) -> usize; + fn num_ports(&self, node: Self::Node, dir: crate::Direction) -> usize; + fn num_inputs(&self, node: Self::Node) -> usize; + fn num_outputs(&self, node: Self::Node) -> usize; fn nodes(&self) -> impl Iterator + Clone; fn node_ports(&self, node: Self::Node, dir: crate::Direction) -> impl Iterator + Clone; fn node_outputs(&self, node: Self::Node) -> impl Iterator + Clone; fn node_inputs(&self, node: Self::Node) -> impl Iterator + Clone; fn all_node_ports(&self, node: Self::Node) -> impl Iterator + Clone; - fn linked_ports( - &self, - node: Self::Node, - port: impl Into, - ) -> impl Iterator + Clone; - fn all_linked_ports( - &self, - node: Self::Node, - dir: crate::Direction, - ) -> itertools::Either< - impl Iterator, - impl Iterator, - >; + fn linked_ports(&self, node: Self::Node, port: impl Into) -> impl Iterator + Clone; + fn all_linked_ports(&self, node: Self::Node, dir: crate::Direction) -> itertools::Either, impl Iterator>; fn all_linked_outputs(&self, node: Self::Node) -> impl Iterator; fn all_linked_inputs(&self, node: Self::Node) -> impl Iterator; fn single_linked_port(&self, node: Self::Node, port: impl Into) -> Option<(Self::Node, crate::Port)>; @@ -67,31 +57,19 @@ macro_rules! hugr_view_methods { fn linked_inputs(&self, node: Self::Node, port: impl Into) -> impl Iterator; fn node_connections(&self, node: Self::Node, other: Self::Node) -> impl Iterator + Clone; fn is_linked(&self, node: Self::Node, port: impl Into) -> bool; - fn num_ports(&self, node: Self::Node, dir: crate::Direction) -> usize; - fn num_inputs(&self, node: Self::Node) -> usize; - fn num_outputs(&self, node: Self::Node) -> usize; fn children(&self, node: Self::Node) -> impl DoubleEndedIterator + Clone; + fn descendants(&self, node: Self::Node) -> impl Iterator + Clone; fn first_child(&self, node: Self::Node) -> Option; fn neighbours(&self, node: Self::Node, dir: crate::Direction) -> impl Iterator + Clone; fn input_neighbours(&self, node: Self::Node) -> impl Iterator + Clone; fn output_neighbours(&self, node: Self::Node) -> impl Iterator + Clone; fn all_neighbours(&self, node: Self::Node) -> impl Iterator + Clone; - fn get_io(&self, node: Self::Node) -> Option<[Self::Node; 2]>; - fn inner_function_type(&self) -> Option>; - fn poly_func_type(&self) -> Option; - // TODO: cannot use delegate here. `PetgraphWrapper` is a thin - // wrapper around `Self`, so falling back to the default impl - // should be harmless. - // fn as_petgraph(&self) -> PetgraphWrapper<'_, Self>; fn mermaid_string(&self) -> String; fn mermaid_string_with_config(&self, config: crate::hugr::views::render::RenderConfig) -> String; fn dot_string(&self) -> String; fn static_source(&self, node: Self::Node) -> Option; fn static_targets(&self, node: Self::Node) -> Option>; - fn signature(&self, node: Self::Node) -> Option>; fn value_types(&self, node: Self::Node, dir: crate::Direction) -> impl Iterator; - fn in_value_types(&self, node: Self::Node) -> impl Iterator; - fn out_value_types(&self, node: Self::Node) -> impl Iterator; fn extensions(&self) -> &crate::extension::ExtensionRegistry; fn validate(&self) -> Result<(), crate::hugr::ValidationError>; fn validate_no_extensions(&self) -> Result<(), crate::hugr::ValidationError>; @@ -128,6 +106,9 @@ macro_rules! hugr_mut_methods { ($arg:ident, $e:expr) => { delegate::delegate! { to ({let $arg=self; $e}) { + fn get_metadata_mut(&mut self, node: Self::Node, key: impl AsRef) -> &mut crate::hugr::NodeMetadata; + fn set_metadata(&mut self, node: Self::Node, key: impl AsRef, metadata: impl Into); + fn remove_metadata(&mut self, node: Self::Node, key: impl AsRef); fn add_node_with_parent(&mut self, parent: Self::Node, op: impl Into) -> Self::Node; fn add_node_before(&mut self, sibling: Self::Node, nodetype: impl Into) -> Self::Node; fn add_node_after(&mut self, sibling: Self::Node, op: impl Into) -> Self::Node; @@ -140,6 +121,8 @@ macro_rules! hugr_mut_methods { fn insert_hugr(&mut self, root: Self::Node, other: crate::Hugr) -> crate::hugr::hugrmut::InsertionResult; fn insert_from_view(&mut self, root: Self::Node, other: &Other) -> crate::hugr::hugrmut::InsertionResult; fn insert_subgraph(&mut self, root: Self::Node, other: &Other, subgraph: &crate::hugr::views::SiblingSubgraph) -> std::collections::HashMap; + fn use_extension(&mut self, extension: impl Into>); + fn use_extensions(&mut self, registry: impl IntoIterator) where crate::extension::ExtensionRegistry: Extend; } } }; diff --git a/hugr-core/src/hugr/views/petgraph.rs b/hugr-core/src/hugr/views/petgraph.rs index 17c3e00623..22da47f0af 100644 --- a/hugr-core/src/hugr/views/petgraph.rs +++ b/hugr-core/src/hugr/views/petgraph.rs @@ -55,7 +55,7 @@ where T: HugrView, { fn node_count(&self) -> usize { - HugrView::node_count(self.hugr) + HugrView::num_nodes(self.hugr) } } @@ -64,15 +64,15 @@ where T: HugrView, { fn node_bound(&self) -> usize { - HugrView::node_count(self.hugr) + HugrView::num_nodes(self.hugr) } fn to_index(&self, ix: Self::NodeId) -> usize { - self.hugr.get_pg_index(ix).into() + self.hugr.to_portgraph_node(ix).into() } fn from_index(&self, ix: usize) -> Self::NodeId { - self.hugr.get_node(portgraph::NodeIndex::new(ix)) + self.hugr.from_portgraph_node(portgraph::NodeIndex::new(ix)) } } @@ -81,7 +81,7 @@ where T: HugrView, { fn edge_count(&self) -> usize { - HugrView::edge_count(self.hugr) + HugrView::num_edges(self.hugr) } } @@ -233,7 +233,7 @@ mod test { assert_eq!(wrapper.node_bound(), 5); assert_eq!(wrapper.edge_count(), 7); - let cx1_index = cx1.node().pg_index().index(); + let cx1_index = cx1.node().into_portgraph().index(); assert_eq!(wrapper.to_index(cx1.node()), cx1_index); assert_eq!(wrapper.from_index(cx1_index), cx1.node()); diff --git a/hugr-core/src/hugr/views/render.rs b/hugr-core/src/hugr/views/render.rs index ecb8549c06..43530e4c14 100644 --- a/hugr-core/src/hugr/views/render.rs +++ b/hugr-core/src/hugr/views/render.rs @@ -36,7 +36,7 @@ pub(super) fn node_style( config: RenderConfig, ) -> Box NodeStyle + '_> { fn node_name(h: &H, n: NodeIndex) -> String { - match h.get_optype(h.get_node(n)) { + match h.get_optype(h.from_portgraph_node(n)) { OpType::FuncDecl(f) => format!("FuncDecl: \"{}\"", f.name), OpType::FuncDefn(f) => format!("FuncDefn: \"{}\"", f.name), op => op.name().to_string(), @@ -45,14 +45,14 @@ pub(super) fn node_style( if config.node_indices { Box::new(move |n| { - NodeStyle::Box(format!( + NodeStyle::boxed(format!( "({ni}) {name}", ni = n.index(), name = node_name(h, n) )) }) } else { - Box::new(move |n| NodeStyle::Box(node_name(h, n))) + Box::new(move |n| NodeStyle::boxed(node_name(h, n))) } } @@ -64,7 +64,7 @@ pub(super) fn port_style( let graph = h.portgraph(); Box::new(move |port| { let node = graph.port_node(port).unwrap(); - let optype = h.get_optype(h.get_node(node)); + let optype = h.get_optype(h.from_portgraph_node(node)); let offset = graph.port_offset(port).unwrap(); match optype.port_kind(offset).unwrap() { EdgeKind::Function(pf) => PortStyle::new(html_escape::encode_text(&format!("{}", pf))), @@ -95,7 +95,7 @@ pub(super) fn edge_style( let graph = h.portgraph(); Box::new(move |src, tgt| { let src_node = graph.port_node(src).unwrap(); - let src_optype = h.get_optype(h.get_node(src_node)); + let src_optype = h.get_optype(h.from_portgraph_node(src_node)); let src_offset = graph.port_offset(src).unwrap(); let tgt_offset = graph.port_offset(tgt).unwrap(); diff --git a/hugr-core/src/hugr/views/sibling.rs b/hugr-core/src/hugr/views/sibling.rs index ac31d2695b..44e29ab1a8 100644 --- a/hugr-core/src/hugr/views/sibling.rs +++ b/hugr-core/src/hugr/views/sibling.rs @@ -51,15 +51,19 @@ pub struct SiblingGraph<'g, Root = Node> { macro_rules! impl_base_members { () => { #[inline] - fn node_count(&self) -> usize { - self.base_hugr() - .hierarchy - .child_count(self.get_pg_index(self.root)) + fn root(&self) -> Self::Node { + self.root + } + + #[inline] + fn num_nodes(&self) -> usize { + self.hierarchy() + .child_count(self.to_portgraph_node(self.root)) + 1 } #[inline] - fn edge_count(&self) -> usize { + fn num_edges(&self) -> usize { // Faster implementation than filtering all the nodes in the internal graph. self.nodes() .map(|n| self.output_neighbours(n).count()) @@ -70,10 +74,9 @@ macro_rules! impl_base_members { fn nodes(&self) -> impl Iterator + Clone { // Faster implementation than filtering all the nodes in the internal graph. let children = self - .base_hugr() - .hierarchy - .children(self.get_pg_index(self.root)) - .map(|n| self.get_node(n)); + .hierarchy() + .children(self.to_portgraph_node(self.root)) + .map(|n| self.from_portgraph_node(n)); iter::once(self.root).chain(children) } @@ -83,10 +86,41 @@ macro_rules! impl_base_members { ) -> impl DoubleEndedIterator + Clone { // Same as SiblingGraph let children = match node == self.root { - true => self.base_hugr().hierarchy.children(self.get_pg_index(node)), + true => self.hierarchy().children(self.to_portgraph_node(node)), false => portgraph::hierarchy::Children::default(), }; - children.map(|n| self.get_node(n)) + children.map(|n| self.from_portgraph_node(n)) + } + + fn get_optype(&self, node: Self::Node) -> &crate::ops::OpType { + self.hugr.get_optype(node) + } + + fn extensions(&self) -> &crate::extension::ExtensionRegistry { + self.hugr.extensions() + } + + fn get_parent(&self, node: Self::Node) -> Option { + match self.hugr.get_parent(node) { + Some(parent) if parent == self.root => Some(self.root), + _ => None, + } + } + + fn descendants(&self, node: Self::Node) -> impl Iterator + Clone { + if node == self.root { + Either::Left(self.hugr.descendants(node)) + } else { + Either::Right(iter::empty()) + } + } + + delegate::delegate! { + to (&self.hugr) { + fn mermaid_string(&self) -> String; + fn mermaid_string_with_config(&self, config: crate::hugr::views::render::RenderConfig) -> String; + fn dot_string(&self) -> String; + } } }; } @@ -96,20 +130,20 @@ impl HugrView for SiblingGraph<'_, Root> { #[inline] fn contains_node(&self, node: Node) -> bool { - self.graph.contains_node(self.get_pg_index(node)) + self.graph.contains_node(self.to_portgraph_node(node)) } #[inline] fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator + Clone { self.graph - .port_offsets(self.get_pg_index(node), dir) + .port_offsets(self.to_portgraph_node(node), dir) .map_into() } #[inline] fn all_node_ports(&self, node: Node) -> impl Iterator + Clone { self.graph - .all_port_offsets(self.get_pg_index(node)) + .all_port_offsets(self.to_portgraph_node(node)) .map_into() } @@ -120,47 +154,52 @@ impl HugrView for SiblingGraph<'_, Root> { ) -> impl Iterator + Clone { let port = self .graph - .port_index(self.get_pg_index(node), port.into().pg_offset()) + .port_index(self.to_portgraph_node(node), port.into().pg_offset()) .unwrap(); self.graph.port_links(port).map(|(_, link)| { let node = self.graph.port_node(link).unwrap(); let offset = self.graph.port_offset(link).unwrap(); - (self.get_node(node), offset.into()) + (self.from_portgraph_node(node), offset.into()) }) } fn node_connections(&self, node: Node, other: Node) -> impl Iterator + Clone { self.graph - .get_connections(self.get_pg_index(node), self.get_pg_index(other)) + .get_connections(self.to_portgraph_node(node), self.to_portgraph_node(other)) .map(|(p1, p2)| [p1, p2].map(|link| self.graph.port_offset(link).unwrap().into())) } #[inline] fn num_ports(&self, node: Node, dir: Direction) -> usize { - self.graph.num_ports(self.get_pg_index(node), dir) + self.graph.num_ports(self.to_portgraph_node(node), dir) } #[inline] fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator + Clone { self.graph - .neighbours(self.get_pg_index(node), dir) - .map(|n| self.get_node(n)) + .neighbours(self.to_portgraph_node(node), dir) + .map(|n| self.from_portgraph_node(n)) } #[inline] fn all_neighbours(&self, node: Node) -> impl Iterator + Clone { self.graph - .all_neighbours(self.get_pg_index(node)) - .map(|n| self.get_node(n)) + .all_neighbours(self.to_portgraph_node(node)) + .map(|n| self.from_portgraph_node(n)) } } impl<'a, Root: NodeHandle> SiblingGraph<'a, Root> { fn new_unchecked(hugr: &'a impl HugrView, root: Node) -> Self { + #[allow(deprecated)] let hugr = hugr.base_hugr(); Self { root, - graph: FlatRegionGraph::new(&hugr.graph, &hugr.hierarchy, hugr.get_pg_index(root)), + graph: FlatRegionGraph::new_with_root( + &hugr.graph, + &hugr.hierarchy, + hugr.to_portgraph_node(root), + ), hugr, _phantom: std::marker::PhantomData, } @@ -173,7 +212,7 @@ where { fn try_new(hugr: &'a impl HugrView, root: Node) -> Result { assert!( - hugr.valid_node(root), + hugr.contains_node(root), "Cannot create a sibling graph from an invalid node {}.", root ); @@ -200,23 +239,34 @@ where } #[inline] - fn base_hugr(&self) -> &Hugr { - self.hugr + fn region_portgraph( + &self, + parent: Self::Node, + ) -> portgraph::view::FlatRegion< + '_, + impl portgraph::view::LinkView + Clone + '_, + > { + self.hugr.region_portgraph(parent) } #[inline] - fn root_node(&self) -> Node { - self.root + fn hierarchy(&self) -> &portgraph::Hierarchy { + self.hugr.hierarchy() } #[inline] - fn get_pg_index(&self, node: impl NodeHandle) -> portgraph::NodeIndex { - self.hugr.get_pg_index(node) + fn base_hugr(&self) -> &Hugr { + self.hugr } #[inline] - fn get_node(&self, index: portgraph::NodeIndex) -> Node { - self.hugr.get_node(index) + fn to_portgraph_node(&self, node: impl NodeHandle) -> portgraph::NodeIndex { + self.hugr.to_portgraph_node(node) + } + + #[inline] + fn from_portgraph_node(&self, index: portgraph::NodeIndex) -> Node { + self.hugr.from_portgraph_node(index) } #[inline] @@ -272,37 +322,50 @@ impl<'g, H: HugrMut, Root: NodeHandle> HugrInternals for SiblingMut<'g, #[inline] fn portgraph(&self) -> Self::Portgraph<'_> { - FlatRegionGraph::new( + FlatRegionGraph::new_with_root( + #[allow(deprecated)] &self.base_hugr().graph, - &self.base_hugr().hierarchy, - self.get_pg_index(self.root), + self.hierarchy(), + self.to_portgraph_node(self.root), ) } #[inline] - fn base_hugr(&self) -> &Hugr { - self.hugr.base_hugr() + fn region_portgraph( + &self, + parent: Self::Node, + ) -> portgraph::view::FlatRegion< + '_, + impl portgraph::view::LinkView + Clone + '_, + > { + self.hugr.region_portgraph(parent) } #[inline] - fn root_node(&self) -> Self::Node { - self.root + fn hierarchy(&self) -> &portgraph::Hierarchy { + self.hugr.hierarchy() } #[inline] - fn get_pg_index(&self, node: impl NodeHandle) -> portgraph::NodeIndex { - self.hugr.get_pg_index(node) + fn to_portgraph_node(&self, node: impl NodeHandle) -> portgraph::NodeIndex { + self.hugr.to_portgraph_node(node) } #[inline] - fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node { - self.hugr.get_node(index) + fn from_portgraph_node(&self, index: portgraph::NodeIndex) -> Self::Node { + self.hugr.from_portgraph_node(index) } #[inline] fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap { self.hugr.node_metadata_map(node) } + + #[inline] + fn base_hugr(&self) -> &Hugr { + #[allow(deprecated)] + self.hugr.base_hugr() + } } impl> HugrView for SiblingMut<'_, H, Root> { @@ -435,7 +498,7 @@ mod test { { let def_io = region.get_io(def).unwrap(); - assert_eq!(region.node_count(), 5); + assert_eq!(region.num_nodes(), 5); assert_eq!(region.portgraph().node_count(), 5); assert!(region.nodes().all(|n| n == def || hugr.get_parent(n) == Some(def) @@ -455,8 +518,8 @@ mod test { inner_region.inner_function_type().map(Cow::into_owned), Some(Signature::new(vec![usize_t()], vec![usize_t()])) ); - assert_eq!(inner_region.node_count(), 3); - assert_eq!(inner_region.edge_count(), 1); + assert_eq!(inner_region.num_nodes(), 3); + assert_eq!(inner_region.num_edges(), 1); assert_eq!(inner_region.children(inner).count(), 2); assert_eq!(inner_region.children(hugr.root()).count(), 0); assert_eq!( @@ -591,8 +654,8 @@ mod test { let region: SiblingGraph = SiblingGraph::try_new(&hugr, inner)?; - assert_eq!(region.node_count(), extracted.node_count()); - assert_eq!(region.root_type(), extracted.root_type()); + assert_eq!(region.num_nodes(), extracted.num_nodes()); + assert_eq!(region.root_optype(), extracted.root_optype()); Ok(()) } diff --git a/hugr-core/src/hugr/views/sibling_subgraph.rs b/hugr-core/src/hugr/views/sibling_subgraph.rs index 680d58a03d..7fd2b9f545 100644 --- a/hugr-core/src/hugr/views/sibling_subgraph.rs +++ b/hugr-core/src/hugr/views/sibling_subgraph.rs @@ -194,7 +194,7 @@ impl SiblingSubgraph { let subpg = Subgraph::new_subgraph(pg.clone(), make_boundary(hugr, &inputs, &outputs)); let nodes = subpg .nodes_iter() - .map(|index| hugr.get_node(index)) + .map(|index| hugr.from_portgraph_node(index)) .collect_vec(); validate_subgraph(hugr, &nodes, &inputs, &outputs)?; @@ -525,7 +525,7 @@ fn make_boundary<'a, N: HugrNode>( ) -> Boundary { let to_pg_index = |n: N, p: Port| { hugr.portgraph() - .port_index(hugr.get_pg_index(n), p.pg_offset()) + .port_index(hugr.to_portgraph_node(n), p.pg_offset()) .unwrap() }; Boundary::new( @@ -1010,9 +1010,9 @@ mod tests { assert_eq!(rep.subgraph().nodes().len(), 4); - assert_eq!(hugr.node_count(), 8); // Module + Def + In + CX + Rz + Const + LoadConst + Out + assert_eq!(hugr.num_nodes(), 8); // Module + Def + In + CX + Rz + Const + LoadConst + Out hugr.apply_patch(rep).unwrap(); - assert_eq!(hugr.node_count(), 4); // Module + Def + In + Out + assert_eq!(hugr.num_nodes(), 4); // Module + Def + In + Out Ok(()) } diff --git a/hugr-core/src/ops/constant.rs b/hugr-core/src/ops/constant.rs index 794e6eaaa7..6aad904cbc 100644 --- a/hugr-core/src/ops/constant.rs +++ b/hugr-core/src/ops/constant.rs @@ -364,7 +364,7 @@ pub enum ConstTypeError { /// Hugrs (even functions) inside Consts must be monomorphic fn mono_fn_type(h: &Hugr) -> Result, ConstTypeError> { let err = || ConstTypeError::NotMonomorphicFunction { - hugr_root_type: h.root_type().clone(), + hugr_root_type: h.root_optype().clone(), }; if let Some(pf) = h.poly_func_type() { match pf.try_into() { diff --git a/hugr-llvm/src/emit/ops.rs b/hugr-llvm/src/emit/ops.rs index 9cb6f9b101..76bb2bb09a 100644 --- a/hugr-llvm/src/emit/ops.rs +++ b/hugr-llvm/src/emit/ops.rs @@ -5,7 +5,6 @@ use hugr_core::ops::{ }; use hugr_core::Node; use hugr_core::{ - hugr::views::SiblingGraph, types::{SumType, Type, TypeEnum}, HugrView, NodeIndex, }; @@ -71,34 +70,33 @@ where debug_assert!(i.out_value_types().count() == self.inputs.as_ref().unwrap().len()); debug_assert!(o.in_value_types().count() == self.outputs.as_ref().unwrap().len()); - let region: SiblingGraph = node.try_new_hierarchy_view().unwrap(); - Topo::new(®ion.as_petgraph()) - .iter(®ion.as_petgraph()) - .filter(|x| (*x != node.node())) - .map(|x| node.hugr().fat_optype(x)) - .try_for_each(|node| { - let inputs_rmb = context.node_ins_rmb(node)?; - let inputs = inputs_rmb.read(context.builder(), [])?; - let outputs = context.node_outs_rmb(node)?.promise(); - match node.as_ref() { - OpType::Input(_) => { - let i = self.take_input()?; - outputs.finish(context.builder(), i) - } - OpType::Output(_) => { - let o = self.take_output()?; - o.finish(context.builder(), inputs) - } - _ => emit_optype( - context, - EmitOpArgs { - node, - inputs, - outputs, - }, - ), + let region_graph = node.hugr().region_portgraph(node.node()); + let topo = Topo::new(®ion_graph); + for n in topo.iter(®ion_graph) { + let node = node.hugr().fat_optype(node.hugr().from_portgraph_node(n)); + let inputs_rmb = context.node_ins_rmb(node)?; + let inputs = inputs_rmb.read(context.builder(), [])?; + let outputs = context.node_outs_rmb(node)?.promise(); + match node.as_ref() { + OpType::Input(_) => { + let i = self.take_input()?; + outputs.finish(context.builder(), i)?; } - }) + OpType::Output(_) => { + let o = self.take_output()?; + o.finish(context.builder(), inputs)?; + } + _ => emit_optype( + context, + EmitOpArgs { + node, + inputs, + outputs, + }, + )?, + } + } + Ok(()) } } diff --git a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__emit_hugr_call_indirect@pre-mem2reg@llvm14.snap b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__emit_hugr_call_indirect@pre-mem2reg@llvm14.snap index b3283ee1bd..124f36b53d 100644 --- a/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__emit_hugr_call_indirect@pre-mem2reg@llvm14.snap +++ b/hugr-llvm/src/emit/snapshots/hugr_llvm__emit__test__test_fns__emit_hugr_call_indirect@pre-mem2reg@llvm14.snap @@ -20,14 +20,14 @@ entry_block: ; preds = %alloca_block define i1 @_hl.main_unary.6(i1 %0) { alloca_block: %"0" = alloca i1, align 1 - %"7_0" = alloca i1, align 1 %"9_0" = alloca i1 (i1)*, align 8 + %"7_0" = alloca i1, align 1 %"10_0" = alloca i1, align 1 br label %entry_block entry_block: ; preds = %alloca_block - store i1 %0, i1* %"7_0", align 1 store i1 (i1)* @_hl.main_unary.6, i1 (i1)** %"9_0", align 8 + store i1 %0, i1* %"7_0", align 1 %"9_01" = load i1 (i1)*, i1 (i1)** %"9_0", align 8 %"7_02" = load i1, i1* %"7_0", align 1 %1 = call i1 %"9_01"(i1 %"7_02") @@ -42,17 +42,17 @@ define { i1, i1 } @_hl.main_binary.11(i1 %0, i1 %1) { alloca_block: %"0" = alloca i1, align 1 %"1" = alloca i1, align 1 + %"14_0" = alloca { i1, i1 } (i1, i1)*, align 8 %"12_0" = alloca i1, align 1 %"12_1" = alloca i1, align 1 - %"14_0" = alloca { i1, i1 } (i1, i1)*, align 8 %"15_0" = alloca i1, align 1 %"15_1" = alloca i1, align 1 br label %entry_block entry_block: ; preds = %alloca_block + store { i1, i1 } (i1, i1)* @_hl.main_binary.11, { i1, i1 } (i1, i1)** %"14_0", align 8 store i1 %0, i1* %"12_0", align 1 store i1 %1, i1* %"12_1", align 1 - store { i1, i1 } (i1, i1)* @_hl.main_binary.11, { i1, i1 } (i1, i1)** %"14_0", align 8 %"14_01" = load { i1, i1 } (i1, i1)*, { i1, i1 } (i1, i1)** %"14_0", align 8 %"12_02" = load i1, i1* %"12_0", align 1 %"12_13" = load i1, i1* %"12_1", align 1 diff --git a/hugr-llvm/src/utils/fat.rs b/hugr-llvm/src/utils/fat.rs index dec866b4eb..5deeb4bf08 100644 --- a/hugr-llvm/src/utils/fat.rs +++ b/hugr-llvm/src/utils/fat.rs @@ -47,7 +47,7 @@ where /// Note that while we do check the type of the node's `get_optype`, we /// do not verify that it is actually equal to `ot`. pub fn new(hugr: &'hugr H, node: H::Node, #[allow(unused)] ot: &OT) -> Self { - assert!(hugr.valid_node(node)); + assert!(hugr.contains_node(node)); assert!(TryInto::<&OT>::try_into(hugr.get_optype(node)).is_ok()); // We don't actually check `ot == hugr.get_optype(node)` so as to not require OT: PartialEq` Self { @@ -63,7 +63,7 @@ where /// If the node is invalid, or if its `get_optype` is not `OT`, returns /// `None`. pub fn try_new(hugr: &'hugr H, node: H::Node) -> Option { - (hugr.valid_node(node)).then_some(())?; + (hugr.contains_node(node)).then_some(())?; Some(Self::new( hugr, node, @@ -99,7 +99,7 @@ impl<'hugr, H: HugrView + ?Sized> FatNode<'hugr, OpType, H, H::Node> { /// /// Panics if the node is not valid in the [Hugr]. pub fn new_optype(hugr: &'hugr H, node: H::Node) -> Self { - assert!(hugr.valid_node(node)); + assert!(hugr.contains_node(node)); FatNode::new(hugr, node, hugr.get_optype(node)) } diff --git a/hugr-passes/src/const_fold/test.rs b/hugr-passes/src/const_fold/test.rs index ff5cd93a5c..3a296fc0bf 100644 --- a/hugr-passes/src/const_fold/test.rs +++ b/hugr-passes/src/const_fold/test.rs @@ -160,7 +160,7 @@ fn test_big() { .unwrap(); let mut h = build.finish_hugr_with_outputs(to_int.outputs()).unwrap(); - assert_eq!(h.node_count(), 8); + assert_eq!(h.num_nodes(), 8); constant_fold_pass(&mut h); @@ -333,7 +333,7 @@ fn test_const_fold_to_nonfinite() { assert_fully_folded_with(&h0, |v| { v.get_custom_value::().unwrap().value() == 1.0 }); - assert_eq!(h0.node_count(), 5); + assert_eq!(h0.num_nodes(), 5); // HUGR computing 1.0 / 0.0 let mut build = DFGBuilder::new(noargfn(vec![float64_type()])).unwrap(); @@ -342,7 +342,7 @@ fn test_const_fold_to_nonfinite() { let x2 = build.add_dataflow_op(FloatOps::fdiv, [x0, x1]).unwrap(); let mut h1 = build.finish_hugr_with_outputs(x2.outputs()).unwrap(); constant_fold_pass(&mut h1); - assert_eq!(h1.node_count(), 8); + assert_eq!(h1.num_nodes(), 8); } #[test] @@ -1362,7 +1362,7 @@ fn test_tail_loop_unknown() { constant_fold_pass(&mut h); // Must keep the loop, even though we know the output, in case the output doesn't happen - assert_eq!(h.node_count(), 12); + assert_eq!(h.num_nodes(), 12); let tl = h .nodes() .filter(|n| h.get_optype(*n).is_tail_loop()) diff --git a/hugr-passes/src/dead_code.rs b/hugr-passes/src/dead_code.rs index d92fed1349..25f6cf798b 100644 --- a/hugr-passes/src/dead_code.rs +++ b/hugr-passes/src/dead_code.rs @@ -145,6 +145,7 @@ impl DeadCodeElimPass { if let Some(res) = cache.get(&n) { return *res; } + #[allow(deprecated)] let res = match self.preserve_callback.as_ref()(h.base_hugr(), n) { PreserveNode::MustKeep => true, PreserveNode::CanRemoveIgnoringChildren => false, diff --git a/hugr-passes/src/force_order.rs b/hugr-passes/src/force_order.rs index ad40e21644..ec59ccefd0 100644 --- a/hugr-passes/src/force_order.rs +++ b/hugr-passes/src/force_order.rs @@ -2,11 +2,7 @@ use std::{cmp::Reverse, collections::BinaryHeap, iter}; use hugr_core::{ - hugr::{ - hugrmut::HugrMut, - views::{DescendantsGraph, HierarchyView, SiblingGraph}, - HugrError, - }, + hugr::{hugrmut::HugrMut, HugrError}, ops::{NamedOp, OpTag, OpTrait}, types::EdgeKind, HugrView as _, Node, @@ -51,34 +47,42 @@ pub fn force_order_by_key, K: Ord>( root: Node, rank: impl Fn(&H, Node) -> K, ) -> Result<(), HugrError> { - let dataflow_parents = DescendantsGraph::::try_new(hugr, root)? - .nodes() + let dataflow_parents = hugr + .descendants(root) .filter(|n| hugr.get_optype(*n).tag() <= OpTag::DataflowParent) .collect_vec(); for dp in dataflow_parents { // we filter out the input and output nodes from the topological sort let [i, o] = hugr.get_io(dp).unwrap(); - let rank = |n| rank(hugr, n); - let sg = SiblingGraph::::try_new(hugr, dp)?; - let petgraph = NodeFiltered::from_fn(sg.as_petgraph(), |x| x != dp && x != i && x != o); - let ordered_nodes = ForceOrder::new(&petgraph, &rank) - .iter(&petgraph) - .filter(|&x| { - let expected_edge = Some(EdgeKind::StateOrder); - let optype = hugr.get_optype(x); - if optype.other_input() == expected_edge || optype.other_output() == expected_edge { - assert_eq!( - optype.other_input(), - optype.other_output(), - "Optype does not have both input and output order edge: {}", - optype.name() - ); - true - } else { - false - } - }) - .collect_vec(); + let ordered_nodes = { + let rank = |n| rank(hugr, hugr.from_portgraph_node(n)); + let sg = hugr.region_portgraph(dp); + let petgraph = NodeFiltered::from_fn(&sg, |x| { + let x = hugr.from_portgraph_node(x); + x != dp && x != i && x != o + }); + ForceOrder::new(&petgraph, &rank) + .iter(&petgraph) + .map(|x| hugr.from_portgraph_node(x)) + .filter(|&x| { + let expected_edge = Some(EdgeKind::StateOrder); + let optype = hugr.get_optype(x); + if optype.other_input() == expected_edge + || optype.other_output() == expected_edge + { + assert_eq!( + optype.other_input(), + optype.other_output(), + "Optype does not have both input and output order edge: {}", + optype.name() + ); + true + } else { + false + } + }) + .collect_vec() + }; // we iterate over the topologically sorted nodes, prepending the input // node and suffixing the output node. diff --git a/hugr-passes/src/lower.rs b/hugr-passes/src/lower.rs index 7e68e600af..403e3d84ba 100644 --- a/hugr-passes/src/lower.rs +++ b/hugr-passes/src/lower.rs @@ -141,6 +141,6 @@ mod test { }); assert_eq!(lowered.unwrap().len(), 1); - assert_eq!(h.node_count(), 3); // DFG, input, output + assert_eq!(h.num_nodes(), 3); // DFG, input, output } } diff --git a/hugr-passes/src/merge_bbs.rs b/hugr-passes/src/merge_bbs.rs index 5c76ba51d6..170ff3789b 100644 --- a/hugr-passes/src/merge_bbs.rs +++ b/hugr-passes/src/merge_bbs.rs @@ -59,7 +59,7 @@ fn mk_rep( let succ_sig = succ_ty.inner_signature(); // Make a Hugr with just a single CFG root node having the same signature. - let mut replacement: Hugr = Hugr::new(cfg.root_type().clone()); + let mut replacement: Hugr = Hugr::new(cfg.root_optype().clone()); let merged = replacement.add_node_with_parent(replacement.root(), { let mut merged_block = DataflowBlock { diff --git a/hugr-passes/src/replace_types.rs b/hugr-passes/src/replace_types.rs index d332341260..25249f5ae8 100644 --- a/hugr-passes/src/replace_types.rs +++ b/hugr-passes/src/replace_types.rs @@ -135,7 +135,7 @@ impl NodeTemplate { ) -> Result<(), Option> { let sig = match self { NodeTemplate::SingleOp(op_type) => op_type, - NodeTemplate::CompoundOp(hugr) => hugr.root_type(), + NodeTemplate::CompoundOp(hugr) => hugr.root_optype(), NodeTemplate::Call(_, _) => return Ok(()), // no way to tell } .dataflow_signature(); @@ -1012,7 +1012,7 @@ mod test { // list -> read -> usz just becomes list -> read -> qb // list> -> read> -> opt becomes list -> get -> opt assert_eq!( - h.root_type().dataflow_signature().unwrap().io(), + h.root_optype().dataflow_signature().unwrap().io(), ( &vec![list_type(qb_t()); 2].into(), &vec![qb_t(), option_type(qb_t()).into()].into()