Qualtran icon indicating copy to clipboard operation
Qualtran copied to clipboard

Add a wrapper bloq to help plug bloqs into each other whose registers don't quite match

Open fdmalone opened this issue 1 year ago • 3 comments

Sometimes we want to use bloqs whose signatures don't quite match up with the signature of a bigger bloq we want to build (for example the bloq might have a flat list of qubits but we have a big register or vice versa). Normally we can just split / join / partition during the decompostion and go on our way, but this leads to unsightly diagrams like this:

Screenshot 2024-03-13 at 1 45 19 PM

Wouldn't it be better if this looked like this: Screenshot 2024-03-13 at 1 45 40 PM

(the example is a little contrived but I recently hit a case where I wanted to batch HWP rotations for a bloq with a flat list of qubits and didn't want to split/join)

Another use case is we often would like to build up nice diagrams we see in the literature (like QPE / block encoding etc). Currently we have BlackBoxSelect and BlackBoxPrepare which appropriately partition and match registers according to the Select/Prepare Oracle spec. But we may want to plug in some other bloq, (like a walk operator), or something else which requires further black boxes whose construction is a little opaque. It should be simpler if this wrapping was handled automatically.

Here is a prototype for a "Wrap" bloq takes a bloq as an argument and appropriately does the partitions however the user specifies (through a mapping from "outer_registers" to "inner_registers"). It's a bit rough but I think something like this could be useful. It's inspired by BlackBoxPrepare etc and would replace those bloqs like so:

from qualtran.bloqs.hubbard_model import SelectHubbard, PrepareHubbard
from qualtran.bloqs.block_encoding import BlackBoxPrepare, BlackBoxSelect, BlackBoxBlockEncoding
dim = 4
# select = BlackBoxSelect(SelectHubbard(x_dim=dim, y_dim=dim))
sel_hubb = SelectHubbard(x_dim=dim, y_dim=dim)
sel = Register('selection', QAny(sum(r.bitsize for r in sel_hubb.selection_registers)))
sys = Register('system', QAny(sum(r.bitsize for r in sel_hubb.target_registers)))
select = Wrap(sel_hubb, outer_registers=(sel, sys), inner_registers=(sel_hubb.selection_registers, sel_hubb.target_registers))
prepare = BlackBoxPrepare(PrepareHubbard(x_dim=dim, y_dim=dim, t=1, mu=4))
black_box_block_bloq = BlackBoxBlockEncoding(select=select, prepare=prepare)
draw_musical_score(get_musical_score_data(black_box_block_bloq.decompose_bloq()))
Screenshot 2024-03-13 at 1 50 03 PM

The interface / name etc is a little rough so I think perhaps a factory method could replace some of the register mapping, but I think it's sort of helpful.

cc @mpharrigan / @tanujkhattar

fdmalone avatar Mar 13 '24 20:03 fdmalone

it's also possible that this could be added to bloq builder as a utility which would handle some of the boilerplate

fdmalone avatar Mar 13 '24 20:03 fdmalone

sweeeeet.

Since you brought it up: would you be able to come up with meaningful register (soquet) labels so we wouldn't need the short_name title?

mpharrigan avatar Mar 13 '24 23:03 mpharrigan

Since you brought it up: would you be able to come up with meaningful register (soquet) labels so we wouldn't need the short_name title?

Sure, this is a separate thing though right? I need to look at the drawing code again.

fdmalone avatar Mar 13 '24 23:03 fdmalone