Skip to content

Commit

Permalink
feat!: Use RPITIT for graph traits (#156)
Browse files Browse the repository at this point in the history
Closes #119

This should simplify the implementation of #155, and any other new
wrapper.

BREAKING CHANGE: Graph trait methods now return `impl Iterator`s instead
of named associated types.
  • Loading branch information
aborgna-q authored Nov 14, 2024
1 parent c91476b commit ebaed87
Show file tree
Hide file tree
Showing 11 changed files with 453 additions and 565 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ proptest = { version = "1.1.0", optional = true }
rand = { version = "0.8.5", optional = true }
petgraph = { version = "0.6.3", optional = true }
delegate = "0.13.0"
context-iterators = "0.2.0"
itertools = "0.13.0"

[features]
Expand Down
3 changes: 2 additions & 1 deletion benches/benchmarks/portgraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ fn remove_all_unordered(graph: &mut PortGraph) {
}
// Remove all remaining nodes
while graph.node_count() > 0 {
graph.remove_node(graph.nodes_iter().next().unwrap());
let next = graph.nodes_iter().next().unwrap();
graph.remove_node(next);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/algorithms/post_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl<'graph> Iterator for PostOrder<'graph> {
if !self.visited.replace(next.index(), true) {
// The node is visited for the first time. We leave the node on the stack and push
// all of its neighbours in the traversal direction.
for port in self.graph.ports(next, self.direction).rev() {
for port in self.graph._ports(next, self.direction).rev() {
if self.ignore_port(next, port) {
continue;
}
Expand Down
192 changes: 50 additions & 142 deletions src/multiportgraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ mod iter;
pub use self::iter::{
Neighbours, NodeConnections, NodeLinks, NodeSubports, Nodes, PortLinks, Ports,
};
use crate::portgraph::{NodePortOffsets, NodePorts, PortOperation};
use crate::portgraph::PortOperation;
use crate::view::{LinkMut, MultiMut, MultiView, PortMut};
use crate::{
Direction, LinkError, LinkView, NodeIndex, PortGraph, PortIndex, PortOffset, PortView,
SecondaryMap,
};
use delegate::delegate;

use bitvec::vec::BitVec;

Expand Down Expand Up @@ -97,77 +98,6 @@ impl MultiPortGraph {
}

impl PortView for MultiPortGraph {
type Nodes<'a> = Nodes<'a>
where
Self: 'a;

type Ports<'a> = Ports<'a>
where
Self: 'a;

type NodePorts<'a> = NodePorts
where
Self: 'a;

type NodePortOffsets<'a> = NodePortOffsets
where
Self: 'a;

#[inline]
fn port_direction(&self, port: impl Into<PortIndex>) -> Option<Direction> {
self.graph.port_direction(port.into())
}

#[inline]
fn port_node(&self, port: impl Into<PortIndex>) -> Option<NodeIndex> {
self.graph.port_node(port.into())
}

#[inline]
fn port_offset(&self, port: impl Into<PortIndex>) -> Option<PortOffset> {
self.graph.port_offset(port.into())
}

#[inline]
fn port_index(&self, node: NodeIndex, offset: PortOffset) -> Option<PortIndex> {
self.graph.port_index(node, offset)
}

#[inline]
fn ports(&self, node: NodeIndex, direction: Direction) -> Self::NodePorts<'_> {
self.graph.ports(node, direction)
}

#[inline]
fn all_ports(&self, node: NodeIndex) -> Self::NodePorts<'_> {
self.graph.all_ports(node)
}

#[inline]
fn input(&self, node: NodeIndex, offset: usize) -> Option<PortIndex> {
self.graph.input(node, offset)
}

#[inline]
fn output(&self, node: NodeIndex, offset: usize) -> Option<PortIndex> {
self.graph.output(node, offset)
}

#[inline]
fn num_ports(&self, node: NodeIndex, direction: Direction) -> usize {
self.graph.num_ports(node, direction)
}

#[inline]
fn port_offsets(&self, node: NodeIndex, direction: Direction) -> Self::NodePortOffsets<'_> {
self.graph.port_offsets(node, direction)
}

#[inline]
fn all_port_offsets(&self, node: NodeIndex) -> Self::NodePortOffsets<'_> {
self.graph.all_port_offsets(node)
}

#[inline]
fn contains_node(&self, node: NodeIndex) -> bool {
self.graph.contains_node(node) && !self.copy_node.get(node)
Expand Down Expand Up @@ -197,18 +127,19 @@ impl PortView for MultiPortGraph {
// addition to all the subports.
self.graph.port_count() - self.subport_count - self.copy_node_count
}

#[inline]
fn nodes_iter(&self) -> Self::Nodes<'_> {
fn nodes_iter(&self) -> impl Iterator<Item = NodeIndex> + Clone {
self::iter::Nodes {
multigraph: self,
iter: self.graph.nodes_iter(),
iter: self.graph._nodes_iter(),
len: self.node_count(),
}
}

#[inline]
fn ports_iter(&self) -> Self::Ports<'_> {
Ports::new(self, self.graph.ports_iter())
fn ports_iter(&self) -> impl Iterator<Item = PortIndex> + Clone {
Ports::new(self, self.graph._ports_iter())
}

#[inline]
Expand All @@ -222,9 +153,21 @@ impl PortView for MultiPortGraph {
self.graph.port_capacity() - self.subport_count - self.copy_node_count
}

#[inline]
fn node_port_capacity(&self, node: NodeIndex) -> usize {
self.graph.node_port_capacity(node)
delegate! {
to (self.graph) {
fn port_direction(&self, port: impl Into<PortIndex>) -> Option<Direction>;
fn port_node(&self, port: impl Into<PortIndex>) -> Option<NodeIndex>;
fn port_offset(&self, port: impl Into<PortIndex>) -> Option<PortOffset>;
fn port_index(&self, node: NodeIndex, offset: PortOffset) -> Option<PortIndex>;
fn ports(&self, node: NodeIndex, direction: Direction) -> impl Iterator<Item = PortIndex> + Clone;
fn all_ports(&self, node: NodeIndex) -> impl Iterator<Item = PortIndex> + Clone;
fn input(&self, node: NodeIndex, offset: usize) -> Option<PortIndex>;
fn output(&self, node: NodeIndex, offset: usize) -> Option<PortIndex>;
fn num_ports(&self, node: NodeIndex, direction: Direction) -> usize;
fn port_offsets(&self, node: NodeIndex, direction: Direction) -> impl Iterator<Item = PortOffset> + Clone;
fn all_port_offsets(&self, node: NodeIndex) -> impl Iterator<Item = PortOffset> + Clone;
fn node_port_capacity(&self, node: NodeIndex) -> usize;
}
}
}

Expand All @@ -236,7 +179,7 @@ impl PortMut for MultiPortGraph {

fn remove_node(&mut self, node: NodeIndex) {
debug_assert!(!self.copy_node.get(node));
for port in self.graph.all_ports(node) {
for port in self.graph._all_ports(node) {
if *self.multiport.get(port) {
self.unlink_port(port);
}
Expand Down Expand Up @@ -316,58 +259,28 @@ impl PortMut for MultiPortGraph {
impl LinkView for MultiPortGraph {
type LinkEndpoint = SubportIndex;

type Neighbours<'a> = Neighbours<'a>
where
Self: 'a;

type NodeConnections<'a> = NodeConnections<'a>
where
Self: 'a;

type NodeLinks<'a> = NodeLinks<'a>
where
Self: 'a;

type PortLinks<'a> = PortLinks<'a>
where
Self: 'a;

#[inline]
fn get_connections(&self, from: NodeIndex, to: NodeIndex) -> Self::NodeConnections<'_> {
NodeConnections::new(self, to, self.output_links(from))
}

#[inline]
fn port_links(&self, port: PortIndex) -> Self::PortLinks<'_> {
PortLinks::new(self, port)
}

#[inline]
fn links(&self, node: NodeIndex, direction: Direction) -> Self::NodeLinks<'_> {
NodeLinks::new(self, self.ports(node, direction), 0..0)
}

#[inline]
fn all_links(&self, node: NodeIndex) -> Self::NodeLinks<'_> {
let output_ports = self.graph.node_outgoing_ports(node);
NodeLinks::new(self, self.all_ports(node), output_ports)
}

#[inline]
fn neighbours(&self, node: NodeIndex, direction: Direction) -> Self::Neighbours<'_> {
Neighbours::new(self, self.subports(node, direction), node, false)
}

#[inline]
fn all_neighbours(&self, node: NodeIndex) -> Self::Neighbours<'_> {
Neighbours::new(self, self.all_subports(node), node, true)
}

#[inline]
fn link_count(&self) -> usize {
// Do not count the links between copy nodes and their main nodes.
self.graph.link_count() - self.copy_node_count
}

delegate! {
to self {
#[call(_get_connections)]
fn get_connections(&self, from: NodeIndex, to: NodeIndex) -> impl Iterator<Item = (Self::LinkEndpoint, Self::LinkEndpoint)> + Clone;
#[call(_port_links)]
fn port_links(&self, port: PortIndex) -> impl Iterator<Item = (Self::LinkEndpoint, Self::LinkEndpoint)> + Clone;
#[call(_links)]
fn links(&self, node: NodeIndex, direction: Direction) -> impl Iterator<Item = (Self::LinkEndpoint, Self::LinkEndpoint)> + Clone;
#[call(_all_links)]
fn all_links(&self, node: NodeIndex) -> impl Iterator<Item = (Self::LinkEndpoint, Self::LinkEndpoint)> + Clone;
#[call(_neighbours)]
fn neighbours(&self, node: NodeIndex, direction: Direction) -> impl Iterator<Item = NodeIndex> + Clone;
#[call(_all_neighbours)]
fn all_neighbours(&self, node: NodeIndex) -> impl Iterator<Item = NodeIndex> + Clone;
}
}
}

impl LinkMut for MultiPortGraph {
Expand Down Expand Up @@ -396,24 +309,19 @@ impl LinkMut for MultiPortGraph {
}

impl MultiView for MultiPortGraph {
type NodeSubports<'a> = NodeSubports<'a>
where
Self: 'a;

fn subport_link(&self, subport: SubportIndex) -> Option<SubportIndex> {
let subport_index = self.get_subport_index(subport)?;
let link = self.graph.port_link(subport_index)?;
self.get_subport_from_index(link)
}

#[inline]
fn subports(&self, node: NodeIndex, direction: Direction) -> Self::NodeSubports<'_> {
NodeSubports::new(self, self.graph.ports(node, direction))
}

#[inline]
fn all_subports(&self, node: NodeIndex) -> Self::NodeSubports<'_> {
NodeSubports::new(self, self.graph.all_ports(node))
delegate! {
to self {
#[call(_subports)]
fn subports(&self, node: NodeIndex, direction: Direction) -> impl Iterator<Item = SubportIndex> + Clone;
#[call(_all_subports)]
fn all_subports(&self, node: NodeIndex) -> impl Iterator<Item = SubportIndex> + Clone;
}
}
}

Expand Down Expand Up @@ -459,7 +367,7 @@ impl MultiPortGraph {
let link = self.graph.links(copy_node, dir).next();
let link = link.map(|(_, tgt)| self.get_subport_from_index(tgt).unwrap());

let mut subports = self.graph.ports(copy_node, dir.reverse());
let mut subports = self.graph._ports(copy_node, dir.reverse());
self.multiport.set(copy_port, false);
self.multiport.set(main_node_port, false);
self.copy_node.set(copy_node, false);
Expand Down Expand Up @@ -583,8 +491,8 @@ impl MultiPortGraph {
/// Returns the PortIndex from the main node that connects to this copy node.
fn copy_node_main_port(&self, copy_node: NodeIndex) -> Option<PortIndex> {
debug_assert!(self.copy_node.get(copy_node));
let mut incoming = self.graph.inputs(copy_node);
let mut outgoing = self.graph.outputs(copy_node);
let mut incoming = self.graph._inputs(copy_node);
let mut outgoing = self.graph._outputs(copy_node);

let internal_copy_port = match (incoming.len(), outgoing.len()) {
(1, 1) => {
Expand Down
69 changes: 67 additions & 2 deletions src/multiportgraph/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,71 @@ use super::{MultiPortGraph, SubportIndex};
use crate::portgraph::{self, NodePorts};
use crate::{Direction, LinkView, NodeIndex, PortIndex, PortOffset, PortView};

/// Iterator methods for [`MultiPortGraph`] with concrete return types.
///
/// Used internally by other iterator implementations to avoid the generic RPITIT return types.
impl MultiPortGraph {
#[inline]
/// Returns an iterator over every pair of matching ports connecting `from`
/// with `to`.
pub(crate) fn _get_connections(&self, from: NodeIndex, to: NodeIndex) -> NodeConnections {
NodeConnections::new(self, to, self._output_links(from))
}

/// Returns the port that the given `port` is linked to.
#[inline]
pub(crate) fn _port_links(&self, port: PortIndex) -> PortLinks {
PortLinks::new(self, port)
}

/// Iterates over the connected links of the `node` in the given
/// `direction`.
#[inline]
pub(crate) fn _links(&self, node: NodeIndex, direction: Direction) -> NodeLinks {
NodeLinks::new(self, self.graph._ports(node, direction), 0..0)
}

/// Iterates over the connected input and output links of the `node` in sequence.
#[inline]
pub(crate) fn _all_links(&self, node: NodeIndex) -> NodeLinks {
let output_ports = self.graph.node_outgoing_ports(node);
NodeLinks::new(self, self.graph._all_ports(node), output_ports)
}

/// Iterates over the connected output links of the `node`. Shorthand for
/// [`LinkView::links`].
#[must_use]
#[inline]
pub(crate) fn _output_links(&self, node: NodeIndex) -> NodeLinks {
self._links(node, Direction::Outgoing)
}

/// Iterates over neighbour nodes in the given `direction`.
/// May contain duplicates if the graph has multiple links between nodes.
#[inline]
pub(crate) fn _neighbours(&self, node: NodeIndex, direction: Direction) -> Neighbours {
Neighbours::new(self, self._subports(node, direction), node, false)
}

/// Iterates over the input and output neighbours of the `node` in sequence.
#[inline]
pub(crate) fn _all_neighbours(&self, node: NodeIndex) -> Neighbours {
Neighbours::new(self, self._all_subports(node), node, true)
}

/// Iterates over all the subports of the `node` in the given `direction`.
#[inline]
pub(crate) fn _subports(&self, node: NodeIndex, direction: Direction) -> NodeSubports {
NodeSubports::new(self, self.graph._ports(node, direction))
}

/// Iterates over the input and output subports of the `node` in sequence.
#[inline]
pub(crate) fn _all_subports(&self, node: NodeIndex) -> NodeSubports {
NodeSubports::new(self, self.graph._all_ports(node))
}
}

/// Iterator over the nodes of a graph.
#[derive(Clone)]
pub struct Nodes<'a> {
Expand Down Expand Up @@ -105,7 +170,7 @@ impl<'a> Iterator for NodeSubports<'a> {
self.current_subports = self
.multigraph
.graph
.port_offsets(copy_node, dir)
._port_offsets(copy_node, dir)
.as_range(dir);
} else {
// The port is not a multiport, return the single subport.
Expand Down Expand Up @@ -316,7 +381,7 @@ impl<'a> PortLinks<'a> {
if multigraph.is_multiport(port) {
let copy_node = multigraph.get_copy_node(port).unwrap();
let dir = multigraph.graph.port_direction(port).unwrap();
let subports = multigraph.graph.ports(copy_node, dir).enumerate();
let subports = multigraph.graph._ports(copy_node, dir).enumerate();
Self::Multiport {
multigraph,
port,
Expand Down
Loading

0 comments on commit ebaed87

Please sign in to comment.