quantumlib / Qualtran

Qᴜᴀʟᴛʀᴀɴ is a Python library for expressing and analyzing Fault Tolerant Quantum algorithms.
https://qualtran.readthedocs.io/en/latest/
Apache License 2.0
132 stars 35 forks source link

ReflectionViaPrepare doesn't work with StatePreparationViaRotations #1045

Open wjhuggins opened 1 month ago

wjhuggins commented 1 month ago

I am getting an error when I try to get the call graph in this situation. I'm on the latest commit on main. Here is a MWE:

from Qualtran.qualtran.bloqs.reflections.reflection_using_prepare import ReflectionUsingPrepare
from Qualtran.qualtran.bloqs.state_preparation.state_preparation_via_rotation import StatePreparationViaRotations

from qualtran.resource_counting.generalizers import ignore_split_join
from qualtran.drawing import show_bloq, show_bloqs
from qualtran.drawing import show_call_graph, show_counts_sigma

state_coefs = (
    (-0.42677669529663675 - 0.1767766952966366j),
    (0.17677669529663664 - 0.4267766952966367j),
    (0.17677669529663675 - 0.1767766952966368j),
    (0.07322330470336305 - 0.07322330470336309j),
    (0.4267766952966366 - 0.17677669529663692j),
    (0.42677669529663664 + 0.17677669529663675j),
    (0.0732233047033631 + 0.17677669529663678j),
    (-0.07322330470336308 - 0.17677669529663678j),
)

prepare_gate = StatePreparationViaRotations(
    phase_bitsize=2, state_coefficients=state_coefs, control_bitsize=0
)

reflection = ReflectionUsingPrepare(prepare_gate=prepare_gate)

def analyze_bloq(my_bloq):
    my_bloq_g, my_bloq_sigma = my_bloq.call_graph(max_depth=100, generalizer=ignore_split_join)
    show_call_graph(my_bloq_g)
    show_counts_sigma(my_bloq_sigma)

# This works fine
analyze_bloq(my_bloq=prepare_gate)

# This throws an error.
analyze_bloq(my_bloq=reflection)

Here is the error I get:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[5], [line 34](vscode-notebook-cell:?execution_count=5&line=34)
     [31](vscode-notebook-cell:?execution_count=5&line=31) analyze_bloq(my_bloq=prepare_gate)
     [33](vscode-notebook-cell:?execution_count=5&line=33) # This throws an error.
---> [34](vscode-notebook-cell:?execution_count=5&line=34) analyze_bloq(my_bloq=reflection)

Cell In[5], [line 26](vscode-notebook-cell:?execution_count=5&line=26)
     [25](vscode-notebook-cell:?execution_count=5&line=25) def analyze_bloq(my_bloq):
---> [26](vscode-notebook-cell:?execution_count=5&line=26)     my_bloq_g, my_bloq_sigma = my_bloq.call_graph(max_depth=100, generalizer=ignore_split_join)
     [27](vscode-notebook-cell:?execution_count=5&line=27)     show_call_graph(my_bloq_g)
     [28](vscode-notebook-cell:?execution_count=5&line=28)     show_counts_sigma(my_bloq_sigma)

File ~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:343, in Bloq.call_graph(self, generalizer, keep, max_depth)
    [319](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:319) """Get the bloq call graph and call totals.
    [320](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:320) 
    [321](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:321) The call graph has edges from a parent bloq to each of the bloqs that it calls in
   (...)
    [339](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:339)         decomposed.
    [340](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:340) """
    [341](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:341) from qualtran.resource_counting import get_bloq_call_graph
--> [343](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/_infra/bloq.py:343) return get_bloq_call_graph(self, generalizer=generalizer, keep=keep, max_depth=max_depth)

File ~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:241, in get_bloq_call_graph(bloq, generalizer, ssa, keep, max_depth)
    [239](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:239) if bloq is None:
    [240](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:240)     raise ValueError("You can't generalize away the root bloq.")
--> [241](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:241) _build_call_graph(bloq, generalizer, ssa, keep, max_depth, g=g, depth=0)
    [242](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:242) sigma = _compute_sigma(bloq, g)
    [243](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:243) return g, sigma

File ~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:153, in _build_call_graph(bloq, generalizer, ssa, keep, max_depth, g, depth)
    [150](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:150)     return
    [152](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:152) # Prep for recursion: get the callees and modify them according to `generalizer`.
--> [153](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:153) callee_counts = get_bloq_callee_counts(bloq, generalizer)
    [155](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:155) # Base case 3: Empty list of callees
    [156](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:156) if not callee_counts:

File ~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:118, in get_bloq_callee_counts(bloq, generalizer, ssa)
    [115](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:115)     ssa = SympySymbolAllocator()
    [117](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:117) try:
--> [118](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:118)     return _generalize_callees(bloq.build_call_graph(ssa), generalizer)
    [119](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:119) except (DecomposeNotImplementedError, DecomposeTypeError):
    [120](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/resource_counting/_call_graph.py:120)     return []

File ~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:170, in ReflectionUsingPrepare.build_call_graph(self, ssa)
    [169](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:169) def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
--> [170](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:170)     n_phase_control = sum(reg.total_bits() for reg in self.selection_registers)
    [171](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:171)     costs: Set['BloqCountT'] = {
    [172](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:172)         (self.prepare_gate, 1),
    [173](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:173)         (self.prepare_gate.adjoint(), 1),
    [174](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:174)         (MultiControlPauli([0] * n_phase_control, target_gate=cirq.Z), 1),
    [175](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:175)     }
    [176](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:176)     if self.control_val is None:

File <attrs generated getattr Qualtran.qualtran.bloqs.reflections.reflection_using_prepare.ReflectionUsingPrepare>:6, in wrapper.<locals>.__getattr__(self, item, cached_properties, original_getattr, _cached_setattr_get)
      [4](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/%3Cattrs%20generated%20getattr%20Qualtran.qualtran.bloqs.reflections.reflection_using_prepare.ReflectionUsingPrepare%3E:4) func = cached_properties.get(item)
      [5](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/%3Cattrs%20generated%20getattr%20Qualtran.qualtran.bloqs.reflections.reflection_using_prepare.ReflectionUsingPrepare%3E:5) if func is not None:
----> [6](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/%3Cattrs%20generated%20getattr%20Qualtran.qualtran.bloqs.reflections.reflection_using_prepare.ReflectionUsingPrepare%3E:6)      result = func(self)
      [7](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/%3Cattrs%20generated%20getattr%20Qualtran.qualtran.bloqs.reflections.reflection_using_prepare.ReflectionUsingPrepare%3E:7)      _setter = _cached_setattr_get(self)
      [8](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/%3Cattrs%20generated%20getattr%20Qualtran.qualtran.bloqs.reflections.reflection_using_prepare.ReflectionUsingPrepare%3E:8)      _setter(item, result)

File ~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:91, in ReflectionUsingPrepare.selection_registers(self)
     [89](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:89) @cached_property
     [90](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:90) def selection_registers(self) -> Tuple[Register, ...]:
---> [91](https://vscode-remote+ssh-002dremote-002bnimbostratus-002ec-002egooglers-002ecom.vscode-resource.vscode-cdn.net/usr/local/google/home/whuggins/Projects/state-prep-qualtran/~/Projects/state-prep-qualtran/Qualtran/qualtran/bloqs/reflections/reflection_using_prepare.py:91)     return self.prepare_gate.selection_registers

AttributeError: 'StatePreparationViaRotations' object has no attribute 'selection_registers'
fdmalone commented 1 month ago

ReflectionUsingPrepare expects the prepare_gate to be a sublcass of PrepareOracle, we should probably enforce all "Prepare" bloqs to inherit from PrepareOracle, but currently there's a bit of a gap.

wjhuggins commented 1 month ago

That makes sense. I'll repeat what I said in chat though: it's a little funny to think of ReflectionViaPrepare as something inherently tied to the LCU context since reflections about a state are useful in a lot of places.

fdmalone commented 1 month ago

That's a good point. We should probably think about this a bit more carefully.

mpharrigan commented 1 month ago

To be a little provocative: the whole idea of using the Python class hierarchy to define abstract properties that influence the quantum signature of a bloq is misguided. You can imagine a world where we have a "quantum interface" which says something like "implementers of the state prep interface has one register named 'select'" and something like #789 can auto-partition

fdmalone commented 1 month ago

how do you enforce the quantum interface if not using some abstract base class? I'm on board with 789 though.

mpharrigan commented 1 month ago

The same way we enforce quantum type checking, which is not by using the python type checker. The abc.ABCMeta metaclass runs some code when the class definition is encountered by the python interpreter that goes through and checks all the methods to see if they're implemented. We'd have our own 'interface' system that would check a bloq's signature (and anything else) to make sure it is compatible with the interface