From e484cc01df955522d7c034199061bcfd77d629f7 Mon Sep 17 00:00:00 2001 From: dobbse42 Date: Thu, 17 Oct 2024 11:24:11 +0300 Subject: [PATCH] Completed implementation of HammingWeightPhasingWithConfigurableAncilla and tests. --- .../bloqs/rotations/hamming_weight_phasing.py | 51 +++++++++++-------- .../rotations/hamming_weight_phasing_test.py | 13 ++--- .../rotations/{my_HWP_test.py => my_HWP.py} | 1 + 3 files changed, 38 insertions(+), 27 deletions(-) rename qualtran/bloqs/rotations/{my_HWP_test.py => my_HWP.py} (99%) diff --git a/qualtran/bloqs/rotations/hamming_weight_phasing.py b/qualtran/bloqs/rotations/hamming_weight_phasing.py index 1bfbe5e4b..ab775915b 100644 --- a/qualtran/bloqs/rotations/hamming_weight_phasing.py +++ b/qualtran/bloqs/rotations/hamming_weight_phasing.py @@ -227,7 +227,7 @@ class HammingWeightPhasingWithConfigurableAncilla(GateWithRegisters): """ bitsize: int - ancillasize: int + ancillasize: int # TODO: verify that ancillasize is always < bitsize-1 exponent: float = 1 eps: SymbolicFloat = 1e-10 @@ -243,34 +243,22 @@ def signature(self) -> 'Signature': HammingWeightPhasing bloqs on subsets of the input. ''' def build_composite_bloq(self, bb: 'BloqBuilder', *, x: 'SoquetT') -> Dict[str, 'SoquetT']: - self.ancillasize = min(self.ancillasize, self.bitsize-1) # TODO: this is surely the wrong way to do this, but this at least allows tests to be run for now. num_iters = self.bitsize // (self.ancillasize + 1) - remainder = self.bitsize - (self.ancillasize + 1) * num_iters + remainder = self.bitsize % (self.ancillasize+1) x = bb.split(x) x_parts = [] - for i in range(num_iters): - x_part = bb.join(x[i*(self.ancillasize+1):(i+1)*(self.ancillasize+1)], dtype=QUInt(self.ancillasize+1)) #maybe off-by-1 + x_part = bb.join(x[i*(self.ancillasize+1):(i+1)*(self.ancillasize+1)], dtype=QUInt(self.ancillasize+1)) x_part = bb.add(HammingWeightPhasing(bitsize=self.ancillasize+1, exponent=self.exponent, eps=self.eps), x=x_part) - x_part = bb.add(HammingWeightPhasing(bitsize=self.ancillasize+1, exponent=self.exponent, eps=self.eps).adjoint(), x=x_part) x_parts.extend(bb.split(x_part)) - - if remainder > 0: + if remainder > 1: x_part = bb.join(x[(-1*remainder):], dtype=QUInt(remainder)) x_part = bb.add(HammingWeightPhasing(bitsize=remainder, exponent=self.exponent, eps=self.eps), x=x_part) - x_part = bb.add(HammingWeightPhasing(bitsize=remainder, exponent=self.exponent, eps=self.eps).adjoint(), x=x_part) - x_parts.extend(bb.split(x_part)) - #print("shape prior to flatten: ", np.shape(x_parts)) - #x_parts.flatten() - ''' x_parts = [ - a - for x_part in x_parts - for a in x_part - ] - ''' - #print("shape after flatten: ", np.shape(x_parts)) - for part in x: - print("next elem: ", part) + x_parts.extend(bb.split(x_part)) + if remainder == 1: + x_part = x[-1] + x_part = bb.add(ZPowGate(exponent=self.exponent, eps=self.eps), q=x_part) + x_parts.append(x_part) x = bb.join(np.array(x_parts), dtype=QUInt(self.bitsize)) return {'x': x} @@ -281,6 +269,27 @@ def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) - return super().wire_symbol(reg, idx) + def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': + num_iters = self.bitsize // (self.ancillasize + 1) + remainder = self.bitsize - (self.ancillasize + 1) * num_iters + # TODO: Surely there is a better way of doing this + if remainder > 1: + + return { + HammingWeightPhasing(self.ancillasize+1, self.exponent, self.eps): num_iters, + HammingWeightPhasing(remainder, self.exponent, self.eps): bool(remainder), + } + elif remainder: + return { + HammingWeightPhasing(self.ancillasize+1, self.exponent, self.eps): num_iters, + ZPowGate(exponent=self.exponent, eps=self.eps): 1 + } + else: + return { + HammingWeightPhasing(self.ancillasize+1, self.exponent, self.eps): num_iters, + } + + @bloq_example def _hamming_weight_phasing_with_configurable_ancilla() -> HammingWeightPhasingWithConfigurableAncilla: hamming_weight_phasing_with_configurable_ancilla = HammingWeightPhasingWithConfigurableAncilla(4, 2, np.pi / 2.0) diff --git a/qualtran/bloqs/rotations/hamming_weight_phasing_test.py b/qualtran/bloqs/rotations/hamming_weight_phasing_test.py index 60cea4458..4b7f55857 100644 --- a/qualtran/bloqs/rotations/hamming_weight_phasing_test.py +++ b/qualtran/bloqs/rotations/hamming_weight_phasing_test.py @@ -129,9 +129,7 @@ def test_hamming_weight_phasing_via_phase_gradient_t_complexity(n: int, theta: f assert total_t < naive_total_t - -@pytest.mark.parametrize('ancillasize', [1, 2, 3, 4, 5, 6, 7]) -@pytest.mark.parametrize('n', [2, 3, 4, 5, 6, 7, 8]) +@pytest.mark.parametrize('n, ancillasize', [(n, ancillasize) for n in range(3, 9) for ancillasize in range(1, n-1)]) @pytest.mark.parametrize('theta', [1 / 10, 1 / 5, 1 / 7, np.pi / 2]) def test_hamming_weight_phasing_with_configurable_ancilla(n: int, ancillasize: int, theta: float): gate = HammingWeightPhasingWithConfigurableAncilla(n, ancillasize, theta) @@ -140,9 +138,12 @@ def test_hamming_weight_phasing_with_configurable_ancilla(n: int, ancillasize: i gate, [ignore_split_join, cirq_to_bloqs, generalize_rotation_angle] ) - assert gate.t_complexity().rotations == ceil(n / ancillasize+1) * ancillasize.bit_length() # possibly wrong - assert gate.t_complexity().t == 4 * ancillasize * ceil(n / (ancillasize+1)) - # TODO: add an ancilla size assertion + remainder = n % (ancillasize+1) + +# assert gate.t_complexity().rotations == (-(-n // (ancillasize+1))-1) * (ancillasize+1).bit_length() + remainder.bit_length() # exact, fails for remainder = 0. + assert gate.t_complexity().rotations <= (-(-n // (ancillasize+1))) * (ancillasize+1).bit_length() + remainder.bit_length() # upper bound + assert gate.t_complexity().t <= 4 * (ancillasize) * -(-n // (ancillasize+1)) + # TODO: add an assertion that number of ancilla allocated is never > ancillasize. gh = GateHelper(gate) sim = cirq.Simulator(dtype=np.complex128) diff --git a/qualtran/bloqs/rotations/my_HWP_test.py b/qualtran/bloqs/rotations/my_HWP.py similarity index 99% rename from qualtran/bloqs/rotations/my_HWP_test.py rename to qualtran/bloqs/rotations/my_HWP.py index 7709dc47d..7bc37616a 100644 --- a/qualtran/bloqs/rotations/my_HWP_test.py +++ b/qualtran/bloqs/rotations/my_HWP.py @@ -1,5 +1,6 @@ from hamming_weight_phasing import HammingWeightPhasing, HammingWeightPhasingWithConfigurableAncilla + import numpy as np from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register from qualtran import QBit, QInt, QUInt, QAny