From de0c513b46af102f93a064ae98ad0a2ff1df752a Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Sun, 9 Feb 2025 08:54:54 +0000 Subject: [PATCH 1/4] feat: Add `HugrMutInternals::insert_ports` --- hugr-core/src/hugr/internal.rs | 97 +++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/hugr-core/src/hugr/internal.rs b/hugr-core/src/hugr/internal.rs index 3f1c6b6ff..1f67ff873 100644 --- a/hugr-core/src/hugr/internal.rs +++ b/hugr-core/src/hugr/internal.rs @@ -6,7 +6,8 @@ use std::rc::Rc; use std::sync::Arc; use delegate::delegate; -use portgraph::{LinkView, MultiPortGraph, PortMut, PortView}; +use itertools::Itertools; +use portgraph::{LinkMut, LinkView, MultiPortGraph, PortMut, PortOffset, PortView}; use crate::ops::handle::NodeHandle; use crate::ops::OpTrait; @@ -174,6 +175,26 @@ pub trait HugrMutInternals: RootTagged { self.hugr_mut().add_ports(node, direction, amount) } + /// Insert `amount` new ports for a node, starting at `index`. The + /// `direction` parameter specifies whether to add ports to the incoming or + /// outgoing list. Links from this node are preserved, even when ports are + /// renumbered by the insertion. + /// + /// Returns the range of newly created ports. + /// # Panics + /// + /// If the node is not in the graph. + fn insert_ports( + &mut self, + node: Node, + direction: Direction, + index: usize, + amount: usize, + ) -> Range { + panic_invalid_node(self, node); + self.hugr_mut().insert_ports(node, direction, index, amount) + } + /// Sets the parent of a node. /// /// The node becomes the parent's last child. @@ -260,6 +281,46 @@ impl + AsMut> HugrMutInternals for T { .set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {}) } + fn insert_ports( + &mut self, + node: Node, + direction: Direction, + index: usize, + amount: usize, + ) -> Range { + let old_num_ports = match direction { + Direction::Incoming => self.base_hugr().graph.num_inputs(node.pg_index()), + Direction::Outgoing => self.base_hugr().graph.num_outputs(node.pg_index()), + }; + + let new_ports = 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)) + .unwrap() + }); + let linked_ports = self + .base_hugr() + .graph + .port_links(from_port_index) + .map(|(_, to_subport)| to_subport.port()) + .collect_vec(); + self.hugr_mut().graph.unlink_port(from_port_index); + for linked_port_index in linked_ports { + let _ = self + .hugr_mut() + .graph + .link_ports(to_port_index, linked_port_index) + .expect("Ports exist"); + } + } + index..new_ports.len() + } + fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range { let mut incoming = self.hugr_mut().graph.num_inputs(node.pg_index()); let mut outgoing = self.hugr_mut().graph.num_outputs(node.pg_index()); @@ -309,3 +370,37 @@ impl + AsMut> HugrMutInternals for T { Ok(std::mem::replace(cur, op.into())) } } + +#[cfg(test)] +mod test { + use crate::{ + builder::{DFGBuilder, Dataflow, DataflowHugr}, + extension::prelude::Noop, + hugr::internal::HugrMutInternals as _, + ops::handle::NodeHandle, + types::{Signature, Type}, + Direction, HugrView as _, + }; + + #[test] + fn insert_ports() { + let (nop, mut hugr) = { + let mut builder = DFGBuilder::new(Signature::new_endo(Type::UNIT)).unwrap(); + let [nop_in] = builder.input_wires_arr(); + let nop = builder + .add_dataflow_op(Noop::new(Type::UNIT), [nop_in]) + .unwrap(); + let [nop_out] = nop.outputs_arr(); + ( + nop.node(), + builder.finish_hugr_with_outputs([nop_out]).unwrap(), + ) + }; + let [i, o] = hugr.get_io(hugr.root()).unwrap(); + hugr.insert_ports(nop, Direction::Incoming, 0, 2); + hugr.insert_ports(nop, Direction::Outgoing, 0, 2); + + assert_eq!(hugr.single_linked_input(i, 0), Some((nop, 2.into()))); + assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 2.into()))); + } +} From f096dd727bbadb3f9c6e01e3317434437bd526dc Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Mon, 10 Feb 2025 11:25:03 +0000 Subject: [PATCH 2/4] fixes --- hugr-core/src/hugr/internal.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hugr-core/src/hugr/internal.rs b/hugr-core/src/hugr/internal.rs index 1f67ff873..51cb7af58 100644 --- a/hugr-core/src/hugr/internal.rs +++ b/hugr-core/src/hugr/internal.rs @@ -293,7 +293,7 @@ impl + AsMut> HugrMutInternals for T { Direction::Outgoing => self.base_hugr().graph.num_outputs(node.pg_index()), }; - let new_ports = self.add_ports(node, direction, amount as isize); + 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; @@ -318,7 +318,7 @@ impl + AsMut> HugrMutInternals for T { .expect("Ports exist"); } } - index..new_ports.len() + index..index + amount } fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range { @@ -374,7 +374,7 @@ impl + AsMut> HugrMutInternals for T { #[cfg(test)] mod test { use crate::{ - builder::{DFGBuilder, Dataflow, DataflowHugr}, + builder::{Container, DFGBuilder, Dataflow, DataflowHugr}, extension::prelude::Noop, hugr::internal::HugrMutInternals as _, ops::handle::NodeHandle, @@ -390,6 +390,7 @@ mod test { let nop = builder .add_dataflow_op(Noop::new(Type::UNIT), [nop_in]) .unwrap(); + builder.add_other_wire(nop.node(), builder.output().node()); let [nop_out] = nop.outputs_arr(); ( nop.node(), @@ -397,10 +398,11 @@ mod test { ) }; let [i, o] = hugr.get_io(hugr.root()).unwrap(); - hugr.insert_ports(nop, Direction::Incoming, 0, 2); - hugr.insert_ports(nop, Direction::Outgoing, 0, 2); + assert_eq!(0..2, hugr.insert_ports(nop, Direction::Incoming, 0, 2)); + assert_eq!(1..3, hugr.insert_ports(nop, Direction::Outgoing, 1, 2)); assert_eq!(hugr.single_linked_input(i, 0), Some((nop, 2.into()))); - assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 2.into()))); + assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 0.into()))); + assert_eq!(hugr.single_linked_output(o, 1), Some((nop, 3.into()))); } } From 504afe507eee5203431993156f926fccd0046aa8 Mon Sep 17 00:00:00 2001 From: Douglas Wilson Date: Mon, 10 Feb 2025 11:33:42 +0000 Subject: [PATCH 3/4] with_prelude --- hugr-core/src/hugr/internal.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hugr-core/src/hugr/internal.rs b/hugr-core/src/hugr/internal.rs index 51cb7af58..33d791266 100644 --- a/hugr-core/src/hugr/internal.rs +++ b/hugr-core/src/hugr/internal.rs @@ -385,7 +385,8 @@ mod test { #[test] fn insert_ports() { let (nop, mut hugr) = { - let mut builder = DFGBuilder::new(Signature::new_endo(Type::UNIT)).unwrap(); + let mut builder = + DFGBuilder::new(Signature::new_endo(Type::UNIT).with_prelude()).unwrap(); let [nop_in] = builder.input_wires_arr(); let nop = builder .add_dataflow_op(Noop::new(Type::UNIT), [nop_in]) From 43f4b76c191339af8cc53542ec21e485a43e16d9 Mon Sep 17 00:00:00 2001 From: Douglas Wilson <141026920+doug-q@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:41:35 +0000 Subject: [PATCH 4/4] Update hugr-core/src/hugr/internal.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Agustín Borgna <121866228+aborgna-q@users.noreply.github.com> --- hugr-core/src/hugr/internal.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hugr-core/src/hugr/internal.rs b/hugr-core/src/hugr/internal.rs index 33d791266..75b0aab1d 100644 --- a/hugr-core/src/hugr/internal.rs +++ b/hugr-core/src/hugr/internal.rs @@ -288,10 +288,7 @@ impl + AsMut> HugrMutInternals for T { index: usize, amount: usize, ) -> Range { - let old_num_ports = match direction { - Direction::Incoming => self.base_hugr().graph.num_inputs(node.pg_index()), - Direction::Outgoing => self.base_hugr().graph.num_outputs(node.pg_index()), - }; + let old_num_ports = self.base_hugr().graph.num_ports(node.pg_index(), direction); self.add_ports(node, direction, amount as isize);