Repository navigation
updates MPO class to allow construction of arbitrary Pauli Hamiltonians - #216
Conversation
… via constructing the full matrix and SVD decomposition
📝 WalkthroughSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughAdds Pauli-string parsing and term-based MPO construction (MPO.hamiltonian, MPO.from_pauli_sum), SVD-based MPO.compress with directional sweeps, and refactors several instance init_* methods into builder-style class/factory APIs (ising, heisenberg, identity, custom, finite_state_machine). Tests and docs updated to use new APIs and validate dense operators. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as Test/User
participant MPO as MPO.hamiltonian / MPO.from_pauli_sum
participant Parser as _parse_pauli_string
participant Builder as _create_term
participant Accumulator as _sum_terms
participant Compressor as _compress_one_sweep
User->>MPO: construct(terms, L, bc, tol, max_bond_dim, n_sweeps)
MPO->>Parser: parse Pauli-term strings
Parser-->>MPO: site→op maps
MPO->>Builder: build MPO tensors per term (with coeff)
Builder-->>Accumulator: provide term tensors
Accumulator-->>MPO: combined MPO tensors
loop n_sweeps
MPO->>Compressor: perform sweep (direction, tol, max_bond_dim)
Compressor-->>MPO: updated/compressed tensors
end
MPO-->>User: return MPO
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/mqt/yaqs/core/data_structures/networks.py(1 hunks)tests/core/data_structures/test_networks.py(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/core/data_structures/test_networks.py (1)
src/mqt/yaqs/core/data_structures/networks.py (3)
MPO(958-1658)init_from_terms(1282-1341)to_matrix(1579-1601)
🪛 Ruff (0.14.0)
src/mqt/yaqs/core/data_structures/networks.py
1421-1421: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1483-1483: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1523-1523: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1524-1524: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1541-1541: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1547-1547: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1548-1548: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1549-1549: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1552-1552: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1555-1555: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1556-1556: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
🔇 Additional comments (1)
src/mqt/yaqs/core/data_structures/networks.py (1)
1282-1342: MPO.init_from_terms: solid construction and compression flowTerm-wise bond‑1 build, block‑diag sum, then local SVD sweeps is correct and matches Hubig et al. API/params read well. LGTM.
…d added test case
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/mqt/yaqs/core/data_structures/networks.py (1)
1505-1562: Remove unused noqa directives.The compression logic is correct, but there are multiple unused
# noqa: N806directives that should be removed.Apply this diff:
- A = self.tensors[k] # noqa: N806 - B = self.tensors[k + 1] # noqa: N806 + A = self.tensors[k] + B = self.tensors[k + 1] phys_dim = A.shape[0] bond_dim_left = A.shape[2] @@ -1540,9 +1540,9 @@ matrix = theta.reshape(bond_dim_left * phys_dim * phys_dim, phys_dim * phys_dim * bond_dim_right) # Apply SVD + truncation - U, S, Vh = np.linalg.svd(matrix, full_matrices=False) # noqa: N806 + U, S, Vh = np.linalg.svd(matrix, full_matrices=False) keep = int(np.sum(tol < S)) if max_bond_dim is not None: keep = min(keep, max_bond_dim) keep = max(1, keep) # keep at least one - U = U[:, :keep] # noqa: N806 # (bond_dim_L phys_dim^2) x bond_dim_trim - S = S[:keep] # noqa: N806 # bond_dim_trim - Vh = Vh[:keep, :] # noqa: N806 # bond_dim_trim x (phys_dim^2 bond_dim_R) + U = U[:, :keep] # (bond_dim_L phys_dim^2) x bond_dim_trim + S = S[:keep] # bond_dim_trim + Vh = Vh[:keep, :] # bond_dim_trim x (phys_dim^2 bond_dim_R) # Rebuild left tensor - UL = U.reshape(bond_dim_left, phys_dim, phys_dim, keep).transpose(1, 2, 0, 3) # noqa: N806 + UL = U.reshape(bond_dim_left, phys_dim, phys_dim, keep).transpose(1, 2, 0, 3) # Rebuild right tensor - SVh = (S[:, None] * Vh).reshape(keep, phys_dim, phys_dim, bond_dim_right) # noqa: N806 - VR = SVh.transpose(1, 2, 0, 3) # noqa: N806 + SVh = (S[:, None] * Vh).reshape(keep, phys_dim, phys_dim, bond_dim_right) + VR = SVh.transpose(1, 2, 0, 3)Based on static analysis hints.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/mqt/yaqs/core/data_structures/networks.py(1 hunks)tests/core/data_structures/test_networks.py(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/core/data_structures/test_networks.py (1)
src/mqt/yaqs/core/data_structures/networks.py (3)
MPO(958-1660)init_from_terms(1282-1341)to_matrix(1581-1603)
🪛 Ruff (0.14.0)
src/mqt/yaqs/core/data_structures/networks.py
1416-1416: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1482-1482: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1525-1525: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1526-1526: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1543-1543: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1549-1549: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1550-1550: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1551-1551: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1554-1554: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1557-1557: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1558-1558: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
🔇 Additional comments (5)
src/mqt/yaqs/core/data_structures/networks.py (2)
1282-1342: LGTM! Well-implemented generic MPO construction.The
init_from_termsmethod correctly implements the Hubig et al. algorithm for constructing MPOs from Pauli strings. The logic handles edge cases (empty terms, single-site), validates input, and applies appropriate compression sweeps.
1371-1414: LGTM! Bond-1 MPO construction is correct.The implementation correctly builds bond-1 MPOs for product terms and applies the coefficient to the first site to avoid numerical overflow.
tests/core/data_structures/test_networks.py (3)
22-22: LGTM! Necessary import for test implementation.The
reduceimport is correctly used for constructing reference Hamiltonians via Kronecker products in the test functions below.
291-327: LGTM! Comprehensive test for multi-term MPO construction.The test correctly validates the MPO construction from a sum of Pauli strings by comparing against a Kronecker-product reference. Static assertions for length, physical dimension, and tensor count are appropriate.
329-349: LGTM! Important edge case test for single-site MPO.This test correctly validates the single-site MPO construction, which is an important edge case that was previously buggy (now fixed). The test ensures the special-case handling in
_mpo_sumworks as expected.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
src/mqt/yaqs/core/data_structures/networks.py (3)
1414-1414: Remove unused noqa directive.The
# noqa: N803directive on line 1414 is unnecessary and should be removed to satisfy the linter.Apply this diff:
- def _mpo_sum(A: list[np.ndarray], B: list[np.ndarray]) -> list[np.ndarray]: # noqa: N803 + def _mpo_sum(A: list[np.ndarray], B: list[np.ndarray]) -> list[np.ndarray]:Based on static analysis hints.
1480-1480: Remove unused noqa directive.The
# noqa: N803directive on line 1480 is unnecessary and should be removed to satisfy the linter.Apply this diff:
- def _mpo_product(A: list[np.ndarray], B: list[np.ndarray]) -> list[np.ndarray]: # noqa: N803 + def _mpo_product(A: list[np.ndarray], B: list[np.ndarray]) -> list[np.ndarray]:Based on static analysis hints.
1503-1560: Remove unused noqa directives and consider relative threshold.Multiple
# noqa: N806directives throughout this method are unnecessary and should be removed to satisfy the linter. Additionally, the current implementation uses an absolute threshold (tol < S), which may not scale well across different problem sizes. Consider using a relative threshold (tol * S[0] < S) to make the truncation scale-aware.Apply this diff to remove unused noqa directives:
- A = self.tensors[k] # noqa: N806 - B = self.tensors[k + 1] # noqa: N806 + A = self.tensors[k] + B = self.tensors[k + 1] phys_dim = A.shape[0] bond_dim_left = A.shape[2] @@ -1538,17 +1538,17 @@ matrix = theta.reshape(bond_dim_left * phys_dim * phys_dim, phys_dim * phys_dim * bond_dim_right) # Apply SVD + truncation - U, S, Vh = np.linalg.svd(matrix, full_matrices=False) # noqa: N806 + U, S, Vh = np.linalg.svd(matrix, full_matrices=False) keep = int(np.sum(tol < S)) if max_bond_dim is not None: keep = min(keep, max_bond_dim) keep = max(1, keep) # keep at least one - U = U[:, :keep] # noqa: N806 # (bond_dim_L phys_dim^2) x bond_dim_trim - S = S[:keep] # noqa: N806 # bond_dim_trim - Vh = Vh[:keep, :] # noqa: N806 # bond_dim_trim x (phys_dim^2 bond_dim_R) + U = U[:, :keep] + S = S[:keep] + Vh = Vh[:keep, :] # Rebuild left tensor - UL = U.reshape(bond_dim_left, phys_dim, phys_dim, keep).transpose(1, 2, 0, 3) # noqa: N806 + UL = U.reshape(bond_dim_left, phys_dim, phys_dim, keep).transpose(1, 2, 0, 3) # Rebuild right tensor - SVh = (S[:, None] * Vh).reshape(keep, phys_dim, phys_dim, bond_dim_right) # noqa: N806 - VR = SVh.transpose(1, 2, 0, 3) # noqa: N806 + SVh = (S[:, None] * Vh).reshape(keep, phys_dim, phys_dim, bond_dim_right) + VR = SVh.transpose(1, 2, 0, 3)Optional: To make the threshold scale-aware, consider changing line 1542:
- keep = int(np.sum(tol < S)) + keep = int(np.sum(tol * S[0] < S)) if len(S) > 0 and S[0] > 0 else len(S)Based on static analysis hints.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
src/mqt/yaqs/core/data_structures/networks.py(1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.2)
src/mqt/yaqs/core/data_structures/networks.py
1414-1414: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1480-1480: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1523-1523: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1524-1524: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1541-1541: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1547-1547: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1548-1548: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1549-1549: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1552-1552: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1555-1555: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
1556-1556: Unused noqa directive (non-enabled: N806)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
🔇 Additional comments (1)
src/mqt/yaqs/core/data_structures/networks.py (1)
1369-1412: LGTM!The bond-1 MPO construction logic is correct and well-documented. The coefficient is appropriately applied to the first site tensor to avoid numerical overflow when summing many terms.
|
Added a MPO initializer |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In @src/mqt/yaqs/core/data_structures/networks.py:
- Around line 990-997: Annotate the module-level/class-level constants to
silence RUF012: declare _PAULI_2 as a ClassVar[Dict[str, np.ndarray]] and _VALID
as a ClassVar[FrozenSet[str]] (and _PAULI_TOKEN_RE as ClassVar[Pattern[str]] if
needed), and add the corresponding imports (from typing import ClassVar, Dict,
FrozenSet, Pattern) so linters treat them as class-level constants rather than
instance attributes; update the type hints for the symbols _PAULI_2, _VALID (and
optionally _PAULI_TOKEN_RE) accordingly.
In @tests/analog/test_analog_tjm.py:
- Around line 57-58: The call to MPO.ising(L, J, g) constructs an MPO but its
return value is unused; either remove this dead statement or assign the result
to a variable (e.g., m = MPO.ising(L, J, g)) and use that variable in subsequent
assertions; update references in the test to use the assigned MPO if the test
intended to validate properties of the constructed MPO.
In @tests/test_simulator.py:
- Around line 462-463: The call to the classmethod MPO.ising is discarding its
returned MPO and leaves H_0 uninitialized; change the call to capture and assign
the returned MPO back to H_0 (e.g., call MPO.ising(L, J, g) or H_0.ising(L, J,
g) and assign the result to H_0) so H_0 holds the new initialized MPO instance.
- Around line 572-573: The call to MPO.ising(L, J, g) is a classmethod that
returns an MPO, but its return value is being discarded; replace the two lines
with a single assignment that captures the returned MPO (e.g., H_0 =
MPO.ising(L, J, g)) so H_0 holds the constructed operator.
- Around line 686-687: The call to the classmethod ising is discarding its
returned MPO; change the test to capture the returned MPO by assigning the
result of MPO.ising(L, J, g) (or H_0 = MPO.ising(L, J, g)) instead of calling
H_0.ising(L, J, g) on the instance; update the reference in
tests/test_simulator.py so H_0 holds the MPO returned by the ising classmethod.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (7)
docs/examples/analog_simulation.mdsrc/mqt/yaqs/core/data_structures/networks.pytests/analog/test_analog_tjm.pytests/core/data_structures/test_networks.pytests/core/methods/test_bug.pytests/core/methods/test_tdvp.pytests/test_simulator.py
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2026-01-08T10:07:23.393Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 20
File: python/mqt/core/plugins/catalyst/device.py:69-69
Timestamp: 2026-01-08T10:07:23.393Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, Ruff is configured with select = ["ALL"] and only specific rules are disabled. SLF001 (flake8-self - private member access) is enabled, so `# noqa: SLF001` directives are necessary when accessing private attributes like `device._to_matrix_ops` in python/mqt/core/plugins/catalyst/device.py, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-14T15:23:54.712Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 23
File: docs/conf.py:110-130
Timestamp: 2025-12-14T15:23:54.712Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, the Ruff configuration has 'ALL' rules enabled with only specific rules disabled. PLR6301 (no-self-use) is active, so `# noqa: PLR6301` directives are necessary for methods that don't use self, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:25.619Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: src/mqt/predictor/rl/predictorenv.py:271-271
Timestamp: 2025-12-25T13:28:25.619Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with an extensive set of rules including SLF (flake8-self) in the extend-select list. The `# noqa: SLF001` directive for private member access (e.g., `self.state._layout = self.layout` in src/mqt/predictor/rl/predictorenv.py) is necessary and appropriate, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:10.402Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: tests/compilation/test_predictor_rl.py:225-225
Timestamp: 2025-12-25T13:28:10.402Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with the "SLF" (flake8-self) rule category enabled in extend-select. SLF001 (private member access) is active, so `# noqa: SLF001` directives are necessary when accessing private methods/attributes (e.g., `_ensure_device_averages_cached()`), even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
🧬 Code graph analysis (5)
tests/core/methods/test_bug.py (1)
src/mqt/yaqs/core/data_structures/networks.py (3)
custom(1294-1314)MPO(957-1617)ising(1054-1090)
src/mqt/yaqs/core/data_structures/networks.py (1)
src/mqt/yaqs/core/libraries/gate_library.py (5)
Destroy(690-714)x(286-292)h(313-319)U(949-983)conj(269-275)
tests/core/methods/test_tdvp.py (1)
src/mqt/yaqs/core/data_structures/networks.py (2)
MPO(957-1617)ising(1054-1090)
tests/test_simulator.py (1)
src/mqt/yaqs/core/data_structures/networks.py (2)
MPO(957-1617)ising(1054-1090)
tests/analog/test_analog_tjm.py (1)
src/mqt/yaqs/core/data_structures/networks.py (2)
MPO(957-1617)ising(1054-1090)
🪛 Ruff (0.14.10)
src/mqt/yaqs/core/data_structures/networks.py
990-995: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
🔇 Additional comments (36)
docs/examples/analog_simulation.md (1)
30-30: LGTM!The documentation correctly demonstrates the new
MPO.ising(L, J, g)class method API, which aligns with the broader refactor replacing instance-based initializers with factory-style constructors.tests/core/methods/test_bug.py (5)
83-85: LGTM!The test correctly uses the new
mpo.custom(tensors, transpose=False)API to create a random MPO.
98-99: LGTM!Correctly updated to use the new
mpo.custom([mpo_tensor])API.
122-123: LGTM!Correctly updated to use the new
mpo.custom(mpo_tensors, transpose=False)API.
255-255: LGTM!Correctly migrated to the factory-style
MPO.ising(1, 1, 0.5)class method.
272-272: LGTM!Correctly migrated to the factory-style
MPO.ising(3, 1, 0.5)class method.tests/analog/test_analog_tjm.py (2)
90-91: LGTM!Correctly migrated to
MPO.ising(L, J, g)and assigned toH.
124-125: LGTM!All remaining test functions correctly use the new
MPO.ising(...)factory method with proper variable assignment.Also applies to: 154-155, 184-185, 214-215, 255-256, 381-382
tests/core/methods/test_tdvp.py (4)
245-246: LGTM!Correctly migrated to
MPO.ising(L, J, g)class method.
274-275: LGTM!Correctly migrated to
MPO.ising(L, J, g)class method.
315-315: LGTM!Correctly migrated to
MPO.ising(L, J, g)class method.
348-348: LGTM!Correctly migrated to
MPO.ising(L, J, g)class method.tests/test_simulator.py (3)
77-77: LGTM!Correctly uses the factory-style
MPO.ising(length, J=1, g=0.5)class method.
130-130: LGTM!Correctly uses the factory-style
MPO.ising(length, J=1, g=0.5)class method.
179-179: LGTM!Correctly uses the factory-style
MPO.ising(length, J=1, g=0.5)class method.tests/core/data_structures/test_networks.py (10)
38-38: LGTM!Import updated to include
GateLibraryandIdfor test usage.
104-160: LGTM!The dense Hamiltonian helper functions (
_embed_one_body,_embed_two_body,_ising_dense,_heisenberg_dense) correctly implement reference dense matrix construction for verifying MPO correctness. These are well-structured and will serve as ground truth for MPO validation tests.
163-183: Excellent addition of correctness verification tests.
test_ising_correct_operatorandtest_heisenberg_correct_operatorvalidate the new Pauli-sum MPO construction against analytically-constructed dense Hamiltonians. This is a strong verification approach that ensures the MPOto_matrix()representation matches the expected physics.
186-196: LGTM!Test correctly migrated to use
mpo.identity(length, physical_dimension=pdim).
207-235: LGTM!Test correctly migrated to use
mpo.finite_state_machine(length, left_bound, inner, right_bound).
238-261: LGTM!Test correctly migrated to use
mpo.custom(tensors).
264-285: LGTM!Test correctly migrated to use
MPO.ising(length, J, g)classmethod.
288-297: LGTM!Test correctly migrated to use
MPO.ising(length, J, g)classmethod.
300-319: LGTM!Test correctly migrated to use
MPO.ising(length, J, g)classmethod.
322-334: LGTM!Test correctly migrated to use
mpo.identity(length, pdim).src/mqt/yaqs/core/data_structures/networks.py (11)
1053-1090: LGTM!The
isingclassmethod cleanly delegates tohamiltonianwith appropriate two-body (-J * Z⊗Z) and one-body (-g * X) terms. The docstring is comprehensive and matches the implementation.
1092-1133: LGTM!The
heisenbergclassmethod correctly constructs an XYZ Heisenberg Hamiltonian with optional Z field. The conditionalone_body=[(-h, "Z")] if h != 0 else []appropriately handles the case when no field is applied.
1250-1265: LGTM!The
identitymethod is renamed frominit_identityand maintains the same functionality.
1267-1292: LGTM!The
finite_state_machinemethod is renamed frominit_custom_hamiltonianand maintains the same functionality for constructing MPOs from explicit boundary and inner tensors.
1294-1314: LGTM!The
custommethod is renamed frominit_customand maintains the same functionality with improved keyword-only argument pattern fortranspose.
1316-1363: LGTM!The
from_pauli_summethod correctly:
- Validates physical dimension and length
- Parses Pauli string specifications
- Creates individual term MPOs
- Sums terms via block-diagonal concatenation
- Compresses the result
The implementation follows the algorithm from Hubig et al. as mentioned in the PR objectives.
1365-1408: LGTM!The
compressmethod provides a clean public API for MPO compression with flexible sweep direction control. Input validation is thorough and the schedule mapping is clear.
1410-1459: LGTM!The
_compress_one_sweepmethod correctly implements local SVD-based compression:
- Contracts adjacent tensors
- Performs SVD with truncation based on tolerance and max_bond_dim
- Reconstructs left and right tensors with proper index ordering
The index manipulation and reshape operations correctly preserve the MPO structure.
1560-1571: LGTM!The
_create_termhelper correctly constructs a single Pauli term MPO with bond dimension 1 throughout, applying the coefficient to the first tensor.
1573-1590: LGTM!The
_parse_pauli_stringmethod provides robust parsing of Pauli string specifications with:
- Support for comma or space-separated tokens
- Case-insensitive matching
- Duplicate site detection
- Validation of remaining tokens after regex matching
1592-1617: LGTM!The
_sum_termsstatic method correctly implements MPO addition via block-diagonal concatenation of virtual bonds. The boundary handling for first/last sites is correct, and the inner site concatenation properly forms block-diagonal structure.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/mqt/yaqs/core/data_structures/networks.py (1)
1254-1318: API inconsistency: mix of classmethods and instance methods.
ising(),heisenberg(),coupled_transmon(), andhamiltonian()are classmethods that return a newMPOinstance, whileidentity(),finite_state_machine(), andcustom()are instance methods that mutateselfin-place. This inconsistency can confuse users:# Classmethod pattern (returns new instance) mpo = MPO.ising(L=10, J=1, g=0.5) # Instance method pattern (mutates in-place) mpo = MPO() mpo.identity(length=10)Consider refactoring
identity(),finite_state_machine(), andcustom()to classmethods for a consistent API surface.
🤖 Fix all issues with AI agents
In @src/mqt/yaqs/core/data_structures/networks.py:
- Around line 990-997: The class-level mutable/static attributes _PAULI_2,
_VALID, and _PAULI_TOKEN_RE should be annotated with typing.ClassVar to satisfy
static analysis; import ClassVar (and re.Pattern if you want precise type for
the regex) unconditionally at top-level and change their annotations to
something like _PAULI_2: ClassVar[dict[str, np.ndarray]] = {...}, _VALID:
ClassVar[frozenset[str]] = frozenset(...), and _PAULI_TOKEN_RE:
ClassVar[re.Pattern] = re.compile(...). Ensure the import of ClassVar is added
(not only under TYPE_CHECKING) so annotations exist at runtime.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
docs/examples/transmon_emulation.mdsrc/mqt/yaqs/core/data_structures/networks.pytests/test_simulator.py
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2026-01-08T10:07:23.393Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 20
File: python/mqt/core/plugins/catalyst/device.py:69-69
Timestamp: 2026-01-08T10:07:23.393Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, Ruff is configured with select = ["ALL"] and only specific rules are disabled. SLF001 (flake8-self - private member access) is enabled, so `# noqa: SLF001` directives are necessary when accessing private attributes like `device._to_matrix_ops` in python/mqt/core/plugins/catalyst/device.py, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-14T15:23:54.712Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 23
File: docs/conf.py:110-130
Timestamp: 2025-12-14T15:23:54.712Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, the Ruff configuration has 'ALL' rules enabled with only specific rules disabled. PLR6301 (no-self-use) is active, so `# noqa: PLR6301` directives are necessary for methods that don't use self, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:25.619Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: src/mqt/predictor/rl/predictorenv.py:271-271
Timestamp: 2025-12-25T13:28:25.619Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with an extensive set of rules including SLF (flake8-self) in the extend-select list. The `# noqa: SLF001` directive for private member access (e.g., `self.state._layout = self.layout` in src/mqt/predictor/rl/predictorenv.py) is necessary and appropriate, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:10.402Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: tests/compilation/test_predictor_rl.py:225-225
Timestamp: 2025-12-25T13:28:10.402Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with the "SLF" (flake8-self) rule category enabled in extend-select. SLF001 (private member access) is active, so `# noqa: SLF001` directives are necessary when accessing private methods/attributes (e.g., `_ensure_device_averages_cached()`), even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
🧬 Code graph analysis (1)
tests/test_simulator.py (1)
src/mqt/yaqs/core/data_structures/networks.py (3)
MPO(957-1621)ising(1054-1090)coupled_transmon(1136-1252)
🪛 Ruff (0.14.10)
src/mqt/yaqs/core/data_structures/networks.py
990-995: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
🔇 Additional comments (18)
docs/examples/transmon_emulation.md (1)
35-42: LGTM!The documentation correctly demonstrates the updated API using the classmethod constructor
MPO.coupled_transmon(...)instead of the previous instance-based initialization pattern.tests/test_simulator.py (7)
77-77: LGTM!The test correctly uses the new
MPO.ising()classmethod constructor with appropriate parameters.
130-130: LGTM!Consistent migration to
MPO.ising()classmethod.
179-179: LGTM!Consistent migration to
MPO.ising()classmethod.
462-462: LGTM!Consistent migration to
MPO.ising()classmethod.
571-571: LGTM!Consistent migration to
MPO.ising()classmethod.
684-684: LGTM!Consistent migration to
MPO.ising()classmethod.
841-849: LGTM!The test correctly uses the new
MPO.coupled_transmon()classmethod constructor, and the parameter names match the new API signature.src/mqt/yaqs/core/data_structures/networks.py (10)
999-1051: LGTM!The
hamiltonian()classmethod correctly:
- Validates inputs (length > 0, valid boundary conditions)
- Builds term specifications for both two-body and one-body interactions
- Properly handles periodic boundary conditions with modulo arithmetic
- Delegates to
from_pauli_sum()for MPO construction
1053-1133: LGTM!The
ising()andheisenberg()classmethods correctly delegate tohamiltonian()with proper term specifications:
- Ising:
$-J \sum Z_i Z_{i+1} - g \sum X_i$ - Heisenberg:
$-J_x \sum X_i X_{i+1} - J_y \sum Y_i Y_{i+1} - J_z \sum Z_i Z_{i+1} - h \sum Z_i$ The conditional
one_bodyforh != 0in Heisenberg avoids unnecessary identity terms.
1135-1252: LGTM!The
coupled_transmon()classmethod correctly implements the transmon-resonator chain Hamiltonian:
- Proper tensor structure for boundary and bulk sites
- Correct physical dimension handling for alternating qubits/resonators
- Appropriate transpose to match MPO index convention
(phys_out, phys_in, left, right)
1358-1364: Verify: zero MPO for empty terms list.When
termsis empty, the method creates a zero MPO (tensors filled with zeros). This produces an MPO representing the zero operator, which may not be the expected behavior for users who accidentally pass an empty list.Consider either:
- Raising an error for empty terms
- Documenting this behavior in the docstring
1414-1463: LGTM!The
_compress_one_sweep()method correctly implements local SVD compression:
- Proper tensor contraction of adjacent sites
- Correct reshape for SVD (grouping left/right virtual and physical indices)
- Appropriate truncation based on tolerance threshold
- Ensures at least one singular value is kept
- Correct reconstruction of left/right tensors with proper transposition
1577-1594: LGTM!The
_parse_pauli_string()method correctly parses Pauli term specifications with proper validation for duplicate sites and invalid tokens. The regex pattern appropriately handles various input formats.
1596-1620: LGTM!The
_sum_terms()method correctly implements MPO summation via bond dimension expansion using block-diagonal concatenation. The special cases for boundary tensors (first and last sites) are handled correctly.
1564-1575: LGTM!The
_create_term()method correctly creates a bond-dimension-1 MPO for a single Pauli string term, with proper coefficient application and identity filling for unspecified sites.
1554-1555: LGTM!The usage of
identity_mpo.identity(self.length)is consistent withidentity()being an instance method.
1465-1481: LGTM!The
rotate()method correctly implements MPO rotation by swapping physical dimensions. The keyword-onlyconjugateargument is a good API choice for boolean flags.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/mqt/yaqs/core/data_structures/networks.py (1)
1291-1308: Bug:identity()ignoresphysical_dimensionparameter.The identity matrix is hardcoded as 2×2, ignoring the
physical_dimensionparameter. This will produce incorrect results for non-qubit systems (e.g., qutrits).🐛 Proposed fix
def identity(self, length: int, physical_dimension: int = 2) -> None: """Initialize identity MPO. Initializes the network with identity matrices. Parameters: length (int): The number of identity matrices to initialize. physical_dimension (int, optional): The physical dimension of the identity matrices. Default is 2. """ - mat = np.eye(2, dtype=np.complex128) + mat = np.eye(physical_dimension, dtype=np.complex128) mat = np.expand_dims(mat, (2, 3)) self.length = length self.physical_dimension = physical_dimension self.tensors = [] for _ in range(length): self.tensors.append(mat)
🤖 Fix all issues with AI agents
In @src/mqt/yaqs/core/data_structures/networks.py:
- Line 1091: Remove the unused noqa directive on the parameter declaration:
locate the parameter "J: float, # noqa: N803" in the affected function/class in
networks.py and delete the " # noqa: N803" suffix so the parameter is simply "J:
float,"; no other changes needed.
- Around line 1130-1132: Remove the unused inline noqa directives from the
parameter names: delete the trailing " # noqa: N803" on the Jx, Jy, and Jz
parameters so the signature simply uses Jx: float, Jy: float, Jz: float (locate
the occurrence in the function/method where Jx, Jy, Jz are declared and remove
the "# noqa: N803" tokens).
In @tests/core/data_structures/test_networks.py:
- Line 47: Remove the unused "# noqa: N803" directives from the function
definitions that currently include them: _embed_one_body, _embed_two_body, and
_embed_three_body; simply delete the trailing "# noqa: N803" from their def
lines so the function signatures remain unchanged but the stale noqa comments
are removed.
- Around line 113-139: Remove the unused lint suppression from the function
definition: edit the _heisenberg_dense function signature to delete the "# noqa:
N803" comment so the line reads "def _heisenberg_dense(L: int, Jx: float, Jy:
float, Jz: float, h: float) -> np.ndarray:"; leave all logic unchanged.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/mqt/yaqs/core/data_structures/networks.pytests/core/data_structures/test_networks.py
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: burgholzer
Repo: munich-quantum-toolkit/yaqs PR: 212
File: CHANGELOG.md:12-15
Timestamp: 2025-10-14T14:37:38.047Z
Learning: In the munich-quantum-toolkit/yaqs project, changelog entries follow the template: "- $TITLE ([#$NUMBER]($URL)) ([**AUTHOR**](https://github.com/$AUTHOR))". Issue references should not be included in changelog entries; the PR number is sufficient for traceability.
📚 Learning: 2026-01-08T10:07:23.393Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 20
File: python/mqt/core/plugins/catalyst/device.py:69-69
Timestamp: 2026-01-08T10:07:23.393Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, Ruff is configured with select = ["ALL"] and only specific rules are disabled. SLF001 (flake8-self - private member access) is enabled, so `# noqa: SLF001` directives are necessary when accessing private attributes like `device._to_matrix_ops` in python/mqt/core/plugins/catalyst/device.py, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-14T15:23:54.712Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 23
File: docs/conf.py:110-130
Timestamp: 2025-12-14T15:23:54.712Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, the Ruff configuration has 'ALL' rules enabled with only specific rules disabled. PLR6301 (no-self-use) is active, so `# noqa: PLR6301` directives are necessary for methods that don't use self, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:25.619Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: src/mqt/predictor/rl/predictorenv.py:271-271
Timestamp: 2025-12-25T13:28:25.619Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with an extensive set of rules including SLF (flake8-self) in the extend-select list. The `# noqa: SLF001` directive for private member access (e.g., `self.state._layout = self.layout` in src/mqt/predictor/rl/predictorenv.py) is necessary and appropriate, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:10.402Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: tests/compilation/test_predictor_rl.py:225-225
Timestamp: 2025-12-25T13:28:10.402Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with the "SLF" (flake8-self) rule category enabled in extend-select. SLF001 (private member access) is active, so `# noqa: SLF001` directives are necessary when accessing private methods/attributes (e.g., `_ensure_device_averages_cached()`), even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
🧬 Code graph analysis (1)
tests/core/data_structures/test_networks.py (2)
src/mqt/yaqs/core/libraries/gate_library.py (6)
GateLibrary(1630-1724)Id(744-763)X(602-621)Z(646-665)H(668-687)h(313-319)src/mqt/yaqs/core/data_structures/networks.py (8)
op(1056-1061)MPO(957-1749)ising(1088-1124)to_matrix(1568-1590)heisenberg(1127-1167)identity(1291-1308)finite_state_machine(1310-1335)custom(1337-1357)
🪛 Ruff (0.14.10)
tests/core/data_structures/test_networks.py
47-47: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
64-64: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
88-88: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
113-113: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
src/mqt/yaqs/core/data_structures/networks.py
1091-1091: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1130-1130: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1131-1131: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1132-1132: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
🔇 Additional comments (13)
tests/core/data_structures/test_networks.py (4)
38-45: LGTM!Defining local Pauli matrices for test verification is appropriate. This isolates tests from the production
GateLibraryimplementation when building reference dense Hamiltonians.
205-228: Excellent correctness tests for the new MPO builders.These tests properly validate that the MPO representation matches the exact dense Hamiltonian. Using
L=5keeps the dense matrix tractable (32×32) while still exercising the construction logic across multiple sites.
230-306: LGTM!The tests correctly exercise the builder methods (
identity,finite_state_machine,custom) using the instance-method pattern and thoroughly validate tensor shapes and values.
308-378: LGTM!Tests are properly updated to use the new
MPO.ising(...)classmethod and continue to validate the core MPO operations (conversion, validation, rotation, identity check).src/mqt/yaqs/core/data_structures/networks.py (9)
21-22: LGTM!Appropriate imports for regex-based Pauli string parsing and proper type annotations.
995-1006: LGTM!The class variables are well-defined. The regex pattern correctly handles case-insensitive Pauli labels with optional whitespace before the site index.
1008-1085: LGTM!The
hamiltonian()classmethod correctly generates Pauli-string terms for both open and periodic boundary conditions. The validation and delegation tofrom_pauli_sum()is clean.
1169-1289: LGTM!The refactoring to a classmethod is clean. The tensor construction correctly implements the coupled transmon-resonator Hamiltonian with proper MPO conventions.
1359-1423: LGTM!The
from_pauli_sum()method correctly assembles MPO terms from Pauli string specifications with proper validation of sites and operators. The handling of empty terms (creating a zero operator) is mathematically sound.
1425-1530: LGTM!The compression implementation is correct. The SVD-based sweep with configurable directions and tolerance is well-implemented, and the minimum rank of 1 ensures numerical stability.
1532-1548: LGTM!The
rotate()method correctly handles physical dimension transposition with optional conjugation.
1631-1662: LGTM!The
_create_term()method correctly constructs a bond-dimension-1 MPO for a single Pauli string term. Applying the coefficient to the first tensor is the standard convention.
1664-1748: LGTM!Both helper methods are well-implemented:
_parse_pauli_string()provides robust parsing with duplicate site detection and validation of malformed tokens._sum_terms()correctly implements block-diagonal concatenation for MPO addition.
There was a problem hiding this comment.
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 (1)
src/mqt/yaqs/core/data_structures/networks.py (1)
1297-1363: Consider API consistency: classmethods vs. instance methods.The builder methods
identity,finite_state_machine, andcustomare implemented as in-place instance methods (returningNone), whileising,heisenberg,hamiltonian, andcoupled_transmonare classmethods that return newMPOinstances.This creates two different usage patterns:
# Classmethod pattern (newer, preferred?) mpo1 = MPO.ising(length=10, J=1.0, g=0.5) # Instance method pattern (legacy?) mpo2 = MPO() mpo2.identity(length=10)Suggested improvement: Consider converting
identity,finite_state_machine, andcustomto classmethods for consistency, or document the rationale for the different patterns.
🤖 Fix all issues with AI agents
In @src/mqt/yaqs/simulator.py:
- Line 150: Wrap the fallback chain that returns os.cpu_count() or
multiprocessing.cpu_count() or 1 in a try/except so multiprocessing.cpu_count()
cannot raise out unhandled (e.g., NotImplementedError); catch
NotImplementedError (and a broad Exception as a safeguard), and on exception
return 1 or use os.cpu_count() result if available, ensuring the expression
using os.cpu_count() and multiprocessing.cpu_count() is evaluated safely.
- Around line 142-147: The attribute-check refactor removed the try/except
around os.sched_getaffinity(0), so when calling sched_getaffinity (via fn =
getattr(os, "sched_getaffinity", None) and sched_getaffinity = cast(...)) the
OSError can bubble up; wrap the call to sched_getaffinity(0) in a try/except
OSError (and OSError subclasses) and on exception fall through to the existing
fallback logic (the subsequent CPU-count fallback) instead of raising; preserve
the current behavior of returning len(result) when the call succeeds.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/mqt/yaqs/core/data_structures/networks.pysrc/mqt/yaqs/simulator.py
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2026-01-08T10:07:23.393Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 20
File: python/mqt/core/plugins/catalyst/device.py:69-69
Timestamp: 2026-01-08T10:07:23.393Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, Ruff is configured with select = ["ALL"] and only specific rules are disabled. SLF001 (flake8-self - private member access) is enabled, so `# noqa: SLF001` directives are necessary when accessing private attributes like `device._to_matrix_ops` in python/mqt/core/plugins/catalyst/device.py, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-14T15:23:54.712Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 23
File: docs/conf.py:110-130
Timestamp: 2025-12-14T15:23:54.712Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, the Ruff configuration has 'ALL' rules enabled with only specific rules disabled. PLR6301 (no-self-use) is active, so `# noqa: PLR6301` directives are necessary for methods that don't use self, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:25.619Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: src/mqt/predictor/rl/predictorenv.py:271-271
Timestamp: 2025-12-25T13:28:25.619Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with an extensive set of rules including SLF (flake8-self) in the extend-select list. The `# noqa: SLF001` directive for private member access (e.g., `self.state._layout = self.layout` in src/mqt/predictor/rl/predictorenv.py) is necessary and appropriate, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
📚 Learning: 2025-12-25T13:28:10.402Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/predictor PR: 526
File: tests/compilation/test_predictor_rl.py:225-225
Timestamp: 2025-12-25T13:28:10.402Z
Learning: In the munich-quantum-toolkit/predictor repository, Ruff is configured with the "SLF" (flake8-self) rule category enabled in extend-select. SLF001 (private member access) is active, so `# noqa: SLF001` directives are necessary when accessing private methods/attributes (e.g., `_ensure_device_averages_cached()`), even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
src/mqt/yaqs/core/data_structures/networks.py
🧬 Code graph analysis (1)
src/mqt/yaqs/core/data_structures/networks.py (1)
src/mqt/yaqs/core/libraries/gate_library.py (5)
x(286-292)h(313-319)u(412-421)conj(269-275)p(400-409)
🪛 Ruff (0.14.10)
src/mqt/yaqs/core/data_structures/networks.py
1097-1097: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1136-1136: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1137-1137: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1138-1138: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Lint / 🚨 Lint
🔇 Additional comments (14)
src/mqt/yaqs/simulator.py (2)
57-60: LGTM! Good typing hygiene.The addition of
castand guardingCallableunderTYPE_CHECKINGis a best practice that reduces runtime overhead while maintaining type safety.
96-96: LGTM! Consistent with the import reorganization.Correctly removed the duplicate
Callableimport since it's now imported at the top-level TYPE_CHECKING block.src/mqt/yaqs/core/data_structures/networks.py (12)
21-21: LGTM: Clean import additions and type alias.The new imports (
re,NDArray,Destroy) and theComplexTensortype alias support the Pauli-string parsing and MPO construction features. The type alias improves code readability.Also applies to: 26-26, 29-29, 956-956
997-1008: LGTM: Well-defined Pauli constants and parsing pattern.The class-level constants are properly defined:
_PAULI_2contains correct 2×2 Pauli matrices_VALIDensures type safety for operator validation_PAULI_TOKEN_REcorrectly parses compact Pauli-string notation like "X0 Y2 Z5"Using
ClassVarappropriately marks these as class-level attributes.
1014-1091: LGTM: Solid API for Hamiltonian construction.The
hamiltonianclassmethod provides a clean interface for building MPOs from one- and two-body Pauli interactions. The implementation correctly:
- Validates inputs (length, boundary conditions, operator labels)
- Handles open vs. periodic boundary conditions
- Expands interaction templates to full Pauli-string terms
- Delegates to
from_pauli_sumfor the actual MPO assembly
1175-1295: LGTM: Clean refactor to classmethod with good documentation.The conversion of
coupled_transmonto a classmethod aligns with the new builder pattern. The implementation correctly:
- Constructs alternating qubit/resonator chain tensors
- Handles boundary conditions (first, last, middle sites)
- Documents the backward-compatibility caveat about
physical_dimensionstoring onlyqubit_dimdespite alternating dimensions- Validates the constructed MPO
1365-1429: Solid Pauli-sum MPO builder with one edge case to verify.The
from_pauli_summethod correctly:
- Validates inputs (dimension, length, sites, operators)
- Parses and assembles Pauli-string terms
- Sums terms via block-diagonal bond concatenation
- Compresses the result to reduce bond dimension
Edge case: When
termsis empty (line 1420), the method constructs a zero MPO (all-zero tensors). Verify this is the intended behavior rather than an identity MPO or an error.# Verify zero MPO behavior for empty terms mpo = MPO() mpo.from_pauli_sum(terms=[], length=4) mat = mpo.to_matrix() print("Zero MPO check:", np.allclose(mat, 0)) # Should be True
1431-1536: Excellent MPO compression implementation.The compression methods are well-designed:
- Public
compressAPI provides flexible multi-sweep scheduling- Internal
_compress_one_sweepimplements the SVD logic cleanly- Proper handling of edge cases (empty MPO, single-site, minimum rank)
The SVD truncation correctly:
- Contracts adjacent tensor pairs
- Reshapes to matrix form for SVD
- Keeps singular values where
tol < s(line 1519)- Enforces
keep = max(1, keep)to prevent rank-zero bonds (line 1522)
1538-1554: LGTM: Simple and correct dimension rotation.The
rotatemethod correctly swaps the physical output/input legs of the MPO, with optional complex conjugation for Hermitian transposition.
1637-1668: LGTM: Correct single-term MPO construction.The
_create_termhelper correctly constructs a bond-dimension-1 MPO for a single Pauli-string term:
- Defaults unspecified sites to identity
- Applies the coefficient to the first site tensor
- Produces properly shaped (2, 2, 1, 1) tensors
1670-1710: LGTM: Robust Pauli-string parser.The
_parse_pauli_stringmethod provides robust parsing with good error handling:
- Accepts flexible whitespace/comma-separated notation
- Detects duplicate site specifications
- Validates token format
- Provides clear error messages
1712-1755: LGTM: Correct MPO direct-sum implementation.The
_sum_termsmethod correctly implements block-diagonal concatenation of MPO bond spaces:
- Handles single-site case (direct addition)
- Properly sizes new tensors with enlarged bonds
- Places sub-blocks correctly (top-left and bottom-right)
- Maintains MPO structural validity
1627-1628: LGTM: Updated to use refactored API.Correctly updated to call
identity(...)instead of the legacyinit_identity(...).
1093-1173: Clean Hamiltonian builder methods with correct noqa directives.The
isingandheisenbergclassmethods provide convenient physics-oriented APIs that delegate to the generalhamiltonianbuilder. The implementations are correct and follow standard conventions for these models.The
# noqa: N803directives on lines 1097, 1136-1138 are necessary and correct. The Ruff configuration enables all rules viaselect = ["ALL"]and does not disable N803, so these directives appropriately suppress the invalid-name warning for the physics-convention parameter names (J, g, Jx, Jy, Jz).
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Aaron Sander <61705296+aaronleesander@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Aaron Sander <61705296+aaronleesander@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/core/data_structures/test_networks.py (1)
303-305: Consider usingstrict=Truefor additional safety.Since the list lengths are already asserted equal on line 301, using
strict=Truewould be more idiomatic and provide an extra validation layer.🧹 Proposed fix
- for original, created in zip(tensors, mpo.tensors, strict=False): + for original, created in zip(tensors, mpo.tensors, strict=True):
🤖 Fix all issues with AI agents
In @tests/core/data_structures/test_networks.py:
- Line 88: Remove the unused " # noqa: N803" directive from the helper function
definitions that disable the N803 rule; specifically edit the function signature
for _ising_dense and the other helper in the same file (e.g., _ising_sparse) in
tests/core/data_structures/test_networks.py to drop the trailing " # noqa:
N803" so the definitions are just plain def _ising_dense(L: int, J: float, g:
float) -> np.ndarray: (and similarly for the other helper).
- Line 64: The function definition for _embed_two_body currently includes an
unnecessary noqa directive ("# noqa: N803"); remove the trailing ", # noqa:
N803" from the def line so the signature reads def _embed_two_body(op1:
np.ndarray, op2: np.ndarray, L: int, i: int) -> np.ndarray: to eliminate the
unused linter suppression; locate the def _embed_two_body function in
tests/core/data_structures/test_networks.py and delete only the noqa comment.
- Line 47: The function definition for _embed_one_body contains an unnecessary
noqa directive ("noqa: N803"); remove the trailing " # noqa: N803" from the def
line in the _embed_one_body function to eliminate the unused suppression (or
alternatively enable the rule in Ruff config if suppression was intended),
leaving the signature as def _embed_one_body(op: np.ndarray, L: int, i: int) ->
np.ndarray:.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
tests/core/data_structures/test_networks.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-27T21:26:39.677Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/qmap PR: 846
File: python/mqt/qmap/plugins/qiskit/sc/load_calibration.py:34-34
Timestamp: 2025-11-27T21:26:39.677Z
Learning: In the qmap project, the Ruff linter has the "PL" (pylint) rule category enabled, which includes PLC0415 (import-outside-top-level). Therefore, `# noqa: PLC0415` directives on lazy imports are appropriate and necessary, not unused.
Applied to files:
tests/core/data_structures/test_networks.py
📚 Learning: 2026-01-08T10:07:32.871Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 20
File: python/mqt/core/plugins/catalyst/device.py:69-69
Timestamp: 2026-01-08T10:07:32.871Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, Ruff is configured with select = ["ALL"] and only specific rules are disabled. SLF001 (flake8-self - private member access) is enabled, so `# noqa: SLF001` directives are necessary when accessing private attributes like `device._to_matrix_ops` in python/mqt/core/plugins/catalyst/device.py, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
tests/core/data_structures/test_networks.py
🧬 Code graph analysis (1)
tests/core/data_structures/test_networks.py (1)
src/mqt/yaqs/core/data_structures/networks.py (7)
op(1062-1067)MPO(959-1755)identity(1297-1314)finite_state_machine(1316-1341)custom(1343-1363)hamiltonian(1015-1091)from_pauli_sum(1365-1429)
🪛 Ruff (0.14.10)
tests/core/data_structures/test_networks.py
47-47: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
64-64: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
88-88: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
113-113: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
🔇 Additional comments (6)
tests/core/data_structures/test_networks.py (6)
38-45: LGTM!The imports and Pauli matrix definitions are correct and properly typed for the dense Hamiltonian construction utilities.
205-227: LGTM!Excellent tests that validate the new
MPO.isingandMPO.heisenbergclass methods against exact dense Hamiltonian representations. This provides strong correctness guarantees for the MPO construction.
230-378: LGTM!The test updates correctly reflect the new builder-style API (
MPO.ising,MPO.heisenberg) while maintaining instance method usage foridentity,finite_state_machine, andcustomwhere appropriate.
1185-1229: LGTM!Comprehensive validation tests for
MPO.hamiltoniancovering non-positive length, invalid boundary conditions, invalid operator labels, and case normalization. The regex patterns correctly match the expected error messages.
1232-1279: LGTM!Thorough validation tests for
from_pauli_sumcovering unsupported physical dimensions, non-positive length, out-of-bounds site indices, invalid operator labels, and empty term handling. The use ofmonkeypatchto inject specific parsing results is an effective technique for testing edge cases.
1282-1307: White-box test for internal behavior—acceptable but brittle.This test verifies that
_create_termis called for each term during MPO construction. While effective for ensuring correct internal flow, note that this test is tightly coupled to implementation details (method names, signatures, call order). If the internal implementation changes, this test will need updates even if external behavior remains correct.Consider whether an integration-style test comparing the final MPO against expected values might provide equivalent coverage with better resilience to refactoring.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In @tests/core/data_structures/test_networks.py:
- Line 113: The function definition _heisenberg_dense has an unnecessary noqa
comment for N803; remove the `# noqa: N803` directive from the def line so the
function name remains as-is and the linter directive does not reference a rule
that’s not enabled.
- Line 1350: The trailing noqa directive on the call to mpo._compress_one_sweep
(the " # noqa: SLF001" comment) is unnecessary because SLF001 is not enabled;
remove the " # noqa: SLF001" text so the call is simply
mpo._compress_one_sweep(direction="xx", tol=1e-12, max_bond_dim=None).
- Line 64: The function definition for _embed_two_body unnecessarily includes a
`# noqa: N803` directive even though N803 is not enabled; remove the unused
directive from the `_embed_two_body(op1: np.ndarray, op2: np.ndarray, L: int, i:
int) -> np.ndarray` definition so the signature is plain and no longer annotated
with `# noqa: N803`.
- Line 47: The noqa N803 directive on the _embed_one_body function is unused;
remove the trailing comment " # noqa: N803" from the def line (function name
_embed_one_body) so the signature reads "def _embed_one_body(op: np.ndarray, L:
int, i: int) -> np.ndarray:" and leave the rest unchanged.
- Line 88: The function definition for _ising_dense contains an unused noqa
directive; remove the " # noqa: N803" suffix from the _ising_dense function
declaration so the line reads a normal def without the N803 suppression (no
other changes needed).
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
tests/core/data_structures/test_networks.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-01-08T10:07:32.871Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 20
File: python/mqt/core/plugins/catalyst/device.py:69-69
Timestamp: 2026-01-08T10:07:32.871Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, Ruff is configured with select = ["ALL"] and only specific rules are disabled. SLF001 (flake8-self - private member access) is enabled, so `# noqa: SLF001` directives are necessary when accessing private attributes like `device._to_matrix_ops` in python/mqt/core/plugins/catalyst/device.py, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
tests/core/data_structures/test_networks.py
📚 Learning: 2025-12-14T15:23:54.712Z
Learnt from: flowerthrower
Repo: munich-quantum-toolkit/core-plugins-catalyst PR: 23
File: docs/conf.py:110-130
Timestamp: 2025-12-14T15:23:54.712Z
Learning: In the munich-quantum-toolkit/core-plugins-catalyst repository, the Ruff configuration has 'ALL' rules enabled with only specific rules disabled. PLR6301 (no-self-use) is active, so `# noqa: PLR6301` directives are necessary for methods that don't use self, even if Ruff reports RUF100 warnings suggesting the directive is unused.
Applied to files:
tests/core/data_structures/test_networks.py
📚 Learning: 2025-11-24T10:19:41.147Z
Learnt from: burgholzer
Repo: munich-quantum-toolkit/core PR: 1326
File: python/mqt/core/__init__.py:22-22
Timestamp: 2025-11-24T10:19:41.147Z
Learning: In the munich-quantum-toolkit/core repository, Ruff is configured with 'ALL' rules enabled by default, and only specific rules are selectively disabled. When reviewing changes that enable previously-disabled rules (like PLC0415), noqa directives for those rules become necessary and should be retained.
Applied to files:
tests/core/data_structures/test_networks.py
🧬 Code graph analysis (1)
tests/core/data_structures/test_networks.py (2)
src/mqt/yaqs/core/libraries/gate_library.py (6)
GateLibrary(1630-1724)Id(744-763)X(602-621)Z(646-665)H(668-687)h(313-319)src/mqt/yaqs/core/data_structures/networks.py (4)
op(1062-1067)MPO(959-1755)identity(1297-1314)hamiltonian(1015-1091)
🪛 Ruff (0.14.10)
tests/core/data_structures/test_networks.py
47-47: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
64-64: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
88-88: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
113-113: Unused noqa directive (non-enabled: N803)
Remove unused noqa directive
(RUF100)
1350-1350: Unused noqa directive (non-enabled: SLF001)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: 🐍 Test (ubuntu-24.04) / 🐍 ubuntu-24.04
- GitHub Check: 🐍 Test (macos-14) / 🐍 macos-14
- GitHub Check: 🐍 Test (windows-2022) / 🐍 windows-2022
- GitHub Check: 🐍 Test (macos-15-intel) / 🐍 macos-15-intel
- GitHub Check: 🐍 Test (ubuntu-24.04-arm) / 🐍 ubuntu-24.04-arm
- GitHub Check: 🐍 Lint / 🚨 Lint
🔇 Additional comments (6)
tests/core/data_structures/test_networks.py (6)
38-45: LGTM!Clean separation of concerns: gate library imports for observable tests, and local numpy Pauli matrices for dense Hamiltonian construction. The operator definitions are correct.
205-227: Solid ground-truth validation tests.Comparing
MPO.to_matrix()against independently constructed dense Hamiltonians is an excellent approach for verifying correctness of the new MPO builders.
230-378: LGTM!The updated tests correctly exercise both the classmethod factory pattern (
MPO.ising(),MPO.heisenberg()) and the instance method initialization pattern (mpo.identity(),mpo.finite_state_machine(),mpo.custom()). Test coverage is comprehensive.
1185-1230: LGTM!Comprehensive input validation tests for
MPO.hamiltonian(). Error message assertions use appropriate regex patterns matching the implementation.
1232-1308: LGTM!Effective use of
monkeypatchto isolate validation logic and test edge cases that would be difficult to trigger through normal API usage. The test for_create_terminvocation count provides good coverage of the construction flow.
1353-1381: LGTM!Solid integration tests covering Pauli string parsing edge cases: empty specs, comma/whitespace handling, case normalization, duplicate site detection, and invalid token rejection. These align well with the
_parse_pauli_stringimplementation shown in the relevant code snippets.
Description
This PR implements a construction method that allows initializing an MPO directly from an arbitrary Hamiltonian expressed as a sum of weighted Pauli tensor product strings. This enables easy construction of complex Hamiltonians (e.g. transverse-field Ising, Fermi–Hubbard) without manually deriving MPOs. The implementation follows the algorithm presented in Hubig et al.
Additionally, it changes the basic usage of Hamiltonian initialization by using constructors:
H = MPO.ising(L, J, g)Fixes #13
Checklist: