Skip to content

Commit

Permalink
Documentation cleanup (unitaryfund#2008)
Browse files Browse the repository at this point in the history
* use note directive

* render URL as `a` tag

* use em-dash

* remove trailing whitespace

* use warning directive

* use em-dashes

* use note directive

* use em-dashes

* diplay URL as a tag

* use different line styles for plot

for readers who may not be able to distinguish between blue/orange

* wordsmithing

* simplify executor logic

* merge cells

* wordsmithing

* double backticks -> single

* convert `testcode` cells to `code-cell`

* remove `make doctest` target/documentation

* remove generated image from hamiltonians example

plot is now generated on the fly

* clean up plot

a11y and axis labeling

* use note directive

* use em-dashes

* clean up links

* use myst image directive

* `>` -> `\rangle`

* dispaly question more prominently

* remove unnecessary whitespace

* upgrade QAOA reference to citation

* remove `mitiq.about()` call

we don't have this in any of the other docs that are run as part of CI

* clean up maxcut references section

* fix citation in API-doc

* use equation formatting for math

* fix docstring formatting in API-doc

the extra whitespace was making the first line bold for some reason

* convert `spacing` description into example

* elevate note to warning

* ensure args are displayed correctly in API-doc

* clean up random shadow docstrings

* remove unused import

* add BQSKit reference

* upgrade arXiv link to reference
  • Loading branch information
natestemen committed Sep 26, 2023
1 parent f9cfae4 commit b6cb5c1
Show file tree
Hide file tree
Showing 20 changed files with 280 additions and 386 deletions.
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ jobs:
export BQSKIT_DOC_CHECK_OVERRIDE=1
export PYDEVD_DISABLE_FILE_VALIDATION=1
make docs
make doctest
make linkcheck
# This is to make sure Mitiq works without optional 3rd party packages like Qiskit, pyQuil, etc.
Expand Down
3 changes: 0 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,6 @@ docker run --rm -idt -p 5000:5000 rigetti/qvm -S
docker run --rm -idt -p 5555:5555 rigetti/quilc -R
```

If you've modified any docstrings/added new functions, run `make doctest` to ensure they are formatted correctly.
You may need to run `make docs` before you are able to run `make doctest`.

### Updating the documentation
Follow these [instructions for contributing to the documentation](https://mitiq.readthedocs.io/en/latest/contributing_docs.html) which include guidelines about updating the API-doc list of modules and writing examples in the users guide.

Expand Down
4 changes: 0 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ docs-clean:
make -C docs clean
make -C docs html

.PHONY: doctest
doctest:
make -C docs doctest

.PHONY: linkcheck
linkcheck:
make -C docs linkcheck
Expand Down
81 changes: 2 additions & 79 deletions docs/CONTRIBUTING_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ in the `conf.py` file.

To add specific feature to the documentation, Sphinx extensions can be added to the build.
As and example, to add classes and functions to the API doc, make sure that autodoc
extension is enabled in the `conf.py` file, and for tests the `doctest` one,
extension is enabled in the `conf.py` file.

```python
extensions = ['sphinx.ext.autodoc','sphinx.ext.doctest']
extensions = ['sphinx.ext.autodoc']
```

## Updating the Documentation
Expand Down Expand Up @@ -154,83 +154,6 @@ highlighting), use the `code-block` directive:
1+1 # simple example
```
````
### Run the code with doctest
In order to make sure that the block is parsed with `make doctest`, use the
`testcode` directive. This can be used in pair with `testoutput`, if something
is printed, and, eventually `testsetup`, to import modules or set up variables
in an invisible block. An example is:

````
```{testcode} python
1+1 # simple example
```
````
with no output and

````
```{testcode} python
print(1+1) # explicitly print
```
```{testoutput} python
2 # match the print message
```
````

If you have code blocks you want to run, but not be displayed, use the
`testsetup` directive:

````
```{testsetup} python
import numpy as np # this block is not rendered in the html
```
```{testcode} python
np.array(2)
```
```{testoutput} python
array(2)
```
````
### IPython code blocks
There is also the `doctest` directive, which allows you to include interactive
Python blocks. These need to be given this way:

````
```{doctest} python
>>> import numpy as np
>>> print(np.array(2))
array(2)
```
````

```{note}
Notice that no space is left between the last input and the output when writing code blocks with interactive inputs and outputs.
```

### Skipping or ignoring a test

In order to skip a test, if this is problematic, one can use the `SKIP` and
`IGNORE` keywords, adding them as comments next to the relevant line or block:

```
>>> something_that_raises() #: doctest: +IGNORE
```

### Running the tests

Mitiq uses the `doctest` [extension](https://www.sphinx-doc.org/en/master/usage/extensions/doctest.html) to run and test code in the docs, which is configured in the `conf.py` file. To execute the tests in bash, run:

```sh
make doctest
```
from the root directory.

This command tests the code examples in the documentation files, as well as testing the docstrings, since these are imported with the `autodoc` extension.

One can also use various `doctest` [features](https://doc.pytest.org/en/latest/how-to/doctest.html#using-doctest-options) by configuring them in the
`docs/pytest.ini` file.

## Additional information
[Here](https://github.com/nathanshammah/scikit-project/blob/master/5-docs.md)
Expand Down
5 changes: 0 additions & 5 deletions docs/pytest.ini

This file was deleted.

2 changes: 1 addition & 1 deletion docs/source/apidoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
:members:
```

See Ref. :cite:`Czarnik_2021_Quantum` for more details on these methods.
See Ref. {cite}`Czarnik_2021_Quantum` for more details on these methods.


## Mitiq - Braket
Expand Down
1 change: 0 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
"sphinx.ext.autosummary",
"sphinx_autodoc_typehints", # after napoleon and autodoc
"sphinx.ext.todo",
"sphinx.ext.doctest",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinx.ext.viewcode",
Expand Down
20 changes: 10 additions & 10 deletions docs/source/examples/bqskit.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ kernelspec:

# Improving the accuracy of BQSKit compiled circuits with error mitigation

In this tutorial we describe how to use error mitigation capabilities from [Mitiq](https://mitiq.readthedocs.io/en/stable/) together with the compilation capabilities of [BQSKit](https://bqskit.lbl.gov/), a compiler for quantum circuits. BQSKit stands for Berkeley Quantum Synthesis Toolkit and it allows one "to compile quantum programs to efficient physical circuits for any QPU".
In this tutorial we describe how to use error mitigation capabilities from [Mitiq](https://mitiq.readthedocs.io/en/stable/) together with the compilation capabilities of [BQSKit](https://bqskit.lbl.gov/) {cite}`Patel_2022_ACM`, a compiler for quantum circuits. BQSKit stands for Berkeley Quantum Synthesis Toolkit and it allows one "to compile quantum programs to efficient physical circuits for any QPU".

To get started, ensure you have the requisite python packages by running the following install commands.

Expand Down Expand Up @@ -87,10 +87,10 @@ Now we mitigate them!

## Error Mitigation

Using `mitiq`'s simplest, and easiest to use method of [Zero Noise Extrapolation](https://mitiq.readthedocs.io/en/stable/guide/zne-1-intro.html) (ZNE) we can obtain more accurate results than we would otherwise.
Using `mitiq`'s simplest, and easiest to use method of [](../guide/zne.md) (ZNE) we can obtain more accurate results than we would otherwise.

```{note}
There are multiple other techniques described in our [user guide](https://mitiq.readthedocs.io/en/stable/guide/guide.html) which could be used as well.
There are multiple other techniques described in our [](../guide/guide.md) which could be used as well.
```

In this tutorial we assume a simple error model of depolarizing noise on two-qubit gates.
Expand Down Expand Up @@ -193,23 +193,23 @@ Because compiling many large circuits is computationally expensive, we leave the

Once the errors are computed for each circuit we can collect the results in a histogram to get an idea of how compilation and mitigation affects accuracy more generally.

+++

<img src="../img/bqskit.png" alt="Histograms of circuit accuracy with and without compilation, and error mitigation." width="600"/>

+++
```{image} ../img/bqskit.png
:alt: Histograms of circuit accuracy with and without compilation, and error mitigation.
:width: 90%
:align: center
```

These results show that using error mitigation improves the accuracy of both uncompiled, and compiled circuits.
The [tutorial](https://github.com/unitaryfund/research/blob/main/ieee-quantum-week/compilation-with-error-mitigation-tutorial/bqskit.ipynb) in the research repository shows further that error mitigation both reduces the mean, and standard deviation of these distributions.

In this tutorial we've seen how one can use error mitigation in conjunction with circuit compilation.
For more information check out the [`bqskit`](https://bqskit.readthedocs.io/en/latest/) and [`mitiq`](https://mitiq.readthedocs.io/en/stable/) documentation.
For more information check out the [BQSKit](https://bqskit.readthedocs.io/en/latest/) and [Mitiq](../index.md) documentation.

+++

### References

- BQSKit documentation: <https://bqskit.readthedocs.io/>
- BQSKit whitepaper: https://doi.org/10.1145/3503222.3507739
- BQSKit whitepaper: <https://doi.org/10.1145/3503222.3507739> {cite}`Patel_2022_ACM`
- Mitiq documentation: <https://mitiq.readthedocs.io/>
- Mitiq whitepaper: <https://quantum-journal.org/papers/q-2022-08-11-774/>
77 changes: 50 additions & 27 deletions docs/source/examples/braket_mirror_circuit.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ kernelspec:

This notebook shows improved performance on a mirror circuit benchmark with zero-noise extrapolation on Rigetti Aspen-9 via Amazon Braket.

> Note: This notebook is intended to be run through the Amazon Web Services (AWS) console - that is, by uploading the `.ipynb` file to https://console.aws.amazon.com/braket/ and running from there. This requires an AWS account. **Without an AWS account, you can still run the notebook on a noisy simulator**.
```{note}
This notebook is intended to be run through the Amazon Web Services (AWS) console --- that is, by uploading the `.ipynb` file to <https://console.aws.amazon.com/braket/> and running from there.
This requires an AWS account.
**Without an AWS account, you can still run the notebook on a noisy simulator**.
```

## Setup

Expand Down Expand Up @@ -43,7 +47,9 @@ from mitiq import benchmarks, zne

We first choose a device to run on.

> Note: Verbatim compiling in Braket - a necessary feature to perform zero-noise extrapolation - is currently only available on Rigetti devices.
```{warning}
Verbatim compiling in Braket --- a necessary feature to perform zero-noise extrapolation --- is currently only available on Rigetti devices.
```

```{code-cell} ipython3
try:
Expand All @@ -59,9 +65,14 @@ on_aws = aws_device.name != "DensityMatrixSimulator"
(examples/braket_mirror_circuit/define-the-circuit)=
## Define the circuit

We use mirror circuits to benchmark the performance of the device. Mirror circuits, introduced in https://arxiv.org/abs/2008.11294, are designed such that only one bitstring should be sampled. When run on a device, any other measured bitstrings are due to noise. The frequency of the correct bitstring is our target metric.
We use mirror circuits to benchmark the performance of the device. Mirror circuits, introduced in {cite}`Proctor_2021_NatPhys`, are designed such that only one bitstring should be sampled. When run on a device, any other measured bitstrings are due to noise. The frequency of the correct bitstring is our target metric.

> Note: Mirror circuits build on Loschmidt echo circuits - i.e., circuits of the form $U U^\dagger$ for some unitary $U$. Loschmidt echo circuits are good benchmarks but have shortcomings - e.g., they are unable to detect coherent errors. Mirror circuits add new features to account for these shortcomings. For more background, see https://arxiv.org/abs/2008.11294.
```{note}
Mirror circuits build on Loschmidt echo circuits --- i.e., circuits of the form $U U^\dagger$ for some unitary $U$.
Loschmidt echo circuits are good benchmarks but have shortcomings --- e.g., they are unable to detect coherent errors.
Mirror circuits add new features to account for these shortcomings.
For more background, see <https://arxiv.org/abs/2008.11294>.
```

To define a mirror circuit, we need the device graph. We will use a subgraph of the device, and our first step is picking a subgraph with good qubits.

Expand All @@ -80,7 +91,7 @@ To pick good qubits, we pull the latest calibration report in the next two cells
```{code-cell} ipython3
if on_aws:
twoq_data = pd.DataFrame.from_dict(aws_device.properties.provider.specs["2Q"]).T
twoq_data.sort_values(by=["fCZ"], ascending=False).head() if on_aws else print()
```

Expand All @@ -89,7 +100,7 @@ And the next cell shows single-qubit calibration data sorted by best readout (RO
```{code-cell} ipython3
if on_aws:
oneq_data = pd.DataFrame.from_dict(aws_device.properties.provider.specs["1Q"]).T
oneq_data.sort_values(by=["fRO"], ascending=False).head() if on_aws else print()
```

Expand All @@ -106,7 +117,7 @@ Now that we have the device (sub)graph, we can generate a mirror circuit and the

```{code-cell} ipython3
circuit, correct_bitstring = benchmarks.generate_mirror_circuit(
nlayers=1,
nlayers=1,
two_qubit_gate_prob=1.0,
two_qubit_gate_name="CZ",
connectivity_graph=connectivity_graph,
Expand Down Expand Up @@ -148,30 +159,42 @@ def compile_to_rigetti_gateset(circuit: Circuit) -> Circuit:
compiled.add_instruction(gates.Instruction(gates.Rz(-np.pi / 2), instr.target))
else:
compiled.add_instruction(instr)
return compiled
```

## Define the executor

Now that we have a circuit, we define the `execute` function which inputs a circuit and returns an expectation value - here, the frequency of sampling the correct bitstring.
Now that we have a circuit, we define the `execute` function which inputs a circuit and returns an expectation value.
In this example we return the frequency of sampling the correct bitstring.

```{code-cell} ipython3
def execute(
circuit: Circuit,
shots: int = 1_000,
shots: int = 1_000,
s3_folder: Tuple[str, str] = ("bucket", "folder/"),
) -> float:
# Add verbatim compiling so that zero-noise extrapolation can be used.
if on_aws:
circuit = Circuit().add_verbatim_box(compile_to_rigetti_gateset(circuit))
# Run the circuit and return the frequency of sampling the correct bitstring.
if on_aws:
aws_task = aws_device.run(circuit, s3_folder, disable_qubit_rewiring=True, shots=shots)
# Add verbatim compiling so that ZNE can be used.
circuit = Circuit().add_verbatim_box(
compile_to_rigetti_gateset(circuit)
)
aws_task = aws_device.run(
circuit, s3_folder, disable_qubit_rewiring=True, shots=shots
)
else:
aws_task = aws_device.run(circuit.copy().apply_gate_noise(Noise.Depolarizing(probability=0.002)), shots=shots)
return aws_task.result().measurement_probabilities.get("".join(map(str, correct_bitstring)), 0.0)
aws_task = aws_device.run(
circuit.copy().apply_gate_noise(
Noise.Depolarizing(probability=0.002)
),
shots=shots,
)
return aws_task.result().measurement_probabilities.get(
"".join(map(str, correct_bitstring)), 0.0
)
```

## Noisy value
Expand All @@ -189,9 +212,9 @@ The result of running the example mirror circuit with zero-noise extrapolation i

```{code-cell} ipython3
zne_value = zne.execute_with_zne(
circuit,
execute,
scale_noise=zne.scaling.fold_global,
circuit,
execute,
scale_noise=zne.scaling.fold_global,
factory=zne.inference.PolyFactory(scale_factors=[1, 3, 5], order=2)
)
print("ZNE value:", zne_value)
Expand All @@ -216,20 +239,20 @@ zne_values = []
for nlayers in nlayers_values:
for i in range(ntrials):
circuit, correct_bitstring = benchmarks.generate_mirror_circuit(
nlayers=nlayers,
nlayers=nlayers,
two_qubit_gate_prob=1.0,
two_qubit_gate_name="CZ",
connectivity_graph=connectivity_graph,
seed=i,
return_type="braket",
)
noisy_values.append(execute(circuit))
zne_values.append(
zne.execute_with_zne(
circuit,
execute,
scale_noise=zne.scaling.fold_global,
circuit,
execute,
scale_noise=zne.scaling.fold_global,
factory=zne.inference.PolyFactory(scale_factors=[1, 3, 5], order=2)),
)
```
Expand All @@ -244,7 +267,7 @@ plt.rcParams.update({"font.family": "serif", "font.size": 16})
plt.figure(figsize=(9, 5))
plt.plot(nlayers_values, average_zne_values, "--o", label="ZNE")
plt.plot(nlayers_values, average_noisy_values, "--o", label="Raw")
plt.plot(nlayers_values, average_noisy_values, "-.o", label="Raw")
plt.xlabel("Circuit depth")
plt.ylabel("Survival probability")
Expand Down
Loading

0 comments on commit b6cb5c1

Please sign in to comment.