BlockEncoding.apply#

BlockEncoding.apply(*operands: QuantumVariable) list[QuantumVariable][source]#

Applies the BlockEncoding unitary to the given operands.

Parameters:
*operandsQuantumVariable

QuantumVariables serving as operands for the block-encoding.

Returns:
list[QuantumVariable]

A list of ancilla QuantumVariables used in the application. Must be measured in \(0\) for success of the block-encoding application.

Raises:
ValueError

If the number of provided operands does not match the required number of operands (self.num_ops).

Examples

Example 1:

Define a block-encoding and apply it using Repeat-Until-Success.

import numpy as np
from qrisp import *
from qrisp.block_encodings import BlockEncoding
from qrisp.operators import X, Y, Z

H = X(0)*X(1) + 0.5*Z(0)*Z(1)
BE = BlockEncoding.from_operator(H)

def operand_prep(phi):
    qv = QuantumFloat(2)
    ry(phi, qv[0])
    return qv

@RUS
def apply_be(BE, phi):
    qv = operand_prep(phi)
    ancillas = BE.apply(qv)

    # Alternatively, also use:
    # ancillas = BE.create_ancillas()
    # BE.unitary(*ancillas, qv)

    bools = jnp.array([(measure(anc) == 0) for anc in ancillas])
    success_bool = jnp.all(bools)

    # garbage collection
    [reset(anc) for anc in ancillas]
    [anc.delete() for anc in ancillas]

    return success_bool, qv

@terminal_sampling
def main(BE):
    qv = apply_be(BE, np.pi / 4)
    return qv

main(BE)
#{3: 0.6828427278345078, 0: 0.17071065215630213, 2: 0.11715730494804945, 1: 0.02928931506114055}

For convenience, the apply_rus() method directly applies the block-encoding using RUS.

Example 2:

Define a block-encoding and apply it using post-selection.

import numpy as np
from qrisp import *
from qrisp.block_encodings import BlockEncoding
from qrisp.operators import X, Y, Z

H = X(0)*X(1) + 0.5*Z(0)*Z(1)
BE = BlockEncoding.from_operator(H)

def operand_prep(phi):
    qv = QuantumFloat(2)
    ry(phi, qv[0])
    return qv

def main(BE):
    operand = operand_prep(np.pi / 4)
    ancillas = BE.apply(operand)
    return operand, ancillas

operand, ancillas = main(BE)
res_dict = multi_measurement([operand] + ancillas)

# Post-selection on ancillas being in |0> state
filtered_dict = {k[0]: p for k, p in res_dict.items() \
                if all(x == 0 for x in k[1:])}
success_prob = sum(filtered_dict.values())
filtered_dict = {k: p / success_prob for k, p in filtered_dict.items()}
filtered_dict
#{3: 0.6828427278345078, 0: 0.17071065215630213, 2: 0.11715730494804945, 1: 0.02928931506114055}