Skip to content
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

CDR Tutorial with Qrack #2451

Merged
merged 26 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b306809
New example md file from ipynb
bdg221 Jul 25, 2024
2f787b9
New thumbnail for tutorial
bdg221 Jul 25, 2024
f69908d
Add CDR with Qrack to Examples TOC
bdg221 Jul 25, 2024
541963d
Match thumbnail to tutorial
bdg221 Jul 25, 2024
badf257
Update md file to install Qrack
bdg221 Jul 25, 2024
b758d1a
Restart kernel if qrack needs to be install
bdg221 Jul 25, 2024
57c05d9
Add pyqrack to for building docs
bdg221 Jul 26, 2024
c34ccd4
Removed pip install but added information in markdown
bdg221 Jul 26, 2024
5b25dd4
Set the latest pyqrack
bdg221 Jul 26, 2024
a3e5d7d
Merge branch 'unitaryfund:main' into 2368-CDR-tutorial-with-Qrack
bdg221 Jul 30, 2024
b4c800f
Update with PYQRACK_SHARED_LIB_PATH
bdg221 Jul 30, 2024
4483a8c
Build Qrack for docs build remove PYQRACK_SHARED_LIB_PATH
bdg221 Jul 30, 2024
4145940
Installing openCL per suggestion
bdg221 Jul 31, 2024
761de12
Adding sudo to apt calls
bdg221 Jul 31, 2024
97f4b4b
Move apt call out of requirements
bdg221 Jul 31, 2024
e1004fa
Update apt format
bdg221 Jul 31, 2024
6e65827
Put apt info back into docs build
bdg221 Jul 31, 2024
3372d92
Cleaned up links to be relative and removed unnecessary line
bdg221 Jul 31, 2024
d38c337
Remove unnecessary sentence about density matrices
bdg221 Jul 31, 2024
5043871
Update execute_with_cdr to full function call
bdg221 Jul 31, 2024
762d432
Remove unnecessary code explanation
bdg221 Jul 31, 2024
8ac71ca
Remove observable=None from execute_with_cdr
bdg221 Jul 31, 2024
fa16a2a
Latest with many suggestions from Nate
bdg221 Jul 31, 2024
094bc35
Update random_state and conclusion
bdg221 Aug 1, 2024
3c54d58
Add section explaining executors
bdg221 Aug 2, 2024
3796a67
Added final sentences with other references and contact info
bdg221 Aug 2, 2024
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
2 changes: 2 additions & 0 deletions .github/workflows/docs-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:

- name: Build and test Sphinx docs
run: |
sudo apt update
sudo apt install ocl-icd-opencl-dev
export BQSKIT_DOC_CHECK_OVERRIDE=1
export PYDEVD_DISABLE_FILE_VALIDATION=1
make docs
Expand Down
2 changes: 2 additions & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ build:
os: ubuntu-22.04
tools:
python: "3.12"
apt_packages:
- ocl-icd-opencl-dev

# Build documentation in the docs/ directory with Sphinx
sphinx:
Expand Down
Binary file added docs/source/_thumbnails/cdr-qrack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ def get_incollection_template(self, e):
"examples/quantum_simulation_scars_ibmq": "_static/qmbs_ibmq.png",
"examples/zne_logical_rb_cirq_stim": "_static/mitiq_stim_logo.png",
"examples/quantum_simulation_1d_ising": "_static/quantum_simulation.png",
"examples/cdr_qrack": "_static/cdr-qrack.png",
# default images if no thumbnail is specified
"examples/*": "_static/mitiq-logo.png",
}
187 changes: 187 additions & 0 deletions docs/source/examples/cdr_qrack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
---
jupytext:
formats: ipynb,md:myst
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.16.3
kernelspec:
display_name: Python 3
language: python
name: python3
---

# CDR with Qrack as Near-Clifford Simulator

In this tutorial, [Clifford Data Regression](../guide/cdr.md) (CDR) is used with [Qrack](https://qrack.readthedocs.io/en/latest/) and a Qiskit fake backend.

+++

## Setup

To start, relevant modules and libraries are imported. Please ensure that the following Python modules are installed: `mitiq`, `numpy`, `pyqrack`, `cirq`, `qiskit`

+++

```{note}
In the code below the environmental variable, `QRACK_MAX_CPU_QB`, is set to `-1`. This enviroment variable sets the maximum on how many qubits can be allocated on a single QEngineCPU instance. More information can be found on the [Qrack README page](https://github.com/unitaryfund/qrack?tab=readme-ov-file#maximum-allocation-guard).
```

```{code-cell}
import numpy as np
import collections

import os
import warnings
warnings.simplefilter("ignore", np.ComplexWarning)

from pyqrack import QrackSimulator, QrackCircuit
os.environ["QRACK_MAX_CPU_QB"]="-1"

import mitiq.interface.mitiq_qiskit
from mitiq.interface.mitiq_cirq import compute_density_matrix
from mitiq import cdr, Observable, PauliString

import cirq

from qiskit.providers.fake_provider import Fake5QV1
```

## Sample Circuit

This sample circuit includes Clifford gates (`H`, `CNOT`, `RX`) and non-Clifford gates (`RZ`).

```{code-cell}
a, b = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
cirq.H.on(a), # Clifford
cirq.H.on(b), # Clifford
cirq.rz(1.75).on(a),
cirq.rz(2.31).on(b),
cirq.CNOT.on(a, b), # Clifford
cirq.rz(-1.17).on(b),
cirq.rz(3.23).on(a),
cirq.rx(np.pi / 2).on(a), # Clifford
cirq.rx(np.pi / 2).on(b), # Clifford
)

# CDR works better if the circuit is not too short. So we increase its depth.
circuit = 5 * circuit
print(circuit)
```

## Devices and Near-Clifford Simulator

During CDR, near-Clifford representations of the original circuit are generated. Those near-Clifford representations are run with a near-Clifford simulator (Qrack Near-Clifford Simulator) and also on the quantum device (or noisy simulator, like Qiskit Fake Backend.) In this example, we also want to show how the unmitigated and mitigated results compare to the exact results, so we will use another simulator (Cirq Simulator) to generate the ideal results.

+++

### Qrack Near-Clifford Simulator

Especially when using CDR at scale, it is important to use an efficient Near-Clifford circuit simulator. In this example, Qrack will be configured and used as the Near-Clifford Simulator. The `qrack_simulate` method accepts a Cirq circuit and the number of shots as parameters. The Qrack simulator is then called and the expectation value for `00` is returned.

Since CDR includes the generation of near-Clifford circuits representing the original circuit, a near-Clifford simulator is ideal for efficiently simulating the circuit. Again, this is particularly important when using CDR at scale.

```{code-cell}
def qrack_simulate(circuit: cirq.Circuit, shots=1000) -> float:
"""Returns the expectation value of 00 from the state prepared by the circuit
executed without noise by Qrack configured as a near-Clifford simulator.
"""

# Cirq -> Qiskit circuit
qiskit_circ = mitiq.interface.mitiq_qiskit.to_qiskit(circuit)

# Qiskit -> Qrack circuit
qcircuit = QrackCircuit.in_from_qiskit_circuit(qiskit_circ)

# Setup the Qrack simulator and run it
qsim = QrackSimulator(qiskit_circ.width(), isStabilizerHybrid=True, isTensorNetwork=False, isSchmidtDecomposeMulti=False, isSchmidtDecompose=False, isOpenCL=False)
qcircuit.run(qsim)

# Use shot measurements to return the expectation value of 00
results = qsim.measure_shots(q=list(range(qiskit_circ.width())), s=shots)
results = dict(collections.Counter(results))
for key, value in results.items():
results[key] = value / shots
return results[0]
```

### Qiskit Fake Backend

CDR requires the use of a quantum device or a noisy simulator. The near-Clifford circuits that are generated from the original circuit are executed on the quantum device or noisy simulator in order to compare against the simulated results.

In this example, a Qiskit 5 Qubit Fake Backend is used. The [Fake5QV1](https://docs.quantum.ibm.com/api/qiskit/qiskit.providers.fake_provider.Fake5QV1) uses configurations and noise settings taken previously from the 5 qubit IBM Quantum Yorktown device. The `qiskit_noisy` function takes the Cirq circuit and uses Mitiq to change it into a Qiskit circuit. After adding measurements, the circuit is run on the fake backend. The expectation value for `00` is then returned.

```{code-cell}
# Use Qiskit's Fave5QV1 as a noisy simulator
def qiskit_noisy(circuit: cirq.Circuit, shots=1000):
"""Execute the input circuit and return the expectation value of |00..0><00..0|"""

# Cirq -> Qiskit circuit
qiskit_circ = mitiq.interface.mitiq_qiskit.to_qiskit(circuit)

# Add measurement gates to the circuit
qiskit_circ.measure_all()

# Setup the fake backend and run the circuit
noisy_backend = Fake5QV1()
job = noisy_backend.run(qiskit_circ, shots=shots)

# Use the resulting counts to return the expectation value of 00
counts = job.result().get_counts()
ret_val = counts[qiskit_circ.num_qubits * "0"] / shots
return ret_val
```

### Cirq Simulator for exact result

The `compute_density_matrix` is the Cirq density matrix simulator with a Mitiq wrapper. It is used to obtain the exact `00` expectation value. This is then used to determine the accuracy of the mitigated and unmitigated reuslts.

```{code-cell}
def cirq_simulate(circuit: cirq.Circuit) -> np.ndarray:
"""Returns Tr[ρ |0⟩⟨0|] where ρ is the state prepared by the circuit
executed without depolarizing noise.
"""
res = compute_density_matrix(circuit, noise_level=(0.0,))
return res[0, 0].real
```

## Executing CDR

With the different executor functions defined for running the Qrack, Qiskit, and Cirq simulators, the `mitiq.cdr.execute_with_cdr` function can now be called.

```{code-cell}
ideal_expval = cirq_simulate(circuit).round(5)
print(f"Ideal expectation value from Cirq Simulator: {ideal_expval:.3f}")

unmitigated_expval = qiskit_noisy(circuit)
print(f"Unmitigated expectation value from Qiskit Fake backend: {unmitigated_expval:.3f}")

mitigated_expval = cdr.execute_with_cdr(
circuit,
qiskit_noisy,
simulator=qrack_simulate,
random_state=0,
)
print(f"Mitigated expectation value with Mitiq CDR: {mitigated_expval:.3f}\n")

```

## Conclusion
By learning from the near-Clifford circuits that resemble the original circuit, CDR is able to apply the noise information learned to the original circuit. From the example, you can see that the mitigated expectation value is closer to the ideal value.

The improvement factor with CDR can be seen below to highlight the mitigated results that can be provided with this technique.

```{code-cell}
unmitigated_error = abs(unmitigated_expval - ideal_expval)
mitigated_error = abs(mitigated_expval - ideal_expval)

print(f"Unmitigated Error: {unmitigated_error:.3f}")
print(f"Mitigated Error: {mitigated_error:.3f}")

improvement_factor = unmitigated_error / mitigated_error
print(f"Improvement factor with CDR: {improvement_factor:.2f}")
```
bdg221 marked this conversation as resolved.
Show resolved Hide resolved
bdg221 marked this conversation as resolved.
Show resolved Hide resolved

To learn more about CDR, please check the [User Guide](../guide/cdr.md) or the [ZNE and CDR with Cirq: 1D Ising Simulation](./quantum_simulation_1d_ising.md) example. If you have any questions, please do not hesitate to open a [Github discussion](https://github.com/unitaryfund/mitiq/discussions) or reach out to the Mitiq team on [Discord](http://discord.unitary.fund).
3 changes: 2 additions & 1 deletion docs/source/examples/examples.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Examples

Below you can find a gallery of tutorials applying Zero Noise Extrapolation (ZNE), Probabilistic Error Cancellation (PEC), and Digital Dynamical Decoupling (DDD) with Mitiq:
Below you can find a gallery of tutorials applying Zero Noise Extrapolation (ZNE), Probabilistic Error Cancellation (PEC), Clifford Data Regression (CDR), and Digital Dynamical Decoupling (DDD) with Mitiq:

```{nbgallery}
ZNE Calibration with Qiskit <calibration-tutorial.md>
Expand Down Expand Up @@ -32,6 +32,7 @@ Classical Shadows with Cirq: State Reconstruction and Observable Estimation <sha
Robust Shadow Estimation with Cirq: Pauli Twirling Calibration of Classical Shadows <rshadows_tutorial.md>
DDD with Cirq: Mirror circuits <ddd_tutorial.md>
DDD with Qiskit: GHZ circuits <ddd_on_ibmq_ghz.md>
CDR with Qrack as Near-Clifford Simulator <cdr_qrack.md>
GGI Summer School ZNE Hands-On Tutorial <ggi_summer_school_unsolved.md>
Composing techniques: REM + ZNE <combine_rem_zne.md>
Composing techniques: DDD + ZNE <combine_ddd_zne.md>
Expand Down
1 change: 1 addition & 0 deletions requirements/requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ bqskit==1.1.1
seaborn==0.13.0
stim==1.13.0
stimcirq==1.13.0
pyqrack==1.30.0
Loading