From 0b666061de138d71dd86cc0364b1c76eb28824de Mon Sep 17 00:00:00 2001 From: Anurudh Peduri Date: Wed, 28 Aug 2024 09:57:58 -0700 Subject: [PATCH 1/4] replace ArbitraryClifford with CNOT, support symbolic bitsizes --- qualtran/bloqs/arithmetic/hamming_weight.py | 30 ++++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/qualtran/bloqs/arithmetic/hamming_weight.py b/qualtran/bloqs/arithmetic/hamming_weight.py index bcf4845c9..3cece7c5e 100644 --- a/qualtran/bloqs/arithmetic/hamming_weight.py +++ b/qualtran/bloqs/arithmetic/hamming_weight.py @@ -20,8 +20,9 @@ from numpy.typing import NDArray from qualtran import GateWithRegisters, QAny, QUInt, Register, Side, Signature -from qualtran.bloqs.bookkeeping import ArbitraryClifford +from qualtran.bloqs.basic_gates import CNOT from qualtran.bloqs.mcmt.and_bloq import And +from qualtran.symbolics import bit_length, is_symbolic, SymbolicInt if TYPE_CHECKING: from qualtran.resource_counting import BloqCountT, SympySymbolAllocator @@ -49,12 +50,12 @@ class HammingWeightCompute(GateWithRegisters): [Halving the cost of quantum addition](https://arxiv.org/abs/1709.06648), Page-4 """ - bitsize: int + bitsize: SymbolicInt @cached_property def signature(self): - jnk_size = self.bitsize - self.bitsize.bit_count() - out_size = self.bitsize.bit_length() + jnk_size = self.junk_bitsize + out_size = self.out_bitsize return Signature( [ Register('x', QUInt(self.bitsize)), @@ -63,6 +64,21 @@ def signature(self): ] ) + @cached_property + def junk_bitsize(self) -> SymbolicInt: + return self.bitsize - self.bit_count_of_bitsize + + @cached_property + def out_bitsize(self) -> SymbolicInt: + return bit_length(self.bitsize) + + @cached_property + def bit_count_of_bitsize(self) -> SymbolicInt: + """lower bound on number of 1s in bitsize""" + if is_symbolic(self.bitsize): + return 1 # worst case + return self.bitsize.bit_count() + def pretty_name(self) -> str: return "out = x.bit_count()" @@ -102,9 +118,9 @@ def decompose_from_registers( yield self._decompose_using_three_to_two_adders(x, junk, out) def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']: - num_and = self.bitsize - self.bitsize.bit_count() - num_clifford = num_and * 5 + self.bitsize.bit_count() - return {(And(), num_and), (ArbitraryClifford(n=2), num_clifford)} + num_and = self.junk_bitsize + num_clifford = num_and * 5 + self.bit_count_of_bitsize + return {(And(), num_and), (CNOT(), num_clifford)} def __pow__(self, power: int): if power == 1: From 1b72c274b026aee4a43242e38f70dfd9fedc4d05 Mon Sep 17 00:00:00 2001 From: Anurudh Peduri Date: Wed, 28 Aug 2024 10:00:22 -0700 Subject: [PATCH 2/4] cleanup __pow__ (GWR handles this case) --- qualtran/bloqs/arithmetic/hamming_weight.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/qualtran/bloqs/arithmetic/hamming_weight.py b/qualtran/bloqs/arithmetic/hamming_weight.py index 3cece7c5e..c87e11945 100644 --- a/qualtran/bloqs/arithmetic/hamming_weight.py +++ b/qualtran/bloqs/arithmetic/hamming_weight.py @@ -121,10 +121,3 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']: num_and = self.junk_bitsize num_clifford = num_and * 5 + self.bit_count_of_bitsize return {(And(), num_and), (CNOT(), num_clifford)} - - def __pow__(self, power: int): - if power == 1: - return self - if power == -1: - return self.adjoint() - raise NotImplementedError("HammingWeightCompute.__pow__ defined only for +1/-1.") From eff53d7f2d7d192e3930fd3749142034916802e0 Mon Sep 17 00:00:00 2001 From: Anurudh Peduri Date: Wed, 28 Aug 2024 10:15:57 -0700 Subject: [PATCH 3/4] address comments --- qualtran/bloqs/arithmetic/hamming_weight.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qualtran/bloqs/arithmetic/hamming_weight.py b/qualtran/bloqs/arithmetic/hamming_weight.py index c87e11945..07211e462 100644 --- a/qualtran/bloqs/arithmetic/hamming_weight.py +++ b/qualtran/bloqs/arithmetic/hamming_weight.py @@ -75,6 +75,8 @@ def out_bitsize(self) -> SymbolicInt: @cached_property def bit_count_of_bitsize(self) -> SymbolicInt: """lower bound on number of 1s in bitsize""" + # TODO https://github.com/quantumlib/Qualtran/issues/1357 + # add explicit support for symbolic functions without relying on pre-computed bounds. if is_symbolic(self.bitsize): return 1 # worst case return self.bitsize.bit_count() @@ -119,5 +121,5 @@ def decompose_from_registers( def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']: num_and = self.junk_bitsize - num_clifford = num_and * 5 + self.bit_count_of_bitsize - return {(And(), num_and), (CNOT(), num_clifford)} + num_cnot = num_and * 5 + self.bit_count_of_bitsize + return {(And(), num_and), (CNOT(), num_cnot)} From 9486725c7ab9020f87ef91b36038c69937cfae9b Mon Sep 17 00:00:00 2001 From: Anurudh Peduri Date: Wed, 28 Aug 2024 10:16:37 -0700 Subject: [PATCH 4/4] slight cleanup --- qualtran/bloqs/arithmetic/hamming_weight.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qualtran/bloqs/arithmetic/hamming_weight.py b/qualtran/bloqs/arithmetic/hamming_weight.py index 07211e462..7a004e385 100644 --- a/qualtran/bloqs/arithmetic/hamming_weight.py +++ b/qualtran/bloqs/arithmetic/hamming_weight.py @@ -54,13 +54,11 @@ class HammingWeightCompute(GateWithRegisters): @cached_property def signature(self): - jnk_size = self.junk_bitsize - out_size = self.out_bitsize return Signature( [ Register('x', QUInt(self.bitsize)), - Register('junk', QAny(jnk_size), side=Side.RIGHT), - Register('out', QUInt(out_size), side=Side.RIGHT), + Register('junk', QAny(self.junk_bitsize), side=Side.RIGHT), + Register('out', QUInt(self.out_bitsize), side=Side.RIGHT), ] )