From 625ff98f68ea1903862c41e9d714f55ce7965a15 Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Wed, 27 Jul 2022 19:19:44 +0200 Subject: [PATCH] Fix converting VectorStateFn to a CircuitStateFn (#8405) --- qiskit/opflow/state_fns/circuit_state_fn.py | 5 ++--- ...vector-to-circuit-fn-02cb3424269fa733.yaml | 21 +++++++++++++++++++ .../python/opflow/test_state_op_meas_evals.py | 13 ++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/fix-opflow-vector-to-circuit-fn-02cb3424269fa733.yaml diff --git a/qiskit/opflow/state_fns/circuit_state_fn.py b/qiskit/opflow/state_fns/circuit_state_fn.py index 9f959e8718c8..7d5b3a2957de 100644 --- a/qiskit/opflow/state_fns/circuit_state_fn.py +++ b/qiskit/opflow/state_fns/circuit_state_fn.py @@ -20,8 +20,7 @@ from qiskit import BasicAer, ClassicalRegister, QuantumCircuit, transpile from qiskit.circuit import Instruction, ParameterExpression from qiskit.circuit.exceptions import CircuitError -from qiskit.circuit.library import IGate -from qiskit.extensions import Initialize +from qiskit.circuit.library import IGate, StatePreparation from qiskit.opflow.exceptions import OpflowError from qiskit.opflow.list_ops.composed_op import ComposedOp from qiskit.opflow.list_ops.list_op import ListOp @@ -123,7 +122,7 @@ def from_vector(statevector: np.ndarray) -> "CircuitStateFn": """ normalization_coeff = np.linalg.norm(statevector) normalized_sv = statevector / normalization_coeff - return CircuitStateFn(Initialize(normalized_sv), coeff=normalization_coeff) + return CircuitStateFn(StatePreparation(normalized_sv), coeff=normalization_coeff) def primitive_strings(self) -> Set[str]: return {"QuantumCircuit"} diff --git a/releasenotes/notes/fix-opflow-vector-to-circuit-fn-02cb3424269fa733.yaml b/releasenotes/notes/fix-opflow-vector-to-circuit-fn-02cb3424269fa733.yaml new file mode 100644 index 000000000000..d101486d0fa9 --- /dev/null +++ b/releasenotes/notes/fix-opflow-vector-to-circuit-fn-02cb3424269fa733.yaml @@ -0,0 +1,21 @@ +--- +fixes: + - | + Previously it was not possible to adjoint a :class:`.CircuitStateFn` that has been + constructed from a :class:`.VectorStateFn`. That's because the statevector has been + converted to a circuit with the :class:`~qiskit.extensions.Initialize` instruction, which + is not unitary. This problem is now fixed by instead using the :class:`.StatePreparation` + instruction, which can be used since the state is assumed to start out in the all 0 state. + + For example we can now do:: + + from qiskit import QuantumCircuit + from qiskit.opflow import StateFn + + left = StateFn([0, 1]) + left_circuit = left.to_circuit_op().primitive + + right_circuit = QuantumCircuit(1) + right_circuit.x(0) + + overlap = left_circuit.inverse().compose(right_circuit) # this line raised an error before! diff --git a/test/python/opflow/test_state_op_meas_evals.py b/test/python/opflow/test_state_op_meas_evals.py index 937065ca691d..d5b36f7d89f4 100644 --- a/test/python/opflow/test_state_op_meas_evals.py +++ b/test/python/opflow/test_state_op_meas_evals.py @@ -24,6 +24,7 @@ from qiskit.utils import QuantumInstance from qiskit.opflow import StateFn, Zero, One, H, X, I, Z, Plus, Minus, CircuitSampler, ListOp from qiskit.opflow.exceptions import OpflowError +from qiskit.quantum_info import Statevector @ddt @@ -217,6 +218,18 @@ def test_quantum_instance_with_backend_shots(self): res = sampler.convert(~Plus @ Plus).eval() self.assertAlmostEqual(res, 1 + 0j, places=2) + def test_adjoint_vector_to_circuit_fn(self): + """Test it is possible to adjoint a VectorStateFn that was converted to a CircuitStateFn.""" + left = StateFn([0, 1]) + left_circuit = left.to_circuit_op().primitive + + right_circuit = QuantumCircuit(1) + right_circuit.x(0) + + circuit = left_circuit.inverse().compose(right_circuit) + + self.assertTrue(Statevector(circuit).equiv([1, 0])) + if __name__ == "__main__": unittest.main()