From cd00a9a4989b9a469bad68f8c2008c87ecb8eded Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 12 Nov 2024 17:46:24 -0800 Subject: [PATCH 1/5] Fix bug in KaliskiStep3 and add tests for all steps --- qualtran/bloqs/arithmetic/comparison.py | 19 ++--- qualtran/bloqs/mod_arithmetic/mod_division.py | 23 +++--- .../bloqs/mod_arithmetic/mod_division_test.py | 78 ++++++++++++++++++- 3 files changed, 96 insertions(+), 24 deletions(-) diff --git a/qualtran/bloqs/arithmetic/comparison.py b/qualtran/bloqs/arithmetic/comparison.py index b28269ae46..fff30d5fc0 100644 --- a/qualtran/bloqs/arithmetic/comparison.py +++ b/qualtran/bloqs/arithmetic/comparison.py @@ -1462,20 +1462,17 @@ def on_classical_vals( c: Optional['ClassicalValT'] = None, target: Optional['ClassicalValT'] = None, ) -> Dict[str, 'ClassicalValT']: + if self._op_symbol in ('>', '<='): + c_val = add_ints(-int(a), int(b), num_bits=self.dtype.bitsize + 1, is_signed=False) + else: + c_val = add_ints(int(a), -int(b), num_bits=self.dtype.bitsize + 1, is_signed=False) if self.uncompute: - assert c == add_ints( - int(a), - int(b), - num_bits=int(self.dtype.bitsize), - is_signed=isinstance(self.dtype, QInt), - ) + assert c == c_val assert target == self._classical_comparison(a, b) return {'a': a, 'b': b} - if self._op_symbol in ('>', '<='): - c = add_ints(-int(a), int(b), num_bits=self.dtype.bitsize + 1, is_signed=False) - else: - c = add_ints(int(a), -int(b), num_bits=self.dtype.bitsize + 1, is_signed=False) - return {'a': a, 'b': b, 'c': c, 'target': int(self._classical_comparison(a, b))} + assert c is None + assert target is None + return {'a': a, 'b': b, 'c': c_val, 'target': int(self._classical_comparison(a, b))} def _compute(self, bb: 'BloqBuilder', a: 'Soquet', b: 'Soquet') -> Dict[str, 'SoquetT']: if self._op_symbol in ('>', '<='): diff --git a/qualtran/bloqs/mod_arithmetic/mod_division.py b/qualtran/bloqs/mod_arithmetic/mod_division.py index c099c75623..06f6435255 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_division.py +++ b/qualtran/bloqs/mod_arithmetic/mod_division.py @@ -72,8 +72,6 @@ def signature(self) -> 'Signature': def on_classical_vals( self, v: int, m: int, f: int, is_terminal: int ) -> Dict[str, 'ClassicalValT']: - print('here') - assert False m ^= f & (v == 0) assert is_terminal == 0 is_terminal ^= m @@ -101,10 +99,10 @@ def build_composite_bloq( def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': if is_symbolic(self.bitsize): - cvs: Union[HasLength, List[int]] = HasLength(self.bitsize) + cvs: Union[HasLength, List[int]] = HasLength(self.bitsize + 1) else: - cvs = [0] * int(self.bitsize) - return {MultiAnd(cvs=cvs): 1, MultiAnd(cvs=cvs).adjoint(): 1, CNOT(): 2} + cvs = [0] * int(self.bitsize) + [1] + return {MultiAnd(cvs=cvs): 1, MultiAnd(cvs=cvs).adjoint(): 1, CNOT(): 3} @frozen @@ -197,11 +195,11 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', u: Soquet, v: Soquet, b: Soquet, a: Soquet, m: Soquet, f: Soquet ) -> Dict[str, 'SoquetT']: - u, v, junk, greater_than = bb.add( + u, v, junk_c, greater_than = bb.add( LinearDepthHalfGreaterThan(QMontgomeryUInt(self.bitsize)), a=u, b=v ) - (greater_than, f, b), junk, ctrl = bb.add( + (greater_than, f, b), junk_m, ctrl = bb.add( MultiAnd(cvs=(1, 1, 0)), ctrl=(greater_than, f, b) ) @@ -209,13 +207,13 @@ def build_composite_bloq( ctrl, m = bb.add(CNOT(), ctrl=ctrl, target=m) greater_than, f, b = bb.add( - MultiAnd(cvs=(1, 1, 0)).adjoint(), ctrl=(greater_than, f, b), junk=junk, target=ctrl + MultiAnd(cvs=(1, 1, 0)).adjoint(), ctrl=(greater_than, f, b), junk=junk_m, target=ctrl ) u, v = bb.add( LinearDepthHalfGreaterThan(QMontgomeryUInt(self.bitsize)).adjoint(), a=u, b=v, - c=junk, + c=junk_c, target=greater_than, ) return {'u': u, 'v': v, 'b': b, 'a': a, 'm': m, 'f': f} @@ -391,7 +389,7 @@ def build_composite_bloq( def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': return { - CNOT(): 4, + CNOT(): 3, XGate(): 2, ModDbl(QMontgomeryUInt(self.bitsize), self.mod): 1, CSwapApprox(self.bitsize): 2, @@ -475,7 +473,7 @@ def on_classical_vals( of `f` and `m`. """ assert m == 0 - is_terminal = f == 1 and v == 0 + is_terminal = int(f == 1 and v == 0) if f == 0: # When `f = 0` this means that the algorithm is nearly over and that we just need to # double the value of `r`. @@ -489,7 +487,8 @@ def on_classical_vals( f = 0 r = (r << 1) % self.mod else: - m = (u % 2 == 1) & (v % 2 == 0) + m = ((u % 2 == 1) & (v % 2 == 0)) or (u % 2 == 1 and v % 2 == 1 and u > v) + m = int(m) # Kaliski iteration as described in Fig7 of https://arxiv.org/pdf/2001.09580. swap = (u % 2 == 0 and v % 2 == 1) or (u % 2 == 1 and v % 2 == 1 and u > v) if swap: diff --git a/qualtran/bloqs/mod_arithmetic/mod_division_test.py b/qualtran/bloqs/mod_arithmetic/mod_division_test.py index 093f0908f7..4d304f127d 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_division_test.py +++ b/qualtran/bloqs/mod_arithmetic/mod_division_test.py @@ -19,6 +19,7 @@ import qualtran.testing as qlt_testing from qualtran import QMontgomeryUInt +from qualtran.bloqs.mod_arithmetic import mod_division from qualtran.bloqs.mod_arithmetic.mod_division import _kaliskimodinverse_example, KaliskiModInverse from qualtran.resource_counting import get_cost_value, QECGatesCost from qualtran.resource_counting.generalizers import ignore_alloc_free, ignore_split_join @@ -36,7 +37,7 @@ def test_kaliski_mod_inverse_classical_action(bitsize, mod): continue x_montgomery = dtype.uint_to_montgomery(x, mod) res = blq.call_classically(x=x_montgomery) - print(x, x_montgomery) + assert res == cblq.call_classically(x=x_montgomery) assert len(res) == 2 assert res[0] == dtype.montgomery_inverse(x_montgomery, mod) @@ -99,3 +100,78 @@ def test_kaliskimodinverse_example(bloq_autotester): @pytest.mark.notebook def test_notebook(): qlt_testing.execute_notebook('mod_division') + + +def test_kaliski_iteration_decomposition(): + mod = 7 + bitsize = 5 + b = mod_division._KaliskiIteration(bitsize, mod) + cb = b.decompose_bloq() + for x in range(mod): + u = mod + v = x + r = 0 + s = 1 + f = 1 + + for _ in range(2 * bitsize): + inputs = {'u': u, 'v': v, 'r': r, 's': s, 'm': 0, 'f': f, 'is_terminal': 0} + res = b.call_classically(**inputs) + assert res == cb.call_classically(**inputs), f'{inputs=}' + u, v, r, s, _, f, _ = res # type: ignore + + qlt_testing.assert_valid_bloq_decomposition(b) + qlt_testing.assert_equivalent_bloq_counts(b, generalizer=(ignore_alloc_free, ignore_split_join)) + + +def test_kaliski_steps(): + bitsize = 5 + mod = 7 + steps = [ + mod_division._KaliskiIterationStep1(bitsize), + mod_division._KaliskiIterationStep2(bitsize), + mod_division._KaliskiIterationStep3(bitsize), + mod_division._KaliskiIterationStep4(bitsize), + mod_division._KaliskiIterationStep5(bitsize), + mod_division._KaliskiIterationStep6(bitsize, mod), + ] + csteps = [b.decompose_bloq() for b in steps] + + # check decomposition is valid. + for step in steps: + qlt_testing.assert_valid_bloq_decomposition(step) + qlt_testing.assert_equivalent_bloq_counts( + step, generalizer=(ignore_alloc_free, ignore_split_join) + ) + + # check that for all inputs all 2n iteration work when excuted directly on the 6 steps + # and their decompositions. + for x in range(mod): + u, v, r, s, f = mod, x, 0, 1, 1 + + for _ in range(2 * bitsize): + a = b = m = is_terminal = 0 + + res = steps[0].call_classically(v=v, m=m, f=f, is_terminal=is_terminal) + assert res == csteps[0].call_classically(v=v, m=m, f=f, is_terminal=is_terminal) + v, m, f, is_terminal = res # type: ignore + + res = steps[1].call_classically(u=u, v=v, b=b, a=a, m=m, f=f) + assert res == csteps[1].call_classically(u=u, v=v, b=b, a=a, m=m, f=f) + u, v, b, a, m, f = res # type: ignore + + res = steps[2].call_classically(u=u, v=v, b=b, a=a, m=m, f=f) + assert res == csteps[2].call_classically(u=u, v=v, b=b, a=a, m=m, f=f) + u, v, b, a, m, f = res # type: ignore + + res = steps[3].call_classically(u=u, v=v, r=r, s=s, a=a) + assert res == csteps[3].call_classically(u=u, v=v, r=r, s=s, a=a) + u, v, r, s, a = res # type: ignore + + res = steps[4].call_classically(u=u, v=v, r=r, s=s, b=b, f=f) + assert res == csteps[4].call_classically(u=u, v=v, r=r, s=s, b=b, f=f) + u, v, r, s, b, f = res # type: ignore + + res = steps[5].call_classically(u=u, v=v, r=r, s=s, b=b, a=a, m=m, f=f) + assert res == csteps[5].call_classically(u=u, v=v, r=r, s=s, b=b, a=a, m=m, f=f) + u, v, r, s, b, a, m, f = res # type: ignore From c84bca1bcd03524f591e48262bf9b37c5cf8e59a Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 12 Nov 2024 18:51:52 -0800 Subject: [PATCH 2/5] cost --- qualtran/bloqs/factoring/ecc/ec_add_test.py | 2 +- qualtran/bloqs/mod_arithmetic/mod_division_test.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qualtran/bloqs/factoring/ecc/ec_add_test.py b/qualtran/bloqs/factoring/ecc/ec_add_test.py index 37c397707a..7f7439d2d1 100644 --- a/qualtran/bloqs/factoring/ecc/ec_add_test.py +++ b/qualtran/bloqs/factoring/ecc/ec_add_test.py @@ -418,7 +418,7 @@ def test_ec_add_symbolic_cost(): # toffoli cost for Kaliski Mod Inverse, n extra toffolis in ModNeg, 2n extra toffolis to do n # 3-controlled toffolis in step 2. The expression is written with rationals because sympy # comparison fails with floats. - assert total_toff == sympy.Rational(253, 2) * n**2 + sympy.Rational(391, 2) * n - 31 + assert total_toff == sympy.Rational(253, 2) * n**2 + sympy.Rational(407, 2) * n - 31 def test_ec_add(bloq_autotester): diff --git a/qualtran/bloqs/mod_arithmetic/mod_division_test.py b/qualtran/bloqs/mod_arithmetic/mod_division_test.py index 4d304f127d..934a26967a 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_division_test.py +++ b/qualtran/bloqs/mod_arithmetic/mod_division_test.py @@ -86,11 +86,11 @@ def test_kaliski_symbolic_cost(): # construction this is just $n-1$ (BitwiseNot -> Add(p+1)). # - The cost of an iteration in Litinski $13n$ since they ignore constants. # Our construction is exactly the same but we also count the constants - # which amout to $3$. for a total cost of $13n + 3$. + # which amout to $3$. for a total cost of $13n + 4$. # For example the cost of ModDbl is 2n+1. In their figure 8, they report # it as just $2n$. ModDbl gets executed within the 2n loop so its contribution # to the overal cost should be 4n^2 + 2n instead of just 4n^2. - assert total_toff == 26 * n**2 + 7 * n - 1 + assert total_toff == 26 * n**2 + 9 * n - 1 def test_kaliskimodinverse_example(bloq_autotester): From 476afec4c4d2efface3e556b79d9648fcb21470a Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 28 Jan 2025 14:28:33 -0800 Subject: [PATCH 3/5] Create a notebook for quantum modular arithmetics --- .../qualtran_modular_arithmetics.ipynb | 965 ++++++++++++++++++ 1 file changed, 965 insertions(+) create mode 100644 qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb diff --git a/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb b/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb new file mode 100644 index 0000000000..d24c99f258 --- /dev/null +++ b/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb @@ -0,0 +1,965 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "title: Quantum Modular Arithmetic in Qualtran\n", + "author: [Noureldin Yosri](https://github.com/NoureldinYosri)\n", + "date: today\n", + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wMDM6DC6FJlO" + }, + "source": [ + "# Introduction\n", + "\n", + "Modular arithmetic is the backbone of number theortic and cryptographic algorithms such as factoring and elliptic curve cryptography. Qualtran provides a library of the state of the art constructions for peforming these operations on a fault tolerant quantum computer.\n", + "\n", + "This notebook shows the different operations, their constructions and computational costs. The following table lists the different operations, their costs and source of the construction.\n", + "\n", + "| operation | Bloq | Qualtran Toffoli Cost | Toffoli Cost From [Figure 8](https://arxiv.org/abs/2306.08585) | references |\n", + "|:-------------------------------|:-----------------------------------------------------------------------------------|:--------------------------|:-----------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n", + "| modular addition | `qualtran.bloqs.mod_arithmetic.mod_addition.ModAdd` | $4 n - 1$ | $4 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular controlled addition | `qualtran.bloqs.mod_arithmetic.mod_addition.CModAdd` | $5 n + 1$ | $5 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular negation | `qualtran.bloqs.mod_arithmetic.mod_subtraction.ModNeg` | $3 n - 3$ | $2 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular controlled negation | `qualtran.bloqs.mod_arithmetic.mod_subtraction.CModNeg` | $3 n - 2$ | $3 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular subtraction | `qualtran.bloqs.mod_arithmetic.mod_subtraction.ModSub` | $6 n - 3$ | $6 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular controlled subtraction | `qualtran.bloqs.mod_arithmetic.mod_subtraction.CModSub` | $7 n - 1$ | $7 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular doubling | `qualtran.bloqs.mod_arithmetic.mod_multiplication.ModDbl` | $2 n + 1$ | $2 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular multiplication | `qualtran.bloqs.mod_arithmetic.mod_multiplication.DirtyOutOfPlaceMontgomeryModMul` | $2.25 n^{2} +$$ 7.25 n - 1$ | $2.25 n^{2} + 9 n$ | - [Performance Analysis of a Repetition Cat Code Architecture: Computing 256-bit Elliptic Curve Logarithm in 9 Hours with 126 133 Cat Qubits](https://arxiv.org/abs/2302.06639)
- [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular multiplicative inverse | `qualtran.bloqs.mod_arithmetic.mod_division.KaliskiModInverse` | $26 n^{2} + 9 n - 1$ | $26 n^{2} + 2 n$ | - [Performance Analysis of a Repetition Cat Code Architecture: Computing 256-bit Elliptic Curve Logarithm in 9 Hours with 126 133 Cat Qubits](https://arxiv.org/abs/2302.06639)
- [Improved quantum circuits for elliptic curve discrete logarithms](https://arxiv.org/abs/2001.09580)
- [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "\n", + "\n", + "\n", + "\n", + "If you compare qualtran's costs with the costs from Figure 8 of [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) you will find that generally we match the coefficient of the leading term while having smaller coefficients for the lower terms and we also list the constants. The two exception to this are modular negation where we have a higher leading coefficient ($3$ vs $2$) and modular inversion where we match the leading coefficient but have a higher coefficient for the lower term ($9$ vs $2$).\n", + "\n", + "### Modular Negatition\n", + "The strucutre of the construction of this operation consists of two operations that cost $n$ toffolis between two n-bit toffolis resulting in $3n$ toffolis. The authors of [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) suggests using measurement based uncomputation (see. [Halving the cost of quantum addition](https://quantum-journal.org/papers/q-2018-06-18-74/#)) to turn the last n-bit toffoli into measurements + cliffords thus reducing the cost to $2n$. However, measurement based uncomputation doesn't strictly apply here since the control register is modified between the initial `And` computation and its adjoint/uncomputation, this leads to a mismatch between the value in the register and the value in the hidden ancillas with the overall effect being the introduction of random phase flips. That is the final state will have some coefficients multiplied by $-1$ randomly. We chose not to introduce this effect into our construction.\n", + "\n", + "\n", + "### Modular Inversion\n", + "Our cost for this operation $26n^2+9n-1$ which differs from their cost of $26n^2+2n$ by $7n-1$. The reason of this, is the constants that they omitted for the other operations. This operation consists of a loop that repeats the same circuit $2n$ times, thus the constants of that inner circuit contribute to the coefficient of $n$ since they get multiplied by $2n$. This bloq shows Qualtran's ability to compute accurate resource estimates." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eR9WcJmytsr4" + }, + "source": [ + "## Assumptions\n", + "1. Certain operations (e.g. modular doubling) assume the modulus is odd. This is because most applications (e.g. factoring) have this assumption and because the construction becomes simpler.\n", + "1. All operations assume their inputs are valid. For example modular inversion assumes that all the input states have an inverse and modular multiplication assumes that its inputs are $\\in [1, \\mod)$ that is they exclude $0$.\n", + "1. In literature modular operations are assumed to become identity when they apply to states outside their valid range. For example, the circuit applying modular negation modulu $m$ with $n$ bits is defined as\n", + "$$\n", + "\\mathbb{O} \\ket{x} →\n", + "\\begin{cases}\n", + "\\ket{- x \\mod m} & 0 \\leq x < m \\\\\n", + "\\ket{x} & p < x < 2^n\n", + "\\end{cases}\n", + "$$\n", + "This is done to ensure that the circuit is unitary. However, constructions always assume that their inputs are valid as explained above.\n", + "\n", + "\n", + "\n", + "## Correctness checks for constructions\n", + "Qualtran provides a suite of tools to check the correctness of bloq construction/decomposition. Out of them, we highlight the classical simulation check. This check is very important to arithmetic bloqs since it ensure that if the input is a single classical state then final state is the expected single classical state with one of the limitations of this test being that it can't detect problems with phases.\n", + "\n", + "Even with this limitation the classical simulation check was able to detect problems with constructions from the literature. For the example, the use of measurement based uncomputation to lower the cost of modular negation in [How to compute a 256-bit elliptic curve private key\n", + "with only 50 million Toffoli gates](https://arxiv.org/pdf/2306.08585) where it is not applicable.\n", + "\n", + "A second test is checking the matrix of the construction which we calculate using tensor network contraction. Since all modular arithmetic function are reversible functions, their matrices are permutation matrices. More preciesly the submatrix for the valid input range (e.g. $[0, \\mod) × [0, \\mod)$ for modular negation) should be a permutation matrix." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "eJ--ENSj4fZq" + }, + "outputs": [], + "source": [ + "import qualtran\n", + "import cirq\n", + "import sympy\n", + "import numpy as np\n", + "\n", + "from qualtran import QMontgomeryUInt\n", + "from qualtran.drawing import show_bloq, show_call_graph\n", + "import qualtran.bloqs.mod_arithmetic as qma\n", + "from qualtran.resource_counting import get_cost_value, QECGatesCost" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5SjFPIudBVJr" + }, + "source": [ + "### Addition\n", + "Quantum modular addition performs the transformation $\\ket{x} \\ket{y} → \\ket{x} \\ket{(x+y) \\mod m}$\n", + "\n", + "In qualtran the bloq that represents this operation is `ModAdd`. The circuit construction for this operation is a translation of the classical program:\n", + "\n", + "```python\n", + "def add_mod(x, y, m):\n", + " y += x # normal in-place addition y := x + y.\n", + " y -= m # subtract constant y := x + y - m.\n", + " c = y < 0 # c := (x + y - m < 0)\n", + " if c:\n", + " y += m # y := x + y\n", + " else:\n", + " # y := x + y - m which is >= 0\n", + " c ^= y > x # Regardless of what happened in the condition above c := 1\n", + " c ^= 1 # c := 0\n", + " return x, y\n", + "```\n", + "\n", + "Which means we will do:\n", + "1. one addition\n", + "1. two addition with a constant\n", + "1. one bit flip\n", + "\n", + "Note that the check $y < 0$ is done by simply checking the overflow bit.\n", + "\n", + "Which can be seen the call graph below" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 563 + }, + "id": "2YIWlwoOBSZE", + "outputId": "0c797205-fa6c-480c-f1a7-2cdedfbb7ddb" + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "my_graph\n", + "\n", + "\n", + "\n", + "x_G3\n", + "x\n", + "\n", + "\n", + "\n", + "ModAdd\n", + "\n", + "ModAdd\n", + "\n", + "x\n", + "\n", + "y\n", + "\n", + "\n", + "\n", + "x_G3:e->ModAdd:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "y_G5\n", + "y\n", + "\n", + "\n", + "\n", + "y_G5:e->ModAdd:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "x_G4\n", + "x\n", + "\n", + "\n", + "\n", + "ModAdd:e->x_G4:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "y_G1\n", + "y\n", + "\n", + "\n", + "\n", + "ModAdd:e->y_G1:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "counts\n", + "\n", + "\n", + "\n", + "b0\n", + "\n", + "ModAdd\n", + "\n", + "Qubits\n", + "\n", + "15\n", + "\n", + "Ands\n", + "\n", + "11\n", + "\n", + "Cliffords\n", + "\n", + "88\n", + "\n", + "Measurements\n", + "\n", + "11\n", + "\n", + "\n", + "\n", + "b1\n", + "\n", + "Add\n", + "\n", + "Ands\n", + "\n", + "3\n", + "\n", + "Cliffords\n", + "\n", + "18\n", + "\n", + "Measurements\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "b0->b1\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b2\n", + "\n", + "AddK\n", + "\n", + "Ands\n", + "\n", + "3\n", + "\n", + "Cliffords\n", + "\n", + "22\n", + "\n", + "Measurements\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "b0->b2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b3\n", + "\n", + "AddK\n", + "\n", + "Ands\n", + "\n", + "2\n", + "\n", + "Cliffords\n", + "\n", + "17\n", + "\n", + "Measurements\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "b0->b3\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b4\n", + "\n", + "LinearDepthGreaterThan\n", + "\n", + "Qubits\n", + "\n", + "12\n", + "\n", + "Ands\n", + "\n", + "3\n", + "\n", + "Cliffords\n", + "\n", + "30\n", + "\n", + "Measurements\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "b0->b4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b5\n", + "\n", + "XGate\n", + "\n", + "Qubits\n", + "\n", + "1\n", + "\n", + "Cliffords\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b0->b5\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "bitsize = 3\n", + "mod = 7\n", + "\n", + "add = qma.ModAdd(bitsize, mod)\n", + "show_bloq(add)\n", + "show_call_graph(add, max_depth=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pUDsoRpBQ4uC", + "outputId": "d5bf5307-b48b-444c-933c-dab2cc8dd46d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "passed classical check :D\n" + ] + } + ], + "source": [ + "# To check the correctness we first do a classical simulation check\n", + "for x in range(mod):\n", + " for y in range(mod):\n", + " assert add.call_classically(x=x, y=y) == (x, (x + y) % mod)\n", + "print('passed classical check :D')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8O9RbxF2PLjd", + "outputId": "f09683aa-6536-461e-fec2-16273637c311" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "passed classical check :D\n" + ] + } + ], + "source": [ + "# Secondly we check that the construction/decomposition also passes the classical check.\n", + "add_decom = add.decompose_bloq()\n", + "for x in range(mod):\n", + " for y in range(mod):\n", + " assert add_decom.call_classically(x=x, y=y) == (x, (x + y) % mod)\n", + "print('passed classical check :D')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rV0e_lJfRqJW", + "outputId": "807768f6-45f9-4221-b3da-9c5b2ba09ad4" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "passed phase check :D\n" + ] + } + ], + "source": [ + "# Thirdly we check that the unitary doesn't add any phases.\n", + "matrix = add.tensor_contract()\n", + "eps = 1e-6\n", + "is_zero = np.abs(matrix) < eps\n", + "is_one = np.abs(matrix - 1) < eps\n", + "assert np.all(is_zero | is_one) # all entries are ~0 or ~1\n", + "print('passed phase check :D')" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "EfseX_p6SMKD", + "outputId": "f2330d6b-99e9-42b0-a29f-ee8dcc3bbc1f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "toffoli cost: 4*n - 1\n", + "passed symbolic cost check :D\n" + ] + } + ], + "source": [ + "# Finally we check the toffoli cost\n", + "# According to table 5 in https://arxiv.org/pdf/2306.08585 this toffoli cost should be 4n up to a constant.\n", + "symbolic_n, symbolic_mod = sympy.symbols('n m')\n", + "cost = get_cost_value(qma.ModAdd(symbolic_n, symbolic_mod), QECGatesCost()).total_toffoli_only()\n", + "print('toffoli cost:', cost)\n", + "const = cost.subs(symbolic_n, 0)\n", + "assert cost - const == 4 * symbolic_n\n", + "print('passed symbolic cost check :D')" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "id": "egBCKvtqSYh7" + }, + "outputs": [], + "source": [ + "# To help with other operations we create a test suite\n", + "\n", + "\n", + "def check_no_phase_change(blq, eps=1e-6):\n", + " matrix = blq.tensor_contract()\n", + " is_zero = np.abs(matrix) < eps\n", + " is_one = np.abs(matrix - 1) < eps\n", + " assert np.all(is_zero | is_one) # all entries are ~0 or ~1\n", + " print('passed phase check :D')\n", + "\n", + "\n", + "def check_symbolic_cost(blq, formula):\n", + " cost = get_cost_value(blq, QECGatesCost()).total_toffoli_only()\n", + " print(f'toffoli cost of {blq}:', cost)\n", + " print(f'expect: {formula}')\n", + " const = cost.subs(symbolic_n, 0)\n", + " assert cost - const == formula\n", + " print('passed symbolic cost check :D')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gI5bdDX5WV3M" + }, + "source": [ + "## Controlled Modular Addition\n", + "\n", + "It's often useful to have special constructions of the controlled version of an operation. That is because controlling every suboperation of the original construction -while being correct- is expensive since it turns every CNOT into a toffoli and every toffoli ladder of size $n$ to a toffoli ladder of size $n+1$.\n", + "\n", + "For the case of controlled modular addition, it is enough to control the first addition and comparision.\n", + "\n", + "```python\n", + "def controlled_add_mod(ctr, x, y, m):\n", + " if ctrl:\n", + " y += x # normal in-place addition.\n", + " y -= m # subtract constant.\n", + " c = y < 0\n", + " if c:\n", + " y += m\n", + " if ctrl:\n", + " c ^= y > x # after this line `c = 1`\n", + " c ^= 1\n", + " return x, y\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 635 + }, + "id": "Tyjk06Z0T0pU", + "outputId": "b4d9c42e-be86-4749-c31f-8a68c832e6b9" + }, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "my_graph\n", + "\n", + "\n", + "\n", + "ctrl_G2\n", + "ctrl\n", + "\n", + "\n", + "\n", + "CModAdd\n", + "\n", + "CModAdd\n", + "\n", + "ctrl\n", + "\n", + "x\n", + "\n", + "y\n", + "\n", + "\n", + "\n", + "ctrl_G2:e->CModAdd:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "x_G3\n", + "x\n", + "\n", + "\n", + "\n", + "x_G3:e->CModAdd:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "y_G5\n", + "y\n", + "\n", + "\n", + "\n", + "y_G5:e->CModAdd:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "ctrl_G0\n", + "ctrl\n", + "\n", + "\n", + "\n", + "CModAdd:e->ctrl_G0:w\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "x_G8\n", + "x\n", + "\n", + "\n", + "\n", + "CModAdd:e->x_G8:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "y_G7\n", + "y\n", + "\n", + "\n", + "\n", + "CModAdd:e->y_G7:w\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "counts\n", + "\n", + "\n", + "\n", + "b0\n", + "\n", + "CModAdd\n", + "\n", + "Qubits\n", + "\n", + "16\n", + "\n", + "Ands\n", + "\n", + "16\n", + "\n", + "Cliffords\n", + "\n", + "125\n", + "\n", + "Measurements\n", + "\n", + "16\n", + "\n", + "\n", + "\n", + "b1\n", + "\n", + "CAdd\n", + "\n", + "Qubits\n", + "\n", + "14\n", + "\n", + "Ands\n", + "\n", + "6\n", + "\n", + "Cliffords\n", + "\n", + "21\n", + "\n", + "Measurements\n", + "\n", + "6\n", + "\n", + "\n", + "\n", + "b0->b1\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b2\n", + "\n", + "AddK\n", + "\n", + "Qubits\n", + "\n", + "11\n", + "\n", + "Ands\n", + "\n", + "3\n", + "\n", + "Cliffords\n", + "\n", + "22\n", + "\n", + "Measurements\n", + "\n", + "3\n", + "\n", + "\n", + "\n", + "b0->b2\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b3\n", + "\n", + "AddK\n", + "\n", + "Qubits\n", + "\n", + "9\n", + "\n", + "Ands\n", + "\n", + "2\n", + "\n", + "Cliffords\n", + "\n", + "17\n", + "\n", + "Measurements\n", + "\n", + "2\n", + "\n", + "\n", + "\n", + "b0->b3\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b4\n", + "\n", + "CLinearDepthGreaterThan\n", + "\n", + "Qubits\n", + "\n", + "16\n", + "\n", + "Ands\n", + "\n", + "5\n", + "\n", + "Cliffords\n", + "\n", + "64\n", + "\n", + "Measurements\n", + "\n", + "5\n", + "\n", + "\n", + "\n", + "b0->b4\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b5\n", + "\n", + "XGate\n", + "\n", + "Qubits\n", + "\n", + "1\n", + "\n", + "Cliffords\n", + "\n", + "1\n", + "\n", + "\n", + "\n", + "b0->b5\n", + "\n", + "\n", + "1\n", + "\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cadd = qma.CModAdd(qualtran.QMontgomeryUInt(bitsize), mod)\n", + "show_bloq(cadd)\n", + "show_call_graph(cadd, max_depth=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ug1x6YyhaGnN", + "outputId": "6d350c03-9af0-4a66-eaec-8a8252803e4d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cadd passed classical check :D\n", + "construction of cadd passed classical check :D\n" + ] + } + ], + "source": [ + "for ctrl in range(2):\n", + " for x in range(mod):\n", + " for y in range(mod):\n", + " want = (x + y) % mod if ctrl else y\n", + " assert cadd.call_classically(ctrl=ctrl, x=x, y=y) == (ctrl, x, want)\n", + "print('cadd passed classical check :D')\n", + "cadd_decom = cadd.decompose_bloq()\n", + "for ctrl in range(2):\n", + " for x in range(mod):\n", + " for y in range(mod):\n", + " want = (x + y) % mod if ctrl else y\n", + " assert cadd_decom.call_classically(ctrl=ctrl, x=x, y=y) == (ctrl, x, want)\n", + "print('construction of cadd passed classical check :D')" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pPqkrKz-T_Nk", + "outputId": "d144d5f8-0ad3-4636-fd00-ec94c2b96404" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "passed phase check :D\n", + "toffoli cost of CModAdd: 5*n + 1\n", + "expect 5*n\n", + "passed symbolic cost check :D\n" + ] + } + ], + "source": [ + "check_no_phase_change(cadd)\n", + "check_symbolic_cost(qma.CModAdd(QMontgomeryUInt(symbolic_n), symbolic_mod), 5 * symbolic_n)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Khhh79zybVtG" + }, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gniHK1YVWRkM" + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hJa4jCVIbMIR" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From 9c9e02b093c28efe0e5687a1257b660e523f3e82 Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 28 Jan 2025 14:36:44 -0800 Subject: [PATCH 4/5] clean --- .../qualtran_modular_arithmetics.ipynb | 611 +----------------- 1 file changed, 19 insertions(+), 592 deletions(-) diff --git a/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb b/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb index d24c99f258..f105b873b7 100644 --- a/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb +++ b/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb @@ -4,11 +4,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "---\n", - "title: Quantum Modular Arithmetic in Qualtran\n", - "author: [Noureldin Yosri](https://github.com/NoureldinYosri)\n", - "date: today\n", - "..." + "

Quantum Modular Arithmetic in Qualtran

\n", + "\n", + "

Noureldin Yosri

" ] }, { @@ -134,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -143,247 +141,7 @@ "id": "2YIWlwoOBSZE", "outputId": "0c797205-fa6c-480c-f1a7-2cdedfbb7ddb" }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "my_graph\n", - "\n", - "\n", - "\n", - "x_G3\n", - "x\n", - "\n", - "\n", - "\n", - "ModAdd\n", - "\n", - "ModAdd\n", - "\n", - "x\n", - "\n", - "y\n", - "\n", - "\n", - "\n", - "x_G3:e->ModAdd:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "y_G5\n", - "y\n", - "\n", - "\n", - "\n", - "y_G5:e->ModAdd:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "x_G4\n", - "x\n", - "\n", - "\n", - "\n", - "ModAdd:e->x_G4:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "y_G1\n", - "y\n", - "\n", - "\n", - "\n", - "ModAdd:e->y_G1:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "counts\n", - "\n", - "\n", - "\n", - "b0\n", - "\n", - "ModAdd\n", - "\n", - "Qubits\n", - "\n", - "15\n", - "\n", - "Ands\n", - "\n", - "11\n", - "\n", - "Cliffords\n", - "\n", - "88\n", - "\n", - "Measurements\n", - "\n", - "11\n", - "\n", - "\n", - "\n", - "b1\n", - "\n", - "Add\n", - "\n", - "Ands\n", - "\n", - "3\n", - "\n", - "Cliffords\n", - "\n", - "18\n", - "\n", - "Measurements\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "b0->b1\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b2\n", - "\n", - "AddK\n", - "\n", - "Ands\n", - "\n", - "3\n", - "\n", - "Cliffords\n", - "\n", - "22\n", - "\n", - "Measurements\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "b0->b2\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b3\n", - "\n", - "AddK\n", - "\n", - "Ands\n", - "\n", - "2\n", - "\n", - "Cliffords\n", - "\n", - "17\n", - "\n", - "Measurements\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "b0->b3\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b4\n", - "\n", - "LinearDepthGreaterThan\n", - "\n", - "Qubits\n", - "\n", - "12\n", - "\n", - "Ands\n", - "\n", - "3\n", - "\n", - "Cliffords\n", - "\n", - "30\n", - "\n", - "Measurements\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "b0->b4\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b5\n", - "\n", - "XGate\n", - "\n", - "Qubits\n", - "\n", - "1\n", - "\n", - "Cliffords\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b0->b5\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "bitsize = 3\n", "mod = 7\n", @@ -395,7 +153,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -403,15 +161,7 @@ "id": "pUDsoRpBQ4uC", "outputId": "d5bf5307-b48b-444c-933c-dab2cc8dd46d" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "passed classical check :D\n" - ] - } - ], + "outputs": [], "source": [ "# To check the correctness we first do a classical simulation check\n", "for x in range(mod):\n", @@ -422,7 +172,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -430,15 +180,7 @@ "id": "8O9RbxF2PLjd", "outputId": "f09683aa-6536-461e-fec2-16273637c311" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "passed classical check :D\n" - ] - } - ], + "outputs": [], "source": [ "# Secondly we check that the construction/decomposition also passes the classical check.\n", "add_decom = add.decompose_bloq()\n", @@ -450,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -458,15 +200,7 @@ "id": "rV0e_lJfRqJW", "outputId": "807768f6-45f9-4221-b3da-9c5b2ba09ad4" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "passed phase check :D\n" - ] - } - ], + "outputs": [], "source": [ "# Thirdly we check that the unitary doesn't add any phases.\n", "matrix = add.tensor_contract()\n", @@ -479,7 +213,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -487,16 +221,7 @@ "id": "EfseX_p6SMKD", "outputId": "f2330d6b-99e9-42b0-a29f-ee8dcc3bbc1f" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "toffoli cost: 4*n - 1\n", - "passed symbolic cost check :D\n" - ] - } - ], + "outputs": [], "source": [ "# Finally we check the toffoli cost\n", "# According to table 5 in https://arxiv.org/pdf/2306.08585 this toffoli cost should be 4n up to a constant.\n", @@ -565,7 +290,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -574,285 +299,7 @@ "id": "Tyjk06Z0T0pU", "outputId": "b4d9c42e-be86-4749-c31f-8a68c832e6b9" }, - "outputs": [ - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "my_graph\n", - "\n", - "\n", - "\n", - "ctrl_G2\n", - "ctrl\n", - "\n", - "\n", - "\n", - "CModAdd\n", - "\n", - "CModAdd\n", - "\n", - "ctrl\n", - "\n", - "x\n", - "\n", - "y\n", - "\n", - "\n", - "\n", - "ctrl_G2:e->CModAdd:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "x_G3\n", - "x\n", - "\n", - "\n", - "\n", - "x_G3:e->CModAdd:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "y_G5\n", - "y\n", - "\n", - "\n", - "\n", - "y_G5:e->CModAdd:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "ctrl_G0\n", - "ctrl\n", - "\n", - "\n", - "\n", - "CModAdd:e->ctrl_G0:w\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "x_G8\n", - "x\n", - "\n", - "\n", - "\n", - "CModAdd:e->x_G8:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "y_G7\n", - "y\n", - "\n", - "\n", - "\n", - "CModAdd:e->y_G7:w\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/svg+xml": [ - "\n", - "\n", - "counts\n", - "\n", - "\n", - "\n", - "b0\n", - "\n", - "CModAdd\n", - "\n", - "Qubits\n", - "\n", - "16\n", - "\n", - "Ands\n", - "\n", - "16\n", - "\n", - "Cliffords\n", - "\n", - "125\n", - "\n", - "Measurements\n", - "\n", - "16\n", - "\n", - "\n", - "\n", - "b1\n", - "\n", - "CAdd\n", - "\n", - "Qubits\n", - "\n", - "14\n", - "\n", - "Ands\n", - "\n", - "6\n", - "\n", - "Cliffords\n", - "\n", - "21\n", - "\n", - "Measurements\n", - "\n", - "6\n", - "\n", - "\n", - "\n", - "b0->b1\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b2\n", - "\n", - "AddK\n", - "\n", - "Qubits\n", - "\n", - "11\n", - "\n", - "Ands\n", - "\n", - "3\n", - "\n", - "Cliffords\n", - "\n", - "22\n", - "\n", - "Measurements\n", - "\n", - "3\n", - "\n", - "\n", - "\n", - "b0->b2\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b3\n", - "\n", - "AddK\n", - "\n", - "Qubits\n", - "\n", - "9\n", - "\n", - "Ands\n", - "\n", - "2\n", - "\n", - "Cliffords\n", - "\n", - "17\n", - "\n", - "Measurements\n", - "\n", - "2\n", - "\n", - "\n", - "\n", - "b0->b3\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b4\n", - "\n", - "CLinearDepthGreaterThan\n", - "\n", - "Qubits\n", - "\n", - "16\n", - "\n", - "Ands\n", - "\n", - "5\n", - "\n", - "Cliffords\n", - "\n", - "64\n", - "\n", - "Measurements\n", - "\n", - "5\n", - "\n", - "\n", - "\n", - "b0->b4\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b5\n", - "\n", - "XGate\n", - "\n", - "Qubits\n", - "\n", - "1\n", - "\n", - "Cliffords\n", - "\n", - "1\n", - "\n", - "\n", - "\n", - "b0->b5\n", - "\n", - "\n", - "1\n", - "\n", - "\n", - "" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "cadd = qma.CModAdd(qualtran.QMontgomeryUInt(bitsize), mod)\n", "show_bloq(cadd)\n", @@ -861,7 +308,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -869,16 +316,7 @@ "id": "ug1x6YyhaGnN", "outputId": "6d350c03-9af0-4a66-eaec-8a8252803e4d" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "cadd passed classical check :D\n", - "construction of cadd passed classical check :D\n" - ] - } - ], + "outputs": [], "source": [ "for ctrl in range(2):\n", " for x in range(mod):\n", @@ -897,7 +335,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -905,18 +343,7 @@ "id": "pPqkrKz-T_Nk", "outputId": "d144d5f8-0ad3-4636-fd00-ec94c2b96404" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "passed phase check :D\n", - "toffoli cost of CModAdd: 5*n + 1\n", - "expect 5*n\n", - "passed symbolic cost check :D\n" - ] - } - ], + "outputs": [], "source": [ "check_no_phase_change(cadd)\n", "check_symbolic_cost(qma.CModAdd(QMontgomeryUInt(symbolic_n), symbolic_mod), 5 * symbolic_n)" From 5c27ed18740b14932e0e28b15f9448d39cceb67e Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 28 Jan 2025 14:40:59 -0800 Subject: [PATCH 5/5] nit --- .../qualtran_modular_arithmetics.ipynb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb b/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb index f105b873b7..9933691522 100644 --- a/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb +++ b/qualtran/bloqs/mod_arithmetic/qualtran_modular_arithmetics.ipynb @@ -23,15 +23,15 @@ "\n", "| operation | Bloq | Qualtran Toffoli Cost | Toffoli Cost From [Figure 8](https://arxiv.org/abs/2306.08585) | references |\n", "|:-------------------------------|:-----------------------------------------------------------------------------------|:--------------------------|:-----------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n", - "| modular addition | `qualtran.bloqs.mod_arithmetic.mod_addition.ModAdd` | $4 n - 1$ | $4 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular controlled addition | `qualtran.bloqs.mod_arithmetic.mod_addition.CModAdd` | $5 n + 1$ | $5 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular negation | `qualtran.bloqs.mod_arithmetic.mod_subtraction.ModNeg` | $3 n - 3$ | $2 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular controlled negation | `qualtran.bloqs.mod_arithmetic.mod_subtraction.CModNeg` | $3 n - 2$ | $3 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular subtraction | `qualtran.bloqs.mod_arithmetic.mod_subtraction.ModSub` | $6 n - 3$ | $6 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular controlled subtraction | `qualtran.bloqs.mod_arithmetic.mod_subtraction.CModSub` | $7 n - 1$ | $7 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular doubling | `qualtran.bloqs.mod_arithmetic.mod_multiplication.ModDbl` | $2 n + 1$ | $2 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular multiplication | `qualtran.bloqs.mod_arithmetic.mod_multiplication.DirtyOutOfPlaceMontgomeryModMul` | $2.25 n^{2} +$$ 7.25 n - 1$ | $2.25 n^{2} + 9 n$ | - [Performance Analysis of a Repetition Cat Code Architecture: Computing 256-bit Elliptic Curve Logarithm in 9 Hours with 126 133 Cat Qubits](https://arxiv.org/abs/2302.06639)
- [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", - "| modular multiplicative inverse | `qualtran.bloqs.mod_arithmetic.mod_division.KaliskiModInverse` | $26 n^{2} + 9 n - 1$ | $26 n^{2} + 2 n$ | - [Performance Analysis of a Repetition Cat Code Architecture: Computing 256-bit Elliptic Curve Logarithm in 9 Hours with 126 133 Cat Qubits](https://arxiv.org/abs/2302.06639)
- [Improved quantum circuits for elliptic curve discrete logarithms](https://arxiv.org/abs/2001.09580)
- [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular addition | `ModAdd` | $4 n - 1$ | $4 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular controlled addition | `CModAdd` | $5 n + 1$ | $5 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular negation | `ModNeg` | $3 n - 3$ | $2 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular controlled negation | `CModNeg` | $3 n - 2$ | $3 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular subtraction | `ModSub` | $6 n - 3$ | $6 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular controlled subtraction | `CModSub` | $7 n - 1$ | $7 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular doubling | `ModDbl` | $2 n + 1$ | $2 n$ | [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular multiplication | `DirtyOutOfPlaceMontgomeryModMul` | $2.25 n^{2} +$$ 7.25 n - 1$ | $2.25 n^{2} + 9 n$ | - [Performance Analysis of a Repetition Cat Code Architecture: Computing 256-bit Elliptic Curve Logarithm in 9 Hours with 126 133 Cat Qubits](https://arxiv.org/abs/2302.06639)
- [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", + "| modular multiplicative inverse | `KaliskiModInverse` | $26 n^{2} + 9 n - 1$ | $26 n^{2} + 2 n$ | - [Performance Analysis of a Repetition Cat Code Architecture: Computing 256-bit Elliptic Curve Logarithm in 9 Hours with 126 133 Cat Qubits](https://arxiv.org/abs/2302.06639)
- [Improved quantum circuits for elliptic curve discrete logarithms](https://arxiv.org/abs/2001.09580)
- [How to compute a 256-bit elliptic curve private key with only 50 million Toffoli gates](https://arxiv.org/abs/2306.08585) |\n", "\n", "\n", "\n", @@ -91,7 +91,7 @@ "\n", "from qualtran import QMontgomeryUInt\n", "from qualtran.drawing import show_bloq, show_call_graph\n", - "import qualtran.bloqs.mod_arithmetic as qma\n", + "import as qma\n", "from qualtran.resource_counting import get_cost_value, QECGatesCost" ] },