Skip to content

BlockEncoding interface seems too permissive: register names or ordering should be defined #1772

@petim0

Description

@petim0

Context

I am implementing the quantum singular value transformation (QSVT) algorithm, see Lin Lin's lecture chapter 8.3 and the circuit is the following:

Image

Figure 8.1. Circuit of quantum singular value transformation to construct $U_{P^\diamond_{Re}} \in BE_{1,m+1}(P^\diamond_{Re}(A))$, using $U_A \in BE_{1,m}(A)$.

$|0^m>$ are the ancillas of the block encoding $U_A$.

The Issue

To translate that into Qualtran, I define a class QSVT(blockEncoding) that takes a blockEncoding. It is easy to define a correct signature, for example:

bloqEnc : BlockEncoding
def signature(self):
        return Signature([
               Register("signal", QBit()), 
               Register("ancilla", QAny(self.bloqEnc.ancilla_bitsize)),
               Register("system", QAny(self.bloqEnc.system_bitsize)),
        ])

But when implementing the build_composite_bloq(), I run into the following problem:

signal, ancilla = bb.add(controlled_rotation_bloq, target=signal, ctrl=ancilla)
ancilla, system = bb.add(bloqEnc, what_to_put_here=ancilla, what_to_put_here=system)

To make this generic, I would need either the names or ordering of the registers expected by an arbitrary block encoding. But the current BlockEncoding interface gives no guarantees about either.

I may be missing something, maybe there is a method to use bb.add correctly, but add_t and add_d don't seem to work here.

One other solution is to create a new interface, child of the BlockEncoding interface, but it seems impractical, every time someone needs to use QSVT they will need to use this other interface.

I could also impose a naming convention myself and throw an error if it is not respected, but this defeats the purpose of a general interface.

I saw that the LinearCombination bloq automatically wraps block encodings using AutoPartition. That might be the best solution, but it feels like a big overhead to do this every time we want to work with general block encodings.

I feel like the cleanest solution would be to change the BlockEncoding interface so that every block encoding must have standard system and ancilla registers (maybe a resource register as well). We know that every block encoding will have a system register and an ancilla register (except in the edge case where the matrix you are block encoding is unitary).
I also saw that this was the case before the commit 0d45c82, so there must be a reason for this design choice.

The only downside I can see in changing the BlockEncoding interface is the amount of refactoring required.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions