Skip to content

Create a Bloq that represents initialization in the Coset representation #1602

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions dev_tools/qualtran_dev_tools/notebook_specs.py
Original file line number Diff line number Diff line change
@@ -564,6 +564,13 @@
qualtran.bloqs.cryptography.ecc.ec_add_r._EC_WINDOW_ADD_BLOQ_DOC,
],
),
NotebookSpecV2(
title='Coset Representation',
module=qualtran.bloqs.mod_arithmetic.coset_representation,
bloq_specs=[
qualtran.bloqs.mod_arithmetic.coset_representation._INIT_COST_REPRESENTATION_DOC
],
),
]

GF_ARITHMETIC = [
1 change: 1 addition & 0 deletions docs/bloqs/index.rst
Original file line number Diff line number Diff line change
@@ -94,6 +94,7 @@ Bloqs Library
cryptography/rsa/rsa.ipynb
cryptography/ecc/ec_add.ipynb
cryptography/ecc/ecc.ipynb
mod_arithmetic/coset_representation.ipynb

.. toctree::
:maxdepth: 2
1 change: 1 addition & 0 deletions qualtran/bloqs/mod_arithmetic/__init__.py
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from .coset_representation import InitCosetRepresntation
from .mod_addition import CModAdd, CModAddK, CtrlScaleModAdd, ModAdd, ModAddK
from .mod_division import KaliskiModInverse
from .mod_multiplication import CModMulK, DirtyOutOfPlaceMontgomeryModMul, ModDbl
159 changes: 159 additions & 0 deletions qualtran/bloqs/mod_arithmetic/coset_representation.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "2feee875",
"metadata": {
"cq.autogen": "title_cell"
},
"source": [
"# Coset Representation"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4e5b47c0",
"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": "521a3742",
"metadata": {
"cq.autogen": "InitCosetRepresntation.bloq_doc.md"
},
"source": [
"## `InitCosetRepresntation`\n",
"A state initialization of an integer in the coset representation.\n",
"\n",
"The cost representation of an integer $k$ modulo $N$ with $c_{pad}$ bits is defined as\n",
"$$\n",
" \\frac{1}{\\sqrt{2^{c_{pad}}}}\\sum_{j=0}^{2^{c_{pad}}} \\ket{jN + k}\n",
"$$\n",
"\n",
"This bloq can be built of only clifford gates ... namely $c_{pad}$ `H` gates on the padding\n",
"qubitsfollowed by `CNOT` gates implementing the reversible operation $jN+k$.\n",
"\n",
"#### Parameters\n",
" - `c_pad`: The number of padding bits.\n",
" - `k_bitsize`: The number of bits used to represent $k$ ($\\geq$ the number of bits of $k$ and $N$).\n",
" - `k`: The value of $k$.\n",
" - `mod`: The value of $N$. \n",
"\n",
"#### Registers\n",
" - `x`: A k_bitsize+c_pad register output register containing the initialized state. \n",
"\n",
"#### References\n",
" - - [Shor's algorithm with fewer (pure) qubits](https://arxiv.org/abs/quant-ph/0601097) section 4. - [How to factor 2048 bit RSA integers in 8 hours using 20 million noisy qubits](https://arxiv.org/abs/1905.09749) section 2.4\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ecf59588",
"metadata": {
"cq.autogen": "InitCosetRepresntation.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.mod_arithmetic import InitCosetRepresntation"
]
},
{
"cell_type": "markdown",
"id": "e8233189",
"metadata": {
"cq.autogen": "InitCosetRepresntation.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "fcbe6508",
"metadata": {
"cq.autogen": "InitCosetRepresntation.init_coset_representation"
},
"outputs": [],
"source": [
"c_pad, k_bitsize = sympy.symbols('c k')\n",
"init_coset_representation = InitCosetRepresntation(c_pad, k_bitsize, k=1, mod=19)"
]
},
{
"cell_type": "markdown",
"id": "76acaa4c",
"metadata": {
"cq.autogen": "InitCosetRepresntation.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9859906c",
"metadata": {
"cq.autogen": "InitCosetRepresntation.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([init_coset_representation],\n",
" ['`init_coset_representation`'])"
]
},
{
"cell_type": "markdown",
"id": "b7764566",
"metadata": {
"cq.autogen": "InitCosetRepresntation.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bce29566",
"metadata": {
"cq.autogen": "InitCosetRepresntation.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"init_coset_representation_g, init_coset_representation_sigma = init_coset_representation.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(init_coset_representation_g)\n",
"show_counts_sigma(init_coset_representation_sigma)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
86 changes: 86 additions & 0 deletions qualtran/bloqs/mod_arithmetic/coset_representation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright 2025 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 TYPE_CHECKING

import attrs
import sympy

from qualtran import Bloq, bloq_example, BloqDocSpec, QUInt, Register, Side, Signature
from qualtran.bloqs.basic_gates import CNOT, Hadamard
from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator

if TYPE_CHECKING:
from qualtran.symbolics import SymbolicInt


@attrs.frozen
class InitCosetRepresntation(Bloq):
r"""A state initialization of an integer in the coset representation.

The cost representation of an integer $k$ modulo $N$ with $c_{pad}$ bits is defined as
$$
\frac{1}{\sqrt{2^{c_{pad}}}}\sum_{j=0}^{2^{c_{pad}}} \ket{jN + k}
$$

This bloq can be built of only clifford gates ... namely $c_{pad}$ `H` gates on the padding
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comma instead of ellipses (...)

qubitsfollowed by `CNOT` gates implementing the reversible operation $jN+k$.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing space


Args:
c_pad: The number of padding bits.
k_bitsize: The number of bits used to represent $k$ ($\geq$ the number of bits of $k$ and $N$).
k: The value of $k$.
mod: The value of $N$.

Registers:
x: A k_bitsize+c_pad register output register containing the initialized state.

References:
- [Shor's algorithm with fewer (pure) qubits](https://arxiv.org/abs/quant-ph/0601097)
section 4.
- [How to factor 2048 bit RSA integers in 8 hours using 20 million noisy qubits](https://arxiv.org/abs/1905.09749)
section 2.4
Comment on lines +51 to +54
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reference format: use newline to separate entries. Don't use -. Include author and year

"""

c_pad: 'SymbolicInt'
k_bitsize: 'SymbolicInt'
k: 'SymbolicInt'
mod: 'SymbolicInt'

@cached_property
def signature(self) -> 'Signature':
return Signature([Register('x', QUInt(self.c_pad + self.k_bitsize), side=Side.RIGHT)])

def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT':
bitsize = self.k_bitsize + self.c_pad
return {
Hadamard(): self.c_pad,
# The matrix representing the reversible operation $jN+x$ consists of 0s and 1s.
# Thus it can be implemented using CNOTs using LUP decomposition or Gaussian elemenation
# utilizing at most $n(n-1)$ CNOTs.
CNOT(): bitsize * (bitsize - 1),
}


@bloq_example
def _init_coset_representation() -> InitCosetRepresntation:
c_pad, k_bitsize = sympy.symbols('c k')
init_coset_representation = InitCosetRepresntation(c_pad, k_bitsize, k=1, mod=19)
return init_coset_representation


_INIT_COST_REPRESENTATION_DOC = BloqDocSpec(
bloq_cls=InitCosetRepresntation, examples=[_init_coset_representation]
)
43 changes: 43 additions & 0 deletions qualtran/bloqs/mod_arithmetic/coset_representation_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright 2025 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
import sympy

import qualtran.testing as qlt_testing
from qualtran.bloqs.mod_arithmetic.coset_representation import (
_init_coset_representation,
InitCosetRepresntation,
)
from qualtran.resource_counting import get_cost_value, QECGatesCost


def test_init_cost_representation_cost():
sym_vars = sympy.symbols('c n k N')
c, n, k, N = sym_vars
blq = InitCosetRepresntation(c, n, k, N)
cost = get_cost_value(blq, QECGatesCost())
assert cost.total_toffoli_only() == 0
resolver = {v: 10**4 for v in sym_vars}
upper_bound = (c + n) * (c + n - 1) + c
assert cost.clifford.subs(resolver) <= upper_bound.subs(resolver) # type: ignore[union-attr]


def test_init_coset_representation(bloq_autotester):
bloq_autotester(_init_coset_representation)


@pytest.mark.notebook
def test_notebook():
qlt_testing.execute_notebook('coset_representation')
1 change: 1 addition & 0 deletions qualtran/serialization/resolver_dict.py
Original file line number Diff line number Diff line change
@@ -342,6 +342,7 @@
"qualtran.bloqs.data_loading.qroam_clean.QROAMCleanAdjoint": qualtran.bloqs.data_loading.qroam_clean.QROAMCleanAdjoint,
"qualtran.bloqs.data_loading.qroam_clean.QROAMCleanAdjointWrapper": qualtran.bloqs.data_loading.qroam_clean.QROAMCleanAdjointWrapper,
"qualtran.bloqs.data_loading.select_swap_qrom.SelectSwapQROM": qualtran.bloqs.data_loading.select_swap_qrom.SelectSwapQROM,
"qualtran.bloqs.mod_arithmetic.coset_representation.InitCosetRepresntation": qualtran.bloqs.mod_arithmetic.coset_representation.InitCosetRepresntation,
"qualtran.bloqs.mod_arithmetic.CModAddK": qualtran.bloqs.mod_arithmetic.CModAddK,
"qualtran.bloqs.mod_arithmetic.mod_addition.ModAdd": qualtran.bloqs.mod_arithmetic.mod_addition.ModAdd,
"qualtran.bloqs.mod_arithmetic.mod_addition.CModAdd": qualtran.bloqs.mod_arithmetic.mod_addition.CModAdd,