|
20 | 20 | from numpy.typing import NDArray |
21 | 21 |
|
22 | 22 | from qualtran import GateWithRegisters, QAny, QUInt, Register, Side, Signature |
23 | | -from qualtran.bloqs.bookkeeping import ArbitraryClifford |
| 23 | +from qualtran.bloqs.basic_gates import CNOT |
24 | 24 | from qualtran.bloqs.mcmt.and_bloq import And |
| 25 | +from qualtran.symbolics import bit_length, is_symbolic, SymbolicInt |
25 | 26 |
|
26 | 27 | if TYPE_CHECKING: |
27 | 28 | from qualtran.resource_counting import BloqCountT, SympySymbolAllocator |
@@ -49,20 +50,35 @@ class HammingWeightCompute(GateWithRegisters): |
49 | 50 | [Halving the cost of quantum addition](https://arxiv.org/abs/1709.06648), Page-4 |
50 | 51 | """ |
51 | 52 |
|
52 | | - bitsize: int |
| 53 | + bitsize: SymbolicInt |
53 | 54 |
|
54 | 55 | @cached_property |
55 | 56 | def signature(self): |
56 | | - jnk_size = self.bitsize - self.bitsize.bit_count() |
57 | | - out_size = self.bitsize.bit_length() |
58 | 57 | return Signature( |
59 | 58 | [ |
60 | 59 | 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), |
63 | 62 | ] |
64 | 63 | ) |
65 | 64 |
|
| 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 | + |
66 | 82 | def pretty_name(self) -> str: |
67 | 83 | return "out = x.bit_count()" |
68 | 84 |
|
@@ -102,13 +118,6 @@ def decompose_from_registers( |
102 | 118 | yield self._decompose_using_three_to_two_adders(x, junk, out) |
103 | 119 |
|
104 | 120 | 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