Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
63 changes: 63 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 @@ -440,6 +442,30 @@ def test_evolve_clifford1(self, gate, label):
self.assertEqual(value, value_h)
self.assertEqual(value_inv, value_s)

@combine(
gate=[
IGate(),
XGate(),
YGate(),
ZGate(),
HGate(),
SGate(),
SdgGate(),
SXGate(),
SXdgGate(),
],
label=pauli_group_labels(1, False),
)
def test_append_circuit_1_qubit(self, gate, label):
"""Test _append_circuit method for 1-qubit clifford gates"""
qc = QuantumCircuit(1)
qc.append(gate, [0])
op = Operator(gate)
pauli = Pauli(label)
target = op.dot(pauli).dot(op.adjoint())
value = Operator(pauli._append_circuit(qc))
self.assertEqual(value, target)

@data(
*it.product(
(
Expand All @@ -449,6 +475,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 @@ -479,6 +506,28 @@ def test_evolve_clifford2(self, gate, label):
self.assertEqual(value, value_h)
self.assertEqual(value_inv, value_s)

@combine(
gate=[
CXGate(),
CYGate(),
CZGate(),
SwapGate(),
iSwapGate(),
ECRGate(),
DCXGate(),
],
label=pauli_group_labels(2, False),
)
def test_append_circuit_2_qubit(self, gate, label):
"""Test _append_circuit method for 2-qubit clifford gates"""
qc = QuantumCircuit(2)
qc.append(gate, [0, 1])
op = Operator(gate)
pauli = Pauli(label)
target = op.dot(pauli).dot(op.adjoint())
value = Operator(pauli._append_circuit(qc))
self.assertEqual(value, target)

@data(
*it.product(
(
Expand All @@ -489,11 +538,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 +576,16 @@ def test_evolve_clifford_qargs(self):
self.assertEqual(value, value_h)
self.assertEqual(value_inv, value_s)

def test_evolve_clifford_circuit(self):
"""Test evolve method for random Clifford circuit"""
num_qubits = 5
qc = random_clifford_circuit(num_qubits, 20, seed=1234)
op = Operator(qc)
pauli = random_pauli(num_qubits, seed=5678)
target = Operator(pauli).compose(op).dot(op.adjoint())
value = Operator(pauli._append_circuit(qc))
self.assertEqual(value, target)

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