Skip to content

Add function to apply CNOTs to a PureFaultSet#690

Open
sunjerry019 wants to merge 26 commits into
mainfrom
PureFaultSet_Extension
Open

Add function to apply CNOTs to a PureFaultSet#690
sunjerry019 wants to merge 26 commits into
mainfrom
PureFaultSet_Extension

Conversation

@sunjerry019
Copy link
Copy Markdown

@sunjerry019 sunjerry019 commented May 14, 2026

Description

"Pushing" fault sets through a CNOT circuit is a commonly-used operation, implementing this function to a PureFaultSet seems like a good quality-of-life improvement. A PureFaultSet now also remembers what kind of error set it represents.

Assisted-by: (Auto) via GitHub Copilot through inline suggestions and reviewed by me.

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). not relevant
  • 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 Coauthored-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.

sunjerry019 and others added 4 commits May 14, 2026 14:58
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <copilot@github.com>
@sunjerry019 sunjerry019 marked this pull request as ready for review May 14, 2026 13:59
@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pehamTom pehamTom added the enhancement Enhancement to existing feature label May 15, 2026
@sunjerry019
Copy link
Copy Markdown
Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Fault tracking now supports different fault kinds (X and Z types)
    • Added capability to apply CNOT transformations to fault sets
  • Tests

    • Comprehensive test coverage added for fault kind validation, CNOT operations, and edge cases

Walkthrough

PureFaultSet now tracks a "kind" parameter (X or Z Pauli type) through constructor, property, and factory methods. A new apply_cnot method implements CNOT transformation logic that differs based on kind. Tests cover kind validation, array dimension checks, and CNOT behavior for both X and Z.

Changes

Fault kind tracking and CNOT transformation

Layer / File(s) Summary
Fault kind property and construction
src/mqt/qecc/circuit_synthesis/faults.py
PureFaultSet constructor accepts and validates a kind parameter (X or Z, default X). A kind property with getter/setter validation is added. from_fault_array and from_cnot_circuit now accept and propagate kind to maintain consistency.
CNOT transformation method
src/mqt/qecc/circuit_synthesis/faults.py
New apply_cnot method validates control/target qubit indices and applies kind-dependent fault update rules: different logic for X vs Z faults. Supports both in-place mutation and returning a new PureFaultSet.
Kind validation and input error tests
tests/circuit_synthesis/test_faults.py
Tests ensure PureFaultSet rejects invalid kind values in constructor, from_fault_array, and property assignment. Tests also validate that from_fault_array rejects 1D (non-2D) fault arrays.
CNOT transformation behavioral tests
tests/circuit_synthesis/test_faults.py
Tests verify apply_cnot correctly transforms faults for both kind=X and kind=Z. Tests validate error handling for invalid qubit indices and confirm inplace=False returns a new fault set without mutating the original.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A fault set now tracks kinds with care,
X's and Z's paired with flair,
CNOT gates transform them true,
Each kind follows its own rules too!
Tests ensure no fault goes astray.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title directly describes the primary change: adding an apply_cnot function to PureFaultSet, which is the main feature being implemented.
Description check ✅ Passed The PR description covers the change summary, motivation, AI assistance disclosure with proper footer, and most checklist items completed. However, documentation updates and CI completion are not yet done.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch PureFaultSet_Extension

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/mqt/qecc/circuit_synthesis/faults.py (4)

270-278: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

copy does not propagate kind.

The copy always has kind="X" regardless of the original's kind, which will cause incorrect behavior if the copy is later used with apply_cnot.

🐛 Proposed fix
     def copy(self) -> PureFaultSet:
         """Create a copy of the PureFaultSet.

         Returns:
             A new PureFaultSet object with the same faults and number of qubits.
         """
-        new_set = PureFaultSet(self.num_qubits)
+        new_set = PureFaultSet(self.num_qubits, kind=self.kind)
         new_set.faults = np.copy(self.faults)
         return new_set
🤖 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 `@src/mqt/qecc/circuit_synthesis/faults.py` around lines 270 - 278, The
PureFaultSet.copy method currently constructs a new_set with
PureFaultSet(self.num_qubits) which defaults kind to "X", so the original
object's kind is lost; update copy to propagate the kind and any other
non-default attributes by assigning new_set.kind = self.kind (and copy any
additional metadata if present) before returning, and ensure faults are still
copied via np.copy(self.faults) as already done.

366-370: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

filter_faults does not propagate kind when inplace=False.

The returned PureFaultSet will have kind="X" regardless of the original's kind.

🐛 Proposed fix
         if inplace:
             self.faults = filtered
             return self

-        return PureFaultSet.from_fault_array(filtered)
+        return PureFaultSet.from_fault_array(filtered, kind=self.kind)
🤖 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 `@src/mqt/qecc/circuit_synthesis/faults.py` around lines 366 - 370, The
filter_faults branch that returns a new PureFaultSet doesn't preserve the
original set's kind (so it always ends up as "X"); update the return path in
filter_faults to propagate self.kind to the new object—either by calling
PureFaultSet.from_fault_array(filtered, kind=self.kind) if that factory accepts
a kind parameter or by creating the PureFaultSet and explicitly setting its
.kind = self.kind before returning; ensure the inplace branch still behaves
unchanged.

88-91: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

combine does not propagate kind and ignores kind mismatch.

When inplace=False, the returned PureFaultSet always has kind="X" (the default) regardless of the original fault sets' kinds. Additionally, combining fault sets of different kinds (e.g., X and Z) should likely raise an error or at least propagate a consistent kind.

🐛 Proposed fix to propagate kind and validate consistency
     def combine(self, other: PureFaultSet, inplace: bool = False) -> PureFaultSet:
         ...
         if self.num_qubits != other.num_qubits:
             msg = "Fault sets must have the same number of qubits to combine."
             raise ValueError(msg)
+        if self.kind != other.kind:
+            msg = "Fault sets must have the same kind to combine."
+            raise ValueError(msg)
         combined_faults = np.vstack([self.faults, other.faults])

         if inplace:
             self.faults = combined_faults
             return self
-        return PureFaultSet.from_fault_array(combined_faults)
+        return PureFaultSet.from_fault_array(combined_faults, kind=self.kind)
🤖 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 `@src/mqt/qecc/circuit_synthesis/faults.py` around lines 88 - 91, The combine
method currently returns a new PureFaultSet with default kind "X" when
inplace=False and does not validate mixed kinds; update the combine
implementation (the combine function that builds combined_faults and calls
PureFaultSet.from_fault_array) to (1) determine the resultant kind by inspecting
self.kind and other.kind, (2) if kinds differ raise a ValueError (or explicit
exception) indicating a kind mismatch, and (3) when constructing the returned
PureFaultSet, pass or set the resolved kind so the new PureFaultSet preserves
the correct kind instead of always defaulting to "X"; if inplace=True, ensure
you also validate kinds before assigning self.faults and preserve self.kind.

387-391: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

permute_qubits does not propagate kind when inplace=False.

The returned PureFaultSet will have kind="X" regardless of the original's kind.

🐛 Proposed fix
         if inplace:
             self.faults = permuted_faults
             return self

-        return PureFaultSet.from_fault_array(permuted_faults)
+        return PureFaultSet.from_fault_array(permuted_faults, kind=self.kind)
🤖 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 `@src/mqt/qecc/circuit_synthesis/faults.py` around lines 387 - 391,
permute_qubits currently returns a new PureFaultSet via
PureFaultSet.from_fault_array(permuted_faults) without preserving the source
object's kind, so when inplace=False the new set ends up with kind="X"; update
permute_qubits to propagate the original kind (e.g. self.kind) to the returned
PureFaultSet — either by calling a constructor/factory that accepts a kind
argument or by setting returned.kind = self.kind immediately after creation —
while keeping the existing inplace behavior intact.
🤖 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 `@src/mqt/qecc/circuit_synthesis/faults.py`:
- Around line 404-409: The current validation in the block that checks control
and target against self.num_qubits allows negative indices due to NumPy negative
indexing; update the check in the method containing control/target (the block
referencing control, target, and self.num_qubits) to also reject negative values
(e.g., ensure control >= 0 and target >= 0) before the existing upper-bound
checks and raise a ValueError with a clear message like "Control and target
indices must be between 0 and {self.num_qubits - 1}." if either is negative or
out of range; keep the existing distinct check that control != target.

In `@tests/circuit_synthesis/test_faults.py`:
- Around line 713-722: Extend the test_apply_cnot_invalid_qubits case to also
assert that negative qubit indices raise the same ValueError: call
fault_set.apply_cnot(control=-1, target=1) and expect the "Control and target
indices must be between 0 and 2." message; update the test function
(test_apply_cnot_invalid_qubits) so it includes this additional with
pytest.raises check against the existing PureFaultSet.apply_cnot usage.

---

Outside diff comments:
In `@src/mqt/qecc/circuit_synthesis/faults.py`:
- Around line 270-278: The PureFaultSet.copy method currently constructs a
new_set with PureFaultSet(self.num_qubits) which defaults kind to "X", so the
original object's kind is lost; update copy to propagate the kind and any other
non-default attributes by assigning new_set.kind = self.kind (and copy any
additional metadata if present) before returning, and ensure faults are still
copied via np.copy(self.faults) as already done.
- Around line 366-370: The filter_faults branch that returns a new PureFaultSet
doesn't preserve the original set's kind (so it always ends up as "X"); update
the return path in filter_faults to propagate self.kind to the new object—either
by calling PureFaultSet.from_fault_array(filtered, kind=self.kind) if that
factory accepts a kind parameter or by creating the PureFaultSet and explicitly
setting its .kind = self.kind before returning; ensure the inplace branch still
behaves unchanged.
- Around line 88-91: The combine method currently returns a new PureFaultSet
with default kind "X" when inplace=False and does not validate mixed kinds;
update the combine implementation (the combine function that builds
combined_faults and calls PureFaultSet.from_fault_array) to (1) determine the
resultant kind by inspecting self.kind and other.kind, (2) if kinds differ raise
a ValueError (or explicit exception) indicating a kind mismatch, and (3) when
constructing the returned PureFaultSet, pass or set the resolved kind so the new
PureFaultSet preserves the correct kind instead of always defaulting to "X"; if
inplace=True, ensure you also validate kinds before assigning self.faults and
preserve self.kind.
- Around line 387-391: permute_qubits currently returns a new PureFaultSet via
PureFaultSet.from_fault_array(permuted_faults) without preserving the source
object's kind, so when inplace=False the new set ends up with kind="X"; update
permute_qubits to propagate the original kind (e.g. self.kind) to the returned
PureFaultSet — either by calling a constructor/factory that accepts a kind
argument or by setting returned.kind = self.kind immediately after creation —
while keeping the existing inplace behavior intact.
🪄 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: 20c121e2-eb38-4d11-8a50-b4c52a9a9776

📥 Commits

Reviewing files that changed from the base of the PR and between 6f6c06f and ea5d490.

📒 Files selected for processing (2)
  • src/mqt/qecc/circuit_synthesis/faults.py
  • tests/circuit_synthesis/test_faults.py

Comment thread src/mqt/qecc/circuit_synthesis/faults.py Outdated
Comment thread tests/circuit_synthesis/test_faults.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Enhancement to existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants