Skip to content

✨ Enable Cut View on AIG#315

Open
wjrforcyber wants to merge 7 commits into
marcelwa:mainfrom
wjrforcyber:cut_view
Open

✨ Enable Cut View on AIG#315
wjrforcyber wants to merge 7 commits into
marcelwa:mainfrom
wjrforcyber:cut_view

Conversation

@wjrforcyber

@wjrforcyber wjrforcyber commented Mar 15, 2026

Copy link
Copy Markdown
Contributor

Description

Expose cut view (and maybe in the future window view) is convenient for developers to do structure level change.

Checklist:

  • The pull request only contains commits that are related to it.
  • I have added appropriate tests and documentation.
  • I have made sure that all CI jobs on GitHub pass.
  • The pull request introduces no new warnings and follows the project's style guidelines.

Summary by CodeRabbit

  • New Features
    • Immutable cut-view class for logic networks: construct from leaves+root, read-only inspection (nodes, gates, pis/pos, counts), copy/clone support, and informative string representation. Mutating operations raise runtime errors on cut views.
  • Documentation
    • New tutorial subsection with ipython examples and validity notes for cut views.
  • Tests
    • End-to-end tests covering counts, iteration, index↔node roundtrips, repr, copy semantics, and immutability.

@coderabbitai

coderabbitai Bot commented Mar 15, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an immutable Cut view API (CutAig / Cut{Network}) with Python type stubs, C++ bindings, docs, and tests; exposes read/query operations, blocks mutating network operations on the view, and clears source-network visited flags before constructing the cut.

Changes

Cut View API (CutAig / Cut{Network})

Layer / File(s) Summary
Python API type contract
python/aigverse/networks.pyi
Defines CutAig(Aig) with two constructor overloads (leaf indices or signals), copy/clone methods, read-only accessors (nodes, gates, pis, pos, is_pi, node_to_index, index_to_node), size/count properties (size, num_pis, num_pos, num_gates), and explicit stubs for immutable-view restrictions (all create_* and clone_node methods marked unavailable).
C++ binding and runtime implementation
src/aigverse/networks/logic_networks.cpp
Implements Cut{Network} binding backed by mockturtle::cut_view<Ntk>, clears visited flags on input network before construction, binds constructors (node/signal leaf variants), clone/copy methods, all read accessors, index mapping, __repr__ formatting, and throws std::runtime_error for all mutating create_* and clone_node operations to enforce immutability.
Documentation and usage examples
docs/aigs.md
Adds "AIGs with Cut Views" section demonstrating construction of small and larger cuts (by signals and by nodes), shows pis(), gates(), and num_* queries, and documents validity conditions (root dependencies must be covered by leaves) and visited-flag initialization behavior.
Comprehensive test suite
test/networks/test_cut_aig.py
Tests CutAig construction variants, validates size/count properties, exercises iteration APIs (nodes, pis, gates, pos), round-trips node_to_index()/index_to_node(), confirms is_pi() classification, validates __repr__ content, verifies clone/copy semantics preserve structure, and asserts all mutating methods raise RuntimeError with immutability messages.

Sequence Diagram(s)

sequenceDiagram
  participant Py as Python caller
  participant Bind as C++ binding (Cut{Network})
  participant Ntk as Base network (ntk)
  participant CV as mockturtle::cut_view

  Py->>+Bind: __init__(ntk, leaves, root)
  Bind->>+Ntk: clear_visited_flags()
  Bind->>+CV: construct_cut_view(ntk, leaves, root)
  CV->>Ntk: traverse subgraph (collect nodes/pis/gates)
  CV-->>-Bind: provide read-only view interfaces
  Bind-->>-Py: return Cut{Network} (immutable view)
  Note over Py,Bind: Mutating ops (create_*, clone_node) raise RuntimeError
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

enhancement, Python, testing, documentation

🐰 I cropped a view from root and leaves,
I hopped through flags and cleared old eaves,
Immutable now — I only peek and count,
Docs and tests sing numbers that I mount,
A tiny nibble, neat and sweetly bright.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly relates to the main change: enabling Cut View functionality on AIG, which is the primary purpose of this PR.
Description check ✅ Passed The description follows the template structure with a summary section and completed checklist, though it lacks a 'Fixes #(issue)' reference and could provide more detailed context.
Docstring Coverage ✅ Passed Docstring coverage is 97.83% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @marcelwa , I think there are settings issue on formatting since I run clang-format it will remove these changes in logic_networks.cpp, but if I run not -s lint it will indeed add these changes automatically.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

What changes do you mean exactly?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sorry I left this as a comment, it doesn't show inline. I mean the lines between 334-337. I didn't manually change this format, but I do think there's a conflict between clang-format and not -s lint on these line, try run one before another and change the order you'll see they make different decision.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

That's odd because nox -s lint simply calls clang-format. Can you make sure that you're using the same version of clang-format for both?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, you are right. I now see how pre-commit works, it has its own packages requirement in .pre-commit-config.yaml. I indeed used an old version on my local. Thanks for pointing out.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/networks/test_cut_aig.py (1)

18-21: The node-based constructor overload is still untested.

create_pi() returns AigSignal, so both of these CutAig(...) calls are exercising the signal overload. Please add one case that passes aig.get_node(...) values so the Sequence[int] / std::vector<Node> constructor path is actually covered.

Also applies to: 49-52

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/networks/test_cut_aig.py` around lines 18 - 21, The tests currently pass
AigSignal values (from create_pi()) into CutAig, so the
Sequence[int]/std::vector<Node> constructor overload isn't exercised; add a
parallel case that fetches Node objects via aig.get_node(...) and passes those
to CutAig. Concretely, create leaves_nodes = [aig.get_node(x1.node),
aig.get_node(x2.node)] and root_node = aig.get_node(f1.node) (or use the
appropriate .node/index property available on the AigSignal), call CutAig(aig,
leaves_nodes, root_node), and duplicate the same assertions; do the same for the
other instance around lines 49-52 to cover both spots.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/aigverse/networks/logic_networks.cpp`:
- Around line 541-556: The two cut_view constructors bound via nb::init<const
Ntk&, const std::vector<Node>&, const Signal&>() and nb::init<const Ntk&, const
std::vector<Signal>&, const Signal&>() must clear the network's mockturtle
visited flags before constructing mockturtle::cut_view; modify these binding
wrappers in logic_networks.cpp so they reset/clear the visited markers on the
provided ntk (or call an existing reset_visited/clear_visited method on Ntk)
immediately prior to invoking the cut_view constructors, or alternatively
provide and bind an explicit Ntk::reset_visited() method to Python and call it
from the constructors to ensure all visited flags are zeroed.
- Around line 533-618: The binding wrongly registers CutNtk as
nb::class_<CutNtk, Ntk>, exposing mutable methods from the full Ntk; change the
registration to a standalone type (nb::class_<CutNtk>(m, ...)) so it does not
inherit Ntk's API, or explicitly block/override mutable methods (e.g.,
create_and, create_pi, clone_node) to raise/return errors to match
mockturtle::immutable_view semantics; also update the two CutNtk constructors'
docstrings to document the visited-flag precondition (all nodes must have
visited==0 before construction and the view will reset visited flags to 0 after
construction).

---

Nitpick comments:
In `@test/networks/test_cut_aig.py`:
- Around line 18-21: The tests currently pass AigSignal values (from
create_pi()) into CutAig, so the Sequence[int]/std::vector<Node> constructor
overload isn't exercised; add a parallel case that fetches Node objects via
aig.get_node(...) and passes those to CutAig. Concretely, create leaves_nodes =
[aig.get_node(x1.node), aig.get_node(x2.node)] and root_node =
aig.get_node(f1.node) (or use the appropriate .node/index property available on
the AigSignal), call CutAig(aig, leaves_nodes, root_node), and duplicate the
same assertions; do the same for the other instance around lines 49-52 to cover
both spots.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 746e4a21-10c4-4fe6-98e3-66ee316d2748

📥 Commits

Reviewing files that changed from the base of the PR and between f7baf9e and c8259a7.

📒 Files selected for processing (4)
  • docs/aigs.md
  • python/aigverse/networks.pyi
  • src/aigverse/networks/logic_networks.cpp
  • test/networks/test_cut_aig.py

Comment thread src/aigverse/networks/logic_networks.cpp Outdated
Comment thread src/aigverse/networks/logic_networks.cpp Outdated

@marcelwa marcelwa left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Many thanks for the addition. It looks pretty nice already. I just have a few comments you can find below. Please also address the clang-tidy warning.

[Run clang-tidy: src/aigverse/networks/logic_networks.cpp#L592](https://github.com/marcelwa/aigverse/pull/315/files#annotation_47738436166)
implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long')

Comment thread docs/aigs.md Outdated
cut_aig2 = CutAig(aig, [x1, x2, x3], f2)

print(f"\nLarger cut has {cut_aig2.num_pis} PIs (leaves)")
print(f"Larger cut has {cut_aig2.num_pos} PO (root)")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
print(f"Larger cut has {cut_aig2.num_pos} PO (root)")
print(f"Larger cut has {cut_aig2.num_pos} POs (roots)")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread docs/aigs.md Outdated
print(f" Gate: {gate}")
```

You can also create larger cuts that include multiple gates:

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The two examples are largely redundant. I would merge them into one that explores two different cuts in the same AIG.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread docs/aigs.md
Comment on lines +338 to +340
:::{note}
A cut is only valid if all dependencies of the root node are either included in the leaves or can be reached through nodes within the cut. The cut view assumes that all nodes' visited flags are set to 0 before creating the view.
:::

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

We could simply reset the visited flags in the constructor.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

def fanouts(self, n: int) -> list[int]:
"""Returns fanout nodes of node ``n``."""

class CutAig(Aig):

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Not sure if you saw: there is a new nox session called stubs that automatically generates the stubs from the bindings. It's not perfect yet, so it will try to overwrite some changes. I'll fix the configuration once I have time. In the meantime, please run it (if not already done) and don't commit the changes that are not caused by your edits.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

nox -s lint and nox -s stubs make different decisions since ruff involved, which one should have higher priority? ruff format failed in nox -s lint if you run stubs:

(venv) (base) ➜  aigverse git:(main) ✗ nox -s lint
nox > Running session lint
nox > Reusing existing virtual environment at .nox/lint.
nox > pre-commit run --all-files
check for added large files..............................................Passed
check for case conflicts.................................................Passed
check vcs permalinks.....................................................Passed
check docstring is first.................................................Passed
check for merge conflicts................................................Passed
check for broken symlinks............................(no files to check)Skipped
check json...........................................(no files to check)Skipped
check toml...............................................................Passed
check yaml...............................................................Passed
debug statements (python)................................................Passed
fix end of files.........................................................Passed
mixed line ending........................................................Passed
trim trailing whitespace.................................................Passed
Fix ligature characters with NFKD normalization..........................Passed
Fix smartquote characters................................................Passed
typos....................................................................Passed
cmake-format.............................................................Passed
clang-format.............................................................Passed
uv-lock..................................................................Passed
ruff format..............................................................Passed
ruff check...............................................................Passed
mypy.....................................................................Passed
nb-clean.............................................(no files to check)Skipped
blacken-docs.............................................................Passed
prettier.................................................................Passed
Validate GitHub Workflows................................................Passed
Validate ReadTheDocs Config..............................................Passed
Validate Renovate Config.................................................Passed
Validate pyproject.toml..................................................Passed
nox > Session lint was successful in 3 seconds.


(venv) (base) ➜  aigverse git:(main) ✗ nox -s stubs
nox > Running session stubs
nox > Reusing existing virtual environment at .nox/stubs.
nox > uv sync --no-dev --group build
Resolved 130 packages in 7ms
      Built aigverse @ file:///xxx/aigverse
Prepared 1 package in 1m 02s
Uninstalled 1 package in 1ms
Installed 1 package in 1ms
 ~ aigverse==0.0.28.dev27+ge1cb0a5de.d20260323 (from file:///xxx/aigverse)
nox > python -m nanobind.stubgen --recursive --include-private --pattern-file /xxx/aigverse/python/aigverse/stubgen.pattern --output-dir /xxx/aigverse/python/aigverse --module aigverse.networks --module aigverse.algorithms --module aigverse.io --module aigverse.generators --module aigverse.utils
Using pattern file "/xxx/aigverse/stubgen.pattern" ..
  - loaded 3 patterns.

Module "aigverse.networks" ..
  - importing ..
  - analyzing ..
  - warning: rule 'algorithms.__prefix__' did not match any elements.
  - warning: rule 'networks.__prefix__' did not match any elements.
  - warning: rule 'rebalance_function: str' did not match any elements.
  - applied 0 patterns.
  - writing stub "/xxx/aigverse/python/aigverse/networks.pyi" ..


Module "aigverse.algorithms" ..
  - importing ..
  - analyzing ..
  - warning: rule 'algorithms.__prefix__' did not match any elements.
  - warning: rule 'networks.__prefix__' did not match any elements.
  - warning: rule 'rebalance_function: str' did not match any elements.
  - applied 0 patterns.
  - writing stub "/xxx/aigverse/python/aigverse/algorithms.pyi" ..


Module "aigverse.io" ..
  - importing ..
  - analyzing ..
  - warning: rule 'algorithms.__prefix__' did not match any elements.
  - warning: rule 'networks.__prefix__' did not match any elements.
  - warning: rule 'rebalance_function: str' did not match any elements.
  - applied 0 patterns.
  - writing stub "/xxx/aigverse/python/aigverse/io.pyi" ..


Module "aigverse.generators" ..
  - importing ..
  - analyzing ..
  - warning: rule 'algorithms.__prefix__' did not match any elements.
  - warning: rule 'networks.__prefix__' did not match any elements.
  - warning: rule 'rebalance_function: str' did not match any elements.
  - applied 0 patterns.
  - writing stub "/xxx/aigverse/python/aigverse/generators.pyi" ..


Module "aigverse.utils" ..
  - importing ..
  - analyzing ..
  - warning: rule 'algorithms.__prefix__' did not match any elements.
  - warning: rule 'networks.__prefix__' did not match any elements.
  - warning: rule 'rebalance_function: str' did not match any elements.
  - applied 0 patterns.
  - writing stub "/xxx/aigverse/python/aigverse/utils.pyi" ..
nox > pre-commit run ruff-format --files
...
...
ruff format..............................................................Failed
- hook id: ruff-format
- files were modified by this hook

5 files reformatted, 1 file left unchanged

nox > pre-commit run ruff-check --files 
...
...
ruff check...............................................................Failed
- hook id: ruff-check
- files were modified by this hook

Fixed 119 errors:
- python/aigverse/algorithms.pyi:
     8 × D212 (multi-line-summary-first-line)
     1 × D200 (unnecessary-multiline-docstring)
     1 × I001 (unsorted-imports)
     1 × E303 (too-many-blank-lines)
     1 × F401 (unused-import)
- python/aigverse/generators.pyi:
     7 × D212 (multi-line-summary-first-line)
- python/aigverse/io.pyi:
    10 × D212 (multi-line-summary-first-line)
     3 × D214 (overindented-section)
- python/aigverse/networks.pyi:
    36 × D212 (multi-line-summary-first-line)
    10 × PYI029 (str-or-repr-defined-in-stub)
     9 × D214 (overindented-section)
     8 × E303 (too-many-blank-lines)
     4 × D200 (unnecessary-multiline-docstring)
     1 × I001 (unsorted-imports)
     1 × W391 (too-many-newlines-at-end-of-file)
- python/aigverse/utils.pyi:
    16 × D212 (multi-line-summary-first-line)
     1 × PYI029 (str-or-repr-defined-in-stub)
     1 × E303 (too-many-blank-lines)

Found 119 errors (119 fixed, 0 remaining).

nox > pre-commit run ruff-check --files
...
...
ruff check...............................................................Passed
nox > Session stubs was successful in a minute.


(venv) (base) ➜  aigverse git:(main) ✗ nox -s lint 
nox > Running session lint
nox > Reusing existing virtual environment at .nox/lint.
nox > pre-commit run --all-files
check for added large files..............................................Passed
check for case conflicts.................................................Passed
check vcs permalinks.....................................................Passed
check docstring is first.................................................Passed
check for merge conflicts................................................Passed
check for broken symlinks............................(no files to check)Skipped
check json...........................................(no files to check)Skipped
check toml...............................................................Passed
check yaml...............................................................Passed
debug statements (python)................................................Passed
fix end of files.........................................................Passed
mixed line ending........................................................Passed
trim trailing whitespace.................................................Passed
Fix ligature characters with NFKD normalization..........................Passed
Fix smartquote characters................................................Passed
typos....................................................................Passed
cmake-format.............................................................Passed
clang-format.............................................................Passed
uv-lock..................................................................Passed
**ruff format..............................................................Failed**
- hook id: ruff-format
- files were modified by this hook

1 file reformatted, 37 files left unchanged

ruff check...............................................................Passed
mypy.....................................................................Passed
nb-clean.............................................(no files to check)Skipped
blacken-docs.............................................................Passed
prettier.................................................................Passed
Validate GitHub Workflows................................................Passed
Validate ReadTheDocs Config..............................................Passed
Validate Renovate Config.................................................Passed
Validate pyproject.toml..................................................Passed
nox > Command pre-commit run --all-files failed with exit code 1
nox > Session lint failed.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I will have to come back to you regarding the stubs. As said, I'm not 100% happy with how stubgen currently generates the stubs. Once I fix that, the behavior should no longer be conflicting.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

What changes do you mean exactly?

"pos",
[](const CutNtk& ntk)
{
std::vector<Signal> pos;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
std::vector<Signal> pos;
std::vector<Signal> pos{};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread src/aigverse/networks/logic_networks.cpp Outdated


def test_cut_aig_with_signals() -> None:
"""Test CutAig creation using signals instead of nodes."""

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

What do you mean by "signals instead of nodes"? The previous test case also passed signals. You must call .get_node() if you want to test node construction.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Add another test later with another constructor for "nodes instead of signals", now 2 are all tested. Done.

Comment on lines +76 to +90
nodes = list(cut_aig.nodes())
assert len(nodes) == cut_aig.size
assert 0 in nodes # constant node

# Iterate over PIs
pis = list(cut_aig.pis())
assert len(pis) == cut_aig.num_pis

# Iterate over gates
gates = list(cut_aig.gates())
assert len(gates) == cut_aig.num_gates

# Iterate over POs
pos = list(cut_aig.pos())
assert len(pos) == 1

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

No need to explicitly convert to lists. The functions return lists already.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The current tests don't cover the methods deleted by mockturtle::immutable_view. Those should be tested for as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Tested all with customised run time error.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
test/networks/test_cut_aig.py (2)

32-50: Clarify the test docstring.

The docstring says "using signals instead of nodes," but test_cut_aig also passes signals. The actual distinction is that test_cut_aig_with_nodes (line 142) tests the node-based constructor overload using get_node(). Consider updating the docstring to describe what this test uniquely covers (e.g., a more complex cut with multiple gates).

📝 Suggested docstring
 def test_cut_aig_with_signals() -> None:
-    """Test CutAig creation using signals instead of nodes."""
+    """Test CutAig creation with a larger cut containing multiple gates."""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/networks/test_cut_aig.py` around lines 32 - 50, Update the docstring for
test_cut_aig_with_signals to clearly state that this test exercises the CutAig
constructor that accepts signal objects (not nodes) and verifies a nontrivial
cut composed of multiple gates (creates two ANDs and an XOR, 4 PIs and 5 gates);
reference the signal-based constructor usage of CutAig and contrast it with
test_cut_aig_with_nodes which uses get_node() to exercise the node-based
overload.

159-198: Consider adding tests for nary methods.

The immutability test covers most blocked methods but is missing create_nary_and, create_nary_or, and create_nary_xor, which are also blocked in the C++ bindings.

🧪 Additional assertions for completeness
     with pytest.raises(RuntimeError, match="clone_node is not available on immutable view"):
         cut_aig.clone_node(aig, aig.get_node(x1), [x1])
+    with pytest.raises(RuntimeError, match="create_nary_and is not available on immutable view"):
+        cut_aig.create_nary_and([x1, x2])
+    with pytest.raises(RuntimeError, match="create_nary_or is not available on immutable view"):
+        cut_aig.create_nary_or([x1, x2])
+    with pytest.raises(RuntimeError, match="create_nary_xor is not available on immutable view"):
+        cut_aig.create_nary_xor([x1, x2])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/networks/test_cut_aig.py` around lines 159 - 198, The test
test_cut_aig_immutability is missing assertions for the n-ary operations; add
pytest.raises checks to assert that calling CutAig.create_nary_and(...),
CutAig.create_nary_or(...), and CutAig.create_nary_xor(...) raise RuntimeError
with the same "is not available on immutable view" message (match string like
the other assertions), using appropriate argument lists (e.g., [x1, x2] or a
list of inputs) and keeping them alongside the existing create_* tests in the
CutAig immutability block.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/networks/test_cut_aig.py`:
- Around line 32-50: Update the docstring for test_cut_aig_with_signals to
clearly state that this test exercises the CutAig constructor that accepts
signal objects (not nodes) and verifies a nontrivial cut composed of multiple
gates (creates two ANDs and an XOR, 4 PIs and 5 gates); reference the
signal-based constructor usage of CutAig and contrast it with
test_cut_aig_with_nodes which uses get_node() to exercise the node-based
overload.
- Around line 159-198: The test test_cut_aig_immutability is missing assertions
for the n-ary operations; add pytest.raises checks to assert that calling
CutAig.create_nary_and(...), CutAig.create_nary_or(...), and
CutAig.create_nary_xor(...) raise RuntimeError with the same "is not available
on immutable view" message (match string like the other assertions), using
appropriate argument lists (e.g., [x1, x2] or a list of inputs) and keeping them
alongside the existing create_* tests in the CutAig immutability block.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b917446-2be2-4182-9004-913f32dfdd56

📥 Commits

Reviewing files that changed from the base of the PR and between c8259a7 and bbb80e8.

📒 Files selected for processing (4)
  • docs/aigs.md
  • python/aigverse/networks.pyi
  • src/aigverse/networks/logic_networks.cpp
  • test/networks/test_cut_aig.py
✅ Files skipped from review due to trivial changes (1)
  • docs/aigs.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • python/aigverse/networks.pyi

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
test/networks/test_cut_aig.py (1)

159-204: Refactor immutability checks with parametrization to reduce repetition.

The current test is correct but repetitive; a parametrized table makes it easier to maintain when APIs change.

♻️ Proposed refactor
 def test_cut_aig_immutability() -> None:
     """Test that network-modifying methods raise RuntimeError on CutAig."""
     aig = Aig()
     x1 = aig.create_pi()
     x2 = aig.create_pi()
     f1 = aig.create_and(x1, x2)
     aig.create_po(f1)
     cut_aig = CutAig(aig, [x1, x2], f1)
-    with pytest.raises(RuntimeError, match="create_pi is not available on immutable view"):
-        cut_aig.create_pi()
-    with pytest.raises(RuntimeError, match="create_po is not available on immutable view"):
-        cut_aig.create_po(f1)
-    with pytest.raises(RuntimeError, match="create_and is not available on immutable view"):
-        cut_aig.create_and(x1, x2)
-    with pytest.raises(RuntimeError, match="create_or is not available on immutable view"):
-        cut_aig.create_or(x1, x2)
-    with pytest.raises(RuntimeError, match="create_xor is not available on immutable view"):
-        cut_aig.create_xor(x1, x2)
-    with pytest.raises(RuntimeError, match="create_not is not available on immutable view"):
-        cut_aig.create_not(x1)
-    with pytest.raises(RuntimeError, match="create_nand is not available on immutable view"):
-        cut_aig.create_nand(x1, x2)
-    with pytest.raises(RuntimeError, match="create_nor is not available on immutable view"):
-        cut_aig.create_nor(x1, x2)
-    with pytest.raises(RuntimeError, match="create_xnor is not available on immutable view"):
-        cut_aig.create_xnor(x1, x2)
-    with pytest.raises(RuntimeError, match="create_buf is not available on immutable view"):
-        cut_aig.create_buf(x1)
-    with pytest.raises(RuntimeError, match="create_maj is not available on immutable view"):
-        cut_aig.create_maj(x1, x2, f1)
-    with pytest.raises(RuntimeError, match="create_ite is not available on immutable view"):
-        cut_aig.create_ite(x1, x2, f1)
-    with pytest.raises(RuntimeError, match="create_xor3 is not available on immutable view"):
-        cut_aig.create_xor3(x1, x2, f1)
-    with pytest.raises(RuntimeError, match="create_lt is not available on immutable view"):
-        cut_aig.create_lt(x1, x2)
-    with pytest.raises(RuntimeError, match="create_le is not available on immutable view"):
-        cut_aig.create_le(x1, x2)
-    with pytest.raises(RuntimeError, match="create_nary_and is not available on immutable view"):
-        cut_aig.create_nary_and([x1, x2])
-    with pytest.raises(RuntimeError, match="create_nary_or is not available on immutable view"):
-        cut_aig.create_nary_or([x1, x2])
-    with pytest.raises(RuntimeError, match="create_nary_xor is not available on immutable view"):
-        cut_aig.create_nary_xor([x1, x2])
-    with pytest.raises(RuntimeError, match="clone_node is not available on immutable view"):
-        cut_aig.clone_node(aig, aig.get_node(x1), [x1])
+    cases = [
+        ("create_pi", ()),
+        ("create_po", (f1,)),
+        ("create_and", (x1, x2)),
+        ("create_or", (x1, x2)),
+        ("create_xor", (x1, x2)),
+        ("create_not", (x1,)),
+        ("create_nand", (x1, x2)),
+        ("create_nor", (x1, x2)),
+        ("create_xnor", (x1, x2)),
+        ("create_buf", (x1,)),
+        ("create_maj", (x1, x2, f1)),
+        ("create_ite", (x1, x2, f1)),
+        ("create_xor3", (x1, x2, f1)),
+        ("create_lt", (x1, x2)),
+        ("create_le", (x1, x2)),
+        ("create_nary_and", ([x1, x2],)),
+        ("create_nary_or", ([x1, x2],)),
+        ("create_nary_xor", ([x1, x2],)),
+        ("clone_node", (aig, aig.get_node(x1), [x1])),
+    ]
+
+    for method_name, args in cases:
+        with pytest.raises(
+            RuntimeError,
+            match=rf"{method_name} is not available on immutable view",
+        ):
+            getattr(cut_aig, method_name)(*args)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/networks/test_cut_aig.py` around lines 159 - 204, Refactor
test_cut_aig_immutability to remove repetitive with pytest.raises blocks by
parametrizing the immutable methods: create_pi, create_po, create_and,
create_or, create_xor, create_not, create_nand, create_nor, create_xnor,
create_buf, create_maj, create_ite, create_xor3, create_lt, create_le,
create_nary_and, create_nary_or, create_nary_xor, clone_node; implement a
pytest.mark.parametrize that supplies the method name (string) and its argument
tuple, then inside the test use getattr(cut_aig, method_name)(*args) within
pytest.raises(RuntimeError, match=f"{method_name} is not available on immutable
view") to assert the error for each case while keeping the existing setup using
Aig(), create_pi/create_and/create_po, and CutAig.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/networks/test_cut_aig.py`:
- Around line 159-204: Refactor test_cut_aig_immutability to remove repetitive
with pytest.raises blocks by parametrizing the immutable methods: create_pi,
create_po, create_and, create_or, create_xor, create_not, create_nand,
create_nor, create_xnor, create_buf, create_maj, create_ite, create_xor3,
create_lt, create_le, create_nary_and, create_nary_or, create_nary_xor,
clone_node; implement a pytest.mark.parametrize that supplies the method name
(string) and its argument tuple, then inside the test use getattr(cut_aig,
method_name)(*args) within pytest.raises(RuntimeError, match=f"{method_name} is
not available on immutable view") to assert the error for each case while
keeping the existing setup using Aig(), create_pi/create_and/create_po, and
CutAig.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 35de727a-453c-4030-b08d-58d007b266c6

📥 Commits

Reviewing files that changed from the base of the PR and between bbb80e8 and 2aa0558.

📒 Files selected for processing (1)
  • test/networks/test_cut_aig.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
test/networks/test_cut_aig.py (2)

159-195: Consider parametrizing immutability cases for clearer failure granularity.

Current loop works, but @pytest.mark.parametrize would report each blocked method as an individual test case, making failures easier to triage.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/networks/test_cut_aig.py` around lines 159 - 195, The test
test_cut_aig_immutability currently iterates a list of (method_name, args) and
asserts RuntimeError for each, which hides per-case granularity; refactor it to
a parametrized test using `@pytest.mark.parametrize` to supply the (method_name,
args) pairs to a single test function so each blocked method is reported as an
individual test case. Update test_cut_aig_immutability to be decorated with
pytest.mark.parametrize (e.g., params = [("create_pi", ()), ...]) and accept
method_name and args as parameters, then inside the test call
getattr(CutAig(aig, [x1, x2], f1), method_name)(*args) within
pytest.raises(RuntimeError, match=rf"{method_name} is not available on immutable
view"); optionally add ids for clarity.

23-26: Remove redundant hasattr assertions.

The direct value assertions on Line [27]–Line [29] already fail if these properties don’t exist, so these checks add noise without extra signal.

♻️ Suggested cleanup
-    assert hasattr(cut_aig, "size")
-    assert hasattr(cut_aig, "num_gates")
-    assert hasattr(cut_aig, "num_pis")
-    assert hasattr(cut_aig, "num_pos")
     assert cut_aig.num_pis == 2
     assert cut_aig.num_pos == 1
     assert cut_aig.num_gates == 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/networks/test_cut_aig.py` around lines 23 - 26, Remove the redundant
hasattr checks for cut_aig ("size", "num_gates", "num_pis", "num_pos") in the
test; the subsequent direct assertions already will raise if those attributes
are missing, so delete the four lines asserting hasattr(cut_aig, "size"),
hasattr(cut_aig, "num_gates"), hasattr(cut_aig, "num_pis"), and hasattr(cut_aig,
"num_pos") and keep the direct value assertions only.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/networks/test_cut_aig.py`:
- Around line 159-195: The test test_cut_aig_immutability currently iterates a
list of (method_name, args) and asserts RuntimeError for each, which hides
per-case granularity; refactor it to a parametrized test using
`@pytest.mark.parametrize` to supply the (method_name, args) pairs to a single
test function so each blocked method is reported as an individual test case.
Update test_cut_aig_immutability to be decorated with pytest.mark.parametrize
(e.g., params = [("create_pi", ()), ...]) and accept method_name and args as
parameters, then inside the test call getattr(CutAig(aig, [x1, x2], f1),
method_name)(*args) within pytest.raises(RuntimeError, match=rf"{method_name} is
not available on immutable view"); optionally add ids for clarity.
- Around line 23-26: Remove the redundant hasattr checks for cut_aig ("size",
"num_gates", "num_pis", "num_pos") in the test; the subsequent direct assertions
already will raise if those attributes are missing, so delete the four lines
asserting hasattr(cut_aig, "size"), hasattr(cut_aig, "num_gates"),
hasattr(cut_aig, "num_pis"), and hasattr(cut_aig, "num_pos") and keep the direct
value assertions only.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4077d9c4-1fee-43bf-938c-5b01b8b513a9

📥 Commits

Reviewing files that changed from the base of the PR and between 2aa0558 and acba8f6.

📒 Files selected for processing (1)
  • test/networks/test_cut_aig.py

@wjrforcyber wjrforcyber requested a review from marcelwa March 26, 2026 00:14
@marcelwa

Copy link
Copy Markdown
Owner

@wjrforcyber in #336 I fixed the stubs generation with stubgen. The respective check is now also built into the CI to verify whether the stubs are up to date. I hope that helps you.

@wjrforcyber wjrforcyber marked this pull request as draft April 23, 2026 08:33
wjrforcyber and others added 4 commits June 5, 2026 14:43
Signed-off-by: JingrenWang <wjrforcyber@163.com>
Signed-off-by: JingrenWang <wjrforcyber@163.com>
Signed-off-by: JingrenWang <wjrforcyber@163.com>
@wjrforcyber wjrforcyber force-pushed the cut_view branch 2 times, most recently from 832d432 to ee38808 Compare June 6, 2026 06:17
Signed-off-by: JingrenWang <wjrforcyber@163.com>
@wjrforcyber wjrforcyber marked this pull request as ready for review June 6, 2026 07:14
@marcelwa

marcelwa commented Jun 7, 2026

Copy link
Copy Markdown
Owner

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/aigverse/networks.pyi`:
- Around line 580-635: The blocked mutating methods in the AIG stubs (create_pi,
create_po, create_buf, create_not, create_and, create_nand, create_or,
create_nor, create_xor, create_xnor, create_lt, create_le, create_maj,
create_ite, create_xor3, create_nary_and, create_nary_or, create_nary_xor, and
clone_node) always raise and should be annotated with typing.NoReturn rather
than their original return types; add NoReturn to the typing imports (matching
the pattern used by SequentialAig.to_index_list) and change each method
signature's return type to NoReturn so type checkers know they never return.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db14eb32-b4e0-4d55-99d9-4c15c6bf90bc

📥 Commits

Reviewing files that changed from the base of the PR and between 9e44442 and 7212a50.

📒 Files selected for processing (4)
  • docs/aigs.md
  • python/aigverse/networks.pyi
  • src/aigverse/networks/logic_networks.cpp
  • test/networks/test_cut_aig.py

Comment thread python/aigverse/networks.pyi Outdated
Signed-off-by: JingrenWang <wjrforcyber@163.com>
@marcelwa

marcelwa commented Jun 8, 2026

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@marcelwa marcelwa left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This looks much better now, thanks a lot for your efforts 🙏

I'd like to discuss the CutAig class in general before we continue work on this PR. Please find my notes on that below. It's important to get the design right the first time to not introduce too many breaking changes down the line.


using CutNtk = mockturtle::cut_view<Ntk>;

auto clear_visited = [](const Ntk& ntk) { ntk.foreach_node([&ntk](const auto& n) { ntk.set_visited(n, 0); }); };

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
auto clear_visited = [](const Ntk& ntk) { ntk.foreach_node([&ntk](const auto& n) { ntk.set_visited(n, 0); }); };
const auto clear_visited = [](const Ntk& ntk) { ntk.foreach_node([&ntk](const auto& n) { ntk.set_visited(n, 0); }); };

the view will have a 0 visited flag after construction.)pb")
.def(
"__init__",
[clear_visited](CutNtk* self, const Ntk& ntk, const std::vector<Node>& leaves, const Signal& root)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
[clear_visited](CutNtk* self, const Ntk& ntk, const std::vector<Node>& leaves, const Signal& root)
[&clear_visited](CutNtk* self, const Ntk& ntk, const std::vector<Node>& leaves, const Signal& root)

root: The root signal (output) of the cut.)pb")
.def(
"__init__",
[clear_visited](CutNtk* self, const Ntk& ntk, const std::vector<Signal>& leaves, const Signal& root)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
[clear_visited](CutNtk* self, const Ntk& ntk, const std::vector<Signal>& leaves, const Signal& root)
[&clear_visited](CutNtk* self, const Ntk& ntk, const std::vector<Signal>& leaves, const Signal& root)

nb::arg("index"), R"pb(Returns the node for an index.)pb")
.def(
"__repr__",
[network_name](const CutNtk& ntk)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Suggested change
[network_name](const CutNtk& ntk)
[&network_name](const CutNtk& ntk)

Comment on lines +539 to +549
nb::class_<CutNtk, Ntk>(m, fmt::format("Cut{}", network_name).c_str(),
R"pb(Implements an isolated view on a single cut in a network.

This view creates a network from a single cut with a single output `root`
and a set of `leaves`. This is an immutable view; network-modifying methods
are not available.

Note:
This view clears all nodes' visited flags before construction to ensure
the cut is constructed correctly. The view guarantees that all nodes in
the view will have a 0 visited flag after construction.)pb")

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Let us briefly pause and think about cuts in aigverse for a second. Currently, this PR exposes mockturtle::cut_view directly and makes it a new network type in aigverse. That means you have to explicitly disable all the regular network functions because of the inheritance from mockturtle::immutable_view, which is not exposed in aigverse for good reason.

Let us consider a different approach. Keep exposing mockturtle::cut_view but name it Cut instead of CutAig, and don't make it inherit from Ntk. That way, we can drop all the exception-throwing overloads because on the Python side of things, it won't look like a network at all. It's simply a cut.

I understand that mockturtle has dedicated mockturtle::cut and mockturtle::cut_set classes, but they rely heavily on compile-time parameters. So exposure to Python is non-trivial.

What do you think of this approach? Is there something against it? Would something break? Would this prevent a use case you have in mind?

@wjrforcyber wjrforcyber Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree, I am thinking of making it simpler rather than a lot of exception-throwing stubs. I'm thinking of supporting indexes directly from the cut (Briefly checked, I think it is doable, since mockturtle::cut_view overrides necessary interfaces) and maybe tell user directly if they would like to perform optimisation operation/statistic analysis on unit cut/cuts, try index to aig method which aigverse already supported.
I'll create another PR $P$ based on main branch, we could still make this PR $O$ open for discussion, if $P$ is ready then we could merge $P$ and close both $P$ and $O$.
Does this plan sound good to you?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I'm not entirely sure I understand what your plan is here. In principle, I'm open to a separate PR for easier comparison of the two approaches, so we can pick the one that better suits the overall library design.

However, what do you mean by "I'm thinking of supporting indexes directly from the cut"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Similar to a cut-scale version of to_index_list().

@marcelwa marcelwa Jun 17, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

How would that differ from my proposal above?

Let us consider a different approach. Keep exposing mockturtle::cut_view but name it Cut instead of CutAig, and don't make it inherit from Ntk. That way, we can drop all the exception-throwing overloads because on the Python side of things, it won't look like a network at all. It's simply a cut.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Your proposal is a first step, but to_index_list() is inherited from Aig if I'm correct, it needs a cut level reconstruction, just an extra step.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

to_index_list() is a member function of Aig. There is no inheritance at work here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes it is a member function of Aig, I mean if you call that on a cut aig such as cut_aig.to_index_list() it is inherited from Aig silently encode whole network.

What I mean is to prevent such case(It will pass):

def test_cut_aig_to_index_list_encodes_whole_network() -> None:
    """to_index_list() is inherited from Aig and operates on the whole network, not the cut.

    Due to mockturtle's non-virtual CRTP dispatch, methods not reimplemented by
    cut_view (like to_index_list) silently encode the entire underlying network
    instead of just the cut's restricted node set.
    """
    aig = Aig()
    x1 = aig.create_pi()
    x2 = aig.create_pi()
    x3 = aig.create_pi()
    x4 = aig.create_pi()

    f1 = aig.create_and(x1, x2)
    f2 = aig.create_and(x3, x4)
    f3 = aig.create_and(f1, f2)
    aig.create_po(f3)

    cut_aig = CutAig(aig, [x1, x2], f1)

    assert cut_aig.num_gates == 1
    assert cut_aig.num_pis == 2

    index_list = cut_aig.to_index_list()
    assert index_list.num_gates == aig.num_gates
    assert index_list.num_pis == aig.num_pis

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

That will already be prevented by my proposal above. If you remove the inheritance from Ntk, CutAig (or Cut, as I would then call it) is no longer a network. It offers some network interface functions, but not enough to be considered one.

Suggested change
nb::class_<CutNtk, Ntk>(m, fmt::format("Cut{}", network_name).c_str(),
R"pb(Implements an isolated view on a single cut in a network.
This view creates a network from a single cut with a single output `root`
and a set of `leaves`. This is an immutable view; network-modifying methods
are not available.
Note:
This view clears all nodes' visited flags before construction to ensure
the cut is constructed correctly. The view guarantees that all nodes in
the view will have a 0 visited flag after construction.)pb")
nb::class_<CutNtk>(m, "Cut",
R"pb(Implements an isolated view on a single cut in a network.
This view creates a network from a single cut with a single output `root`
and a set of `leaves`. This is an immutable view; network-modifying methods
are not available.
Note:
This view clears all nodes' visited flags before construction to ensure
the cut is constructed correctly. The view guarantees that all nodes in
the view will have a 0 visited flag after construction.)pb")

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.

2 participants