# Advanced usage¶

## Options for M3Mitigation class¶

`iter_threshold`

¶

The main `mthree.M3Mitigation`

class accepts the iter_threshold keyword argument
that determines when the automated method selector pickes the iterative method
over direct LU factorization (selection also depends on free memory).

```
from qiskit.test.mock.backends import FakeCasablanca
import mthree
backend = FakeCasablanca()
mit = mthree.M3Mitigation(backend, iter_threshold=4321)
```

## Options for calibration¶

`shots`

¶

When calibrating the mitigator, it is possible to vary the number of shots per calibration circuit:

```
mit = mthree.M3Mitigation(backend)
mit.cals_from_system(range(5), shots=4321)
```

`method`

¶

There are three ways to do the calibration. The default `balanced`

method executes \(2N\) circuits
with varying bitstring patterns such that the \(|0\rangle\) and \(|1\rangle\) states are each
prepared \(N\) times and averaged over. For example, the balanced bit-strings over four qubits are

```
mthree.mitigation._balanced_cal_strings(4)
```

```
['0101', '1010', '0011', '1100', '0001', '1110', '0000', '1111']
```

The `independent`

method also sends \(2N\) circuits but measures only a single qubit at a time.
As such, this is a truely uncorrelated calibration process.

Finally, a `marginal`

calibration can also be done that sends only two circuits,
\(|0\rangle^{\otimes N}\) and \(|1\rangle^{\otimes N}\), and marginalizes over the
results to get the needed \(2N\) error rates. These two states are a sub-set 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

```
mit = mthree.M3Mitigation(backend)
mit.cals_from_system(range(5), method='independent')
```

`rep_delay`

¶

Caution

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
option.

```
mit = mthree.M3Mitigation(backend)
mit.cals_from_system(range(5), rep_delay=400e-6)
```

`initial_reset`

¶

Caution

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
calibration circuits. Ideally this helps to supress 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.

## Options when applying corrections¶

Here we first calibrate a mitigator and generate raw counts:

```
from qiskit import *
qc = QuantumCircuit(6)
qc.reset(range(6))
qc.h(3)
qc.cx(3,1)
qc.cx(3,5)
qc.cx(1,0)
qc.cx(5,4)
qc.cx(1,2)
qc.measure_all()
mit = mthree.M3Mitigation(backend)
mit.cals_from_system(range(6))
trans_qc = transpile(qc, backend)
raw_counts = backend.run(trans_qc, shots=8192).result().get_counts()
```

`method`

¶

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`

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
can simply set the option:

```
quasis = mit.apply_correction(raw_counts, range(6), method='iterative')
```

`distance`

¶

Optionally one may trucate the M3 assignment matrix to only those elements of the matrix that
are transistions 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.

```
quasis = mit.apply_correction(raw_counts, range(6), distance=3)
```

`details`

¶

Allows one to see additional information about the solution. This changes the return of the
:method:`mthree.M3Mitigation.apply_correction`

method to a tuple of two values:

```
quasis, details = mit.apply_correction(raw_counts, range(6), details=True)
print(details)
```

```
{'method': 'direct', 'time': 0.0003200990000209458, 'dimension': 49, 'col_norms': array([0.9998407 , 0.99188325, 0.99963648, 0.98618859, 0.99953992,
0.97286867, 0.99260666, 0.99881015, 0.9929688 , 0.97335932,
0.9924084 , 0.99889106, 0.97932129, 0.99920674, 0.97863749,
0.98599189, 0.9595409 , 0.98594814, 0.97988848, 0.99902757,
0.95809713, 0.97742433, 0.96191575, 0.91076145, 0.97797902,
0.99752584, 0.99280639, 0.96147706, 0.97294227, 0.92914108,
0.97344883, 0.93356755, 0.90693233, 0.94100664, 0.99624405,
0.9859301 , 0.90272346, 0.99844082, 0.9309082 , 0.9571516 ,
0.99590663, 0.97162568, 0.93448713, 0.96103888, 0.99638125,
0.9504996 , 0.99540398, 0.99754419, 0.99983079])}
```

`max_iter`

¶

Caution

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

Sets the maximum number of iterations performed by the iterative solver.

```
quasis = mit.apply_correction(raw_counts, range(6), method='iterative', max_iter=10)
```

`tol`

¶

Caution

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
is set too low.

```
quasis = mit.apply_correction(raw_counts, range(6), method='iterative', tol=1e-6)
```