Skip to content
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
40 changes: 20 additions & 20 deletions docs/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
Advanced usage
##############

Options for M3Mitigation class
------------------------------
Options for `M3Mitigation` class
--------------------------------

``iter_threshold``
~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -41,10 +41,10 @@ When calibrating the mitigator, it is possible to vary the number of shots per c
``method``
~~~~~~~~~~

There are three ways to do the calibration. The default ``balanced`` method a set of circuits
There are three ways to do the calibration. The default ``balanced`` method sends a set of circuits
with varying bitstring patterns such that the :math:`|0\rangle` and :math:`|1\rangle` states are each
prepared an even number of times, as is their pair-wise correlations. For example, the
balanced bit-strings over four qubits are:
balanced bitstrings over four qubits are:

.. jupyter-execute::

Expand All @@ -56,11 +56,11 @@ As such, this is a truly uncorrelated calibration process.

Finally, a ``marginal`` calibration can also be done that sends only two circuits,
:math:`|0\rangle^{\otimes N}` and :math:`|1\rangle^{\otimes N}`, and marginalizes over the
results to get the needed :math:`2N` error rates. These two states are a sub-set of the ``balanced``
results to get the needed :math:`2N` error rates. These two states are a subset of the ``balanced``
calibrations, and are what Qiskit uses in its readout mitigation. This method is very sensitive to
state preparation errors, and should not be used in practice.

An example setting the method is
An example setting the method is as follows:

.. jupyter-execute::

Expand All @@ -75,9 +75,9 @@ An example setting the method is

Do not set this unless you know what you are doing.

The ``rep_delay`` keyword argument sets the time between calibration circuits on IBM Quantum systems.
This option exists to test and reduce the presence of state prep errors. The calibration circuits
in M3 all contain conditional resets at the beginning so as to minimize the need for setting this
The ``rep_delay`` keyword argument sets the time between calibration circuits on IBM Quantum® backends.
This option exists to test and reduce the presence of state prep errors. All the calibration circuits
in M3 contain conditional resets at the beginning so as to minimize the need for setting this
option.

.. jupyter-execute::
Expand All @@ -93,12 +93,12 @@ option.

Do not set this unless you know what you are doing.

A boolean value that specifies whether reset instructions should be used at the beginning of the
`initial_reset` is a boolean value that specifies whether reset instructions should be used at the beginning of the
calibration circuits. Ideally this helps to suppress any residual state prep errors that occur from
imperfect reset of the qubits. Can be used in concert with, or as an alternative to ``rep_delay``.
Note that, in order for this to work, the circuits that need to be mitigated must also have reset
instructions at the beginning. Otherwise you are calibrating for no state-prep errors, but the
actual circuits may still suffer from these errors.
instructions at the beginning; otherwise, you are calibrating for no state-prep errors, but the
actual circuits might still suffer from these errors.


Options when applying corrections
Expand Down Expand Up @@ -132,9 +132,9 @@ Here we first calibrate a mitigator and generate raw counts:
There are two ways to solve the linear system of equations generated by M3. First, the
``direct`` method uses LU-factorization by constructing the reduced assignment matrix.
Second the ``iterative`` method uses preconditioned iterative solvers to find the
solution vector without explicit matrix construction. By default M3 uses an ``auto``
solution vector without explicit matrix construction. By default, M3 uses an ``auto``
method that selects the appropriate solution method based on the number of unique
bit-strings and the available free memory on the computer. To override this, one
bitstrings and the available free memory on the computer. To override this, you
can simply set the option:


Expand All @@ -145,12 +145,12 @@ can simply set the option:

``distance``
~~~~~~~~~~~~
Optionally one may truncate the M3 assignment matrix to only those elements of the matrix that
Optionally you can truncate the M3 assignment matrix to only those elements of the matrix that
are transitions between elements less than or equal to a given Hamming distance away from
each other. This does not change the dimensionality of the underlying matrix, but rather
changes the sparsity pattern of the elements. This is done using the ``distance`` keyword argument.
By default, M3 computes the corrections out to the full distance. In practice, including only
up to ``distance=3`` elements yields accurate answers in most cases.
By default, M3 computes the corrections out to the full distance. In practice, if you include only
up to ``distance=3`` elements, the result will be accurate answers in most cases.

.. jupyter-execute::

Expand All @@ -160,7 +160,7 @@ up to ``distance=3`` elements yields accurate answers in most cases.
``details``
~~~~~~~~~~~

Allows one to see additional information about the solution. This changes the return of the
With `details`, you can see additional information about the solution. This changes the return of the
:method:``mthree.M3Mitigation.apply_correction`` method to a tuple of two values:

.. jupyter-execute::
Expand All @@ -176,7 +176,7 @@ Allows one to see additional information about the solution. This changes the r

Do not set this unless you know what you are doing.

Sets the maximum number of iterations performed by the iterative solver.
`max_iter` sets the maximum number of iterations performed by the iterative solver.

.. jupyter-execute::

Expand All @@ -190,7 +190,7 @@ Sets the maximum number of iterations performed by the iterative solver.

Do not set this unless you know what you are doing.

Sets the tolerance of the iterative solver. Might need adjustments to ``max_iter`` if value
`tol` sets the tolerance of the iterative solver. You might need adjustments to ``max_iter`` if the value
is set too low.

.. jupyter-execute::
Expand Down
24 changes: 12 additions & 12 deletions docs/balanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ Balanced calibrations
#####################

The default calibration method for M3 is what is called "balanced" calibration. Balanced calibrations
sample all independent and pair-wise readout error rates evenly; hence the name "balanced". In M3 v3
sample all independent and pair-wise readout error rates evenly, hence the name "balanced". In M3 v3
and higher, this routine has been updated to use a method from Bravyi et al, Phys. Rev. A 103, 042605 (2021).

To see the bit-patterns used to generate the calibration circuits one can call the generator explicitly. E.g. to
see the strings for 5-qubits one would do
To see the bit-patterns used to generate the calibration circuits, we can call the generator explicitly. For example, to
see the strings for five qubits:

.. jupyter-execute::

Expand All @@ -19,14 +19,14 @@ see the strings for 5-qubits one would do
list(gen)


For every position in the bit-string you will see that `0` or `1` appear an equal number of times,
For every position in the bitstring you will see that `0` or `1` appear an equal number of times,
and the same is true for all pair-wise combinations of `0` and `1`.
If there is a `0`, then that circuit samples the :math:`|0\rangle` state for that qubit,
similarly for the `1` element. So when we execute the balanced calibration circuits
similarly for the `1` element. Therefore, when we execute the balanced calibration circuits
using `shots` number of samples, each error rate in the calibration data is actually
being sampled more times than requested. Thus, when you pass the `shots` value to M3, in the balanced
calibration mode internally it divides by the number of measured qubits so that the precision of each
error rate matches the precision of the other methods. That is to say that the following:
being sampled more times than requested. Thus, when you pass the `shots` value to M3, the balanced
calibration mode internally divides by the number of measured qubits so that the precision of each
error rate matches the precision of the other methods. Consider the following:

.. jupyter-execute::

Expand All @@ -36,9 +36,9 @@ error rate matches the precision of the other methods. That is to say that the
mit = mthree.M3Mitigation(backend)
mit.cals_from_system(method='balanced')

Will sample each independent qubit error rate `10000` times (or the max allowed by the target system if less)
regardless of which method is used. All pair-wise correlations are measured half this number of times. This
yields a calibration process whose overhead is independent of the number of qubits used; there is no additional
This example samples each independent qubit error rate `10000` times (or the max allowed by the target backend if less)
regardless of which method is used. All pair-wise correlations are measured half this number of times. The result is
a calibration process with an overhead that is independent of the number of qubits used; there is no additional
cost to compute the calibration over a full device. Note that, when using a simulator or "fake" device,
M3 defaults to `independent` calibration mode for efficiency. As such, to enable `balanced` calibration on a
simulator one must explicitly set the `method`` as done above.
simulator, you must explicitly set the `method`` as seen in the example above.
19 changes: 10 additions & 9 deletions docs/basic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ Basic usage

Using M3 involves three steps (steps one and two can usually be done in reverse order if desired).

1) Select a system and calibrate over the desired set of qubits.
1. Select a backend and calibrate over the desired set of qubits.

2) Run the circuit(s) of interest on the system.
2. Run the circuit(s) of interest on the backend.

3) Apply the readout correction and post-process.
3. Apply the readout correction and post-process.


Simple example
--------------
Here we use a noisy simulator to perform the three steps above. First we import the
needed modules, and construct a circuit of interest.
needed modules and construct a circuit of interest.

.. jupyter-execute::

Expand All @@ -36,7 +36,7 @@ needed modules, and construct a circuit of interest.
qc.measure_all()
qc.draw('mpl')

Next we calibrate an M3 mitigator instance over qubits 0 -> 6 (Step #1):
Next we calibrate an M3 mitigator instance over qubits 0 through 6 (Step #1):

.. jupyter-execute::

Expand All @@ -60,9 +60,10 @@ simply computing the expectation value from the returned quasi-probabilities:
print('Expectation value:',quasis.expval())


Specifying qubits to mitigate over
----------------------------------
The circuit above also fits on other systems without SWAP mapping
Specify qubits to mitigate over
-------------------------------

The circuit above also fits on other backends without SWAP mapping,
provided that we select the correct layout.

.. jupyter-execute::
Expand All @@ -74,7 +75,7 @@ provided that we select the correct layout.

In our case, ``qubits = [10, 12, 15, 13, 11, 14]`` is an appropriate layout. Importantly, the
zeroth entry of the list tells us what physical qubit is readout to generate bit 0 in the output
bit-strings. We must pass this list to both the calibration and correction steps of M3.
bitstrings. We must pass this list to both the calibration and correction steps of M3.

.. jupyter-execute::

Expand Down
8 changes: 4 additions & 4 deletions docs/cal_io.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
.. _calio:

###################################
Saving and loading calibration data
###################################
##############################
Save and load calibration data
##############################

It is possible to save calibration data and, optionally, re-load it at a later time.
Let us generate some calibration data and save it.
Here we generate some calibration data and save it.

.. jupyter-execute::

Expand Down
12 changes: 6 additions & 6 deletions docs/collections.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
.. _collections:

##############################
Using distribution collections
##############################
############################
Use distribution collections
############################

When you mitigate over multiple circuits the return object is a :class:`mthree.classes.QuasiCollection`
When you mitigate over multiple circuits, the return object is a :class:`mthree.classes.QuasiCollection`:

.. jupyter-execute::

Expand Down Expand Up @@ -32,8 +32,8 @@ When you mitigate over multiple circuits the return object is a :class:`mthree.c
quasis = mit.apply_correction(raw_counts, range(6), return_mitigation_overhead=True)
type(quasis)

``QuasiCollection`` objects allow one to work with multiple distributions in the same manner as
a single one. E.g. we can get the mitigation overhead of the whole collection
With ``QuasiCollection`` objects, you can work with multiple distributions in the same manner as
a single one. For example, we can get the mitigation overhead of the whole collection:

.. jupyter-execute::

Expand Down
12 changes: 6 additions & 6 deletions docs/error.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ results in increased uncertainty in the computed results. M3 will optionally co
overhead and return an upper-bound on the expected standard deviation (variance) of the
computed expectation values.

Let us first calibrate the mitigator and get raw results:
First we calibrate the mitigator and get raw results:

.. jupyter-execute::

Expand Down Expand Up @@ -42,20 +42,20 @@ Let us first calibrate the mitigator and get raw results:
raw_counts = backend.run(trans_qc, shots=8192).result().get_counts()


In order to compute the standard deviation of our mitigated expectation values
In order to compute the standard deviation of our mitigated expectation values,
we need to request the information be computed:

.. jupyter-execute::

quasis = mit.apply_correction(raw_counts, range(6), return_mitigation_overhead=True)

The mitigation overhead is returned as an attribute of the returned quasi-probabilities
The mitigation overhead is returned as an attribute of the returned quasi-probabilities:

.. jupyter-execute::

quasis.mitigation_overhead

that, together with the number of shots taken, determines the upper-bound on the standard
That, together with the number of shots taken, determines the upper bound on the standard
deviation:

.. jupyter-execute::
Expand All @@ -68,5 +68,5 @@ It is also possible to return both the expectation value and standard deviation

quasis.expval_and_stddev()

Although this standard deviation is an upper-bound, it is usually a tight upper-bound that can be
faithfully used further analysis.
Although this standard deviation is an upper bound, it is usually a tight upper bound that can be
faithfully used for further analysis.
18 changes: 9 additions & 9 deletions docs/expvals.rst
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
.. _expvals:

############################
Obtaining expectation values
############################
#########################
Obtain expectation values
#########################

Given a quasi- or standard probability distribution, it is possible to compute the
expectation value of diagonal operators directly from the distributions (or collections)
of distributions. This can be done using string representation for standard diagonal
operators such as ``I``, ``Z``, ``0`` or ``1``, or via dictionaries for custom operators.
operators such as ``I``, ``Z``, ``0``, or ``1``, or via dictionaries for custom operators.


Let us first generate some quasi-distributions by mitigating 2- and 3-qubit GHZ circuits on
a noisy-simulator.
Here we first generate some quasi-distributions by mitigating two- and three-qubit GHZ circuits on
a noisy simulator.

.. jupyter-execute::

Expand Down Expand Up @@ -47,7 +47,7 @@ a noisy-simulator.
quasi3 = mit.apply_correction(raw3, [0,1,2], return_mitigation_overhead=True)


Now let us compute the expectation values of these distributions for the default
Now we compute the expectation values of these distributions for the default
case of ``Z`` operators on each qubit:

.. jupyter-execute::
Expand Down Expand Up @@ -80,15 +80,15 @@ We can also pass lists of strings:
quasi3.expval_and_stddev(['ZZZ','ZIZ'])

Alternatively, users can specify their own custom diagonal operators using dictionaries. Here
we form the projectors on the all ones and zeros states:
we form the projectors on the all-ones and all-zeros states:

.. jupyter-execute::

all_zeros_proj = {'000': 1}
all_ones_proj = {'111': 1}
quasi3.expval(all_zeros_proj)

Like strings, one can pass an array of dicts:
Like strings, we can pass an array of dicts:

.. jupyter-execute::

Expand Down
10 changes: 5 additions & 5 deletions docs/grouped.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
Grouped operators
#################

Often times when evaluating expectation values it is possible to group operators
together if the Pauli operators from which they are comprised commute with each other. when
It is often possible when evaluating expectation values to group operators
together, if the Pauli operators from which they are comprised commute with each other. When
possible, this batching can greatly reduce the number of executions needed. To see how to do
this consider the following simple example:

Expand Down Expand Up @@ -45,7 +45,7 @@ We can now mitigate as usual:
mit.cals_from_system(mappings, shots=10000)
quasis = mit.apply_correction(counts, mappings, return_mitigation_overhead=True)

Now that we have the final mitigated quasi-distributions we can compute expectation values.
Now that we have the final mitigated quasi-distributions, we can compute expectation values.
For batched operators, the expectation values are grouped together based on which quasi-distribution
you want to evaluate them with:

Expand All @@ -60,13 +60,13 @@ for expectation values and standard deviations:

quasis.expval_and_stddev([['IIII', 'ZZZZ', '0000', '1111'], ['IIII']])

If you have a single expectation value string then you do not need to wrap it in a list:
If you have a single expectation value string, you do not need to wrap it in a list:

.. jupyter-execute::

quasis.expval([['IIII', 'ZZZZ', '0000', '1111'], 'IIII'])

Of course probability-distributions work the same way as quasi-distributions:
Of course, probability distributions work the same way as quasi-distributions:

.. jupyter-execute::

Expand Down
Loading
Loading