Skip to content

Commit

Permalink
Add GF2AddK for in place addition of a constant over GF(2^m)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanujkhattar committed Oct 7, 2024
1 parent 43d185a commit 94b9a8a
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 0 deletions.
6 changes: 6 additions & 0 deletions dev_tools/autogenerate-bloqs-notebooks-v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
import qualtran.bloqs.data_loading.select_swap_qrom
import qualtran.bloqs.factoring.ecc
import qualtran.bloqs.factoring.mod_exp
import qualtran.bloqs.gf_arithmetic.gf2_add_k
import qualtran.bloqs.gf_arithmetic.gf2_addition
import qualtran.bloqs.gf_arithmetic.gf2_inverse
import qualtran.bloqs.gf_arithmetic.gf2_multiplication
Expand Down Expand Up @@ -569,6 +570,11 @@
module=qualtran.bloqs.gf_arithmetic.gf2_addition,
bloq_specs=[qualtran.bloqs.gf_arithmetic.gf2_addition._GF2_ADDITION_DOC],
),
NotebookSpecV2(
title='GF($2^m$) Add Constant',
module=qualtran.bloqs.gf_arithmetic.gf2_add_k,
bloq_specs=[qualtran.bloqs.gf_arithmetic.gf2_add_k._GF2_ADD_K_DOC],
),
NotebookSpecV2(
title='GF($2^m$) Square',
module=qualtran.bloqs.gf_arithmetic.gf2_square,
Expand Down
1 change: 1 addition & 0 deletions docs/bloqs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Bloqs Library

gf_arithmetic/gf2_multiplication.ipynb
gf_arithmetic/gf2_addition.ipynb
gf_arithmetic/gf2_add_k.ipynb
gf_arithmetic/gf2_square.ipynb
gf_arithmetic/gf2_inverse.ipynb

Expand Down
168 changes: 168 additions & 0 deletions qualtran/bloqs/gf_arithmetic/gf2_add_k.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "b02daa35",
"metadata": {
"cq.autogen": "title_cell"
},
"source": [
"# GF($2^m$) Add Constant"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c57ce930",
"metadata": {
"cq.autogen": "top_imports"
},
"outputs": [],
"source": [
"from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register\n",
"from qualtran import QBit, QInt, QUInt, QAny\n",
"from qualtran.drawing import show_bloq, show_call_graph, show_counts_sigma\n",
"from typing import *\n",
"import numpy as np\n",
"import sympy\n",
"import cirq"
]
},
{
"cell_type": "markdown",
"id": "e4620511",
"metadata": {
"cq.autogen": "GF2AddK.bloq_doc.md"
},
"source": [
"## `GF2AddK`\n",
"In place addition of a constant $k$ for elements in GF($2^m$).\n",
"\n",
"The bloq implements in place addition of a classical constant $k$ and a quantum register\n",
"$|x\\rangle$ storing elements from GF($2^m$). Addition in GF($2^m$) simply reduces to a component\n",
"wise XOR, which can be implemented via X gates.\n",
"\n",
" $$\n",
" |x\\rangle \\rightarrow |x + k\\rangle\n",
" $$\n",
"\n",
"#### Parameters\n",
" - `bitsize`: The degree $m$ of the galois field GF($2^m$). Also corresponds to the number of qubits in the input register x.\n",
" - `k`: Integer representation of constant over GF($2^m$) that should be added to the input register x. \n",
"\n",
"#### Registers\n",
" - `x`: Input THRU register of size $m$ that stores elements from $GF(2^m)$.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "04dc8f2b",
"metadata": {
"cq.autogen": "GF2AddK.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.gf_arithmetic import GF2AddK"
]
},
{
"cell_type": "markdown",
"id": "a0d774d4",
"metadata": {
"cq.autogen": "GF2AddK.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0588ca5b",
"metadata": {
"cq.autogen": "GF2AddK.gf16_add_k"
},
"outputs": [],
"source": [
"gf16_add_k = GF2AddK(4, 1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8250af55",
"metadata": {
"cq.autogen": "GF2AddK.gf2_add_k_symbolic"
},
"outputs": [],
"source": [
"import sympy\n",
"\n",
"m, k = sympy.symbols('m, k', positive=True, integers=True)\n",
"gf2_add_k_symbolic = GF2AddK(m, k)"
]
},
{
"cell_type": "markdown",
"id": "fe4c4550",
"metadata": {
"cq.autogen": "GF2AddK.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2374ad42",
"metadata": {
"cq.autogen": "GF2AddK.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([gf16_add_k, gf2_add_k_symbolic],\n",
" ['`gf16_add_k`', '`gf2_add_k_symbolic`'])"
]
},
{
"cell_type": "markdown",
"id": "f64d8798",
"metadata": {
"cq.autogen": "GF2AddK.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "578f0f39",
"metadata": {
"cq.autogen": "GF2AddK.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"gf16_add_k_g, gf16_add_k_sigma = gf16_add_k.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(gf16_add_k_g)\n",
"show_counts_sigma(gf16_add_k_sigma)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
106 changes: 106 additions & 0 deletions qualtran/bloqs/gf_arithmetic/gf2_add_k.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from functools import cached_property
from typing import Dict, Sequence, TYPE_CHECKING

import attrs

from qualtran import Bloq, bloq_example, BloqDocSpec, DecomposeTypeError, QGF, Register, Signature
from qualtran.bloqs.basic_gates import XGate
from qualtran.symbolics import is_symbolic, SymbolicInt

if TYPE_CHECKING:
from qualtran import BloqBuilder, Soquet
from qualtran.resource_counting import BloqCountDictT, BloqCountT, SympySymbolAllocator
from qualtran.simulation.classical_sim import ClassicalValT


@attrs.frozen
class GF2AddK(Bloq):
r"""In place addition of a constant $k$ for elements in GF($2^m$).
The bloq implements in place addition of a classical constant $k$ and a quantum register
$|x\rangle$ storing elements from GF($2^m$). Addition in GF($2^m$) simply reduces to a component
wise XOR, which can be implemented via X gates.
$$
|x\rangle \rightarrow |x + k\rangle
$$
Args:
bitsize: The degree $m$ of the galois field GF($2^m$). Also corresponds to the number of
qubits in the input register x.
k: Integer representation of constant over GF($2^m$) that should be added to the input
register x.
Registers:
x: Input THRU register of size $m$ that stores elements from $GF(2^m)$.
"""

bitsize: SymbolicInt
k: SymbolicInt

@cached_property
def signature(self) -> 'Signature':
return Signature([Register('x', dtype=self.qgf)])

@cached_property
def qgf(self) -> QGF:
return QGF(characteristic=2, degree=self.bitsize)

@cached_property
def _bits_k(self) -> Sequence[int]:
return self.qgf.to_bits(self.qgf.gf_type(self.k))

def is_symbolic(self):
return is_symbolic(self.k, self.bitsize)

def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'Soquet') -> Dict[str, 'Soquet']:
if self.is_symbolic():
raise DecomposeTypeError(f"Cannot decompose symbolic {self}")
xs = bb.split(x)

for i, bit in enumerate(self._bits_k):
if bit == 1:
xs[i] = bb.add(XGate(), q=xs[i])

x = bb.join(xs, dtype=self.qgf)

return {'x': x}

def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT':
num_flips = self.bitsize if self.is_symbolic() else sum(self._bits_k)
return {XGate(): num_flips}

def on_classical_vals(self, *, x) -> Dict[str, 'ClassicalValT']:
assert isinstance(x, self.qgf.gf_type)
return {'x': x + self.qgf.gf_type(self.k)}


@bloq_example
def _gf16_add_k() -> GF2AddK:
gf16_add_k = GF2AddK(4, 1)
return gf16_add_k


@bloq_example
def _gf2_add_k_symbolic() -> GF2AddK:
import sympy

m, k = sympy.symbols('m, k', positive=True, integers=True)
gf2_add_k_symbolic = GF2AddK(m, k)
return gf2_add_k_symbolic


_GF2_ADD_K_DOC = BloqDocSpec(bloq_cls=GF2AddK, examples=(_gf16_add_k, _gf2_add_k_symbolic))
44 changes: 44 additions & 0 deletions qualtran/bloqs/gf_arithmetic/gf2_add_k_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest
from galois import GF

from qualtran.bloqs.gf_arithmetic.gf2_add_k import _gf2_add_k_symbolic, _gf16_add_k, GF2AddK
from qualtran.testing import assert_consistent_classical_action


def test_gf16_multiplication(bloq_autotester):
bloq_autotester(_gf16_add_k)


def test_gf2_multiplication_symbolic(bloq_autotester):
bloq_autotester(_gf2_add_k_symbolic)


def test_gf2_multiplication_classical_sim_quick():
m = 2
GFM = GF(2**m)
for k in GFM.elements:
bloq = GF2AddK(m, int(k))
assert_consistent_classical_action(bloq, x=GFM.elements)


@pytest.mark.slow
@pytest.mark.parametrize('m', [3, 4, 5])
def test_gf2_multiplication_classical_sim(m):
GFM = GF(2**m)
for k in GFM.elements:
bloq = GF2AddK(m, int(k))
assert_consistent_classical_action(bloq, x=GFM.elements)
2 changes: 2 additions & 0 deletions qualtran/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ def assert_bloq_example_serializes_for_pytest(bloq_ex: BloqExample):
'symbolic_hamsim_by_gqsp',
'gf16_addition', # cannot serialize QGF
'gf2_addition_symbolic', # cannot serialize QGF
'gf16_add_k', # cannot serialize QGF
'gf2_add_k_symbolic', # cannot serialize QGF
'gf16_multiplication', # cannot serialize QGF
'gf2_multiplication_symbolic', # cannot serialize QGF
'gf16_square', # cannot serialize QGF
Expand Down

0 comments on commit 94b9a8a

Please sign in to comment.