Skip to content

Commit 2c1cb72

Browse files
committed
dedent
1 parent f067d04 commit 2c1cb72

1 file changed

Lines changed: 124 additions & 124 deletions

File tree

qiskit/primitives/statevector_estimator.py

Lines changed: 124 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -29,131 +29,131 @@
2929

3030

3131
class StatevectorEstimator(BaseEstimatorV2):
32-
r"""
33-
Simple implementation of :class:`BaseEstimatorV2` with full state vector simulation.
34-
35-
This class is implemented via :class:`~.Statevector` which turns provided circuits into
36-
pure state vectors. These states are subsequently acted on by :class:`~.SparsePauliOp`,
37-
which implies that, at present, this implementation is only compatible with Pauli-based
38-
observables.
39-
40-
Each tuple of ``(circuit, observables, <optional> parameter values, <optional> precision)``,
41-
called an estimator primitive unified bloc (PUB), produces its own array-based result. The
42-
:meth:`~.StatevectorEstimator.run` method can be given a sequence of pubs to run in one call.
43-
44-
The default precision value used by this estimator, ``default_precision=0.0``, results in
45-
exact expecation value estimates for unitary circuits, up to numerical precision. If a
46-
positive value is provided, then it is used to add artificial noise to the exact estimates
47-
by drawing a random variates whose mean values are equal to the exact values, and whose
48-
standard deviations are equal to ``precision`` clipped to the largest value consistent with
49-
the expectation value's space of support. The method of doing so is described below.
50-
51-
When an observable is an n-qubit Pauli, its expectation value must live in the interval
52-
:math:`[-1, 1]`, so that it is natural for this estimator implementation to always report
53-
estimates in :math:`[-1,1]` even when the precision is set to a positive value. More
54-
generally, for a multi-term observable :math:`A=\sum_k b_k P_k` expanded in the Pauli basis
55-
and a quantum state :math:`\rho`, using Hölder's inequality and the triangle inequality, the
56-
expectation value is bounded by
32+
r"""Simple implementation of :class:`BaseEstimatorV2` with full state vector simulation.
33+
34+
This class is implemented via :class:`~.Statevector` which turns provided circuits into
35+
pure state vectors. These states are subsequently acted on by :class:`~.SparsePauliOp`,
36+
which implies that, at present, this implementation is only compatible with Pauli-based
37+
observables.
38+
39+
Each tuple of ``(circuit, observables, <optional> parameter values, <optional> precision)``,
40+
called an estimator primitive unified bloc (PUB), produces its own array-based result. The
41+
:meth:`~.StatevectorEstimator.run` method can be given a sequence of pubs to run in one call.
42+
43+
The default precision value used by this estimator, ``default_precision=0.0``, results in
44+
exact expecation value estimates for unitary circuits, up to numerical precision. If a
45+
positive value is provided, then it is used to add artificial noise to the exact estimates
46+
by drawing a random variates whose mean values are equal to the exact values, and whose
47+
standard deviations are equal to ``precision`` clipped to the largest value consistent with
48+
the expectation value's space of support. The method of doing so is described below.
49+
50+
When an observable is an n-qubit Pauli, its expectation value must live in the interval
51+
:math:`[-1, 1]`, so that it is natural for this estimator implementation to always report
52+
estimates in :math:`[-1,1]` even when the precision is set to a positive value. More
53+
generally, for a multi-term observable :math:`A=\sum_k b_k P_k` expanded in the Pauli basis
54+
and a quantum state :math:`\rho`, using Hölder's inequality and the triangle inequality, the
55+
expectation value is bounded by
56+
57+
.. math::
58+
59+
|\mathrm{Tr}(\rho A)|
60+
\leq \left\lVert \rho \right\rVert_1 \left\lVert B \right\rVert_\infty
61+
\leq \sum_k |b_k|.
62+
63+
While this inequality is loose, in the sense that for a particular observable :math:`A` one
64+
can generally not find a state :math:`\rho` for which the inequality is saturated, it is
65+
still useful, because, in practical experiments, expectation values are often estimated
66+
term-by-term such that the right-hand-side naturally represents a typical bound seen
67+
experimentally.
68+
69+
This class chooses to use the Beta distribution to bound returned estimates to the interval
70+
:math:`[-b, b]` when non-zero precision is present, where :math:`b=\sum_k |b_k|`. Since the
71+
Beta distribution has support on the interval :math:`[0, 1]`, it is used in conjunction with
72+
an affine transformation between :math:`[-b, b]` and :math:`[0, 1]`. In particular, given an
73+
exact expecation value :math:`a`, setting
74+
75+
.. math::
76+
77+
\mu = \frac{a + b}{2b} \\
78+
\sigma^2 = \frac{\mathrm{min}(\mu(1-\mu), \mathrm{precision}^2)}{4b^2} \\
79+
\alpha = \frac{\mu^2(1-\mu)}{\sigma^2} - \mu \\
80+
\beta = \frac{\mu(1-\mu)^2}{\sigma^2} - (1-\mu)
81+
82+
and drawing :math:`\hat{a} \sim \mathrm{Beta}(\alpha, \beta)` leads to
83+
:math:`\mathbb{E}[\hat{a}]=a`, :math:`\mathbb{V}[\hat{a}]=\mathrm{precision}^2`, and
84+
:math:`-b\leq \hat{a} \leq b`. The minimum with $\mu(1-\mu)$ is taken in $\sigma^2$ because
85+
no random variable with support on a unit-length interval can have a variance greater
86+
than $\mu(1-\mu)$, where $\mu$ is its mean value; failing to do this would lead to negative
87+
values of $\alpha$ or $\beta$.
88+
89+
.. note::
90+
Assuming the precision is set to zero, the result of this class is exact if the circuit
91+
contains only unitary operations. On the other hand, the result could be stochastic if
92+
the circuit contains a non-unitary operation such as a reset for some subsystems.
93+
The stochastic result can be made reproducible by setting ``seed``, e.g.,
94+
``StatevectorEstimator(seed=123)``.
95+
96+
.. plot::
97+
:alt: Output from the previous code.
98+
:include-source:
99+
100+
from qiskit.circuit import Parameter, QuantumCircuit
101+
from qiskit.primitives import StatevectorEstimator
102+
from qiskit.quantum_info import Pauli, SparsePauliOp
103+
104+
import matplotlib.pyplot as plt
105+
import numpy as np
106+
107+
# Define a circuit with two parameters.
108+
circuit = QuantumCircuit(2)
109+
circuit.h(0)
110+
circuit.cx(0, 1)
111+
circuit.ry(Parameter("a"), 0)
112+
circuit.rz(Parameter("b"), 0)
113+
circuit.cx(0, 1)
114+
circuit.h(0)
115+
116+
# Define a sweep over parameter values, where the second axis is over
117+
# the two parameters in the circuit.
118+
params = np.vstack([
119+
np.linspace(-np.pi, np.pi, 100),
120+
np.linspace(-4 * np.pi, 4 * np.pi, 100)
121+
]).T
122+
123+
# Define three observables. Many formats are supported here including
124+
# classes such as qiskit.quantum_info.SparsePauliOp. The inner length-1
125+
# lists cause this array of observables to have shape (3, 1), rather
126+
# than shape (3,) if they were omitted.
127+
observables = [
128+
[SparsePauliOp(["XX", "IY"], [0.5, 0.5])],
129+
[Pauli("XX")],
130+
[Pauli("IY")]
131+
]
132+
133+
# Instantiate a new statevector simulation based estimator object.
134+
estimator = StatevectorEstimator()
135+
136+
# Estimate the expectation value for all 300 combinations of
137+
# observables and parameter values, where the pub result will have
138+
# shape (3, 100). This shape is due to our array of parameter
139+
# bindings having shape (100,), combined with our array of observables
140+
# having shape (3, 1)
141+
pub = (circuit, observables, params)
142+
job = estimator.run([pub])
143+
144+
# Extract the result for the 0th pub (this example only has one pub).
145+
result = job.result()[0]
146+
147+
# Error-bar information is also available, but the error is 0
148+
# for this StatevectorEstimator.
149+
result.data.stds
150+
151+
# Pull out the array-based expectation value estimate data from the
152+
# result and plot a trace for each observable.
153+
for idx, pauli in enumerate(observables):
154+
plt.plot(result.data.evs[idx], label=pauli)
155+
plt.legend()
57156
58-
.. math::
59-
60-
|\mathrm{Tr}(\rho A)|
61-
\leq \left\lVert \rho \right\rVert_1 \left\lVert B \right\rVert_\infty
62-
\leq \sum_k |b_k|.
63-
64-
While this inequality is loose, in the sense that for a particular observable :math:`A` one
65-
can generally not find a state :math:`\rho` for which the inequality is saturated, it is
66-
still useful, because, in practical experiments, expectation values are often estimated
67-
term-by-term such that the right-hand-side naturally represents a typical bound seen
68-
experimentally.
69-
70-
This class chooses to use the Beta distribution to bound returned estimates to the interval
71-
:math:`[-b, b]` when non-zero precision is present, where :math:`b=\sum_k |b_k|`. Since the
72-
Beta distribution has support on the interval :math:`[0, 1]`, it is used in conjunction with
73-
an affine transformation between :math:`[-b, b]` and :math:`[0, 1]`. In particular, given an
74-
exact expecation value :math:`a`, setting
75-
76-
.. math::
77-
78-
\mu = \frac{a + b}{2b} \\
79-
\sigma^2 = \frac{\mathrm{min}(\mu(1-\mu), \mathrm{precision}^2)}{4b^2} \\
80-
\alpha = \frac{\mu^2(1-\mu)}{\sigma^2} - \mu \\
81-
\beta = \frac{\mu(1-\mu)^2}{\sigma^2} - (1-\mu)
82-
83-
and drawing :math:`\hat{a} \sim \mathrm{Beta}(\alpha, \beta)` leads to
84-
:math:`\mathbb{E}[\hat{a}]=a`, :math:`\mathbb{V}[\hat{a}]=\mathrm{precision}^2`, and
85-
:math:`-b\leq \hat{a} \leq b`. The minimum with $\mu(1-\mu)$ is taken in $\sigma^2$ because
86-
no random variable with support on a unit-length interval can have a variance greater
87-
than $\mu(1-\mu)$, where $\mu$ is its mean value; failing to do this would lead to negative
88-
values of $\alpha$ or $\beta$.
89-
90-
.. note::
91-
Assuming the precision is set to zero, the result of this class is exact if the circuit
92-
contains only unitary operations. On the other hand, the result could be stochastic if
93-
the circuit contains a non-unitary operation such as a reset for some subsystems.
94-
The stochastic result can be made reproducible by setting ``seed``, e.g.,
95-
``StatevectorEstimator(seed=123)``.
96-
97-
.. plot::
98-
:alt: Output from the previous code.
99-
:include-source:
100-
101-
from qiskit.circuit import Parameter, QuantumCircuit
102-
from qiskit.primitives import StatevectorEstimator
103-
from qiskit.quantum_info import Pauli, SparsePauliOp
104-
105-
import matplotlib.pyplot as plt
106-
import numpy as np
107-
108-
# Define a circuit with two parameters.
109-
circuit = QuantumCircuit(2)
110-
circuit.h(0)
111-
circuit.cx(0, 1)
112-
circuit.ry(Parameter("a"), 0)
113-
circuit.rz(Parameter("b"), 0)
114-
circuit.cx(0, 1)
115-
circuit.h(0)
116-
117-
# Define a sweep over parameter values, where the second axis is over
118-
# the two parameters in the circuit.
119-
params = np.vstack([
120-
np.linspace(-np.pi, np.pi, 100),
121-
np.linspace(-4 * np.pi, 4 * np.pi, 100)
122-
]).T
123-
124-
# Define three observables. Many formats are supported here including
125-
# classes such as qiskit.quantum_info.SparsePauliOp. The inner length-1
126-
# lists cause this array of observables to have shape (3, 1), rather
127-
# than shape (3,) if they were omitted.
128-
observables = [
129-
[SparsePauliOp(["XX", "IY"], [0.5, 0.5])],
130-
[Pauli("XX")],
131-
[Pauli("IY")]
132-
]
133-
134-
# Instantiate a new statevector simulation based estimator object.
135-
estimator = StatevectorEstimator()
136-
137-
# Estimate the expectation value for all 300 combinations of
138-
# observables and parameter values, where the pub result will have
139-
# shape (3, 100). This shape is due to our array of parameter
140-
# bindings having shape (100,), combined with our array of observables
141-
# having shape (3, 1)
142-
pub = (circuit, observables, params)
143-
job = estimator.run([pub])
144-
145-
# Extract the result for the 0th pub (this example only has one pub).
146-
result = job.result()[0]
147-
148-
# Error-bar information is also available, but the error is 0
149-
# for this StatevectorEstimator.
150-
result.data.stds
151-
152-
# Pull out the array-based expectation value estimate data from the
153-
# result and plot a trace for each observable.
154-
for idx, pauli in enumerate(observables):
155-
plt.plot(result.data.evs[idx], label=pauli)
156-
plt.legend()
157157
"""
158158

159159
def __init__(

0 commit comments

Comments
 (0)