Skip to content
This repository was archived by the owner on Dec 7, 2021. It is now read-only.
Merged
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
3 changes: 2 additions & 1 deletion qiskit/aqua/operators/converters/circuit_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class CircuitSampler(ConverterBase):
the same circuit efficiently. If you are converting multiple different Operators,
you are better off using a different CircuitSampler for each Operator to avoid cache thrashing.
"""

def __init__(self,
backend: Union[BaseBackend, QuantumInstance] = None,
statevector: Optional[bool] = None,
Expand Down Expand Up @@ -302,7 +303,7 @@ def sample_circuits(self,
result_sfn = StateFn(op_c.coeff * results.get_statevector(circ_index))
else:
shots = self.quantum_instance._run_config.shots
result_sfn = StateFn({b: (v * op_c.coeff / shots) ** .5
result_sfn = StateFn({b: (v / shots) ** 0.5 * op_c.coeff
for (b, v) in results.get_counts(circ_index).items()})
if self._attach_results:
result_sfn.execution_results = circ_results
Expand Down
4 changes: 2 additions & 2 deletions qiskit/aqua/operators/list_ops/composed_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ def reduce(self) -> OperatorBase:
def distribute_compose(l, r):
if isinstance(l, ListOp) and l.distributive:
# Either ListOp or SummedOp, returns correct type
return l.__class__([distribute_compose(l_op, r) for l_op in l.oplist])
return l.__class__([distribute_compose(l_op * l.coeff, r) for l_op in l.oplist])
if isinstance(r, ListOp) and r.distributive:
return r.__class__([distribute_compose(l, r_op) for r_op in r.oplist])
return r.__class__([distribute_compose(l, r_op * r.coeff) for r_op in r.oplist])
else:
return l.compose(r)

Expand Down
3 changes: 2 additions & 1 deletion qiskit/aqua/operators/state_fns/operator_state_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ def eval(self,
front = StateFn(front)

if isinstance(self.primitive, ListOp) and self.primitive.distributive:
evals = [OperatorStateFn(op, coeff=self.coeff, is_measurement=self.is_measurement).eval(
coeff = self.coeff * self.primitive.coeff
evals = [OperatorStateFn(op, coeff=coeff, is_measurement=self.is_measurement).eval(
front) for op in self.primitive.oplist]
return self.primitive.combo_fn(evals)

Expand Down
9 changes: 9 additions & 0 deletions releasenotes/notes/operator-coeff-eval-95efb26e95f6421a.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
The evaluation of some operator expressions, such as of ``SummedOp``s
and evaluations with the ``CircuitSampler`` did not treat coefficients
correctly or ignored them completely. E.g. evaluating
``~StateFn(0 * (I + Z)) @ Plus`` did not yield 0 or the normalization
of ``~StateFn(I) @ ((Plus + Minus) / sqrt(2))`` missed a factor
of ``sqrt(2)``. This has been fixed.
2 changes: 1 addition & 1 deletion test/aqua/operators/test_pauli_expectation.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def test_pauli_expect_op_vector(self):
# !!NOTE!!: Depolarizing channel (Sampling) means interference
# does not happen between circuits in sum, so expectation does
# not equal expectation for Zero!!
np.testing.assert_array_almost_equal(sampled_zero_mean.eval(), [0, 0, 0, 2], decimal=1)
np.testing.assert_array_almost_equal(sampled_zero_mean.eval(), [0, 0, 0, 1], decimal=1)

for i, op in enumerate(paulis_op.oplist):
mat_op = op.to_matrix()
Expand Down
23 changes: 22 additions & 1 deletion test/aqua/operators/test_state_op_meas_evals.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

import unittest
from test.aqua import QiskitAquaTestCase
from qiskit.aqua.operators import StateFn, Zero, One, H, X
import numpy
from qiskit import Aer
from qiskit.aqua.operators import StateFn, Zero, One, H, X, I, Z, Plus, Minus, CircuitSampler


# pylint: disable=invalid-name
Expand Down Expand Up @@ -56,6 +58,25 @@ def test_wf_evals_x(self):
self.assertAlmostEqual(wf.adjoint().eval(op.eval(wf_vec)), .25)
self.assertAlmostEqual(wf_vec.adjoint().eval(op.eval(wf_vec)), .25)

def test_coefficients_correctly_propagated(self):
"""Test that the coefficients in SummedOp and states are correctly used."""
with self.subTest('zero coeff in SummedOp'):
op = 0 * (I + Z)
state = Plus
self.assertEqual((~StateFn(op) @ state).eval(), 0j)

backend = Aer.get_backend('qasm_simulator')
op = I
with self.subTest('zero coeff in summed StateFn and CircuitSampler'):
state = 0 * (Plus + Minus)
sampler = CircuitSampler(backend).convert(~StateFn(op) @ state)
self.assertEqual(sampler.eval(), 0j)

with self.subTest('coeff gets squared in CircuitSampler shot-based readout'):
state = (Plus + Minus) / numpy.sqrt(2)
sampler = CircuitSampler(backend).convert(~StateFn(op) @ state)
self.assertAlmostEqual(sampler.eval(), 1+0j)


if __name__ == '__main__':
unittest.main()