Skip to content

Commit f28481c

Browse files
authored
HammingWeightCompute: replace ArbitraryClifford with CNOT, support symbolic bitsizes (#1355)
* replace ArbitraryClifford with CNOT, support symbolic bitsizes * cleanup __pow__ (GWR handles this case) * address comments * slight cleanup
1 parent bfa5bc1 commit f28481c

File tree

1 file changed

+25
-16
lines changed

1 file changed

+25
-16
lines changed

qualtran/bloqs/arithmetic/hamming_weight.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
from numpy.typing import NDArray
2121

2222
from qualtran import GateWithRegisters, QAny, QUInt, Register, Side, Signature
23-
from qualtran.bloqs.bookkeeping import ArbitraryClifford
23+
from qualtran.bloqs.basic_gates import CNOT
2424
from qualtran.bloqs.mcmt.and_bloq import And
25+
from qualtran.symbolics import bit_length, is_symbolic, SymbolicInt
2526

2627
if TYPE_CHECKING:
2728
from qualtran.resource_counting import BloqCountT, SympySymbolAllocator
@@ -49,20 +50,35 @@ class HammingWeightCompute(GateWithRegisters):
4950
[Halving the cost of quantum addition](https://arxiv.org/abs/1709.06648), Page-4
5051
"""
5152

52-
bitsize: int
53+
bitsize: SymbolicInt
5354

5455
@cached_property
5556
def signature(self):
56-
jnk_size = self.bitsize - self.bitsize.bit_count()
57-
out_size = self.bitsize.bit_length()
5857
return Signature(
5958
[
6059
Register('x', QUInt(self.bitsize)),
61-
Register('junk', QAny(jnk_size), side=Side.RIGHT),
62-
Register('out', QUInt(out_size), side=Side.RIGHT),
60+
Register('junk', QAny(self.junk_bitsize), side=Side.RIGHT),
61+
Register('out', QUInt(self.out_bitsize), side=Side.RIGHT),
6362
]
6463
)
6564

65+
@cached_property
66+
def junk_bitsize(self) -> SymbolicInt:
67+
return self.bitsize - self.bit_count_of_bitsize
68+
69+
@cached_property
70+
def out_bitsize(self) -> SymbolicInt:
71+
return bit_length(self.bitsize)
72+
73+
@cached_property
74+
def bit_count_of_bitsize(self) -> SymbolicInt:
75+
"""lower bound on number of 1s in bitsize"""
76+
# TODO https://github.com/quantumlib/Qualtran/issues/1357
77+
# add explicit support for symbolic functions without relying on pre-computed bounds.
78+
if is_symbolic(self.bitsize):
79+
return 1 # worst case
80+
return self.bitsize.bit_count()
81+
6682
def pretty_name(self) -> str:
6783
return "out = x.bit_count()"
6884

@@ -102,13 +118,6 @@ def decompose_from_registers(
102118
yield self._decompose_using_three_to_two_adders(x, junk, out)
103119

104120
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
105-
num_and = self.bitsize - self.bitsize.bit_count()
106-
num_clifford = num_and * 5 + self.bitsize.bit_count()
107-
return {(And(), num_and), (ArbitraryClifford(n=2), num_clifford)}
108-
109-
def __pow__(self, power: int):
110-
if power == 1:
111-
return self
112-
if power == -1:
113-
return self.adjoint()
114-
raise NotImplementedError("HammingWeightCompute.__pow__ defined only for +1/-1.")
121+
num_and = self.junk_bitsize
122+
num_cnot = num_and * 5 + self.bit_count_of_bitsize
123+
return {(And(), num_and), (CNOT(), num_cnot)}

0 commit comments

Comments
 (0)