Skip to content

Conversation

@acl-cqc
Copy link
Contributor

@acl-cqc acl-cqc commented Aug 13, 2025

Closes #2355.

This adds a new trait HugrLinking: HugrMut with methods insert_link_hugr_by_node and insert_link_view_by_node that allow inserting a Hugr/View into self - the entrypoint subtree (anywhere) and/or the module-children (under the module-root of self). An error is raised if you're trying to insert the entrypoint-subtree into two places. The added nodes can be linked i.e. static edges added from module-children to uses, both from new to existing or vice versa. The new methods are default-implemented on top of HugrMut::insert_(view_)forest, and there's a blanket impl for any HugrMut, so the trait is just to keep these methods separated out.

Note that it would be possible to deprecate insert_hugr now, although I have not: insert_link_hugr_by_node(other, Some(parent), HashMap::new()) does the same job (explicitly not copying any module-children), and returns an error, which is probably what we want.

@codecov
Copy link

codecov bot commented Aug 13, 2025

Codecov Report

❌ Patch coverage is 97.60192% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.94%. Comparing base (4b38008) to head (70b4e3f).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
hugr-core/src/builder/build_traits.rs 83.72% 5 Missing and 2 partials ⚠️
hugr-core/src/hugr/linking.rs 99.34% 2 Missing ⚠️
hugr-core/src/builder/module.rs 98.11% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2521      +/-   ##
==========================================
+ Coverage   82.75%   82.94%   +0.19%     
==========================================
  Files         252      254       +2     
  Lines       47065    47590     +525     
  Branches    42581    43101     +520     
==========================================
+ Hits        38950    39475     +525     
+ Misses       6055     6052       -3     
- Partials     2060     2063       +3     
Flag Coverage Δ
python 91.42% <ø> (+<0.01%) ⬆️
rust 82.06% <97.60%> (+0.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@acl-cqc acl-cqc force-pushed the acl/insert_link_nodes branch from 3a47eb3 to 5774665 Compare August 13, 2025 11:15
@acl-cqc acl-cqc requested a review from aborgna-q August 13, 2025 11:24
@acl-cqc acl-cqc marked this pull request as ready for review August 13, 2025 11:24
@acl-cqc acl-cqc requested a review from a team as a code owner August 13, 2025 11:24
@acl-cqc acl-cqc marked this pull request as draft August 13, 2025 12:32
@acl-cqc
Copy link
Contributor Author

acl-cqc commented Aug 13, 2025

Just realized I am not handling corner cases of same node in target Hugr being replaced by multiple new (::Added) nodes, or being replaced while also being ::UseExistingd...these will break ATM

transfers: Transfers<SN, TGT::Node>,
node_map: &mut HashMap<SN, TGT::Node>,
) {
// Resolve `use_existing` first in case the existing node is also replaced by
Copy link
Contributor Author

@acl-cqc acl-cqc Aug 13, 2025

Choose a reason for hiding this comment

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

No test yet, coming up...(EDIT: added)

Alternatively we could error if the same existing-node is target of both a replace and a UseExisting.

@acl-cqc acl-cqc marked this pull request as ready for review August 13, 2025 13:29
@acl-cqc acl-cqc changed the title feat: add trait+funcs for linking Hugrs explicitly by Node feat: add trait+funcs for linking Hugrs explicitly by Node (linking 2/4) Aug 25, 2025
Base automatically changed from acl/insert_forest to main September 2, 2025 13:16
@acl-cqc
Copy link
Contributor Author

acl-cqc commented Sep 2, 2025

Ok, #2518 now merged into main, and I hope that's fixed a number of issues here. As mentioned, I've gone with trait HugrLinking and add_hugr_link_nodes / add_view_link_nodes, and Dataflow builder versions have extra with_wires. ModuleBuilder I've gone with the slightly inconsistent link_hugr_by_node as later I expect just to add a "link_hugr", but it might be more consistent to call it add_hugr_link_nodes there too (but the followup would then be..."add_hugr_link"?? "add_link_hugr"?? hmmm, you see why 😉 )

@acl-cqc acl-cqc requested a review from lmondada September 2, 2025 15:46
///
/// This is done by module-children from the inserted (source) Hugr replacing, or being replaced by,
/// module-children already in the target Hugr; static edges from the replaced node,
/// are transferred to come from the replacing node, and the replaced node(/subtree) then deleted.
Copy link
Contributor

Choose a reason for hiding this comment

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

Excellent, I think HugrLinking is very good.

/// If `parent` is `Some` but not in the graph.
#[allow(clippy::type_complexity)]
fn insert_from_view_link_nodes<H: HugrView>(
fn add_view_link_nodes<H: HugrView>(
Copy link
Contributor

@lmondada lmondada Sep 3, 2025

Choose a reason for hiding this comment

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

Ok, good name proposals!

  1. I prefer insert to add (add sounds to me like adding an element to a container, whereas insert is a more complex process?) I admit this is subjective, so up to you.

  2. Given your explanation, I think a good suffix for the names would be _by_nodes. Names with by are pretty idiomatic.

  3. If you say linking by name will be the most common use case, then I am not fussed if the method names for linking explicitly by node are quite verbose. As you suggest I would just drop the by_nodes suffix for the link-by-name versions.

So maybe insert_link_view_by_nodes and insert_link_hugr_by_nodes? I don't know at this point 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, so

  • I think you're right about insert rather than add: I think "insert" is "put the entrypoint-subtree under a new parent" whereas "link" is "do stuff with the module children" (only). Using "add" for "maybe insert" is a faux pas, will just go with insert.
  • Let's also establish the "link....by_nodes" convention (foreshadowing upcoming+shorter "link...." that's by name), replacing current "...._link_nodes".
  • I also think rejecting names for being too long may be a bad move here. There's an old idea that the more a method does, the longer its name should be. These methods do quite a lot, so long names are at least ok....
  • Hence: I propose: HugrMut::insert_link_hugr_by_node (and s/hugr/view/), Dataflow builder add_link_hugr_by_node (where add in the builder means insert elsewhere but nvm), Module builder link_hugr_by_node (without the add: it only does stuff with module children).

Will enact shortly unless you object @lmondada...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh, by_node singular or plural? I think I favour singular

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes I like it!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, done. insert_link_view_.... isn't great because there is also a thing called a LinkView but it is portgraph really.

And the Dataflow builder now has add_link_hugr_by_node_with_wires which is a lot of suffixes 👎 so better ideas welcome, but add.....with_wires_by_node is worse (it's not the wires that are by node it's the "link"!)

@acl-cqc acl-cqc changed the title feat: add trait+funcs for linking Hugrs explicitly by Node (linking 2/4) feat: add trait+funcs for linking Hugrs explicitly by Node Sep 16, 2025
@acl-cqc acl-cqc enabled auto-merge September 16, 2025 09:14
@acl-cqc acl-cqc disabled auto-merge September 16, 2025 09:14
@acl-cqc acl-cqc enabled auto-merge September 16, 2025 09:16
@acl-cqc acl-cqc added this pull request to the merge queue Sep 16, 2025
Merged via the queue into main with commit ef06013 Sep 16, 2025
29 checks passed
@acl-cqc acl-cqc deleted the acl/insert_link_nodes branch September 16, 2025 09:21
@hugrbot hugrbot mentioned this pull request Sep 16, 2025
github-merge-queue bot pushed a commit that referenced this pull request Sep 30, 2025
## 🤖 New release

* `hugr-model`: 0.22.4 -> 0.23.0 (✓ API compatible changes)
* `hugr-core`: 0.22.4 -> 0.23.0 (⚠ API breaking changes)
* `hugr-llvm`: 0.22.4 -> 0.23.0 (✓ API compatible changes)
* `hugr-passes`: 0.22.4 -> 0.23.0 (⚠ API breaking changes)
* `hugr-persistent`: 0.2.3 -> 0.3.0 (✓ API compatible changes)
* `hugr`: 0.22.4 -> 0.23.0 (✓ API compatible changes)
* `hugr-cli`: 0.22.4 -> 0.23.0 (✓ API compatible changes)

### ⚠ `hugr-core` breaking changes

```text
--- failure enum_variant_missing: pub enum variant removed or renamed ---

Description:
A publicly-visible enum has at least one variant that is no longer available under its prior name. It may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/enum_variant_missing.ron

Failed in:
  variant PackageEncodingError::ExtensionVersion, previously in file /tmp/.tmp8eoQo1/hugr-core/src/envelope/package_json.rs:89

--- failure function_parameter_count_changed: pub fn parameter count changed ---

Description:
A publicly-visible function now takes a different number of parameters.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#fn-change-arity
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/function_parameter_count_changed.ron

Failed in:
  hugr_core::import::import_package now takes 3 parameters instead of 2, in /tmp/.tmpBTXSed/hugr/hugr-core/src/import.rs:187

--- failure struct_missing: pub struct removed or renamed ---

Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/struct_missing.ron

Failed in:
  struct hugr_core::extension::prelude::PRELUDE_REGISTRY, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
  struct hugr_core::extension::PRELUDE_REGISTRY, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
  struct hugr_core::std_extensions::logic::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/logic.rs:134
  struct hugr_core::extension::prelude::PRELUDE, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
  struct hugr_core::extension::PRELUDE, previously in file /tmp/.tmp8eoQo1/hugr-core/src/extension/prelude.rs:43
  struct hugr_core::std_extensions::ptr::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/ptr.rs:112
  struct hugr_core::std_extensions::arithmetic::int_types::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/int_types.rs:209
  struct hugr_core::std_extensions::arithmetic::conversions::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/conversions.rs:174
  struct hugr_core::std_extensions::collections::array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/array.rs:93
  struct hugr_core::std_extensions::arithmetic::int_types::INT_TYPES, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/int_types.rs:49
  struct hugr_core::std_extensions::arithmetic::float_types::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/float_types.rs:104
  struct hugr_core::std_extensions::collections::static_array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/static_array.rs:142
  struct hugr_core::std_extensions::collections::list::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/list.rs:289
  struct hugr_core::std_extensions::STD_REG, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions.rs:35
  struct hugr_core::std_extensions::collections::value_array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/value_array.rs:99
  struct hugr_core::std_extensions::collections::borrow_array::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/collections/borrow_array.rs:290
  struct hugr_core::std_extensions::arithmetic::float_ops::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/float_ops.rs:115
  struct hugr_core::std_extensions::arithmetic::int_ops::EXTENSION, previously in file /tmp/.tmp8eoQo1/hugr-core/src/std_extensions/arithmetic/int_ops.rs:254
```

### ⚠ `hugr-passes` breaking changes

```text
--- failure enum_missing: pub enum removed or renamed ---

Description:
A publicly-visible enum cannot be imported by its prior path. A `pub use` may have been removed, or the enum itself may have been renamed or removed entirely.
        ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
       impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.43.0/src/lints/enum_missing.ron

Failed in:
  enum hugr_passes::non_local::NonLocalEdgesError, previously in file /tmp/.tmp8eoQo1/hugr-passes/src/non_local.rs:57
```

<details><summary><i><b>Changelog</b></i></summary><p>

## `hugr-model`

<blockquote>

##
[0.23.0](hugr-model-v0.22.4...hugr-model-v0.23.0)
- 2025-09-30

### Bug Fixes

- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))

### New Features

- Documentation and error hints
([#2523](#2523))
</blockquote>

## `hugr-core`

<blockquote>

##
[0.23.0](hugr-core-v0.22.4...hugr-core-v0.23.0)
- 2025-09-30

### Bug Fixes

- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))
- *(core)* check extension versions on model import
([#2580](#2580))
- [**breaking**] test extension version compatibility on ModelWithExts
([#2587](#2587))
- *(core)* check used extension versions against resolved extensions
([#2588](#2588))
- [**breaking**] model import loads Package extensions
([#2590](#2590))

### Miscellaneous Tasks

- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))

### New Features

- add trait+funcs for linking Hugrs explicitly by Node
([#2521](#2521))
- Documentation and error hints
([#2523](#2523))
- Allow creating DFG builders from existing hugrs
([#2562](#2562))
- add_input/output for arbitrary DFGBuilders
([#2564](#2564))
- [**breaking**] Return error instead of panicking in
DFGWrapper::add_{in,out}put
([#2571](#2571))
- *(core)* inner acccesors for WithGenerator error
([#2583](#2583))
- Normalize CFGs ([#2591](#2591))

### Refactor

- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>

## `hugr-llvm`

<blockquote>

##
[0.23.0](hugr-llvm-v0.22.4...hugr-llvm-v0.23.0)
- 2025-09-30

### Miscellaneous Tasks

- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))

### Refactor

- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))

### Testing

- Add framework for LLVM execution tests involving panics
([#2568](#2568))
</blockquote>

## `hugr-passes`

<blockquote>

##
[0.23.0](hugr-passes-v0.22.4...hugr-passes-v0.23.0)
- 2025-09-30

### Bug Fixes

- DeadCodeElim keeps consumers of linear outputs
([#2560](#2560))
- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))

### Miscellaneous Tasks

- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))

### New Features

- [**breaking**] DeadCodeElimPass reports error on non-existent
entry_points ([#2566](#2566))
- Normalize CFGs ([#2591](#2591))

### Refactor

- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>

## `hugr-persistent`

<blockquote>

##
[0.3.0](hugr-persistent-v0.2.3...hugr-persistent-v0.3.0)
- 2025-09-30

### Miscellaneous Tasks

- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))

### Refactor

- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>

## `hugr`

<blockquote>

##
[0.23.0](hugr-v0.22.4...hugr-v0.23.0)
- 2025-09-30

### Bug Fixes

- DeadCodeElim keeps consumers of linear outputs
([#2560](#2560))
- [**breaking**] Appease `cargo-audit` by replacing unmaintained
dependencies ([#2572](#2572))
- *(core)* check extension versions on model import
([#2580](#2580))
- [**breaking**] test extension version compatibility on ModelWithExts
([#2587](#2587))
- *(core)* check used extension versions against resolved extensions
([#2588](#2588))
- [**breaking**] model import loads Package extensions
([#2590](#2590))

### Miscellaneous Tasks

- [**breaking**] Cleanup deprecated definitions
([#2594](#2594))

### New Features

- [**breaking**] DeadCodeElimPass reports error on non-existent
entry_points ([#2566](#2566))
- add trait+funcs for linking Hugrs explicitly by Node
([#2521](#2521))
- Documentation and error hints
([#2523](#2523))
- Allow creating DFG builders from existing hugrs
([#2562](#2562))
- add_input/output for arbitrary DFGBuilders
([#2564](#2564))
- [**breaking**] Return error instead of panicking in
DFGWrapper::add_{in,out}put
([#2571](#2571))
- *(core)* inner acccesors for WithGenerator error
([#2583](#2583))
- Normalize CFGs ([#2591](#2591))

### Refactor

- [**breaking**] Replace lazy_static with std::sync::LazyLock
([#2567](#2567))
</blockquote>

## `hugr-cli`

<blockquote>

##
[0.22.3](hugr-cli-v0.22.2...hugr-cli-v0.22.3)
- 2025-09-11

### New Features

- *(hugr-cli)* CliError::validate helper
([#2507](#2507))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
@hugrbot hugrbot mentioned this pull request Oct 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linking with explicit Node directives (no names)

3 participants