From 90dc07173e377558911cd091459d1af05801c041 Mon Sep 17 00:00:00 2001 From: "Davide Gessa (dakk)" Date: Fri, 24 Nov 2023 10:21:11 +0100 Subject: [PATCH] update docs --- .github/workflows/documentation.yaml | 27 +++++++++++++++++++++++ README.md | 3 ++- TODO.md | 7 +++--- docs/source/api.rst | 1 + docs/source/howitworks.rst | 22 +++++++++---------- docs/source/supported.rst | 33 ++++++++++++++++++++++++++-- qlasskit/__init__.py | 2 +- qlasskit/qlassfun.py | 2 +- test/test_algo_grover.py | 20 +++++++++++++++++ 9 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/documentation.yaml diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml new file mode 100644 index 00000000..f538c3ef --- /dev/null +++ b/.github/workflows/documentation.yaml @@ -0,0 +1,27 @@ +name: documentation + +on: [push, pull_request, workflow_dispatch] + +permissions: + contents: write + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + - name: Install dependencies + run: | + pip install sphinx sphinx_rtd_theme myst_parser + - name: Sphinx build + run: | + sphinx-build doc _build + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + with: + publish_branch: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: _build/ + force_orphan: true \ No newline at end of file diff --git a/README.md b/README.md index 419c08ff..115d9ae2 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ def h(k: Qint4) -> bool: return h ``` + Qlasskit will take care of translating the function to boolean expressions, simplify them and translate to a quantum circuit. @@ -36,7 +37,7 @@ algo = Grover(h, True) qc = algo.circuit().export("circuit", "qiskit") ``` -And that's it: +And that's the result: ![Grover](docs/source/_images/grover_circ.png) diff --git a/TODO.md b/TODO.md index 708d91a7..171ca065 100644 --- a/TODO.md +++ b/TODO.md @@ -93,11 +93,13 @@ - [x] Qint multiplier - [x] Allow quantum gates inside sympy expressions - [x] CNotSim dummy simulator for circuit testing -- [ ] Improve exporting utilities + +## Month 3: + +- [x] Improve exporting utilities - [ ] Use cases - [ ] Documentation -## Month 3: ### Week 1: (20 Nov 23) ### Week 2: (27 Nov 23) @@ -144,7 +146,6 @@ - [ ] PyQrack (without qiskit provider) - [ ] QuTip - [ ] Pennylane -- [ ] Cirq - [ ] Sympy quantum computing expressions ### Tools diff --git a/docs/source/api.rst b/docs/source/api.rst index e86d86a4..9a31913d 100644 --- a/docs/source/api.rst +++ b/docs/source/api.rst @@ -6,6 +6,7 @@ API :recursive: qlasskit.qlassfun.qlassf + qlasskit.qlassfun.qlassfa qlasskit.qlassfun.QlassF qlasskit.algorithms.qalgorithm qlasskit.algorithms.grover.Grover diff --git a/docs/source/howitworks.rst b/docs/source/howitworks.rst index 32de8104..479fcd51 100644 --- a/docs/source/howitworks.rst +++ b/docs/source/howitworks.rst @@ -1,18 +1,18 @@ How it works ============ -In order to translate python code to quantum circuit, qlasskit performs several transformations; +To convert Python code into a quantum circuit, qlasskit implements a series of transformations: -1. it starts from the python *AST* (abstract syntax tree) rewriting it to a simplified version -by the _ast2ast_ module. -2. Then the simplified *AST* is translated to *boolean expressions* as intermediate -form by the _ast2logic_ module. In this step, boolean expression are simplified and optimized -for the final transformation. -3. Finally, these boolean expressions are compiled into a *quantum circuit* by the _compiler_ module. +1. It begins with the Python *AST* (Abstract Syntax Tree), converting it into a more streamlined form using the _ast2ast_ module. +2. Next, the streamlined AST is translated into *boolean expressions* as an intermediate step by the _ast2logic_ module. +During this phase, boolean expressions are refined and optimized in preparation for the final transformation. +3. Finally, the _compiler_ module takes these optimized boolean expressions and compiles them into a +*quantum circuit*. + +Unlike other libraries that translate individual operations into quantum circuits before combining them, +qlasskit constructs a singular boolean expression for each output qubit of the entire function. +This unique approach facilitates advanced optimization leveraging boolean algebraic properties. -While other existing libraries translate individual operations into quantum circuits and then -combine them, qlasskit creates a single boolean expression for every output qubit of the entire -function. This approach allows for further optimization using boolean properties. For instance, let assume we have the following function: @@ -91,7 +91,7 @@ Is translated to this boolean expression: Compiler ------------ -The boolean expressions are then being fed to the `qlasskit.compiler`` which translates boolean expressions +The boolean expressions are then being fed to the `qlasskit.compiler`` which compiles boolean expressions to invertible circuits, introducing auxiliary qubits. In this step, the compiler will automatically uncompute auxiliary qubits in order to reduce the number of qubits needed and the circuit footprint. diff --git a/docs/source/supported.rst b/docs/source/supported.rst index d7e8b19b..a396e9fc 100644 --- a/docs/source/supported.rst +++ b/docs/source/supported.rst @@ -42,7 +42,9 @@ Container type holding different types. List ^^^^ -A fixed size list; its type is `Qlist[T, size]`. +Qlist[T, size] denotes a fixed-size list in qlasskit. +For example, the list `[1,2,3]` is typed as `Qlist[Qint2,3]`. + Expressions @@ -110,7 +112,7 @@ Comparators .. code-block:: python - a > b or b <= c + a > b or b <= c and c == d or c != a Unary Op @@ -141,6 +143,10 @@ Bin Op a - b +.. code-block:: python + + a * b + Function call @@ -184,6 +190,10 @@ For loop a += i +.. note:: + Please note that in qlasskit, for loops are unrolled during compilation. Therefore, + it is essential that the number of iterations for each for loop is known at the + time of compilation. Function def ^^^^^^^^^^^^ @@ -204,3 +214,22 @@ If then else c += 12 else: c += 13 + +.. note:: + At present, the if-then-else statement in qlasskit is designed to support branch bodies + that exclusively contain assignment statements. + + + +Quantum Hybrid +--------------- + +In a qlassf function, you have the option to utilize quantum gates through the Q module. It's +important to keep in mind that incorporating quantum gates within a qlasskit function leads +to a Python function that exhibits distinct behaviors compared to its quantum counterpart. + +.. code-block:: python + + def bell(a: bool, b: bool) -> bool: + return Q.CX(Q.H(a), b) + diff --git a/qlasskit/__init__.py b/qlasskit/__init__.py index 75de10b5..46b8ebc2 100644 --- a/qlasskit/__init__.py +++ b/qlasskit/__init__.py @@ -16,7 +16,7 @@ __version__ = "0.0.2" from .qcircuit import QCircuit, SupportedFrameworks, SupportedFramework # noqa: F401 -from .qlassfun import QlassF, qlassf, qlassf_a # noqa: F401 +from .qlassfun import QlassF, qlassf, qlassfa # noqa: F401 from .ast2ast import ast2ast # noqa: F401 from .ast2logic import exceptions # noqa: F401 from .types import ( # noqa: F401, F403 diff --git a/qlasskit/qlassfun.py b/qlasskit/qlassfun.py index afc753f4..c06f7bcc 100644 --- a/qlasskit/qlassfun.py +++ b/qlasskit/qlassfun.py @@ -257,7 +257,7 @@ def qlassf( ) -def qlassf_a( +def qlassfa( types: List[Qtype] = [], defs: List[QlassF] = [], to_compile: bool = True, diff --git a/test/test_algo_grover.py b/test/test_algo_grover.py index 0a1f27d4..47cff3ad 100644 --- a/test/test_algo_grover.py +++ b/test/test_algo_grover.py @@ -40,6 +40,26 @@ def hash(k: Qint4) -> bool: self.assertEqual(algo.output_qubits, [0, 1, 2, 3]) self.assertEqual(counts_readable[15] > 600, True) + def test_grover_list_search(self): + f = """ +def hash(k: Qint4) -> bool: + h = False + for i in [7]: + if i == k: + h = True + return h +""" + qf = qlassf(f) + algo = Grover(qf, True) + + qc = algo.circuit().export("circuit", "qiskit") + counts = qiskit_measure_and_count(qc, shots=1024) + counts_readable = algo.decode_counts(counts) + + self.assertEqual(15 in counts_readable, True) + self.assertEqual(algo.output_qubits, [0, 1, 2, 3]) + self.assertEqual(counts_readable[7] > 600, True) + def test_grover_without_element_to_search(self): f = """ def hash(k: Qint4) -> bool: