From 0a220e099641819d40e78462398d2d22ff5be365 Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 29 Apr 2025 17:20:16 -0700 Subject: [PATCH 1/4] relax the restriction no the bitsize of DirtyOutOfPlaceMontgomeryModMul --- .../mod_arithmetic/mod_multiplication.py | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py index c0242f973..c27183b18 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py +++ b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py @@ -586,10 +586,14 @@ def __attrs_post_init__(self): assert self.mod > 1 and self.mod % 2 == 1 # Must be an odd integer greater than 1. if isinstance(self.mod, int) and isinstance(self.bitsize, int): - assert 2 * self.mod - 1 < 2**self.bitsize, f'bitsize={self.bitsize} is too small' + assert self.mod - 1 < 2**self.bitsize, f'bitsize={self.bitsize} is too small' if isinstance(self.window_size, int) and isinstance(self.bitsize, int): - assert self.bitsize % self.window_size == 0 + assert (self.bitsize + self._add_extra_qubit) % self.window_size == 0 + + @cached_property + def _add_extra_qubit(self): + return 2*self.mod - 1 >= 2**self.bitsize @cached_property def signature(self) -> 'Signature': @@ -656,7 +660,7 @@ def on_classical_vals( if self.uncompute: assert ( target is not None - and target == (x * y * pow(2, self.bitsize * (self.mod - 2), self.mod)) % self.mod + and target == (x * y * pow(2, (self.bitsize + self._add_extra_qubit) * (self.mod - 2), self.mod)) % self.mod ) assert qrom_indices is not None assert reduced is not None @@ -671,20 +675,20 @@ def on_classical_vals( target = 0 qrom_indices = 0 reduced = 0 - for i in range(0, self.bitsize, self.window_size): + for i in range(0, self.bitsize + self._add_extra_qubit, self.window_size): target, qrom_indices = self._classical_action_window(x >> i, y, target, qrom_indices) if target >= self.mod: target -= self.mod reduced = 1 - montgomery_prod = (x * y * pow(2, self.bitsize * (self.mod - 2), self.mod)) % self.mod + montgomery_prod = (x * y * pow(2, (self.bitsize + self._add_extra_qubit)* (self.mod - 2), self.mod)) % self.mod assert target == montgomery_prod return {'x': x, 'y': y, 'target': target, 'qrom_indices': qrom_indices, 'reduced': reduced} @cached_property def _mod_mul_impl(self) -> Bloq: - b: Bloq = _DirtyOutOfPlaceMontgomeryModMulImpl(self.bitsize, self.window_size, self.mod) + b: Bloq = _DirtyOutOfPlaceMontgomeryModMulImpl(self.bitsize + self._add_extra_qubit, self.window_size, self.mod) if self.uncompute: b = b.adjoint() return b @@ -703,6 +707,11 @@ def build_composite_bloq( assert qrom_indices is not None assert reduced is not None + if self._add_extra_qubit: + x = bb.join([x, bb.allocate(1, QMontgomeryUInt(1))]) + y = bb.join([x, bb.allocate(y, QMontgomeryUInt(1))]) + target = bb.join([x, bb.allocate(target, QMontgomeryUInt(1))]) + x, y, target, qrom_indices, reduced = bb.add_from( # type: ignore self._mod_mul_impl, x=x, @@ -718,6 +727,10 @@ def build_composite_bloq( return {'x': x, 'y': y} target = bb.allocate(self.bitsize, QMontgomeryUInt(self.bitsize)) + if self._add_extra_qubit: + x = bb.join([x, bb.allocate(1, QMontgomeryUInt(1))]) + y = bb.join([x, bb.allocate(y, QMontgomeryUInt(1))]) + target = bb.join([x, bb.allocate(target, QMontgomeryUInt(1))]) num_windows = (self.bitsize + self.window_size - 1) // self.window_size qrom_indices = bb.allocate( num_windows * self.window_size, QMontgomeryUInt(num_windows * self.window_size) @@ -727,6 +740,21 @@ def build_composite_bloq( x, y, target, qrom_indices, reduced = bb.add_from( self._mod_mul_impl, x=x, y=y, target=target, qrom_indices=qrom_indices, reduced=reduced ) + + if self._add_extra_qubit: + x_arr = bb.split(x) + bb.free(x_arr[0]) + x = bb.join(x_arr[1:]) + + y_arr = bb.split(y) + bb.free(y_arr[0]) + y = bb.join(y_arr[1:]) + + target_arr = bb.split(target) + bb.free(target_arr[0]) + target = bb.join(target_arr[1:]) + + return {'x': x, 'y': y, 'target': target, 'qrom_indices': qrom_indices, 'reduced': reduced} def build_call_graph( From aa6d21c495c75f9c46b7b7e2740a41b35d57c742 Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 29 Apr 2025 17:27:40 -0700 Subject: [PATCH 2/4] nit --- .../mod_arithmetic/mod_multiplication.py | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py index c27183b18..e5b40a9c5 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py +++ b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py @@ -593,7 +593,7 @@ def __attrs_post_init__(self): @cached_property def _add_extra_qubit(self): - return 2*self.mod - 1 >= 2**self.bitsize + return self.mod - 1 >= 2**self.bitsize @cached_property def signature(self) -> 'Signature': @@ -660,7 +660,13 @@ def on_classical_vals( if self.uncompute: assert ( target is not None - and target == (x * y * pow(2, (self.bitsize + self._add_extra_qubit) * (self.mod - 2), self.mod)) % self.mod + and target + == ( + x + * y + * pow(2, (self.bitsize + self._add_extra_qubit) * (self.mod - 2), self.mod) + ) + % self.mod ) assert qrom_indices is not None assert reduced is not None @@ -682,13 +688,17 @@ def on_classical_vals( target -= self.mod reduced = 1 - montgomery_prod = (x * y * pow(2, (self.bitsize + self._add_extra_qubit)* (self.mod - 2), self.mod)) % self.mod + montgomery_prod = ( + x * y * pow(2, (self.bitsize + self._add_extra_qubit) * (self.mod - 2), self.mod) + ) % self.mod assert target == montgomery_prod return {'x': x, 'y': y, 'target': target, 'qrom_indices': qrom_indices, 'reduced': reduced} @cached_property def _mod_mul_impl(self) -> Bloq: - b: Bloq = _DirtyOutOfPlaceMontgomeryModMulImpl(self.bitsize + self._add_extra_qubit, self.window_size, self.mod) + b: Bloq = _DirtyOutOfPlaceMontgomeryModMulImpl( + self.bitsize + self._add_extra_qubit, self.window_size, self.mod + ) if self.uncompute: b = b.adjoint() return b @@ -708,9 +718,9 @@ def build_composite_bloq( assert reduced is not None if self._add_extra_qubit: - x = bb.join([x, bb.allocate(1, QMontgomeryUInt(1))]) - y = bb.join([x, bb.allocate(y, QMontgomeryUInt(1))]) - target = bb.join([x, bb.allocate(target, QMontgomeryUInt(1))]) + x = bb.join([x, bb.allocate(1, dtype=QMontgomeryUInt(1))]) + y = bb.join([y, bb.allocate(1, dtype=QMontgomeryUInt(1))]) + target = bb.join([target, bb.allocate(1, dtype=QMontgomeryUInt(1))]) x, y, target, qrom_indices, reduced = bb.add_from( # type: ignore self._mod_mul_impl, @@ -728,9 +738,9 @@ def build_composite_bloq( target = bb.allocate(self.bitsize, QMontgomeryUInt(self.bitsize)) if self._add_extra_qubit: - x = bb.join([x, bb.allocate(1, QMontgomeryUInt(1))]) - y = bb.join([x, bb.allocate(y, QMontgomeryUInt(1))]) - target = bb.join([x, bb.allocate(target, QMontgomeryUInt(1))]) + x = bb.join([x, bb.allocate(1, dtype=QMontgomeryUInt(1))]) + y = bb.join([y, bb.allocate(1, dtype=QMontgomeryUInt(1))]) + target = bb.join([target, bb.allocate(1, dtype=QMontgomeryUInt(1))]) num_windows = (self.bitsize + self.window_size - 1) // self.window_size qrom_indices = bb.allocate( num_windows * self.window_size, QMontgomeryUInt(num_windows * self.window_size) @@ -742,19 +752,18 @@ def build_composite_bloq( ) if self._add_extra_qubit: - x_arr = bb.split(x) + x_arr = bb.split(x) # type: ignore[arg-type] bb.free(x_arr[0]) x = bb.join(x_arr[1:]) - - y_arr = bb.split(y) + + y_arr = bb.split(y) # type: ignore[arg-type] bb.free(y_arr[0]) y = bb.join(y_arr[1:]) - target_arr = bb.split(target) + target_arr = bb.split(target) # type: ignore[arg-type] bb.free(target_arr[0]) target = bb.join(target_arr[1:]) - return {'x': x, 'y': y, 'target': target, 'qrom_indices': qrom_indices, 'reduced': reduced} def build_call_graph( From 6c5d85ae52f3caa63f7207d7cd2b5222f76f082f Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 29 Apr 2025 17:29:02 -0700 Subject: [PATCH 3/4] nit --- qualtran/bloqs/mod_arithmetic/mod_multiplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py index e5b40a9c5..e4ccdde5e 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py +++ b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py @@ -593,7 +593,7 @@ def __attrs_post_init__(self): @cached_property def _add_extra_qubit(self): - return self.mod - 1 >= 2**self.bitsize + return 2*self.mod - 2 >= 2**self.bitsize @cached_property def signature(self) -> 'Signature': From 561b19907c50cd052ac507a659a412ca5538f7da Mon Sep 17 00:00:00 2001 From: Nour Yosri Date: Tue, 29 Apr 2025 17:32:39 -0700 Subject: [PATCH 4/4] format --- qualtran/bloqs/mod_arithmetic/mod_multiplication.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py index e4ccdde5e..84cd0232d 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_multiplication.py +++ b/qualtran/bloqs/mod_arithmetic/mod_multiplication.py @@ -593,7 +593,7 @@ def __attrs_post_init__(self): @cached_property def _add_extra_qubit(self): - return 2*self.mod - 2 >= 2**self.bitsize + return 2 * self.mod - 2 >= 2**self.bitsize @cached_property def signature(self) -> 'Signature':