Skip to content

Conversation

@NatPath
Copy link

@NatPath NatPath commented Nov 5, 2025

Summary

This PR adds a new utility function, operator_schmidt_decomposition, to qiskit.quantum_info. It computes the operator Schmidt decomposition of an n‑qubit operator across an arbitrary bipartition.


Highlights

  • API

    operator_schmidt_decomposition(op, qargs, *, k=None, return_reconstruction=False)
    • Computes

    $$ U = \sum_{r} s_r \ A_r \otimes B_r $$

    in a permuted basis where qubits are ordered as [Sc, S] (complement first, then selected subset).

    • Returns:
      • partition: {"S": tuple, "Sc": tuple}
      • permutation: {"new_order": tuple(Sc)+tuple(S), "matrix": P}
      • singular_values: full spectrum (descending)
      • A_factors, B_factors: Schmidt factors for kept terms in the permuted basis
      • truncation: kept/discarded terms, Frobenius tail error, relative error
      • Optional reconstruction in the original qubit order
    • Truncation: k gives the best rank‑k approximation (Frobenius‑optimal) via SVD of the realigned matrix.

Tests

  • Exact reconstruction for random unitaries and dense operators (no truncation).
  • Rank‑1 Kronecker case: single nonzero Schmidt value.
  • Truncation correctness: tail Frobenius error matches discarded singular values.
  • Basis/permutation contract:
    • In the permuted basis, U_perm == Σ kron(A_r, B_r)
    • Original operator satisfies U == P^T U_perm P.

Notes

  • Schmidt factors are returned in the permuted [Sc, S] basis by design.
  • Permutation metadata (order and matrix) is included so users can map results back to the original qubit order.

Scope

  • New module:
    qiskit/quantum_info/operators/operator_schmidt_decomposition.py
  • Tests:
    test/python/quantum_info/operators/test_operator_schmidt_decomposition.py

Details and comments

AI assistance: Microsoft Copilot Chat (GPT‑5)

@NatPath NatPath requested a review from a team as a code owner November 5, 2025 12:52
@qiskit-bot qiskit-bot added the Community PR PRs from contributors that are not 'members' of the Qiskit repo label Nov 5, 2025
@qiskit-bot
Copy link
Collaborator

Thank you for opening a new pull request.

Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient.

While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone.

One or more of the following people are relevant to this code:

  • @Qiskit/terra-core

@CLAassistant
Copy link

CLAassistant commented Nov 5, 2025

CLA assistant check
All committers have signed the CLA.

@ShellyGarion ShellyGarion added mod: quantum info Related to the Quantum Info module (States & Operators) Intern PR PR submitted by IBM Quantum interns and removed Community PR PRs from contributors that are not 'members' of the Qiskit repo labels Nov 5, 2025
@ShellyGarion ShellyGarion added this to the 2.3.0 milestone Nov 5, 2025
@github-project-automation github-project-automation bot moved this to Ready in Qiskit 2.3 Nov 5, 2025
@ShellyGarion ShellyGarion added the Changelog: New Feature Include in the "Added" section of the changelog label Nov 5, 2025
@coveralls
Copy link

coveralls commented Nov 5, 2025

Pull Request Test Coverage Report for Build 19238258836

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 64 of 73 (87.67%) changed or added relevant lines in 2 files are covered.
  • 1338 unchanged lines in 29 files lost coverage.
  • Overall coverage decreased (-0.05%) to 88.149%

Changes Missing Coverage Covered Lines Changed/Added Lines %
qiskit/quantum_info/operators/operator_schmidt_decomposition.py 63 72 87.5%
Files with Coverage Reduction New Missed Lines %
crates/circuit/src/converters.rs 1 96.05%
crates/circuit/src/parameter/parameter_expression.rs 1 81.99%
crates/circuit/src/parameter/symbol_expr.rs 1 72.94%
crates/qasm2/src/expr.rs 1 93.82%
crates/transpiler/src/passes/gate_direction.rs 1 96.34%
qiskit/quantum_info/operators/mixins/group.py 1 92.59%
qiskit/transpiler/passes/optimization/litinski_transformation.py 1 91.67%
crates/qasm2/src/lex.rs 3 91.26%
crates/quantum_info/src/clifford.rs 3 95.1%
crates/circuit/src/lib.rs 7 94.57%
Totals Coverage Status
Change from base Build 19099290035: -0.05%
Covered Lines: 94282
Relevant Lines: 106957

💛 - Coveralls

Copy link
Member

@ShellyGarion ShellyGarion left a comment

Choose a reason for hiding this comment

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

@NatPath - thanks for your contribution to Qiskit. I think this will be a great addition to the qiskit quantum info module.
I have some preliminary comments on the documnetation.

associate github account with the commit
associate github account with the commit
associate github account with the commit
associate github account with the commit
associate github account with the commit
…tors.predicates

associate github account with the commit
…ition to __init__.py under quantum_info and its docs

associate github account with the commit
associate github account with the commit
Comment on lines +214 to +221
# Determine number of terms to keep
total_terms = len(sing_vals) # = min(dim_a*dim_a, dim_b*dim_b)
if k is None:
num = total_terms
else:
if not (isinstance(k, int) and k > 0):
raise QiskitError("`k` must be a positive integer if provided.")
num = min(k, total_terms)

Choose a reason for hiding this comment

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

When users request k Schmidt terms, the code (line 221) clips to available terms without checking if singular values represent real signal versus numerical noise. Can SVD return values like [5.2, 2.8, 0.02, 1.3e-14, 8.7e-15] where the last two are floating-point rounding errors, not actual operator features? If that's the case then will code treats all as equally valid, building Schmidt factors from pure noise? Is it possible that high-fidelity gates can incorrectly show Schmidt rank 4 instead of 1? Should we add numerical rank check at line 215 using threshold max_singular_value × machine_epsilon × matrix_dimension, then warn users if requested k exceeds numerically significant terms.

Copy link
Author

Choose a reason for hiding this comment

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

Thank you Debasmita for this review.

Q >
Can SVD return values like [5.2, 2.8, 0.02, 1.3e-14, 8.7e-15] where the last two are floating-point rounding errors, not actual operator features?
A >
It can and often (almost always) does.

Q >
If that's the case then will code treats all as equally valid, building Schmidt factors from pure noise?
A >
The different terms "importance" is dictated by the singular values. Notice how the actual matrices are constructed - absorbing the weight of the singular values into A and B. For instance, in your example, the last two terms contribution to the reconstruction is negligible.

Q >
Is it possible that high-fidelity gates can incorrectly show Schmidt rank 4 instead of 1?
A >
Notice the schmidt rank is not part of the output. It can be interpreted elsewhere, given some threshold for the singular values which determines what is considered as non-zero.

Q>
Should we add numerical rank check at line 215 using threshold max_singular_value × machine_epsilon × matrix_dimension, then warn users if requested k exceeds numerically significant terms.
A>
Maybe! I thought that this kind of check could be done by the user according to its needs, but I guess it can also fit here.

Copy link
Member

@ShellyGarion ShellyGarion left a comment

Choose a reason for hiding this comment

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

@NatPath - thanks for your contribution to Qiskit.
After trying to use this function, I think that perhaps the API should be simplified.
Perhaps you can provide a simple example of using your code?

(sum of kept terms) mapped back to the **original** qubit order.

Returns:
dict:
Copy link
Member

@ShellyGarion ShellyGarion Nov 12, 2025

Choose a reason for hiding this comment

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

I think that this API should be simplified, currently it's not so easy to decompose a tensor-product unitary and obtain back the same matrix. See this example.

        from qiskit.circuit import QuantumCircuit
        from qiskit.quantum_info import Operator
        from qiskit.circuit.library import UnitaryGate

        num_qubits = 4
        qc = QuantumCircuit(num_qubits)
        mat1 = random_unitary(4, seed=1234).to_matrix()
        mat2 = random_unitary(4, seed=5678).to_matrix()
        mat = np.kron(mat1, mat2)
        out_full = operator_schmidt_decomposition(mat, (0,1))
        perm_matrix = out_full["permutation"]["matrix"]
        a_factors = out_full["A_factors"][0]
        b_factors = out_full["B_factors"][0]
        up_from_factors = np.kron(a_factors, b_factors)
        up_direct = perm_matrix @ up_from_factors @ perm_matrix.T
        qc.append(UnitaryGate(a_factors), [0, 1])
        qc.append(UnitaryGate(b_factors), [2, 3])
        print (Operator(qc).equiv(Operator(mat))) # should be True
        print(Operator(qc) == Operator(up_direct)) # should be True

self, seed: int, n_qubits: int, subset_a: tuple[int, ...]
):
"""Exact reconstruction (full sum) for random unitaries."""
unitary = np.array(random_unitary(2**n_qubits, seed=seed), dtype=complex)
Copy link
Member

@ShellyGarion ShellyGarion Nov 12, 2025

Choose a reason for hiding this comment

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

you can use here: random_unitary(2 ** n_qubits).to_matrix() to get the np.array

@ShellyGarion ShellyGarion removed this from the 2.3.0 milestone Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: New Feature Include in the "Added" section of the changelog Intern PR PR submitted by IBM Quantum interns mod: quantum info Related to the Quantum Info module (States & Operators)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants