Skip to content

Commit

Permalink
HammingWeightCompute: replace ArbitraryClifford with CNOT, support sy…
Browse files Browse the repository at this point in the history
…mbolic bitsizes (#1355)

* replace ArbitraryClifford with CNOT, support symbolic bitsizes

* cleanup __pow__ (GWR handles this case)

* address comments

* slight cleanup
  • Loading branch information
anurudhp authored Aug 28, 2024
1 parent bfa5bc1 commit f28481c
Showing 1 changed file with 25 additions and 16 deletions.
41 changes: 25 additions & 16 deletions qualtran/bloqs/arithmetic/hamming_weight.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -49,20 +50,35 @@ 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()
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),
]
)

@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"""
# 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()

def pretty_name(self) -> str:
return "out = x.bit_count()"

Expand Down Expand Up @@ -102,13 +118,6 @@ 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)}

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.")
num_and = self.junk_bitsize
num_cnot = num_and * 5 + self.bit_count_of_bitsize
return {(And(), num_and), (CNOT(), num_cnot)}

0 comments on commit f28481c

Please sign in to comment.