mirror of https://github.com/Qiskit/qiskit.git
fix 6547 (#6562)
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:
parent
10468e6434
commit
4c6a0f3e7b
|
@ -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
|
||||
|
|
|
@ -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`.
|
|
@ -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."""
|
||||
|
|
Loading…
Reference in New Issue