forked from Qiskit/documentation
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate open source docs (attempt #2) (Qiskit#118)
Recreates Qiskit#91, but without squash merging.
- Loading branch information
Showing
18 changed files
with
18,627 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
######################### | ||
Order of qubits in Qiskit | ||
######################### | ||
|
||
While most physics textbooks represent an :math:`n`-qubit system as the tensor product :math:`Q_0\otimes Q_1 \otimes ... \otimes Q_{n-1}`, where :math:`Q_j` is the :math:`j^{\mathrm{th}}` qubit, Qiskit uses the inverse order, that is, :math:`Q_{n-1}\otimes ... \otimes Q_1 \otimes Q_{0}`. As explained in `this video <https://www.youtube.com/watch?v=EiqHj3_Avps>`_ from `Qiskit's YouTube channel <https://www.youtube.com/@qiskit>`_, this is done to follow the convention in classical computing, in which the :math:`n^{\mathrm{th}}` bit or most significant bit (MSB) is placed on the left (with index 0) while the least significant bit (LSB) is placed on the right (index :math:`n-1`). This ordering convention is called little-endian while the one from the physics textbooks is called big-endian. | ||
|
||
This means that if we have, for example, a 3-qubit system with qubit 0 in state :math:`|1\rangle` and qubits 1 and 2 in state :math:`|0\rangle`, Qiskit would represent this state as :math:`|001\rangle` while most physics textbooks would represent this state as :math:`|100\rangle`. | ||
|
||
The matrix representation of any multi-qubit gate is also affected by this different qubit ordering. For example, if we consider the single-qubit gate | ||
|
||
.. math:: | ||
U = \begin{pmatrix} u_{00} & u_{01} \\ u_{10} & u_{11} \end{pmatrix} | ||
And we want a controlled version :math:`C_U` whose control qubit is qubit 0 and whose target is qubit 1, following Qiskit's ordering its matrix representation would be | ||
|
||
.. math:: | ||
C_U = \begin{pmatrix} 1 & 0 & 0 & 0 \\0 & u_{00} & 0 & u_{01} \\ 0 & 0 & 1 & 0 \\ 0 & u_{10} & 0& u_{11} \end{pmatrix} | ||
while in a physics textbook it would be written as | ||
|
||
.. math:: | ||
C_U = \begin{pmatrix} 1 & 0 & 0 & 0 \\0 & 1 & 0 & 0 \\ 0 & 0 & u_{00} & u_{01} \\ 0 & 0 & u_{00} & u_{01} \end{pmatrix} | ||
For more details about how this ordering of MSB and LSB affects the matrix representation of any particular gate, check its entry in the circuit :mod:`~qiskit.circuit.library`. | ||
|
||
This different order can also make the circuit corresponding to an algorithm from a textbook a bit more complicated to visualize. Fortunately, Qiskit provides a way to represent a :class:`~.QuantumCircuit` with the most significant qubits on top, just like in the textbooks. This can be done by setting the ``reverse_bits`` argument of the :meth:`~.QuantumCircuit.draw` method to ``True``. | ||
|
||
Let's try this for a 3-qubit Quantum Fourier Transform (:class:`~.QFT`). | ||
|
||
.. plot:: | ||
:include-source: | ||
:context: | ||
|
||
from qiskit.circuit.library import QFT | ||
|
||
qft = QFT(3) | ||
qft.decompose().draw('mpl') | ||
|
||
.. plot:: | ||
:include-source: | ||
:context: close-figs | ||
|
||
qft.decompose().draw('mpl', reverse_bits=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
.. _faq: | ||
|
||
========================== | ||
Frequently Asked Questions | ||
========================== | ||
|
||
**Q: How should I cite Qiskit in my research?** | ||
|
||
**A:** Please cite Qiskit by using the included `BibTeX file | ||
<https://github.com/Qiskit/qiskit-terra/blob/main/CITATION.bib>`__. | ||
|
||
| | ||
**Q: Why do I receive the error message** ``AttributeError: QuantumCircuit object has no attribute save_state`` | ||
**when using ``save_*``method on a circuit?** | ||
|
||
**A:** The ``save_*`` instructions are part of Qiskit Aer project, | ||
a high performance simulator for quantum circuits. These instructions do not | ||
exist outside of Qiskit Aer and are added dynamically to the | ||
:class:`~.QuantumCircuit` class by Qiskit Aer on import. If you would like to | ||
use these instructions you must first ensure that you have imported | ||
``qiskit_aer`` in your program before trying to call these methods. You | ||
can refer to :mod:`qiskit_aer.library` for the details of these custom | ||
instructions included with Qiskit Aer. | ||
|
||
**Q: Why do my results from real devices differ from my results from the simulator?** | ||
|
||
**A:** The simulator runs jobs as though is was in an ideal environment; one | ||
without noise or decoherence. However, when jobs are run on the real devices | ||
there is noise from the environment and decoherence, which causes the qubits | ||
to behave differently than what is intended. | ||
|
||
| | ||
**Q: Why do I receive the error message,** ``No Module 'qiskit'`` **when using Jupyter Notebook?** | ||
|
||
**A:** If you used ``pip install qiskit`` and set up your virtual environment in | ||
Anaconda, then you may experience this error when you run a tutorial | ||
in Jupyter Notebook. If you have not installed Qiskit or set up your | ||
virtual environment, you can follow the :ref:`installation` steps. | ||
|
||
The error is caused when trying to import the Qiskit package in an | ||
environment where Qiskit is not installed. If you launched Jupyter Notebook | ||
from the Anaconda-Navigator, it is possible that Jupyter Notebook is running | ||
in the base (root) environment, instead of in your virtual | ||
environment. Choose a virtual environment in the Anaconda-Navigator from the | ||
**Applications on** dropdown menu. In this menu, you can see | ||
all of the virtual environments within Anaconda, and you can | ||
select the environment where you have Qiskit installed to launch Jupyter | ||
Notebook. | ||
|
||
| | ||
**Q: Why am I getting a compilation error while installing ``qiskit``?** | ||
|
||
**A:** Qiskit depends on a number of other open source Python packages, which | ||
are automatically installed when doing ``pip install qiskit``. Depending on | ||
your system's platform and Python version, it is possible that a particular | ||
package does not provide pre-built binaries for your system. You can refer | ||
to :ref:`platform_support` for a list of platforms supported by Qiskit, some | ||
of which may need an extra compiler. In cases where there are | ||
no precompiled binaries available ``pip`` will attempt to compile the package | ||
from source, which in turn might require some extra dependencies that need to | ||
be installed manually. | ||
|
||
If the output of ``pip install qiskit`` contains similar lines to: | ||
|
||
.. code:: sh | ||
Failed building wheel for SOME_PACKAGE | ||
... | ||
build/temp.linux-x86_64-3.5/_openssl.c:498:30: fatal error | ||
compilation terminated. | ||
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1 | ||
please check the documentation of the package that failed to install (in the | ||
example code, ``SOME_PACKAGE``) for information on how to install the libraries | ||
needed for compiling from source. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
############################################################### | ||
Compute circuit output probabilities with ``Sampler`` primitive | ||
############################################################### | ||
|
||
This guide shows how to get the probability distribution of a quantum circuit with the :class:`~qiskit.primitives.Sampler` primitive. | ||
|
||
.. note:: | ||
|
||
While this guide uses Qiskit’s reference implementation, the ``Sampler`` primitive can be run with any provider using :class:`~qiskit.primitives.BackendSampler`. | ||
|
||
.. code-block:: | ||
from qiskit.primitives import BackendSampler | ||
from <some_qiskit_provider> import QiskitProvider | ||
provider = QiskitProvider() | ||
backend = provider.get_backend('backend_name') | ||
sampler = BackendSampler(backend) | ||
There are some providers that implement primitives natively (see `this page <http://qiskit.org/providers/#primitives>`_ for more details). | ||
|
||
Initialize quantum circuits | ||
=========================== | ||
|
||
The first step is to create the :class:`~qiskit.circuit.QuantumCircuit`\ s from which you want to obtain the probability distribution. | ||
|
||
.. plot:: | ||
:include-source: | ||
|
||
from qiskit import QuantumCircuit | ||
|
||
qc = QuantumCircuit(2) | ||
qc.h(0) | ||
qc.cx(0,1) | ||
qc.measure_all() | ||
qc.draw("mpl") | ||
|
||
.. testsetup:: | ||
|
||
# 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) | ||
qc.measure_all() | ||
|
||
.. note:: | ||
|
||
The :class:`~qiskit.circuit.QuantumCircuit` you pass to :class:`~qiskit.primitives.Sampler` has to include measurements. | ||
|
||
Initialize the ``Sampler`` | ||
========================== | ||
|
||
Then, you need to create a :class:`~qiskit.primitives.Sampler` instance. | ||
|
||
.. testcode:: | ||
|
||
from qiskit.primitives import Sampler | ||
|
||
sampler = Sampler() | ||
|
||
Run and get results | ||
=================== | ||
|
||
Now that you have defined your ``sampler``, you can run it by calling the :meth:`~qiskit.primitives.Sampler.run` method, | ||
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.SamplerResult` object) | ||
with the :meth:`~qiskit.providers.JobV1.result` method. | ||
|
||
.. testcode:: | ||
|
||
job = sampler.run(qc) | ||
result = job.result() | ||
print(result) | ||
|
||
.. testoutput:: | ||
|
||
SamplerResult(quasi_dists=[{0: 0.4999999999999999, 3: 0.4999999999999999}], metadata=[{}]) | ||
|
||
While this example only uses one :class:`~qiskit.circuit.QuantumCircuit`, if you want to sample multiple circuits you can | ||
pass a ``list`` of :class:`~qiskit.circuit.QuantumCircuit` instances to the :meth:`~qiskit.primitives.Sampler.run` method. | ||
|
||
Get the probability distribution | ||
-------------------------------- | ||
|
||
From these results you can extract the quasi-probability distributions with the attribute :attr:`~qiskit.primitives.SamplerResult.quasi_dists`. | ||
|
||
Even though there is only one circuit in this example, :attr:`~qiskit.primitives.SamplerResult.quasi_dists` returns a list of :class:`~qiskit.result.QuasiDistribution`\ s. | ||
``result.quasi_dists[i]`` is the quasi-probability distribution of the ``i``-th circuit. | ||
|
||
.. note:: | ||
|
||
A quasi-probability distribution differs from a probability distribution in that negative values are also allowed. | ||
However the quasi-probabilities must sum up to 1 like probabilities. | ||
Negative quasi-probabilities may appear when using error mitigation techniques. | ||
|
||
.. testcode:: | ||
|
||
quasi_dist = result.quasi_dists[0] | ||
print(quasi_dist) | ||
|
||
.. testoutput:: | ||
|
||
{0: 0.4999999999999999, 3: 0.4999999999999999} | ||
|
||
Probability distribution with binary outputs | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
If you prefer to see the output keys as binary strings instead of decimal numbers, you can use the | ||
:meth:`~qiskit.result.QuasiDistribution.binary_probabilities` method. | ||
|
||
.. testcode:: | ||
|
||
print(quasi_dist.binary_probabilities()) | ||
|
||
.. testoutput:: | ||
|
||
{'00': 0.4999999999999999, '11': 0.4999999999999999} | ||
|
||
Parameterized circuit with ``Sampler`` | ||
======================================== | ||
|
||
The :class:`~qiskit.primitives.Sampler` primitive can be run with unbound parameterized circuits like the one below. | ||
You can also manually bind values to the parameters of the circuit and follow the steps | ||
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) | ||
param_qc.measure_all() | ||
print(param_qc.draw()) | ||
|
||
.. testoutput:: | ||
|
||
┌───────┐ ░ ┌─┐ | ||
q_0: ┤ Ry(θ) ├──■───░─┤M├─── | ||
└───────┘┌─┴─┐ ░ └╥┘┌─┐ | ||
q_1: ─────────┤ X ├─░──╫─┤M├ | ||
└───┘ ░ ║ └╥┘ | ||
meas: 2/══════════════════╩══╩═ | ||
0 1 | ||
|
||
The main difference from the previous case is that now you need to specify the sets of parameter values | ||
for which you want to evaluate the expectation value as a ``list`` of ``list``\ s of ``float``\ s. | ||
The ``i``-th element of the outer ``list`` is the set of parameter values | ||
that corresponds to the ``i``-th circuit. | ||
|
||
.. testcode:: | ||
|
||
import numpy as np | ||
|
||
parameter_values = [[0], [np.pi/6], [np.pi/2]] | ||
|
||
job = sampler.run([param_qc]*3, parameter_values=parameter_values) | ||
dists = job.result().quasi_dists | ||
|
||
for i in range(3): | ||
print(f"Parameter: {parameter_values[i][0]:.5f}\t Probabilities: {dists[i]}") | ||
|
||
.. testoutput:: | ||
|
||
Parameter: 0.00000 Probabilities: {0: 1.0} | ||
Parameter: 0.52360 Probabilities: {0: 0.9330127018922194, 3: 0.0669872981077807} | ||
Parameter: 1.57080 Probabilities: {0: 0.5000000000000001, 3: 0.4999999999999999} | ||
|
||
Change run options | ||
================== | ||
|
||
Your workflow might require tuning primitive run options, such as the amount of shots. | ||
|
||
By default, the reference :class:`~qiskit.primitives.Sampler` class performs an exact statevector | ||
calculation based on the :class:`~qiskit.quantum_info.Statevector` class. However, this can be | ||
modified to include shot noise if the number of ``shots`` is set. | ||
For reproducibility purposes, a ``seed`` will also be set in the following examples. | ||
|
||
There are two main ways of setting options in the :class:`~qiskit.primitives.Sampler`: | ||
|
||
* Set keyword arguments in the :meth:`~qiskit.primitives.Sampler.run` method. | ||
* Modify :class:`~qiskit.primitives.Sampler` options. | ||
|
||
Set keyword arguments for :meth:`~qiskit.primitives.Sampler.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.Sampler.run` method. You can do this by | ||
passing them as keyword arguments. | ||
|
||
.. testcode:: | ||
|
||
job = sampler.run(qc, shots=2048, seed=123) | ||
result = job.result() | ||
print(result) | ||
|
||
.. testoutput:: | ||
|
||
SamplerResult(quasi_dists=[{0: 0.5205078125, 3: 0.4794921875}], metadata=[{'shots': 2048}]) | ||
|
||
Modify :class:`~qiskit.primitives.Sampler` options | ||
--------------------------------------------------- | ||
|
||
If you want to keep some configuration values for several runs, it can be better to | ||
change the :class:`~qiskit.primitives.Sampler` options. That way you can use the same | ||
:class:`~qiskit.primitives.Sampler` object as many times as you wish without having to | ||
rewrite the configuration values every time you use :meth:`~qiskit.primitives.Sampler.run`. | ||
|
||
Modify existing :class:`~qiskit.primitives.Sampler` | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
If you prefer to change the options of an already-defined :class:`~qiskit.primitives.Sampler`, you can use | ||
:meth:`~qiskit.primitives.Sampler.set_options` and introduce the new options as keyword arguments. | ||
|
||
.. testcode:: | ||
|
||
sampler.set_options(shots=2048, seed=123) | ||
|
||
job = sampler.run(qc) | ||
result = job.result() | ||
print(result) | ||
|
||
.. testoutput:: | ||
|
||
SamplerResult(quasi_dists=[{0: 0.5205078125, 3: 0.4794921875}], metadata=[{'shots': 2048}]) | ||
|
||
Define a new :class:`~qiskit.primitives.Sampler` with the options | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
If you prefer to define a new :class:`~qiskit.primitives.Sampler` 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.Sampler` with the | ||
``options`` argument. | ||
|
||
.. testcode:: | ||
|
||
sampler = Sampler(options=options) | ||
|
||
job = sampler.run(qc) | ||
result = job.result() | ||
print(result) | ||
|
||
.. testoutput:: | ||
|
||
SamplerResult(quasi_dists=[{0: 0.5205078125, 3: 0.4794921875}], metadata=[{'shots': 2048}]) |
Oops, something went wrong.