Skip to content

Commit 35db018

Browse files
authored
Simplify GQSP call graph (#1328)
* simplify GQSP call graph * simplify HamiltonianSimulation call graph * fix notebook test * make hamsim a bloq * address feedback is_zero tests * link issue about tensor vs cirq unitary * format
1 parent 0d9d974 commit 35db018

7 files changed

Lines changed: 82 additions & 45 deletions

File tree

qualtran/bloqs/hamiltonian_simulation/hamiltonian_simulation_by_gqsp.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
from collections import Counter
1415
from functools import cached_property
1516
from typing import cast, Dict, Set, Tuple, TYPE_CHECKING, Union
1617

1718
import numpy as np
1819
from attrs import field, frozen
1920
from numpy.typing import NDArray
2021

21-
from qualtran import bloq_example, BloqDocSpec, GateWithRegisters, Signature, Soquet
22+
from qualtran import Bloq, bloq_example, BloqDocSpec, CtrlSpec, Signature, Soquet
23+
from qualtran.bloqs.basic_gates.su2_rotation import SU2RotationGate
2224
from qualtran.bloqs.qsp.generalized_qsp import GeneralizedQSP
2325
from qualtran.bloqs.qubitization.qubitization_walk_operator import QubitizationWalkOperator
2426
from qualtran.linalg.polynomial.jacobi_anger_approximations import (
@@ -34,7 +36,7 @@
3436

3537

3638
@frozen
37-
class HamiltonianSimulationByGQSP(GateWithRegisters):
39+
class HamiltonianSimulationByGQSP(Bloq):
3840
r"""Hamiltonian simulation using Generalized QSP given a qubitized quantum walk operator.
3941
4042
Given the Szegedy Quantum Walk Operator for a Hamiltonian $H$ constructed from SELECT and PREPARE oracles,
@@ -161,7 +163,6 @@ def __add_prepare(
161163
return gqsp_soqs, prepare_out_soqs
162164

163165
def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str, 'SoquetT']:
164-
# TODO open issue: alloc/free does not work with cirq api
165166
state_prep_ancilla: Dict[str, 'SoquetT'] = {
166167
reg.name: bb.allocate(reg.total_bits())
167168
for reg in self.walk_operator.prepare.junk_registers
@@ -182,19 +183,16 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str
182183
return soqs
183184

184185
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
185-
if self.is_symbolic():
186-
from qualtran.bloqs.basic_gates.su2_rotation import SU2RotationGate
187-
188-
d = self.degree
189-
return {
190-
(self.walk_operator.prepare, 1),
191-
(self.walk_operator.prepare.adjoint(), 1),
192-
(self.walk_operator.controlled(control_values=[0]), d),
193-
(self.walk_operator.adjoint().controlled(), d),
194-
(SU2RotationGate.arbitrary(ssa), 2 * d + 1),
195-
}
196-
197-
return super().build_call_graph(ssa)
186+
counts = Counter[Bloq]()
187+
188+
d = self.degree
189+
counts[self.walk_operator.prepare] += 1
190+
counts[self.walk_operator.prepare.adjoint()] += 1
191+
counts[self.walk_operator.controlled(ctrl_spec=CtrlSpec(cvs=0))] += d
192+
counts[self.walk_operator.adjoint().controlled()] += d
193+
counts[SU2RotationGate.arbitrary(ssa)] += 2 * d + 1
194+
195+
return set(counts.items())
198196

199197

200198
@bloq_example

qualtran/bloqs/hamiltonian_simulation/hamiltonian_simulation_by_gqsp_test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
verify_generalized_qsp,
3434
)
3535
from qualtran.bloqs.qubitization.qubitization_walk_operator import QubitizationWalkOperator
36+
from qualtran.cirq_interop import BloqAsCirqGate
3637
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
3738
from qualtran.resource_counting import big_O, BloqCount, get_cost_value
3839
from qualtran.symbolics import Shaped
@@ -75,7 +76,9 @@ def verify_hamiltonian_simulation_by_gqsp(
7576
N = H.shape[0]
7677

7778
W_e_iHt = HamiltonianSimulationByGQSP(W, t=t, precision=precision)
78-
result_unitary = cirq.unitary(W_e_iHt)
79+
# TODO This cirq.unitary call is 4-5x faster than tensor_contract.
80+
# https://github.com/quantumlib/Qualtran/issues/1336
81+
result_unitary = cirq.unitary(BloqAsCirqGate(W_e_iHt))
7982

8083
expected_top_left = scipy.linalg.expm(-1j * H * t)
8184
actual_top_left = result_unitary[:N, :N]

qualtran/bloqs/qsp/generalized_qsp.py

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
from numpy.typing import NDArray
2222

2323
from qualtran import (
24+
Bloq,
2425
bloq_example,
2526
BloqDocSpec,
27+
CtrlSpec,
2628
DecomposeTypeError,
2729
GateWithRegisters,
2830
QBit,
@@ -31,7 +33,16 @@
3133
)
3234
from qualtran.bloqs.basic_gates.su2_rotation import SU2RotationGate
3335
from qualtran.linalg.polynomial.qsp_testing import assert_is_qsp_polynomial
34-
from qualtran.symbolics import is_symbolic, Shaped, slen, smax, smin, SymbolicFloat, SymbolicInt
36+
from qualtran.symbolics import (
37+
is_symbolic,
38+
is_zero,
39+
Shaped,
40+
slen,
41+
smax,
42+
smin,
43+
SymbolicFloat,
44+
SymbolicInt,
45+
)
3546

3647
if TYPE_CHECKING:
3748
import cirq
@@ -359,29 +370,17 @@ def is_symbolic(self) -> bool:
359370
return is_symbolic(self.P, self.Q, self.negative_power)
360371

361372
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
362-
if isinstance(self.P, Shaped) or self.is_symbolic():
363-
degree = slen(self.P) - 1
364-
365-
return {
366-
(self.U.controlled(control_values=[0]), smax(0, degree - self.negative_power)),
367-
(self.U.adjoint(), smax(0, self.negative_power - degree)),
368-
(self.U.adjoint().controlled(), smin(degree, self.negative_power)),
369-
(SU2RotationGate.arbitrary(ssa), degree + 1),
370-
}
371-
372-
degree = len(self.P) - 1
373+
counts = Counter[Bloq]()
373374

374-
counts: Set['BloqCountT'] = set(Counter(self.signal_rotations).items())
375-
376-
if degree > self.negative_power:
377-
counts.add((self.U.controlled(control_values=[0]), degree - self.negative_power))
378-
elif self.negative_power > degree:
379-
counts.add((self.U.adjoint(), self.negative_power - degree))
380-
381-
if isinstance(self.negative_power, int) and self.negative_power > 0:
382-
counts.add((self.U.adjoint().controlled(), min(degree, self.negative_power)))
375+
degree = slen(self.P) - 1
376+
counts[SU2RotationGate.arbitrary(ssa)] += degree + 1
377+
counts[self.U.controlled(ctrl_spec=CtrlSpec(cvs=0))] += smax(
378+
0, degree - self.negative_power
379+
)
380+
counts[self.U.adjoint()] += smax(0, self.negative_power - degree)
381+
counts[self.U.adjoint().controlled()] += smin(degree, self.negative_power)
383382

384-
return counts
383+
return set((bloq, count) for bloq, count in counts.items() if not is_zero(count))
385384

386385

387386
@bloq_example

qualtran/bloqs/qsp/generalized_qsp_test.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
from qualtran.linalg.testing import assert_matrices_almost_equal
4444
from qualtran.resource_counting import SympySymbolAllocator
4545
from qualtran.symbolics import Shaped
46+
from qualtran.testing import execute_notebook
4647

4748

4849
def test_gqsp_example(bloq_autotester):
@@ -198,12 +199,15 @@ def catch_rotations(bloq: Bloq) -> Bloq:
198199

199200
_, sigma = gqsp.call_graph(max_depth=1, generalizer=catch_rotations)
200201

201-
assert sigma == {
202-
arbitrary_rotation: degree + 1,
203-
Controlled(U, CtrlSpec(cvs=0)): max(0, degree - negative_power),
204-
Controlled(U.adjoint(), CtrlSpec()): min(degree, negative_power),
205-
U.adjoint(): max(0, negative_power - degree),
206-
}
202+
expected_sigma: dict[Bloq, int] = {arbitrary_rotation: degree + 1}
203+
if degree > negative_power:
204+
expected_sigma[Controlled(U, CtrlSpec(cvs=0))] = degree - negative_power
205+
if negative_power > 0:
206+
expected_sigma[Controlled(U.adjoint(), CtrlSpec())] = min(degree, negative_power)
207+
if negative_power > degree:
208+
expected_sigma[U.adjoint()] = negative_power - degree
209+
210+
assert sigma == expected_sigma
207211

208212

209213
@define(slots=False)
@@ -304,3 +308,8 @@ def test_complementary_polynomials_for_jacobi_anger_approximations(t: float, pre
304308
list(P), Q, random_state=random_state, rtol=precision
305309
)
306310
verify_generalized_qsp(MatrixGate.random(1, random_state=random_state), list(P), Q)
311+
312+
313+
@pytest.mark.notebook
314+
def test_notebook():
315+
execute_notebook('generalized_qsp')

qualtran/symbolics/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
bit_length,
1919
ceil,
2020
floor,
21+
is_zero,
2122
ln,
2223
log2,
2324
pi,

qualtran/symbolics/math_funcs.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,15 @@ def shape(x: Shaped) -> Tuple[SymbolicInt, ...]:
313313

314314
def shape(x: Union[np.ndarray, Shaped]):
315315
return x.shape
316+
317+
318+
def is_zero(x: SymbolicInt) -> bool:
319+
"""check if a symbolic integer is zero
320+
321+
If it returns True, then the value is definitely 0.
322+
If it returns False, then the value is either non-zero,
323+
or could not be symbolically symplified to a zero.
324+
"""
325+
if is_symbolic(x):
326+
return x.equals(0)
327+
return x == 0

qualtran/symbolics/math_funcs_test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
bit_length,
2323
ceil,
2424
is_symbolic,
25+
is_zero,
2526
log2,
2627
sarg,
2728
sexp,
@@ -137,3 +138,17 @@ def test_shaped(shape: tuple[int, ...]):
137138
shaped = Shaped(shape=shape)
138139
assert is_symbolic(shaped)
139140
assert slen(shaped) == shape[0]
141+
142+
143+
def test_is_zero():
144+
assert is_zero(0)
145+
assert not is_zero(1)
146+
147+
n = sympy.Symbol("n")
148+
assert not is_zero(n)
149+
assert is_zero(n - n)
150+
assert is_zero(n * 0)
151+
assert is_zero(n * 2 - n - n)
152+
153+
assert is_zero(sympy.sympify("0"))
154+
assert not is_zero(sympy.sympify("1"))

0 commit comments

Comments
 (0)