-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Add how-to guides about primitives #9716
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 49 commits
2f1e42f
d39833c
bb661fd
59e06f9
9c87269
109b049
63d6f81
9cc7f76
d28748a
e7b2e47
352a7c4
ba14c27
4cf2634
ed2115c
a7b38d8
861baaa
9354aa0
02298c6
0dbd593
6ad73b0
571db61
2081f4a
082b04e
205370c
84f98cf
a6053bb
3ac6be1
3b260e8
5a3a74a
5a30873
54071ee
89da1ac
130f5ac
8f83d18
6daed2f
ffbc8de
bc3da86
8fc6f30
e9f7924
cdf6745
16977be
6f837cc
9ad583a
1dc2ef7
25141f2
9c92b80
bbd57b1
ce362e1
053b7c6
cf8def3
1e1044c
6a7c92c
3d7ee62
215a0a8
919e316
f0dd1ab
849396f
d514216
645792f
6d89eb0
f37e2e5
f27d7ee
1d6e25a
bf39db2
bc24efe
38ce964
80213cc
0e170c3
af5aceb
d653451
f46be30
87de7c0
0255ce8
785bdd2
47c4e27
18c90cc
8906ea8
e60b253
32ab2f3
23fbd02
f819ebe
d4c5802
c125f06
b352958
278df5a
e51e29e
644d8c7
1607aac
36d54f3
254c8de
3ee6158
004f4ad
3d7e5a8
51a1260
973f1e0
9418b52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| .. _how_to: | ||
|
|
||
| ############# | ||
| How-to Guides | ||
| ############# | ||
|
|
||
|
|
||
| Use the primitives | ||
| ================== | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 1 | ||
|
|
||
| use_sampler | ||
| use_estimator |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,256 @@ | ||
| ############################################### | ||
| Compute an expectation value with ``Estimator`` | ||
| ############################################### | ||
|
|
||
| This guide shows how to get the expected value of an observable for a given quantum circuit with the :class:`~qiskit.primitives.Estimator` primitive. | ||
|
|
||
| .. note:: | ||
|
|
||
| While this guide only uses Qiskit Terra's implementation of the ``Estimator`` primitive, there are other | ||
| implementations of this primitive like Qiskit Terra's :class:`~qiskit.primitives.BackendEstimator`, Qiskit Aer's :class:`~qiskit_aer.primitives.Estimator` | ||
| and Qiskit Runtime's :class:`~qiskit_ibm_runtime.Estimator`. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is also this tutorial being done around selection Qiskit/qiskit-tutorials#1385 since you mention others here. That maybe helpful to link eventually to perhaps give clarity to the fact that there other others and how to select. Now the runtime has a bunch of tutorials for the runtime primitives too - would that be a "better" link than the API ref (Or in addition?)
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
|
|
||
| Initialize observable | ||
| ===================== | ||
|
|
||
| The first step is to define the observable whose expected value you want to compute. This observable can be any ``BaseOperator``, like the operators from :mod:`qiskit.quantum_info`. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| Among them it is preferable to use :class:`~qiskit.quantum_info.SparsePauliOp`. | ||
|
|
||
| .. testcode:: | ||
|
|
||
| from qiskit.quantum_info import SparsePauliOp | ||
|
|
||
| observable = SparsePauliOp(["II", "XX", "YY", "ZZ"], coeffs=[1, 1, -1, 1]) | ||
|
|
||
| Initialize quantum circuits | ||
|
1ucian0 marked this conversation as resolved.
Outdated
|
||
| =========================== | ||
|
|
||
| Then you need to create the :class:`~qiskit.circuit.QuantumCircuit` for which you want to obtain the expected value. | ||
|
|
||
| .. plot:: | ||
| :include-source: | ||
|
|
||
| from qiskit import QuantumCircuit | ||
|
|
||
| qc = QuantumCircuit(2) | ||
| qc.h(0) | ||
| qc.cx(0,1) | ||
| qc.draw("mpl") | ||
|
|
||
| .. testsetup:: | ||
|
|
||
|
HuangJunye marked this conversation as resolved.
|
||
| # This code is repeated (but hidden) because we will need to use the variables with the extension sphinx.ext.doctest (testsetup/testcode/testoutput directives) | ||
| # and we can't reuse the variables from the plot directive above because they are incompatible. | ||
| # The plot directive is used to draw the circuit with matplotlib and the code is shown because of the include-source flag. | ||
|
|
||
| from qiskit import QuantumCircuit | ||
|
|
||
| qc = QuantumCircuit(2) | ||
| qc.h(0) | ||
| qc.cx(0,1) | ||
|
|
||
| .. note:: | ||
|
|
||
| The :class:`~qiskit.circuit.QuantumCircuit` you pass to :class:`~qiskit.primitives.Estimator` must not include any measurements. | ||
|
|
||
| Initialize the ``Estimator`` | ||
| ============================ | ||
|
|
||
| Then, you need to create an :class:`~qiskit.primitives.Estimator` object. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
| .. testcode:: | ||
|
|
||
| from qiskit.primitives import Estimator | ||
|
|
||
| estimator = Estimator() | ||
|
HuangJunye marked this conversation as resolved.
|
||
|
|
||
| Run and get results | ||
| =================== | ||
|
|
||
| Now that you have defined ``estimator``, you can create a :class:`~.PrimitiveJob` (subclass of :class:`~qiskit.providers.JobV1`) with the | ||
| :meth:`~qiskit.primitives.Estimator.run` method and, then, you can get the results (as a :class:`~qiskit.primitives.EstimatorResult` object) with | ||
| the results with the :meth:`~qiskit.providers.JobV1.result` method. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
| .. testcode:: | ||
|
|
||
| job = estimator.run(qc, observable) | ||
| result = job.result() | ||
| print(result) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| EstimatorResult(values=array([4.]), metadata=[{}]) | ||
|
|
||
| Get the expected value | ||
| ---------------------- | ||
|
|
||
| From these results you can take the expected values with the attribute :attr:`~qiskit.primitives.EstimatorResult.values`. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
| Generally, :attr:`~qiskit.primitives.EstimatorResult.values` returns a :class:`numpy.ndarray` | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| whose ``i``-th element would be the expectation value corresponding to the ``i``-th circuit and ``i``-th observable. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
| .. testcode:: | ||
|
|
||
| exp_value = result.values[0] | ||
| print(exp_value) | ||
|
|
||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
|
||
| .. testoutput:: | ||
|
|
||
| 3.999999999999999 | ||
|
|
||
| Parameterized circuits with ``Estimator`` | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a how-to not a tutorial. Options in how-tos are fine |
||
| ========================================= | ||
|
|
||
| The :class:`~qiskit.primitives.Estimator` primitive also has the option to include unbound parameterized circuits like the one below. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here this starts to get close to using an optimizer with a parameterized circuit to find minimum exp val. i.e VQE. Would we want a howto to show using an estimator for that. Of course we have a more comprehensive pre-built VQE algo - but its a nice simple howto to build a simple one. Here the parameters are applied sequentially - rather than all at once in this example.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe it can be a nice topic for a future how-to. As I see it we could show both ways to get the minimum eigenvalue: with We also have several tutorials covering the usage of the It could also be a more generic "how to run a variational algorithm with
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess I see people using the Estimator with an optimizer to make a simple VQE. It just seemed more like an aspect someone might be wanting to do and a howto, that includes parameterized circuits, which seemed to be the aspect the latter section was bringing in, might be a task that had more relevancy. I agree its bit more complex than what is there and maybe is more applicable for a future howto. It was less about VQE and more that this a common way to use parameterized ccts with an Estimator.
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| You can also bind values to the parameters of the circuit and follow the steps | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| of the previous example. | ||
|
|
||
| .. testcode:: | ||
|
|
||
| from qiskit.circuit import Parameter | ||
|
|
||
| theta = Parameter('θ') | ||
| param_qc = QuantumCircuit(2) | ||
| param_qc.ry(theta, 0) | ||
| param_qc.cx(0,1) | ||
| print(param_qc.draw()) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| ┌───────┐ | ||
| q_0: ┤ Ry(θ) ├──■── | ||
| └───────┘┌─┴─┐ | ||
| q_1: ─────────┤ X ├ | ||
| └───┘ | ||
|
|
||
| The main difference from the previous case is that now you need to include the parameter values | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| for which you want to evaluate the expectation value as a ``list`` of ``list``\ s of ``float``\ s. | ||
| The idea is that the ``i``-th element of the bigger ``list`` is the set of parameter values | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| that corresponds to the ``i``-th circuit and observable. | ||
|
|
||
| .. testcode:: | ||
|
|
||
| import numpy as np | ||
|
|
||
| parameter_values = [[0], [np.pi/6], [np.pi/2]] | ||
|
|
||
| job = estimator.run([param_qc]*3, [observable]*3, parameter_values=parameter_values) | ||
| values = job.result().values | ||
|
|
||
| for i in range(3): | ||
| print(f"Parameter: {parameter_values[i][0]:.5f}\t Expectation value: {values[i]}") | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| Parameter: 0.00000 Expectation value: 2.0 | ||
| Parameter: 0.52360 Expectation value: 3.0 | ||
| Parameter: 1.57080 Expectation value: 4.0 | ||
|
|
||
| Change run options | ||
| ================== | ||
|
|
||
| It is also possible that you may want to change any other option. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
| For example, in the previous sections the :class:`~qiskit.primitives.Estimator` | ||
| is :class:`~qiskit.quantum_info.Statevector`-based but it can be changed | ||
| to shot-based by setting a number of ``shots``. For reproducibility purposes, in this | ||
| guide a ``seed`` will also be set. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
| There are two main ways of doing this: | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
|
|
||
| * Setting keyword arguments in the :meth:`~qiskit.primitives.Estimator.run` method. | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| * Modify :class:`~qiskit.primitives.Estimator` options. | ||
|
|
||
| Set keyword arguments for :meth:`~qiskit.primitives.Estimator.run` | ||
| ------------------------------------------------------------------ | ||
|
|
||
| If you only want to change the settings for a specific run, it can be more convenient to | ||
| set the options inside the :meth:`~qiskit.primitives.Estimator.run` method. You can do this by | ||
| passing them as keyword arguments. | ||
|
|
||
| .. testcode:: | ||
|
|
||
| job = estimator.run(qc, observable, shots=2048, seed=123) | ||
| result = job.result() | ||
| print(result) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| EstimatorResult(values=array([4.]), metadata=[{'variance': 3.552713678800501e-15, 'shots': 2048}]) | ||
|
|
||
| .. testcode:: | ||
|
|
||
| print(result.values[0]) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| 3.999999998697238 | ||
|
|
||
| Change :class:`~qiskit.primitives.Estimator` options | ||
|
Guillermo-Mijares-Vilarino marked this conversation as resolved.
Outdated
|
||
| ----------------------------------------------------- | ||
|
|
||
| If you want to keep some configuration values for several runs, it can be better to | ||
| change the :class:`~qiskit.primitives.Estimator` options. That way you can use the same | ||
| :class:`~qiskit.primitives.Estimator` object as many times as you wish without having to | ||
| rewrite the configuration values every time you use :meth:`~qiskit.primitives.Estimator.run`. | ||
|
|
||
| Modify existing :class:`~qiskit.primitives.Estimator` | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| If you prefer to change the options of an already-defined :class:`~qiskit.primitives.Estimator`, you can use | ||
| :meth:`~qiskit.primitives.Estimator.set_options` and introduce the new options as keyword arguments. | ||
|
|
||
| .. testcode:: | ||
|
|
||
| estimator.set_options(shots=2048, seed=123) | ||
|
|
||
| job = estimator.run(qc, observable) | ||
| result = job.result() | ||
| print(result) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| EstimatorResult(values=array([4.]), metadata=[{'variance': 3.552713678800501e-15, 'shots': 2048}]) | ||
|
|
||
| .. testcode:: | ||
|
|
||
| print(result.values[0]) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| 3.999999998697238 | ||
|
|
||
|
|
||
| Define a new :class:`~qiskit.primitives.Estimator` with the options | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| If you prefer to define a new :class:`~qiskit.primitives.Estimator` with new options, you need to | ||
| define a ``dict`` like this one: | ||
|
|
||
| .. testcode:: | ||
|
|
||
| options = {"shots": 2048, "seed": 123} | ||
|
|
||
| And then you can introduce it into your new :class:`~qiskit.primitives.Estimator` with the | ||
| ``options`` argument. | ||
|
|
||
| .. testcode:: | ||
|
|
||
| estimator = Estimator(options=options) | ||
|
|
||
| job = estimator.run(qc, observable) | ||
| result = job.result() | ||
| print(result) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| EstimatorResult(values=array([4.]), metadata=[{'variance': 3.552713678800501e-15, 'shots': 2048}]) | ||
|
|
||
| .. testcode:: | ||
|
|
||
| print(result.values[0]) | ||
|
|
||
| .. testoutput:: | ||
|
|
||
| 3.999999998697238 | ||
Uh oh!
There was an error while loading. Please reload this page.