Skip to content

✨Map scf.for operations by restoration using the 4-approximation token swap algorithm#1805

Open
MatthiasReumann wants to merge 55 commits into
mainfrom
enh/sc-map-scf-for-loops
Open

✨Map scf.for operations by restoration using the 4-approximation token swap algorithm#1805
MatthiasReumann wants to merge 55 commits into
mainfrom
enh/sc-map-scf-for-loops

Conversation

@MatthiasReumann

@MatthiasReumann MatthiasReumann commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Changes

  • ✨Add functionality to handle operation with nested operations.
  • ✨ Implement the 4-Approximation Algorithm described in arXiv:1602.05150v3.
  • ✨Add two unit tests for quantum programs using scf.for operations and one unrolling unit test.
  • 📝 Use LLVM codebase style function description (consistent with the IRVerifier and some other parts of the cc).
  • 🚛 Move Layout class to separate file.

Checklist

  • The pull request only contains commits that are focused and relevant to this change.
  • I have added appropriate tests that cover the new/changed functionality.
  • I have updated the documentation to reflect these changes.
  • I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals.
  • I have added migration instructions to the upgrade guide (if needed).
  • The changes follow the project's style guidelines and introduce no new warnings.
  • The changes are fully tested and pass the CI checks.
  • I have reviewed my own code changes.

If PR contains AI-assisted content:

  • I have disclosed the use of AI tools in the PR description as per our AI Usage Guidelines.
  • AI-assisted commits include an Assisted-by: [Model Name] via [Tool Name] footer.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

@MatthiasReumann MatthiasReumann self-assigned this Jun 23, 2026
@MatthiasReumann MatthiasReumann added enhancement Improvement of existing feature c++ Anything related to C++ code MLIR Anything related to MLIR labels Jun 23, 2026
@MatthiasReumann MatthiasReumann added this to the MLIR Support milestone Jun 23, 2026
@mergify mergify Bot added the conflict label Jun 23, 2026
@mergify mergify Bot removed the conflict label Jun 25, 2026
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.88889% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mlir/include/mlir/Dialect/QCO/Utils/Graph.h 75.0% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@MatthiasReumann

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added improved qubit layout and graph handling for QCO workflows.
    • Mapping now supports a broader coupling-map format and better routes operations through nested regions.
    • Added utilities for layout creation, graph distances, and cycle detection.
  • Bug Fixes

    • Improved consistency of qubit mapping and routing behavior.
    • Fixed iterator handling for operations without results.
  • Documentation

    • Updated the changelog entry for the latest release.

Walkthrough

The PR replaces QCO qubit and graph utilities with graph and layout abstractions, rewrites the mapping pass around coupling sets and new routing state, updates mapping tests to use a new executable check, and tightens one QTensor iterator guard.

Changes

QCO mapping and utility refactor

Layer / File(s) Summary
Graph and layout primitives
mlir/include/mlir/Dialect/QCO/Utils/Algorithms.h, mlir/include/mlir/Dialect/QCO/Utils/Graph.h, mlir/lib/Dialect/QCO/Utils/Graph.cpp, mlir/include/mlir/Dialect/QCO/Utils/Layout.h, mlir/lib/Dialect/QCO/Utils/Layout.cpp
Graph utilities add adjacency, distance, and cycle queries, and Layout adds bidirectional program/hardware mappings with randomization and swaps.
Driver and pass API updates
mlir/include/mlir/Dialect/QCO/Transforms/Mapping/Mapping.h, mlir/include/mlir/Dialect/QCO/Utils/Drivers.h, mlir/unittests/Dialect/QCO/Utils/test_drivers.cpp
createMappingPass now takes a coupling set, the old QCO program-walk driver API is removed, and the driver test include list is trimmed.
Device model and pass setup
mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
MappingPass is rebuilt around AugmentedDevice, RoutingMode, and the new graph/layout helpers, and the constructor and entry checks switch to the coupling-set-based device model.
Placement and search pipeline
mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
Computation collection, placement, layout generation, and A* search now operate on Wires, WireInfos, and Layout program-to-hardware mappings.
Routing reconciliation and recursive execution
mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
restore, window selection, SWAP insertion, and recursive route handling are rewritten around the coupling graph and nested scf::ForOp bodies.
Mapping test harness
mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp
The mapping test harness introduces a Device struct, a layout-aware executable check, and a runPass wrapper that accepts coupling sets.
Mapping scenario tests
mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp
GHZ, GHZUnrolled, GroverLike, ParallelLoops, and Sabre are updated to run the pass with coupling sets and validate executability with the new helper.

QTensor iterator guard

Layer / File(s) Summary
Iterator terminal check
mlir/lib/Dialect/QTensor/Utils/TensorIterator.cpp
TensorIterator::tensor() changes the null-operation branch before testing terminal ops.

Sequence Diagram(s)

sequenceDiagram
  participant MappingPass
  participant AugmentedDevice
  participant getComputation
  participant place
  participant route
  participant Layout
  participant restore

  MappingPass->>AugmentedDevice: read couplings and distance matrix
  MappingPass->>getComputation: collect Wires and WireInfos
  getComputation-->>MappingPass: wires, infos
  MappingPass->>place: create static qubits and rewrite extracts
  place-->>MappingPass: placed Wires and WireInfos
  MappingPass->>route: route nested scf::ForOp bodies
  route->>Layout: query program and hardware indices
  route->>restore: reconcile child and parent layouts
  route-->>MappingPass: routed IR and inserted SWAPs
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

Suggested labels

feature, refactor

Suggested reviewers

  • burgholzer

Poem

I hopped through graphs and laid new trails,
With qubit maps and coupling scales. 🐇
SWAPs now twirl in tidy rows,
And every route where logic flows,
Leaves the carrot patch in better shape.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the main change: mapping scf.for operations via the 4-approximation token swap algorithm.
Description check ✅ Passed The description gives a clear summary and checklist, but it misses the template's exact Description heading, issue reference, and dependency details.
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.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch enh/sc-map-scf-for-loops

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 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 `@mlir/include/mlir/Dialect/QCO/Utils/Graph.h`:
- Around line 206-213: The adjacency bucket initialization in addDirectedEdge
uses the wrong element type, since adj_ stores Vector<IdT> but the new buckets
are created as Vector<size_t>(). Update the addDirectedEdge method in Graph to
initialize missing buckets with Vector<IdT>() so the template works for
non-size_t IdT instantiations, or otherwise explicitly constrain the graph to
size_t IDs if that is the intended design.
- Around line 186-193: The cycle-detection logic in Graph::dfs currently treats
a Seen neighbor as a back edge even when it is just the parent in an undirected
graph, so a single undirected edge can be reported as a cycle. Update the
Seen-handling branch in Graph::dfs to ignore the parent edge for
GraphType::Undirected by checking the current node against parents/top before
building and returning the cycle path, while preserving the existing behavior
for directed graphs.
- Around line 69-71: The getNodes() accessor in Graph returns an ArrayRef built
from a temporary created by to_vector(adj_.keys()), so the returned view becomes
dangling immediately. Update getNodes() to return owned storage by value (for
example a Vector/SmallVector of IdT) or otherwise ensure the node container is
stored with Graph lifetime, and adjust any callers of getNodes() to use the
owned return type rather than an ArrayRef.

In `@mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp`:
- Around line 811-819: The `Mapping::` unitary handling in `Mapping.cpp` assumes
every `UnitaryOpInterface` has two indices, but single-qubit gates like `h` can
reach this path and make `indices[1]` invalid. Update the ready-item loop to
distinguish one-qubit versus two-qubit unitary ops before indexing, using the
`UnitaryOpInterface` check plus the size/arity of `indices` (or the op’s qubit
count) to route single-qubit gates through the appropriate program lookup and
only read `indices[1]` for true two-qubit cases.
- Around line 293-299: The layout refinement failure path in the mapping pass
should stop execution immediately after `signalPassFailure()` instead of falling
through to `place(...)`. Update the `generateLayout` handling in the mapping
logic so that when `failed(layout)` is true, `func->emitError()` and
`signalPassFailure()` are followed by an early return from the current
pass/function, preventing dereference of `*layout` and any work with invalid
state.
- Around line 546-585: The trial selection in generateLayout is using cumulative
swap counts from Statistics, but SABRE should rank layouts by the swaps from the
final backward pass only. Update the routing loop in generateLayout so each
Trial records the swap count from the last route<WireDirection::Backward>
invocation separately, then use that value instead of stats.nswaps when choosing
the best Trial. Keep the existing routing logic in route<WireDirection::Forward>
and route<WireDirection::Backward>, but add a dedicated per-trial field for the
final backward-pass score and compare trials against that field near the
best-trial selection.

In `@mlir/lib/Dialect/QCO/Utils/Layout.cpp`:
- Around line 37-42: The Layout::add() method currently overwrites
programToHardware_ and hardwareToProgram_ without preserving the bijection, so
add checks for any existing assignment before writing a new prog/hw pair. Update
Layout::add() to either reject duplicates or clear the previous reverse/forward
mapping for the existing program or hardware entry before assigning the new one,
ensuring programToHardware_ and hardwareToProgram_ always stay consistent.
- Around line 54-59: The public Layout::swap method currently indexes
hardwareToProgram_ directly without validating hwA and hwB, so add the same
bounds assertions used by Layout::add and the getters before reading
hardwareToProgram_ and programToHardware_. Update swap(const size_t hwA, const
size_t hwB) to check both hardware IDs are in range before performing the swaps,
keeping the validation consistent with the rest of Layout.

In `@mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp`:
- Around line 406-409: Restore the qubits into the same tensor slots they were
extracted from by updating the qtensorInsert calls in test_mapping.cpp so the
sequence in the mapping test uses indices 0 through 3, not 1 through 4. The
issue is in the tensor reinsertion around the builder.qtensorInsert calls for
q0, q1, q2, and q3; fix the off-by-one indexing so index 0 is restored and no
write goes past the allocated size-4 tensor.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0a87896b-2b2d-4c87-bb91-fd7e2fa45fd6

📥 Commits

Reviewing files that changed from the base of the PR and between 95e7e05 and d29150b.

📒 Files selected for processing (13)
  • mlir/include/mlir/Dialect/QCO/Transforms/Mapping/Mapping.h
  • mlir/include/mlir/Dialect/QCO/Utils/Algorithms.h
  • mlir/include/mlir/Dialect/QCO/Utils/Drivers.h
  • mlir/include/mlir/Dialect/QCO/Utils/Graph.h
  • mlir/include/mlir/Dialect/QCO/Utils/Layout.h
  • mlir/include/mlir/Dialect/QCO/Utils/Qubits.h
  • mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
  • mlir/lib/Dialect/QCO/Utils/Algorithms.cpp
  • mlir/lib/Dialect/QCO/Utils/Layout.cpp
  • mlir/lib/Dialect/QCO/Utils/Qubits.cpp
  • mlir/lib/Dialect/QTensor/Utils/TensorIterator.cpp
  • mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp
  • mlir/unittests/Dialect/QCO/Utils/test_drivers.cpp
💤 Files with no reviewable changes (6)
  • mlir/lib/Dialect/QCO/Utils/Algorithms.cpp
  • mlir/unittests/Dialect/QCO/Utils/test_drivers.cpp
  • mlir/include/mlir/Dialect/QCO/Utils/Algorithms.h
  • mlir/include/mlir/Dialect/QCO/Utils/Qubits.h
  • mlir/lib/Dialect/QCO/Utils/Qubits.cpp
  • mlir/include/mlir/Dialect/QCO/Utils/Drivers.h

Comment thread mlir/include/mlir/Dialect/QCO/Utils/Graph.h Outdated
Comment thread mlir/include/mlir/Dialect/QCO/Utils/Graph.h Outdated
Comment thread mlir/include/mlir/Dialect/QCO/Utils/Graph.h Outdated
Comment thread mlir/include/mlir/Dialect/QCO/Utils/Graph.h Outdated
Comment thread mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
Comment thread mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
Comment thread mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
Comment thread mlir/lib/Dialect/QCO/Utils/Layout.cpp
Comment thread mlir/lib/Dialect/QCO/Utils/Layout.cpp
Comment thread mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp Outdated
@MatthiasReumann MatthiasReumann marked this pull request as ready for review June 26, 2026 10:16
@MatthiasReumann

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@CHANGELOG.md`:
- Around line 45-46: The changelog entry currently groups `#1805` under the
initial infrastructure bullet, but it belongs with the place-and-route work.
Update the CHANGELOG.md release note so the reference to `#1805` is moved from the
initial infrastructure list to the existing place-and-route entry, keeping the
mapping aligned with the scf.for restoration support described by that PR.

In `@mlir/include/mlir/Dialect/QCO/Transforms/Mapping/Mapping.h`:
- Around line 27-29: The createMappingPass API currently takes only the coupling
edge set, which loses explicit qubit cardinality and breaks devices with
isolated qubits. Update the pass interface in Mapping.h so createMappingPass
preserves nqubits explicitly, or accepts a separate node set alongside the
DenseSet of couplings. Then propagate that preserved cardinality through the
mapping pass implementation so capacity checks and layout generation can still
account for disconnected qubits.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 338ea373-9f6e-4be1-8acd-5f865529457a

📥 Commits

Reviewing files that changed from the base of the PR and between 95e7e05 and b7950da.

📒 Files selected for processing (15)
  • CHANGELOG.md
  • mlir/include/mlir/Dialect/QCO/Transforms/Mapping/Mapping.h
  • mlir/include/mlir/Dialect/QCO/Utils/Algorithms.h
  • mlir/include/mlir/Dialect/QCO/Utils/Drivers.h
  • mlir/include/mlir/Dialect/QCO/Utils/Graph.h
  • mlir/include/mlir/Dialect/QCO/Utils/Layout.h
  • mlir/include/mlir/Dialect/QCO/Utils/Qubits.h
  • mlir/lib/Dialect/QCO/Transforms/Mapping/Mapping.cpp
  • mlir/lib/Dialect/QCO/Utils/Algorithms.cpp
  • mlir/lib/Dialect/QCO/Utils/Graph.cpp
  • mlir/lib/Dialect/QCO/Utils/Layout.cpp
  • mlir/lib/Dialect/QCO/Utils/Qubits.cpp
  • mlir/lib/Dialect/QTensor/Utils/TensorIterator.cpp
  • mlir/unittests/Dialect/QCO/Transforms/Mapping/test_mapping.cpp
  • mlir/unittests/Dialect/QCO/Utils/test_drivers.cpp
💤 Files with no reviewable changes (6)
  • mlir/lib/Dialect/QCO/Utils/Algorithms.cpp
  • mlir/include/mlir/Dialect/QCO/Utils/Drivers.h
  • mlir/include/mlir/Dialect/QCO/Utils/Qubits.h
  • mlir/unittests/Dialect/QCO/Utils/test_drivers.cpp
  • mlir/include/mlir/Dialect/QCO/Utils/Algorithms.h
  • mlir/lib/Dialect/QCO/Utils/Qubits.cpp

Comment thread CHANGELOG.md
Comment on lines +45 to +46
[#1774], [#1780], [#1781], [#1782], [#1787], [#1802], [#1805], [#1806],
[#1807], [#1808]) ([**@burgholzer**], [**@denialhaag**], [**@taminob**],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Move #1805 to the place-and-route entry instead.

This PR extends the mapping/place-and-route pass for scf.for restoration support, so attaching [#1805] to the “initial infrastructure” bullet makes the release note misleading. It should be grouped with the existing place-and-route entry around Lines 34-37. This matches the PR objective of extending the place-and-route mapping pass with scf.for restoration support.

🤖 Prompt for 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.

In `@CHANGELOG.md` around lines 45 - 46, The changelog entry currently groups
`#1805` under the initial infrastructure bullet, but it belongs with the
place-and-route work. Update the CHANGELOG.md release note so the reference to
`#1805` is moved from the initial infrastructure list to the existing
place-and-route entry, keeping the mapping aligned with the scf.for restoration
support described by that PR.

Comment thread mlir/include/mlir/Dialect/QCO/Transforms/Mapping/Mapping.h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Anything related to C++ code enhancement Improvement of existing feature MLIR Anything related to MLIR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant