Skip to content

Commit c991910

Browse files
Guillermo-Mijares-Vilarinowoodsp-ibmHuangJunyeElePT1ucian0
authored andcommitted
Add how-to guides about primitives (Qiskit#9716)
* Added how-to section * added how to compose circuits guide * added how to visualize circuit guide * add how to create parameterized circuit guide * add guides * removed latex circuit visualization * fixed title underlines * Fix typo * explicitly set cregbundle to False when appending circuit with classical register * Fix typo * Added explanation about needed latex distribution * added link to qiskit.visualization module * Simplified references * Change 'we' to 'you' * Changed how_to.rst to how_to/index.rst * Removed jupyter-execute from create_a_quantum_circuit * Removed jupyter-execute from create_a_parameterized_circuit * Removed jupyter-execute from compose_quantum_circuits * Removed jupyter-execute from visualize_a_quantum_circuit * Add sphinx.ext.doctest to conf.py * Change header symbol for index and visualization guide * Added guides for sampler and estimator and simplified toctree * Fixed underline * Add links to how-to create circuit * Added section about parameterized circuits to primitives how-tos * Remove other how-tos * Remove links * Added reference to other implementations of primitives * Update docs/how_to/use_estimator.rst Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com> * Improved titles * set global doctest flags and disable automatic doctests * Added part about changing options * Add new aer docs page to intersphinx * Added notes about circuit measurements * Improved notes about circuit measurements * Update docs/how_to/use_estimator.rst Co-authored-by: Junye Huang <h.jun.ye@gmail.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Junye Huang <h.jun.ye@gmail.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Junye Huang <h.jun.ye@gmail.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Junye Huang <h.jun.ye@gmail.com> * Added numpy to intersphinx and note about doctest and plot directive * Added note about quasi-probabilities * rename how to to How-to Guides * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Update docs/how_to/use_sampler.rst Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> * Remove generally * Changed sampler initial note to mention BackendSampler * Update docs/how_to/use_sampler.rst Co-authored-by: Luciano Bello <bel@zurich.ibm.com> * Added code example for backend primitives and link to providers page * Update intersphinx mapping to ecosystem for aer and runtime * Change rustworkx link * Add "primitive" to estimator how-to title Co-authored-by: Luciano Bello <bel@zurich.ibm.com> * Change hypothetical import to avoid confusion Co-authored-by: Luciano Bello <bel@zurich.ibm.com> * Update docs/how_to/use_estimator.rst Co-authored-by: Luciano Bello <bel@zurich.ibm.com> * Include "primitive" word in sampler how-to title Co-authored-by: Luciano Bello <bel@zurich.ibm.com> * Improve phrasing Co-authored-by: Luciano Bello <bel@zurich.ibm.com> * Include notice about doctest and plot directive incompatibility in sampler guide * change->modify sampler options * change qiskit_provider to <some_qiskit_provider> * shots->amount of shots in estimator how-to * Add quick explanation about using multiple circuits and observables and adjust plurals * singular * singular --------- Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com> Co-authored-by: Junye Huang <h.jun.ye@gmail.com> Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com> Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
1 parent ebc8baf commit c991910

5 files changed

Lines changed: 546 additions & 10 deletions

File tree

docs/conf.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@
6565
modindex_common_prefix = ["qiskit."]
6666

6767
intersphinx_mapping = {
68-
"retworkx": ("https://qiskit.org/documentation/retworkx/", None),
69-
"qiskit-ibm-runtime": ("https://qiskit.org/documentation/partners/qiskit_ibm_runtime/", None),
70-
"qiskit-aer": ("https://qiskit.org/documentation/aer/", None),
68+
"rustworkx": ("https://qiskit.org/ecosystem/rustworkx/", None),
69+
"qiskit-ibm-runtime": ("https://qiskit.org/ecosystem/ibm-runtime/", None),
70+
"qiskit-aer": ("https://qiskit.org/ecosystem/aer/", None),
7171
"numpy": ("https://numpy.org/doc/stable/", None)
7272
}
7373

@@ -116,17 +116,13 @@
116116

117117
autoclass_content = "both"
118118

119-
# -- Options for Doctest --------------------------------------------------------
120119

121-
import sphinx.ext.doctest
120+
# -- Options for Doctest --------------------------------------------------------
122121

123-
# This option will make doctest ignore whitespace when testing code.
124-
# It's specially important for circuit representation as it gives an
125-
# error otherwise
126-
doctest_default_flags = sphinx.ext.doctest.doctest.NORMALIZE_WHITESPACE
122+
doctest_default_flags = doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | doctest.IGNORE_EXCEPTION_DETAIL | doctest.DONT_ACCEPT_TRUE_FOR_1
127123

128124
# Leaving this string empty disables testing of doctest blocks from docstrings.
129125
# Doctest blocks are structures like this one:
130126
# >> code
131127
# output
132-
doctest_test_doctest_blocks = ""
128+
doctest_test_doctest_blocks = ""

docs/how_to/index.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.. _how_to:
2+
3+
#############
4+
How-to Guides
5+
#############
6+
7+
8+
Use the primitives
9+
==================
10+
11+
.. toctree::
12+
:maxdepth: 1
13+
14+
use_sampler
15+
use_estimator

docs/how_to/use_estimator.rst

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
#########################################################
2+
Compute an expectation value with ``Estimator`` primitive
3+
#########################################################
4+
5+
This guide shows how to get the expected value of an observable for a given quantum circuit with the :class:`~qiskit.primitives.Estimator` primitive.
6+
7+
.. note::
8+
9+
While this guide uses Qiskit’s reference implementation, the ``Estimator`` primitive can be run with any provider using :class:`~qiskit.primitives.BackendEstimator` .
10+
11+
.. code-block::
12+
13+
from qiskit.primitives import BackendEstimator
14+
from <some_qiskit_provider> import QiskitProvider
15+
16+
provider = QiskitProvider()
17+
backend = provider.get_backend('backend_name')
18+
estimator = BackendEstimator(backend)
19+
20+
There are some providers that implement primitives natively (see `this page <http://qiskit.org/providers/#primitives>`_ for more details).
21+
22+
23+
Initialize observables
24+
======================
25+
26+
The first step is to define the observables whose expected value you want to compute. Each observable can be any ``BaseOperator``, like the operators from :mod:`qiskit.quantum_info`.
27+
Among them it is preferable to use :class:`~qiskit.quantum_info.SparsePauliOp`.
28+
29+
.. testcode::
30+
31+
from qiskit.quantum_info import SparsePauliOp
32+
33+
observable = SparsePauliOp(["II", "XX", "YY", "ZZ"], coeffs=[1, 1, -1, 1])
34+
35+
Initialize quantum circuit
36+
==========================
37+
38+
Then you need to create the :class:`~qiskit.circuit.QuantumCircuit`\ s for which you want to obtain the expected value.
39+
40+
.. plot::
41+
:include-source:
42+
43+
from qiskit import QuantumCircuit
44+
45+
qc = QuantumCircuit(2)
46+
qc.h(0)
47+
qc.cx(0,1)
48+
qc.draw("mpl")
49+
50+
.. testsetup::
51+
52+
# This code is repeated (but hidden) because we will need to use the variables with the extension sphinx.ext.doctest (testsetup/testcode/testoutput directives)
53+
# and we can't reuse the variables from the plot directive above because they are incompatible.
54+
# The plot directive is used to draw the circuit with matplotlib and the code is shown because of the include-source flag.
55+
56+
from qiskit import QuantumCircuit
57+
58+
qc = QuantumCircuit(2)
59+
qc.h(0)
60+
qc.cx(0,1)
61+
62+
.. note::
63+
64+
The :class:`~qiskit.circuit.QuantumCircuit` you pass to :class:`~qiskit.primitives.Estimator` must not include any measurements.
65+
66+
Initialize the ``Estimator``
67+
============================
68+
69+
Then, you need to instantiate an :class:`~qiskit.primitives.Estimator`.
70+
71+
.. testcode::
72+
73+
from qiskit.primitives import Estimator
74+
75+
estimator = Estimator()
76+
77+
Run and get results
78+
===================
79+
80+
Now that you have defined your ``estimator``, you can run your estimation by calling the :meth:`~qiskit.primitives.Estimator.run` method,
81+
which returns an instance of :class:`~.PrimitiveJob` (subclass of :class:`~qiskit.providers.JobV1`). You can get the results from the job (as a :class:`~qiskit.primitives.EstimatorResult` object)
82+
with the :meth:`~qiskit.providers.JobV1.result` method.
83+
84+
.. testcode::
85+
86+
job = estimator.run(qc, observable)
87+
result = job.result()
88+
print(result)
89+
90+
.. testoutput::
91+
92+
EstimatorResult(values=array([4.]), metadata=[{}])
93+
94+
While this example only uses one :class:`~qiskit.circuit.QuantumCircuit` and one observable, if you want to get expectation values for multiple circuits and observables you can
95+
pass a ``list`` of :class:`~qiskit.circuit.QuantumCircuit`\ s and a list of ``BaseOperator``\ s to the :meth:`~qiskit.primitives.Estimator.run` method. Both ``list``\ s must have
96+
the same length.
97+
98+
Get the expected value
99+
----------------------
100+
101+
From these results you can extract the expected values with the attribute :attr:`~qiskit.primitives.EstimatorResult.values`.
102+
103+
:attr:`~qiskit.primitives.EstimatorResult.values` returns a :class:`numpy.ndarray`
104+
whose ``i``-th element is the expectation value corresponding to the ``i``-th circuit and ``i``-th observable.
105+
106+
.. testcode::
107+
108+
exp_value = result.values[0]
109+
print(exp_value)
110+
111+
.. testoutput::
112+
113+
3.999999999999999
114+
115+
Parameterized circuit with ``Estimator``
116+
========================================
117+
118+
The :class:`~qiskit.primitives.Estimator` primitive can be run with unbound parameterized circuits like the one below.
119+
You can also manually bind values to the parameters of the circuit and follow the steps
120+
of the previous example.
121+
122+
.. testcode::
123+
124+
from qiskit.circuit import Parameter
125+
126+
theta = Parameter('θ')
127+
param_qc = QuantumCircuit(2)
128+
param_qc.ry(theta, 0)
129+
param_qc.cx(0,1)
130+
print(param_qc.draw())
131+
132+
.. testoutput::
133+
134+
┌───────┐
135+
q_0: ┤ Ry(θ) ├──■──
136+
└───────┘┌─┴─┐
137+
q_1: ─────────┤ X ├
138+
└───┘
139+
140+
The main difference with the previous case is that now you need to specify the sets of parameter values
141+
for which you want to evaluate the expectation value as a ``list`` of ``list``\ s of ``float``\ s.
142+
The ``i``-th element of the outer``list`` is the set of parameter values
143+
that corresponds to the ``i``-th circuit and observable.
144+
145+
.. testcode::
146+
147+
import numpy as np
148+
149+
parameter_values = [[0], [np.pi/6], [np.pi/2]]
150+
151+
job = estimator.run([param_qc]*3, [observable]*3, parameter_values=parameter_values)
152+
values = job.result().values
153+
154+
for i in range(3):
155+
print(f"Parameter: {parameter_values[i][0]:.5f}\t Expectation value: {values[i]}")
156+
157+
.. testoutput::
158+
159+
Parameter: 0.00000 Expectation value: 2.0
160+
Parameter: 0.52360 Expectation value: 3.0
161+
Parameter: 1.57080 Expectation value: 4.0
162+
163+
Change run options
164+
==================
165+
166+
Your workflow might require tuning primitive run options, such as the amount of shots.
167+
168+
By default, the reference :class:`~qiskit.primitives.Estimator` class performs an exact statevector
169+
calculation based on the :class:`~qiskit.quantum_info.Statevector` class. However, this can be
170+
modified to include shot noise if the number of ``shots`` is set.
171+
For reproducibility purposes, a ``seed`` will also be set in the following examples.
172+
173+
There are two main ways of setting options in the :class:`~qiskit.primitives.Estimator`:
174+
175+
* Set keyword arguments in the :meth:`~qiskit.primitives.Estimator.run` method.
176+
* Modify :class:`~qiskit.primitives.Estimator` options.
177+
178+
Set keyword arguments for :meth:`~qiskit.primitives.Estimator.run`
179+
------------------------------------------------------------------
180+
181+
If you only want to change the settings for a specific run, it can be more convenient to
182+
set the options inside the :meth:`~qiskit.primitives.Estimator.run` method. You can do this by
183+
passing them as keyword arguments.
184+
185+
.. testcode::
186+
187+
job = estimator.run(qc, observable, shots=2048, seed=123)
188+
result = job.result()
189+
print(result)
190+
191+
.. testoutput::
192+
193+
EstimatorResult(values=array([4.]), metadata=[{'variance': 3.552713678800501e-15, 'shots': 2048}])
194+
195+
.. testcode::
196+
197+
print(result.values[0])
198+
199+
.. testoutput::
200+
201+
3.999999998697238
202+
203+
Modify :class:`~qiskit.primitives.Estimator` options
204+
-----------------------------------------------------
205+
206+
If you want to keep some configuration values for several runs, it can be better to
207+
change the :class:`~qiskit.primitives.Estimator` options. That way you can use the same
208+
:class:`~qiskit.primitives.Estimator` object as many times as you wish without having to
209+
rewrite the configuration values every time you use :meth:`~qiskit.primitives.Estimator.run`.
210+
211+
Modify existing :class:`~qiskit.primitives.Estimator`
212+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
213+
214+
If you prefer to change the options of an already-defined :class:`~qiskit.primitives.Estimator`, you can use
215+
:meth:`~qiskit.primitives.Estimator.set_options` and introduce the new options as keyword arguments.
216+
217+
.. testcode::
218+
219+
estimator.set_options(shots=2048, seed=123)
220+
221+
job = estimator.run(qc, observable)
222+
result = job.result()
223+
print(result)
224+
225+
.. testoutput::
226+
227+
EstimatorResult(values=array([4.]), metadata=[{'variance': 3.552713678800501e-15, 'shots': 2048}])
228+
229+
.. testcode::
230+
231+
print(result.values[0])
232+
233+
.. testoutput::
234+
235+
3.999999998697238
236+
237+
238+
Define a new :class:`~qiskit.primitives.Estimator` with the options
239+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
240+
241+
If you prefer to define a new :class:`~qiskit.primitives.Estimator` with new options, you need to
242+
define a ``dict`` like this one:
243+
244+
.. testcode::
245+
246+
options = {"shots": 2048, "seed": 123}
247+
248+
And then you can introduce it into your new :class:`~qiskit.primitives.Estimator` with the
249+
``options`` argument.
250+
251+
.. testcode::
252+
253+
estimator = Estimator(options=options)
254+
255+
job = estimator.run(qc, observable)
256+
result = job.result()
257+
print(result)
258+
259+
.. testoutput::
260+
261+
EstimatorResult(values=array([4.]), metadata=[{'variance': 3.552713678800501e-15, 'shots': 2048}])
262+
263+
.. testcode::
264+
265+
print(result.values[0])
266+
267+
.. testoutput::
268+
269+
3.999999998697238

0 commit comments

Comments
 (0)