Environment
- Qiskit version: 2.5.2
Also reproduced on 2.6.0.dev0+b6f798f (b6f798f0bd88965821a54bff3785323a39c3a6c5)
- Python version: 3.12.13
- Operating system: Linux
What is happening?
LightCone reverses the association between bit_terms and indices when constructing its initial observable.
The sparse observable interface associates the entries positionally. Therefore:
bit_terms = "XZ"
indices = [0, 1]
represents:
However, the implementation constructs:
lightcone_qubits = [dag.qubits[i] for i in self.indices]
lightcone_operations = [
(PauliGate(self.bit_terms), lightcone_qubits)
]
Relevant source:
|
lightcone_qubits = [dag.qubits[i] for i in self.indices] |
|
# `lightcone_operations` is a list of tuples, each containing (operation, list_of_qubits) |
|
lightcone_operations = [(PauliGate(self.bit_terms), lightcone_qubits)] |
A PauliGate label uses Qiskit's dense Pauli convention: the rightmost character acts on local qubit 0. Consequently:
PauliGate("XZ") on [q0, q1]
acts as:
This reverses the requested observable and can cause the pass to remove noncommuting gates.
How can we reproduce the issue?
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp, Statevector
from qiskit.transpiler import PassManager
from qiskit.transpiler.passes import LightCone
# Sparse form: X acts on q0 and Z acts on q1.
observable = SparsePauliOp.from_sparse_list(
[("XZ", [0, 1], 1.0)],
num_qubits=2,
)
bit_terms, indices, _ = observable.to_sparse_list()[0]
source = QuantumCircuit(2)
source.h(0)
source.z(0)
output = PassManager(
[
LightCone(
bit_terms=bit_terms,
indices=indices,
)
]
).run(source)
source_expectation = Statevector.from_instruction(
source
).expectation_value(observable).real
output_expectation = Statevector.from_instruction(
output
).expectation_value(observable).real
print("bit_terms:", bit_terms)
print("indices:", indices)
print(
"source operations:",
[instruction.operation.name for instruction in source.data],
)
print(
"output operations:",
[instruction.operation.name for instruction in output.data],
)
print("source expectation:", source_expectation)
print("output expectation:", output_expectation)
assert np.isclose(source_expectation, -1.0)
# Fails on the affected implementation.
assert np.isclose(output_expectation, source_expectation)
Observed output:
bit_terms: XZ
indices: [0, 1]
source operations: ['h', 'z']
output operations: ['h']
source expectation: approximately -1.0
output expectation: approximately 1.0
The Z(q0) gate should be retained because it does not commute with the requested observable X(q0) Z(q1).
Instead, LightCone interprets the observable as Z(q0) X(q1), concludes that Z(q0) commutes, and removes it. This changes the expectation value from -1 to 1.
What should happen?
LightCone should preserve the positional association:
bit_terms[i] -> indices[i]
For this example, the Z(q0) gate should remain and the transformed circuit should preserve:
Any suggestions?
Construct the initial Pauli operation without changing the sparse term/index association. For example, the label must be reversed before being passed to PauliGate, or represented directly in a sparse Pauli form.
A regression test should use an asymmetric observable such as "XZ" on indices [0, 1] and verify the expectation value before and after the pass.
Environment
Also reproduced on
2.6.0.dev0+b6f798f(b6f798f0bd88965821a54bff3785323a39c3a6c5)What is happening?
LightConereverses the association betweenbit_termsandindiceswhen constructing its initial observable.The sparse observable interface associates the entries positionally. Therefore:
represents:
However, the implementation constructs:
Relevant source:
qiskit/qiskit/transpiler/passes/optimization/light_cone.py
Lines 84 to 86 in b6f798f
A
PauliGatelabel uses Qiskit's dense Pauli convention: the rightmost character acts on local qubit 0. Consequently:acts as:
This reverses the requested observable and can cause the pass to remove noncommuting gates.
How can we reproduce the issue?
Observed output:
The
Z(q0)gate should be retained because it does not commute with the requested observableX(q0) Z(q1).Instead,
LightConeinterprets the observable asZ(q0) X(q1), concludes thatZ(q0)commutes, and removes it. This changes the expectation value from-1to1.What should happen?
LightConeshould preserve the positional association:For this example, the
Z(q0)gate should remain and the transformed circuit should preserve:Any suggestions?
Construct the initial Pauli operation without changing the sparse term/index association. For example, the label must be reversed before being passed to
PauliGate, or represented directly in a sparse Pauli form.A regression test should use an asymmetric observable such as
"XZ"on indices[0, 1]and verify the expectation value before and after the pass.