Skip to content

Commit

Permalink
Add an equiv method to the StabilizerState class (#9543)
Browse files Browse the repository at this point in the history
* add equiv method to StabilizerState class

* add a test for equiv method

* add release notes

* add explanantion to the tests

* update comment in tests

* updates following review

* update exp_val calculation

* updates following review

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
ShellyGarion and mergify[bot] authored Feb 8, 2023
1 parent d4006dd commit 8ec6749
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 1 deletion.
43 changes: 42 additions & 1 deletion qiskit/quantum_info/states/stabilizerstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from qiskit.exceptions import QiskitError
from qiskit.quantum_info.operators.op_shape import OpShape
from qiskit.quantum_info.operators.symplectic import Clifford, Pauli
from qiskit.quantum_info.operators.symplectic import Clifford, Pauli, PauliList
from qiskit.quantum_info.operators.symplectic.clifford_circuits import _append_x
from qiskit.quantum_info.states.quantum_state import QuantumState

Expand Down Expand Up @@ -266,6 +266,47 @@ def expectation_value(self, oper, qargs=None):

return pauli_phase

def equiv(self, other):
"""Return True if the two generating sets generate the same stabilizer group.
Args:
other (StabilizerState): another StabilizerState.
Returns:
bool: True if other has a generating set that generates the same StabilizerState.
"""
if not isinstance(other, StabilizerState):
try:
other = StabilizerState(other)
except QiskitError:
return False

num_qubits = self.num_qubits
if other.num_qubits != num_qubits:
return False

pauli_orig = PauliList.from_symplectic(
self._data.stab_z, self._data.stab_x, 2 * self._data.stab_phase
)
pauli_other = PauliList.from_symplectic(
other._data.stab_z, other._data.stab_x, 2 * other._data.stab_phase
)

# Check that each stabilizer from the original set commutes with each stabilizer
# from the other set
if not np.all([pauli.commutes(pauli_other) for pauli in pauli_orig]):
return False

# Compute the expected value of each stabilizer from the original set on the stabilizer state
# determined by the other set. The two stabilizer states coincide if and only if the
# expected value is +1 for each stabilizer
for i in range(num_qubits):
exp_val = self.expectation_value(pauli_other[i])
if exp_val != 1:
return False

return True

def probabilities(self, qargs=None, decimals=None):
"""Return the subsystem measurement probability vector.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
features:
- |
Added the method :class:`.StabilizerState.equiv`,
that checks if the generating sets of two stabilizer states generate the same stabilizer group.
For example, the stabilizer group of the two-qubit Bell state contains the four elements
:math:`\{II, XX, -YY, ZZ\}` and hence can be generated by either :math:`[XX, ZZ]`,
:math:`[XX, -YY]` or :math:`[-YY, ZZ]`.
44 changes: 44 additions & 0 deletions test/python/quantum_info/states/test_stabilizerstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,50 @@ def test_expval_random_subsystem(self, num_qubits):
target = Statevector(qc).expectation_value(op, qargs)
self.assertAlmostEqual(exp_val, target)

def test_stabilizer_bell_equiv(self):
"""Test that two circuits produce the same stabilizer group."""

qc1 = QuantumCircuit(2)
qc1.h(0)
qc1.x(1)
qc1.cx(0, 1)

qc2 = QuantumCircuit(2)
qc2.h(0)
qc2.cx(0, 1)
qc2.sdg(0)
qc2.sdg(1)
qc2.h(0)
qc2.h(1)

qc3 = QuantumCircuit(2)
qc3.h(0)
qc3.cx(0, 1)

qc4 = QuantumCircuit(2)
qc4.h(0)
qc4.cx(0, 1)
qc4.s(0)
qc4.sdg(1)
qc4.h(0)
qc4.h(1)

cliff1 = StabilizerState(qc1) # ['+XX', '-ZZ']
cliff2 = StabilizerState(qc2) # ['+YY', '+XX']
cliff3 = StabilizerState(qc3) # ['+XX', '+ZZ']
cliff4 = StabilizerState(qc4) # ['-YY', '+XX']

# [XX, -ZZ] and [XX, YY] both generate the stabilizer group {II, XX, YY, -ZZ}
self.assertTrue(cliff1.equiv(cliff2))
self.assertEqual(cliff1.probabilities_dict(), cliff2.probabilities_dict())

# [XX, ZZ] and [XX, -YY] both generate the stabilizer group {II, XX, -YY, ZZ}
self.assertTrue(cliff3.equiv(cliff4))
self.assertEqual(cliff3.probabilities_dict(), cliff4.probabilities_dict())

self.assertFalse(cliff1.equiv(cliff3))
self.assertFalse(cliff2.equiv(cliff4))


if __name__ == "__main__":
unittest.main()

0 comments on commit 8ec6749

Please sign in to comment.