Skip to content

Commit

Permalink
Merge branch 'main' into encoding-circuits
Browse files Browse the repository at this point in the history
  • Loading branch information
pehamTom committed Nov 20, 2024
2 parents dc782c6 + b53722d commit f63bba1
Show file tree
Hide file tree
Showing 157 changed files with 6,282 additions and 486 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
path: dist
merge-multiple: true
- name: Generate artifact attestation for sdist and wheel(s)
uses: actions/[email protected].3
uses: actions/[email protected].4
with:
subject-path: "dist/*"
- uses: pypa/gh-action-pypi-publish@release/v1
Expand Down
15 changes: 8 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
ci:
autoupdate_commit_msg: "⬆️🪝 update pre-commit hooks"
autofix_commit_msg: "🎨 pre-commit fixes"
autoupdate_schedule: quarterly
skip: [mypy]

repos:
Expand All @@ -32,7 +33,7 @@ repos:

# Clean jupyter notebooks
- repo: https://github.com/srstevenson/nb-clean
rev: 3.3.0
rev: 4.0.1
hooks:
- id: nb-clean
args:
Expand All @@ -58,22 +59,22 @@ repos:

# Python linting and formatting using ruff
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9
rev: v0.7.3
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
- id: ruff-format

# Also run Black on examples in the documentation
- repo: https://github.com/adamchainz/blacken-docs
rev: 1.19.0
rev: 1.19.1
hooks:
- id: blacken-docs
additional_dependencies: [black==24.*]

# Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.2
rev: v1.13.0
hooks:
- id: mypy
files: ^(src/mqt|test/python|noxfile.py)
Expand All @@ -86,13 +87,13 @@ repos:

# Check for spelling
- repo: https://github.com/crate-ci/typos
rev: v1.26.0
rev: v1.27.3
hooks:
- id: typos

# Clang-format the C++ part of the code base automatically
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.1
rev: v19.1.3
hooks:
- id: clang-format
types_or: [c++, c, cuda]
Expand Down Expand Up @@ -139,6 +140,6 @@ repos:

# Check the pyproject.toml file
- repo: https://github.com/henryiii/validate-pyproject-schema-store
rev: 2024.10.14
rev: 2024.11.11
hooks:
- id: validate-pyproject
156 changes: 154 additions & 2 deletions docs/StatePrep.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -253,20 +253,172 @@
"cc_simulator.plot_state_prep(ps, min_errors=50, name=\"Distance 5\")"
]
},
{
"cell_type": "markdown",
"id": "81eec694ef6af97a",
"metadata": {},
"source": [
"## Deterministic state preparation ($d < 5$)\n",
"A possible disadvantage of the above approach is that the verification circuits are non-deterministic. This means that we potentially have to run the circuit multiple times to successfully prepare the state. This can be circumvented by using the information gained from the verification measurements to possibly identify the dangerous error and correct it. If this this is done for every possible (single) error, we refer to the state preparation as deterministic [^1].\n",
"\n",
"For small codes ($d < 5$ i.e. we need to consider only a single error) this problem is still tractable and can be solved in an optimal way using satisfiability solvers. QECC can automatically generate deterministic state preparation circuits for such codes.\n",
"\n",
"[^1]: https://arxiv.org/abs/2301.10017\n",
"\n",
"For this we come back to our $d=3$ Steane code. "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2373b4ee6cee29d",
"metadata": {},
"outputs": [],
"source": [
"non_ft_sp.circ.draw(output=\"mpl\", initial_state=True)"
]
},
{
"cell_type": "markdown",
"id": "6c8eecaac4df6b88",
"metadata": {},
"source": [
"And initialize an instance of the deterministic verification helper class to facilitate the generation of the deterministic FT state preparation circuit."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1877841300be6d01",
"metadata": {},
"outputs": [],
"source": [
"from mqt.qecc.ft_stateprep import DeterministicVerificationHelper\n",
"\n",
"det_helper = DeterministicVerificationHelper(non_ft_sp)"
]
},
{
"cell_type": "markdown",
"id": "40c9070837bcd21",
"metadata": {},
"source": [
"Calling the `get_solution` method will generate the non-deterministic verification circuit using either the optimal or the heuristic method discussed above. The deterministic verification circuit, separated into X and Z correction layers) is then generated using the satisfiability solver."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3c83621b4ca7a1a1",
"metadata": {},
"outputs": [],
"source": [
"det_verify = det_helper.get_solution(use_optimal_verification=True)\n",
"det_verify_x, det_verify_z = det_verify"
]
},
{
"cell_type": "markdown",
"id": "15b8f7d65e69be64",
"metadata": {},
"source": [
"Such a `DeterministicVerification` object contains the stabilizer measurements for the non-deterministic verification circuit, the stabilizer measurements for the different deterministic verification circuits, depending on the non-deterministic measurement outcomes, and the final correction Pauli operators that need to be applied to the data qubits.\n",
"\n",
"The non-deterministic verification measurements are stored in the `stabs` attribute as a list of numpy arrays where each array represents a stabilizer measurement.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "75ac41577e4c0296",
"metadata": {},
"outputs": [],
"source": [
"det_verify_x.stabs"
]
},
{
"cell_type": "markdown",
"id": "ddecefba679c91c1",
"metadata": {},
"source": [
"The deterministic verification measurements are stored in the `det_stabs` attribute as a dictionary where the keys are the non-deterministic measurement outcomes (converted to int) and the values is a tuple with the first element being the deterministic stabilizer measurements and the second element being again a dictionary with the Pauli corrections for the deterministic measurement outcomes.\n",
"\n",
"For example for the Steane code whenever the non-deterministic verification triggers (1) the logical operator on qubits 2,3,6 hast to measured. If the outcome is 1, a Pauli correction on qubit 3 has to be applied, otherwise no correction is necessary."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "45c29390eb2eb0e4",
"metadata": {},
"outputs": [],
"source": [
"det_verify_x.det_correction"
]
},
{
"cell_type": "markdown",
"id": "42c85a709d72bf40",
"metadata": {},
"source": [
"For the case where the non-deterministic verification measurements need to be flagged (not the case for the Steane code), the `hook_corrections` attribute contains the additional stabilizer measurements and corrections in the same format as the `det_stabs` attribute."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ab975d4c4a1c11b7",
"metadata": {},
"outputs": [],
"source": [
"det_verify_x.hook_corrections"
]
},
{
"cell_type": "markdown",
"id": "d4527b797f83f919",
"metadata": {},
"source": [
"### Simulating deterministic state preparation circuits with Qsample\n",
"The resulting `DeterministicVerification` object can be used to directly simulate the deterministic state preparation circuit using the [Qsample](https://github.com/dpwinter/qsample) under the hood. The `NoisyDFTStatePrepSimulator` class automatically constructs a valid Qsample protocol containing the correct circuits and conditional paths to simulate the deterministic state preparation. The passed Error Model and simulation parameters are directly passed to Qsample and explained in the [Qsample documentation](https://dpwinter.github.io/qsample/). Similarly also the Qsample callbacks can be used to e.g. directly plot the logical error rates, showing the expected quadratic scaling."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "90f4d2760bc20453",
"metadata": {},
"outputs": [],
"source": [
"from qsample import callbacks, noise\n",
"\n",
"from mqt.qecc.ft_stateprep import NoisyDFTStatePrepSimulator\n",
"\n",
"error_model = noise.E1_1 # depolarizing error model\n",
"err_params = {\"q\": [1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1]}\n",
"shots_dss = 2000\n",
"p_max = {\"q\": 0.01}\n",
"L = 1\n",
"\n",
"qsample_sim = NoisyDFTStatePrepSimulator(non_ft_sp.circ, det_verify, steane_code, error_model)\n",
"sampling_stats = qsample_sim.dss_logical_error_rates(err_params, p_max, L, shots_dss, callbacks=[callbacks.PlotStats()])"
]
},
{
"cell_type": "markdown",
"id": "f9ad305e-929f-470f-86c5-e3e958750539",
"metadata": {},
"source": [
"# Circuits and Evaluations\n",
"\n",
"The circuits and benchmark scripts used for our work https://arxiv.org/abs/2408.11894, can be found [here](https://github.com/cda-tum/mqt-qecc/tree/main/src/mqt/qecc/ft_stateprep/eval)."
"The circuits and benchmark scripts used for our non-deterministic work https://arxiv.org/abs/2408.11894, can be found [here](https://github.com/cda-tum/mqt-qecc/tree/main/scripts/ft_stateprep/eval) and for the deterministic work [here](https://github.com/cda-tum/mqt-qecc/tree/main/scripts/ft_stateprep/eval_det)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "venv3_12",
"language": "python",
"name": "python3"
},
Expand Down
20 changes: 20 additions & 0 deletions docs/library/StatePrep.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,23 @@ State preparation circuits can be simulated using the :class:`NoisyNDFTStatePrep

.. autoclass:: NoisyNDFTStatePrepSimulator
:members:

:math:`d<5` codes
---------------------------------------------------------
For small distance codes QECC provides functionality to not only synthesize state preparation circuits based on post-selection but also preparation protocols that yield the logical Pauli state deterministically.
Such a deterministic protocol consists of three parts: (1) a (non-deterministic) verification, (2) a deterministic correction if one of the verification measurements yields a non-trivial result, and (3) a hook correction for the case that one of the verification measurement flags indicates a hook error.
To facilitate the handling (e.g. collecting statistics regarding ancilla and CNOT count) QECC provides the :class:`DeterministicVerification` class.

.. autoclass:: DeterministicVerification
:members:

The :class:`DeterministicVerification` for a certain :class:`StatePrepCircuit` can be obtained using the wrapper class :class:`DeterministicVerificationHelper` which provides the two functions :func:`get_solution` and :func:`get_global_solution` where the latter optimizes over all possible(*potentially exponentially many*) non-deterministic verifications to find the global optimum (recommended only for codes with small qubit number).
The two :class:`DeterministicVerification` objects returned correspond to the two layers of verification (X and Z errors).

.. autoclass:: DeterministicVerificationHelper
:members:
The resulting protocol consisting of the two-layered verification can be converted to a `Qsample <https://github.com/dpwinter/qsample>`_ protocol and simulated using Dynamic Subset Sampling :cite:labelpar:`heussenDynamicalSubsetSampling2024`.
The protocol construction and simulation is done automatically by the :class:`NoisyDFTStatePrepSimulator` class where the returned numbers correspond to the upper and lower bounds with corresponding errors as described at the `Qsample Documentation <https://dpwinter.github.io/qsample/>`_.

.. autoclass:: NoisyDFTStatePrepSimulator
:members:
13 changes: 13 additions & 0 deletions docs/refs.bib
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,16 @@ @article{pryadko2023qdistrnd
journal={arXiv preprint arXiv:2308.15140},
year={2023}
}

@article{heussenDynamicalSubsetSampling2024,
title = {Dynamical Subset Sampling of Quantum Error-Correcting Protocols},
author = {Heu{\ss}en, Sascha and Winter, Don and Rispler, Manuel and M{\"u}ller, Markus},
year = {2024},
month = feb,
journal = {Physical Review Research},
volume = {6},
number = {1},
pages = {013177},
publisher = {American Physical Society},
doi = {10.1103/PhysRevResearch.6.013177},
}
11 changes: 9 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ requires-python = ">=3.9"
dependencies = [
"z3-solver>=4.12",
"qecsim",
"ldpc>=0.1.53",
"ldpc>=0.1.53,<2", # temporary upper cap due to failures seen with ldpc v2
"numpy>=1.26; python_version > '3.11'",
"numpy>=1.24; python_version <= '3.11'",
"qiskit[qasm3-import]>=1.0.0",
Expand All @@ -56,6 +56,9 @@ dependencies = [
"numba>=0.59; python_version > '3.11'",
"numba>=0.57; python_version <= '3.11'",
"pymatching>=2.2.1",
"qsample>=0.0.2",
"urllib3>=1.26.20,<2.0", # Required by qsample
"fastcore>=1.7.10" # Required by qsample (to be removed)
]
dynamic = ["version"]

Expand Down Expand Up @@ -158,6 +161,10 @@ filterwarnings = [
"ignore:.*pkg_resources.*:DeprecationWarning:",
"ignore:.*The retworkx package is deprecated*:DeprecationWarning:pymatching",
'ignore:.*qiskit.providers.provider.Provider.*:DeprecationWarning:',
'ignore::DeprecationWarning:.*(simpleeval).*',
'ignore::RuntimeWarning:.*(qsample).*',
'ignore:.*invalid escape sequence.*::.*qsample.*',
'ignore:.*invalid escape sequence.*::.*latextools.*',
]

[tool.coverage]
Expand Down Expand Up @@ -186,7 +193,7 @@ exclude = [

[[tool.mypy.overrides]]
module = ["qiskit.*", "qecsim.*", "qiskit_aer.*", "matplotlib.*", "scipy.*", "ldpc.*", "pytest_console_scripts.*",
"z3.*", "bposd.*", "numba.*", "pymatching.*", "stim.*", "multiprocess.*"]
"z3.*", "bposd.*", "numba.*", "pymatching.*", "stim.*", "multiprocess.*", "qsample.*", "pandas.*"]
ignore_missing_imports = true


Expand Down
11 changes: 11 additions & 0 deletions scripts/ft_stateprep/eval/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
If you want to run evaluations on the example circuits in this directory, do the following.

To estimate the logical error rate for a physical error rate p_err, run

`python estimate_logical_error_rate CODE -p p_err`

The script prints 4 numbers: logical error rate per qubit, acceptance rate (if using post-selection), number of logical errors, total number of shots

The python script has further options with which you can select which circuits to construct, how many logical errors should occur before stopping and more.

To generate these values for a circuit for a range between p_err = 0.5 and p_err = 0.00005, the script `run_eval_on_code FILENAME ARGS` can be used. It runs multiple instances of `estimate_logical_error_rate` in parallel (using GNU Parallel) and stores the results in `FILENAME.csv`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
OPENQASM 2.0;
include "qelib1.inc";
qreg q[12];
qreg z_anc[2];
qreg x_anc[1];
qreg a47[1];
creg z_c[2];
creg x_c[1];
creg c47[1];
h q[0];
h q[1];
h q[2];
h q[4];
h q[7];
cx q[7],q[11];
cx q[1],q[5];
cx q[7],q[9];
cx q[4],q[10];
cx q[2],q[8];
cx q[1],q[3];
cx q[0],q[6];
cx q[10],q[9];
cx q[8],q[7];
cx q[6],q[11];
cx q[4],q[3];
cx q[2],q[1];
cx q[0],q[5];
cx q[11],q[10];
cx q[9],q[8];
cx q[7],q[6];
cx q[5],q[4];
cx q[3],q[2];
cx q[1],q[0];
cx q[1],z_anc[0];
cx q[4],z_anc[0];
cx q[7],z_anc[0];
cx q[10],z_anc[0];
cx q[1],z_anc[1];
cx q[2],z_anc[1];
cx q[7],z_anc[1];
cx q[8],z_anc[1];
measure z_anc[0] -> z_c[0];
measure z_anc[1] -> z_c[1];
h x_anc[0];
cx x_anc[0],q[0];
cx x_anc[0],a47[0];
cx x_anc[0],q[2];
cx x_anc[0],q[4];
cx x_anc[0],q[6];
cx x_anc[0],q[8];
cx x_anc[0],a47[0];
measure a47[0] -> c47[0];
cx x_anc[0],q[10];
h x_anc[0];
measure x_anc[0] -> x_c[0];
Loading

0 comments on commit f63bba1

Please sign in to comment.