Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
This commit is contained in:
Ikko Hamamura 2021-06-26 18:25:05 +09:00 committed by GitHub
parent 10468e6434
commit 4c6a0f3e7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 101 additions and 49 deletions

View File

@ -12,6 +12,7 @@
"""PauliOp Class """
from math import pi
from typing import Dict, List, Optional, Set, Union, cast
import numpy as np
@ -20,6 +21,7 @@ from scipy.sparse import spmatrix
from qiskit import QuantumCircuit
from qiskit.circuit import Instruction, ParameterExpression
from qiskit.circuit.library import IGate, RXGate, RYGate, RZGate, XGate, YGate, ZGate
from qiskit.circuit.library.generalized_gates import PauliGate
from qiskit.opflow.exceptions import OpflowError
from qiskit.opflow.list_ops.summed_op import SummedOp
from qiskit.opflow.list_ops.tensored_op import TensoredOp
@ -27,8 +29,6 @@ from qiskit.opflow.operator_base import OperatorBase
from qiskit.opflow.primitive_ops.primitive_op import PrimitiveOp
from qiskit.quantum_info import Pauli, SparsePauliOp, Statevector
PAULI_GATE_MAPPING = {"X": XGate(), "Y": YGate(), "Z": ZGate(), "I": IGate()}
class PauliOp(PrimitiveOp):
"""Class for Operators backed by Terra's ``Pauli`` module."""
@ -167,8 +167,8 @@ class PauliOp(PrimitiveOp):
)
# pylint: disable=cyclic-import
from .circuit_op import CircuitOp
from ..state_fns.circuit_state_fn import CircuitStateFn
from .circuit_op import CircuitOp
if isinstance(other, (CircuitOp, CircuitStateFn)):
return new_self.to_circuit_op().compose(other)
@ -207,10 +207,10 @@ class PauliOp(PrimitiveOp):
return self.to_matrix_op()
# pylint: disable=cyclic-import
from ..state_fns.state_fn import StateFn
from ..state_fns.dict_state_fn import DictStateFn
from ..state_fns.circuit_state_fn import CircuitStateFn
from ..list_ops.list_op import ListOp
from ..state_fns.circuit_state_fn import CircuitStateFn
from ..state_fns.dict_state_fn import DictStateFn
from ..state_fns.state_fn import StateFn
from .circuit_op import CircuitOp
new_front = None
@ -312,15 +312,25 @@ class PauliOp(PrimitiveOp):
return EvolvedOp(self)
def to_circuit(self) -> QuantumCircuit:
# If Pauli equals identity, don't skip the IGates
is_identity = sum(self.primitive.x + self.primitive.z) == 0
# Note: Reversing endianness!!
qc = QuantumCircuit(len(self.primitive))
for q, pauli_str in enumerate(reversed(self.primitive.to_label())):
gate = PAULI_GATE_MAPPING[pauli_str]
if not pauli_str == "I" or is_identity:
qc.append(gate, qargs=[q])
pauli = self.primitive.to_label()[-self.num_qubits :]
phase = self.primitive.phase
qc = QuantumCircuit(self.num_qubits)
if pauli == "I" * self.num_qubits:
qc.global_phase = -phase * pi / 2
return qc
if self.num_qubits == 1:
gate = {"I": IGate(), "X": XGate(), "Y": YGate(), "Z": ZGate()}[pauli]
else:
gate = PauliGate(pauli)
qc.append(gate, range(self.num_qubits))
if not phase:
return qc
qc.global_phase = -phase * pi / 2
return qc
def to_instruction(self) -> Instruction:
@ -329,7 +339,7 @@ class PauliOp(PrimitiveOp):
# (Reduce removes extra IGates).
# return PrimitiveOp(self.primitive.to_instruction(), coeff=self.coeff).reduce()
return self.to_circuit().to_instruction()
return self.primitive.to_instruction()
def to_pauli_op(self, massive: bool = False) -> "PauliOp":
return self

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Fixed the bug that caused :meth:`~qiskit.opflow.PauliOp.to_circuit` to fail when
:class:`~qiskit.opflow.PauliOp` had a phase. At the same time, it was made more efficient to
use :class:`~qiskit.circuit.library.generalized_gates.PauliGate`.

View File

@ -13,50 +13,49 @@
""" Test Operator construction, including OpPrimitives and singletons. """
import unittest
from test.python.opflow import QiskitOpflowTestCase
import itertools
import scipy
from scipy.stats import unitary_group
import unittest
from math import pi
from test.python.opflow import QiskitOpflowTestCase
import numpy as np
from ddt import ddt, data
import scipy
from ddt import data, ddt
from scipy.stats import unitary_group
from qiskit import QiskitError
from qiskit.circuit import QuantumCircuit, QuantumRegister, Instruction, Parameter, ParameterVector
from qiskit.extensions.exceptions import ExtensionError
from qiskit.quantum_info import Operator, Pauli, Statevector
from qiskit.circuit import Instruction, Parameter, ParameterVector, QuantumCircuit, QuantumRegister
from qiskit.circuit.library import CZGate, ZGate
from qiskit.extensions.exceptions import ExtensionError
from qiskit.opflow import (
CX,
CircuitOp,
CircuitStateFn,
ComposedOp,
DictStateFn,
EvolvedOp,
H,
I,
ListOp,
MatrixOp,
Minus,
OperatorBase,
OperatorStateFn,
OpflowError,
PauliOp,
PrimitiveOp,
SparseVectorStateFn,
StateFn,
SummedOp,
T,
TensoredOp,
VectorStateFn,
X,
Y,
Z,
I,
CX,
T,
H,
Minus,
PrimitiveOp,
PauliOp,
CircuitOp,
MatrixOp,
EvolvedOp,
StateFn,
CircuitStateFn,
VectorStateFn,
DictStateFn,
OperatorStateFn,
ListOp,
ComposedOp,
TensoredOp,
SummedOp,
OperatorBase,
Zero,
OpflowError,
SparseVectorStateFn,
)
from qiskit.quantum_info import Operator, Pauli, Statevector
# pylint: disable=invalid-name
@ -495,7 +494,7 @@ class TestOpConstruction(QiskitOpflowTestCase):
expected_circuit_op = expected_pauli_op.to_circuit_op()
self.assertEqual(
permuted_circuit_op.primitive.__str__(), expected_circuit_op.primitive.__str__()
Operator(permuted_circuit_op.primitive), Operator(expected_circuit_op.primitive)
)
# MatrixOp
@ -867,6 +866,43 @@ class TestOpConstruction(QiskitOpflowTestCase):
self.assertTrue(Operator(unitary).equiv(circuit))
def test_pauli_op_to_circuit(self):
"""Test PauliOp.to_circuit()"""
with self.subTest("single Pauli"):
pauli = PauliOp(Pauli("Y"))
expected = QuantumCircuit(1)
expected.y(0)
self.assertEqual(pauli.to_circuit(), expected)
with self.subTest("single Pauli with phase"):
pauli = PauliOp(Pauli("-iX"))
expected = QuantumCircuit(1)
expected.x(0)
expected.global_phase = -pi / 2
self.assertEqual(Operator(pauli.to_circuit()), Operator(expected))
with self.subTest("two qubit"):
pauli = PauliOp(Pauli("IX"))
expected = QuantumCircuit(2)
expected.pauli("IX", range(2))
self.assertEqual(pauli.to_circuit(), expected)
expected = QuantumCircuit(2)
expected.x(0)
expected.id(1)
self.assertEqual(pauli.to_circuit().decompose(), expected)
with self.subTest("two qubit with phase"):
pauli = PauliOp(Pauli("iXZ"))
expected = QuantumCircuit(2)
expected.pauli("XZ", range(2))
expected.global_phase = pi / 2
self.assertEqual(pauli.to_circuit(), expected)
expected = QuantumCircuit(2)
expected.z(0)
expected.x(1)
expected.global_phase = pi / 2
self.assertEqual(pauli.to_circuit().decompose(), expected)
def test_op_to_circuit_with_parameters(self):
"""On parameterized SummedOp, to_matrix_op returns ListOp, instead of MatrixOp. To avoid
the infinite recursion, OpflowError is raised."""