Skip to content
This repository was archived by the owner on Dec 7, 2021. It is now read-only.

Commit f059f99

Browse files
authored
Use Operator rather than unitary simulator to convert circuit to unitary matrix (#1224)
* Fix factor of 2 error in converting exp_i to rotation gates * Make CircuitOp use Operator rather than unitary simulator to get matrix The unitary simulator does not account for the global phase in a circuit. qiskit.quantum_info.Operator does account for global phase when converting (when possible) a circuit to a unitary matrix. Closes #1218 * Remove note on reversing order of qubits Using Operator(QuantumCircuit) gives the same qubit ordering that the previous unitary-simulator-based code did. I removed the comment entirely because the behavior depends only on Operator(QuantumCircuit), which is not obscure.
1 parent a5fa52b commit f059f99

File tree

5 files changed

+32
-12
lines changed

5 files changed

+32
-12
lines changed

qiskit/aqua/operators/primitive_ops/circuit_op.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
import logging
1717
import numpy as np
1818

19-
from qiskit import QuantumCircuit, BasicAer, execute
19+
import qiskit
20+
from qiskit import QuantumCircuit
2021
from qiskit.circuit.library import IGate
2122
from qiskit.circuit import Instruction, ParameterExpression
2223

@@ -139,14 +140,7 @@ def to_matrix(self, massive: bool = False) -> np.ndarray:
139140
' in this case {0}x{0} elements.'
140141
' Set massive=True if you want to proceed.'.format(2 ** self.num_qubits))
141142

142-
# NOTE: not reversing qubits!! We generally reverse endianness when converting between
143-
# circuit or Pauli representation and matrix representation, but we don't need to here
144-
# because the Unitary simulator already presents the endianness of the circuit unitary in
145-
# forward endianness.
146-
unitary_backend = BasicAer.get_backend('unitary_simulator')
147-
unitary = execute(self.to_circuit(),
148-
unitary_backend,
149-
optimization_level=0).result().get_unitary()
143+
unitary = qiskit.quantum_info.Operator(self.to_circuit()).data
150144
# pylint: disable=cyclic-import
151145
from ..operator_globals import EVAL_SIG_DIGITS
152146
return np.round(unitary * self.coeff, decimals=EVAL_SIG_DIGITS)

qiskit/aqua/operators/primitive_ops/pauli_op.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,13 @@ def exp_i(self) -> OperatorBase:
220220
else self.coeff
221221
# Y rotation
222222
if corrected_x[sig_qubit_index] and corrected_z[sig_qubit_index]:
223-
rot_op = PrimitiveOp(RYGate(coeff))
223+
rot_op = PrimitiveOp(RYGate(2 * coeff))
224224
# Z rotation
225225
elif corrected_z[sig_qubit_index]:
226-
rot_op = PrimitiveOp(RZGate(coeff))
226+
rot_op = PrimitiveOp(RZGate(2 * coeff))
227227
# X rotation
228228
elif corrected_x[sig_qubit_index]:
229-
rot_op = PrimitiveOp(RXGate(coeff))
229+
rot_op = PrimitiveOp(RXGate(2 * coeff))
230230

231231
from ..operator_globals import I
232232
left_pad = I.tensorpower(sig_qubit_index)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
fixes:
3+
- |
4+
Make PauliOp.exp_i() generate the correct matrix with the following changes.
5+
1) There was previously an error in the phase of a factor of 2.
6+
2) The global phase was ignored when converting the circuit
7+
to a matrix. We now use qiskit.quantum_info.Operator, which is
8+
generally useful for converting a circuit to a unitary matrix,
9+
when possible.

test/aqua/operators/test_evolution.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import numpy as np
1919
import scipy.linalg
2020

21+
import qiskit
2122
from qiskit.circuit import ParameterVector, Parameter
2223

2324
from qiskit.aqua.operators import (X, Y, Z, I, CX, H, ListOp, CircuitOp, Zero, EvolutionFactory,
@@ -29,6 +30,13 @@
2930
class TestEvolution(QiskitAquaTestCase):
3031
"""Evolution tests."""
3132

33+
def test_exp_i(self):
34+
""" exponential of Pauli test """
35+
op = Z.exp_i()
36+
gate = op.to_circuit().data[0][0]
37+
self.assertIsInstance(gate, qiskit.circuit.library.RZGate)
38+
self.assertEqual(gate.params[0], 2)
39+
3240
def test_pauli_evolution(self):
3341
""" pauli evolution test """
3442
op = (-1.052373245772859 * I ^ I) + \

test/aqua/operators/test_op_construction.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from test.aqua import QiskitAquaTestCase
1919
import itertools
20+
import scipy
2021
from scipy.stats import unitary_group
2122
import numpy as np
2223
from ddt import ddt, data
@@ -201,6 +202,14 @@ def test_to_matrix(self):
201202
np.testing.assert_array_almost_equal(
202203
op6.to_matrix(), op5.to_matrix() + Operator.from_label('+r').data)
203204

205+
def test_circuit_op_to_matrix(self):
206+
""" test CircuitOp.to_matrix """
207+
qc = QuantumCircuit(1)
208+
qc.rz(1.0, 0)
209+
qcop = CircuitOp(qc)
210+
np.testing.assert_array_almost_equal(
211+
qcop.to_matrix(), scipy.linalg.expm(-0.5j * Z.to_matrix()))
212+
204213
def test_matrix_to_instruction(self):
205214
"""Test MatrixOp.to_instruction yields an Instruction object."""
206215
matop = (H ^ 3).to_matrix_op()

0 commit comments

Comments
 (0)