Skip to content

Commit

Permalink
feat: Add SiblingSubgraph::from_node (#1655)
Browse files Browse the repository at this point in the history
Complementary improvement to #1654.
Creating a k-node subgraph in an n-node graph should ideally be `O(k)`.
However, due to CQCL/portgraph#155 this ends
up being `O(n)`.

For `k=1`, this results in a linear cost overhead.
This PR adds a special case (written by @doug-q) that completely skips
the unnecessary checks.

```
group                         before                                 from_node
-----                         ------                                 ---------
multinode_subgraph/10         1.01     17.7±0.26µs        ? ?/sec    1.00     17.5±0.23µs        ? ?/sec
multinode_subgraph/100        1.00   169.1±11.34µs        ? ?/sec    1.00    168.8±4.37µs        ? ?/sec
multinode_subgraph/1000       1.01      2.3±0.46ms        ? ?/sec    1.00      2.3±0.34ms        ? ?/sec
singleton_subgraph/10         12.26     3.0±0.06µs        ? ?/sec    1.00   245.6±21.24ns        ? ?/sec
singleton_subgraph/100        20.01     4.7±0.06µs        ? ?/sec    1.00    234.4±6.50ns        ? ?/sec
singleton_subgraph/1000       93.34    22.0±0.25µs        ? ?/sec    1.00    235.6±4.93ns        ? ?/sec
```

---------

Co-authored-by: Douglas Wilson <[email protected]>
  • Loading branch information
aborgna-q and doug-q authored Nov 15, 2024
1 parent e63878f commit c2c5752
Showing 1 changed file with 34 additions and 1 deletion.
35 changes: 34 additions & 1 deletion hugr-core/src/hugr/views/sibling_subgraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ impl SiblingSubgraph {
/// The subgraph signature will be given by the types of the incoming and
/// outgoing edges ordered by the node order in `nodes` and within each node
/// by the port order.

///
/// The in- and out-arity of the signature will match the
/// number of incoming and outgoing edges respectively. In particular, the
/// assumption is made that no two incoming edges have the same source
Expand All @@ -238,6 +238,14 @@ impl SiblingSubgraph {
checker: &impl ConvexChecker,
) -> Result<Self, InvalidSubgraph> {
let nodes = nodes.into();

// If there's one or less nodes, we don't need to check convexity.
match nodes.as_slice() {
[] => return Err(InvalidSubgraph::EmptySubgraph),
[node] => return Ok(Self::from_node(*node, hugr)),
_ => {}
};

let nodes_set = nodes.iter().copied().collect::<HashSet<_>>();
let incoming_edges = nodes
.iter()
Expand Down Expand Up @@ -265,6 +273,31 @@ impl SiblingSubgraph {
Self::try_new_with_checker(inputs, outputs, hugr, checker)
}

/// Create a subgraph containing a single node.
///
/// The subgraph signature will be given by signature of the node.
pub fn from_node(node: Node, hugr: &impl HugrView) -> Self {
// TODO once https://github.com/CQCL/portgraph/issues/155
// is fixed we can just call try_from_nodes here.
// Until then, doing this saves a lot of work.
let nodes = vec![node];
let inputs = hugr
.node_inputs(node)
.filter(|&p| hugr.is_linked(node, p))
.map(|p| vec![(node, p)])
.collect_vec();
let outputs = hugr
.node_outputs(node)
.filter_map(|p| hugr.is_linked(node, p).then_some((node, p)))
.collect_vec();

Self {
nodes,
inputs,
outputs,
}
}

/// An iterator over the nodes in the subgraph.
pub fn nodes(&self) -> &[Node] {
&self.nodes
Expand Down

0 comments on commit c2c5752

Please sign in to comment.