Skip to content

Commit 20069b3

Browse files
Create ModNeg and CModNeg (#1300)
1 parent 1be9e26 commit 20069b3

11 files changed

Lines changed: 674 additions & 71 deletions

File tree

dev_tools/autogenerate-bloqs-notebooks-v2.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,14 @@
499499
qualtran.bloqs.mod_arithmetic.mod_addition._C_MOD_ADD_DOC,
500500
],
501501
),
502+
NotebookSpecV2(
503+
title='Modular Subtraction',
504+
module=qualtran.bloqs.mod_arithmetic.mod_subtraction,
505+
bloq_specs=[
506+
qualtran.bloqs.mod_arithmetic.mod_subtraction._MOD_NEG_DOC,
507+
qualtran.bloqs.mod_arithmetic.mod_subtraction._CMOD_NEG_DOC,
508+
],
509+
),
502510
NotebookSpecV2(
503511
title='Modular Multiplication',
504512
module=qualtran.bloqs.factoring.mod_mul,

docs/bloqs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Bloqs Library
8080
:caption: Modular Arithmetic:
8181

8282
mod_arithmetic/mod_addition.ipynb
83+
mod_arithmetic/mod_subtraction.ipynb
8384
factoring/mod_mul.ipynb
8485
factoring/mod_exp.ipynb
8586
factoring/ecc/ec_add.ipynb

qualtran/bloqs/factoring/ecc/ec_add.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,8 @@
1919

2020
from qualtran import Bloq, bloq_example, BloqDocSpec, QUInt, Register, Signature
2121
from qualtran.bloqs.arithmetic._shims import MultiCToffoli
22-
from qualtran.bloqs.mod_arithmetic import CModAdd, ModAdd
23-
from qualtran.bloqs.mod_arithmetic._shims import (
24-
CModNeg,
25-
CModSub,
26-
ModDbl,
27-
ModInv,
28-
ModMul,
29-
ModNeg,
30-
ModSub,
31-
)
22+
from qualtran.bloqs.mod_arithmetic import CModAdd, CModNeg, ModAdd, ModNeg
23+
from qualtran.bloqs.mod_arithmetic._shims import CModSub, ModDbl, ModInv, ModMul, ModSub
3224
from qualtran.resource_counting import BloqCountT, SympySymbolAllocator
3325

3426

@@ -80,8 +72,8 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
8072
(CModAdd(QUInt(self.n), mod=self.mod), 2),
8173
(ModSub(n=self.n, mod=self.mod), 2),
8274
(CModSub(n=self.n, mod=self.mod), 4),
83-
(ModNeg(n=self.n, mod=self.mod), 2),
84-
(CModNeg(n=self.n, mod=self.mod), 1),
75+
(ModNeg(QUInt(self.n), mod=self.mod), 2),
76+
(CModNeg(QUInt(self.n), mod=self.mod), 1),
8577
(ModDbl(n=self.n, mod=self.mod), 2),
8678
(ModMul(n=self.n, mod=self.mod), 10),
8779
(ModInv(n=self.n, mod=self.mod), 4),

qualtran/bloqs/factoring/mod_sub.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515
from functools import cached_property
16-
from typing import Dict, Set, TYPE_CHECKING
16+
from typing import Dict, Set, TYPE_CHECKING, Union
1717

1818
from attrs import frozen
1919

@@ -22,6 +22,7 @@
2222
from qualtran.bloqs.basic_gates import CNOT, XGate
2323
from qualtran.bloqs.mcmt import MultiControlX
2424
from qualtran.bloqs.mod_arithmetic import ModAdd
25+
from qualtran.symbolics import HasLength
2526

2627
if TYPE_CHECKING:
2728
from qualtran import BloqBuilder
@@ -183,13 +184,14 @@ def pretty_name(self) -> str:
183184
return f'x = -x mod {self.p}'
184185

185186
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
186-
if not isinstance(self.bitsize, int):
187-
raise NotImplementedError(f'symbolic call graph is not supported for {self}')
188-
189-
# TODO: support symbolic cost
187+
cvs: Union[list[int], HasLength]
188+
if isinstance(self.bitsize, int):
189+
cvs = [0] * self.bitsize
190+
else:
191+
cvs = HasLength(self.bitsize)
190192
return {
191193
(XGate(), 2),
192-
(MultiControlX(cvs=[0] * self.bitsize), 2),
194+
(MultiControlX(cvs=cvs), 2),
193195
(CNOT(), self.bitsize),
194196
(AddK(bitsize=self.bitsize, k=self.p + 1, cvs=(1,), signed=False), 1),
195197
}

qualtran/bloqs/factoring/mod_sub_test.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import sympy
1717

1818
from qualtran.bloqs.factoring.mod_sub import MontgomeryModNeg, MontgomeryModSub
19+
from qualtran.resource_counting import get_cost_value, QECGatesCost
1920
from qualtran.resource_counting.generalizers import ignore_alloc_free, ignore_split_join
2021
from qualtran.testing import assert_equivalent_bloq_counts, assert_valid_bloq_decomposition
2122

@@ -71,3 +72,12 @@ def test_classical_action_mod_neg(bitsize, prime):
7172
valid_range = range(prime)
7273
for x in valid_range:
7374
assert b.call_classically(x=x) == cb.call_classically(x=x) == ((-x) % prime,)
75+
76+
77+
def test_montgomerymodneg_symbolic_cost():
78+
n = sympy.Symbol('n')
79+
p = 13
80+
b = MontgomeryModNeg(n, p)
81+
cost = get_cost_value(b, QECGatesCost()).total_t_and_ccz_count()
82+
assert cost['n_t'] == 0
83+
assert cost['n_ccz'] == 3 * (n - 1)

qualtran/bloqs/mod_arithmetic/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from ._shims import CModNeg, CModSub, ModDbl, ModInv, ModMul, ModNeg, ModSub
15+
from ._shims import CModSub, ModDbl, ModInv, ModMul, ModSub
1616
from .mod_addition import CModAdd, CModAddK, CtrlScaleModAdd, ModAdd, ModAddK
17+
from .mod_subtraction import CModNeg, ModNeg

qualtran/bloqs/mod_arithmetic/_shims.py

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -207,55 +207,3 @@ def wire_symbol(
207207
elif reg.name == 'out':
208208
return TextBox('$2x$')
209209
raise ValueError(f'Unrecognized register name {reg.name}')
210-
211-
212-
@frozen
213-
class ModNeg(Bloq):
214-
n: int
215-
mod: int
216-
217-
@cached_property
218-
def signature(self) -> 'Signature':
219-
return Signature([Register('x', QUInt(self.n))])
220-
221-
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
222-
# litinski
223-
return {
224-
(MultiCToffoli(self.n), 2),
225-
(CNOT(), self.n),
226-
(AddK(self.n, k=self.mod).controlled(), 1),
227-
}
228-
229-
def wire_symbol(
230-
self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple()
231-
) -> 'WireSymbol':
232-
if reg is None:
233-
return Text("")
234-
if reg.name == 'x':
235-
return TextBox('$-x$')
236-
raise ValueError(f'Unrecognized register name {reg.name}')
237-
238-
239-
@frozen
240-
class CModNeg(Bloq):
241-
n: int
242-
mod: int
243-
244-
@cached_property
245-
def signature(self) -> 'Signature':
246-
return Signature([Register('ctrl', QBit()), Register('x', QUInt(self.n))])
247-
248-
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
249-
# Roetteler
250-
return {(Toffoli(), ceil(8 * self.n * log2(self.n) - 14.5 * self.n))}
251-
252-
def wire_symbol(
253-
self, reg: Optional['Register'], idx: Tuple[int, ...] = tuple()
254-
) -> 'WireSymbol':
255-
if reg is None:
256-
return Text("")
257-
if reg.name == 'ctrl':
258-
return Circle()
259-
elif reg.name == 'x':
260-
return TextBox('$-x$')
261-
raise ValueError(f'Unrecognized register name {reg.name}')

0 commit comments

Comments
 (0)