Skip to content
45 changes: 45 additions & 0 deletions qiskit/quantum_info/operators/symplectic/base_pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,22 @@ def _evolve_sdg(base_pauli, qubit):
return base_pauli


def _evolve_sx(base_pauli, qubit):
"""Update P -> SX.P.SXdg"""
z = base_pauli._z[:, qubit]
base_pauli._x[:, qubit] ^= z
base_pauli._phase -= z.T.astype(base_pauli._phase.dtype)
return base_pauli


def _evolve_sxdg(base_pauli, qubit):
"""Update P -> SXdg.P.SX"""
z = base_pauli._z[:, qubit]
base_pauli._x[:, qubit] ^= z
base_pauli._phase += z.T.astype(base_pauli._phase.dtype)
return base_pauli


def _evolve_i(base_pauli, qubit):
"""Update P -> P"""
return base_pauli
Expand Down Expand Up @@ -690,6 +706,15 @@ def _evolve_cy(base_pauli, qctrl, qtrgt):
return base_pauli


def _evolve_dcx(base_pauli, qctrl, qtrgt):
"""Update P -> DCX.P.DCXdg"""
base_pauli._x[:, qtrgt] ^= base_pauli._x[:, qctrl]
base_pauli._z[:, qctrl] ^= base_pauli._z[:, qtrgt]
base_pauli._x[:, qctrl] ^= base_pauli._x[:, qtrgt]
base_pauli._z[:, qtrgt] ^= base_pauli._z[:, qctrl]
return base_pauli


def _evolve_swap(base_pauli, q1, q2):
"""Update P -> SWAP.P.SWAP"""
x1 = base_pauli._x[:, q1].copy()
Expand All @@ -701,6 +726,22 @@ def _evolve_swap(base_pauli, q1, q2):
return base_pauli


def _evolve_iswap(base_pauli, q1, q2):
"""Update P -> iSWAP.P.iSWAP"""
x1 = base_pauli._x[:, q1].copy()
z1 = base_pauli._z[:, q1].copy()
x2 = base_pauli._x[:, q2].copy()
z2 = base_pauli._z[:, q2].copy()

base_pauli._x[:, q1] = x2
base_pauli._x[:, q2] = x1
base_pauli._z[:, q1] = x1 ^ x2 ^ z2
base_pauli._z[:, q2] = x1 ^ x2 ^ z1

base_pauli._phase += np.logical_xor(x1, x2).T.astype(base_pauli._phase.dtype)
return base_pauli


def _evolve_ecr(base_pauli, q1, q2):
"""Update P -> ECR.P.ECR"""
base_pauli = _evolve_s(base_pauli, q1)
Expand Down Expand Up @@ -740,13 +781,17 @@ def _count_y(x, z, dtype=None):
"s": _evolve_s,
"sdg": _evolve_sdg,
"sinv": _evolve_sdg,
"sx": _evolve_sx,
"sxdg": _evolve_sxdg,
}
_basis_2q = {
"cx": _evolve_cx,
"cz": _evolve_cz,
"cy": _evolve_cy,
"swap": _evolve_swap,
"iswap": _evolve_iswap,
"ecr": _evolve_ecr,
"dcx": _evolve_dcx,
}

# Non-Clifford gates
Expand Down
20 changes: 20 additions & 0 deletions test/python/quantum_info/operators/symplectic/test_pauli.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

from qiskit import QuantumCircuit
from qiskit.circuit import Qubit
from qiskit.circuit.random import random_clifford_circuit
from qiskit.circuit.library import (
CXGate,
CYGate,
Expand All @@ -36,6 +37,7 @@
SGate,
SwapGate,
iSwapGate,
DCXGate,
XGate,
YGate,
ZGate,
Expand Down Expand Up @@ -449,6 +451,7 @@ def test_evolve_clifford1(self, gate, label):
SwapGate(),
iSwapGate(),
ECRGate(),
DCXGate(),
CPhaseGate(theta=np.pi),
CRXGate(theta=np.pi),
CRYGate(theta=np.pi),
Expand Down Expand Up @@ -489,11 +492,15 @@ def test_evolve_clifford2(self, gate, label):
HGate(),
SGate(),
SdgGate(),
SXGate(),
SXdgGate(),
CXGate(),
CYGate(),
CZGate(),
SwapGate(),
iSwapGate(),
ECRGate(),
DCXGate(),
),
[int, np.int8, np.uint8, np.int16, np.uint16, np.int32, np.uint32, np.int64, np.uint64],
)
Expand Down Expand Up @@ -523,6 +530,19 @@ def test_evolve_clifford_qargs(self):
self.assertEqual(value, value_h)
self.assertEqual(value_inv, value_s)

def test_evolve_clifford_circuit_qargs(self):
"""Test evolve method for random Clifford circuit"""
qargs = [2, 4, 1, 0]
qc = random_clifford_circuit(4, 100, seed=123)
op = Operator(qc)
pauli = random_pauli(5, seed=5678)
target_s = Operator(pauli).compose(op, qargs=qargs).dot(op.adjoint(), qargs=qargs)
target_h = Operator(pauli).compose(op.adjoint(), qargs=qargs).dot(op, qargs=qargs)
value_evolve_s = Operator(pauli.evolve(qc, frame="s", qargs=qargs))
value_evolve_h = Operator(pauli.evolve(qc, frame="h", qargs=qargs))
self.assertEqual(value_evolve_s, target_s)
self.assertEqual(value_evolve_h, target_h)

@data("s", "h")
def test_evolve_with_misleading_name(self, frame):
"""Test evolve by circuit contents, not by name (fixed bug)."""
Expand Down