Skip to content

workbench_algorithms.subroutines

Submodule for defining subroutines.

AliasSampling

AliasSampling(
    qrom: QROM, usp: UniformStatePreparation, **kwargs
)

Bases: Qubrick

Qubrick for implementing alias sampling.

Parameters:

Name Type Description Default
qrom Qubrick

Data lookup instance.

required
usp Qubrick

Uniform state preparation instance.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute_num_states staticmethod

compute_num_states(input_list)

Helper to compute number of states to prepare in alias sampling (works for symbolics & numerics).

Parameters:

Name Type Description Default
input_list list or SymbolicArray

List of coefficients to prepare.

required

Returns:

Type Description
tuple

Number of states to prepare, and value to pad combined list by.

Raises:

Type Description
ValueError

If the inputs are not the correct type for either numerics or symbolics.

compute

compute(
    prep_reg,
    input_list,
    bit_precision,
    lambda_val=None,
    ctrl: int = 0,
    **kwargs,
) -> None

State preparation by alias sampling.

Note

Uses the circuit in Fig. 11 of arXiv:1805.03662 .

Parameters:

Name Type Description Default
prep_reg Qubits or SymbolicQubits

Register to prepare coefficients onto.

required
input_list list or SymbolicArray

List of coefficients to prepare.

required
bit_precision int or Parameter

Number of bits to represent each coefficient.

required
lambda_val int or Parameter

Power-of-two knob to trade off between gates and qubits. If None (default), then optimal lambda is calculated.

None
ctrl Qubits, SymbolicQubits, or int

Control register. Defaults to no control, i.e. ctrl=0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

AmpAmp

AmpAmp(
    init_refl: Qubrick,
    good_refl: Qubrick,
    fixed_point: bool = False,
    eps: float = 0.001,
    use_radians: bool = False,
    **kwargs,
)

Bases: Qubrick

Performs amplitude amplification to boost the amplitude of a desired outcome.

Amplitude amplification takes two reflections: a "good" reflection about a target state \(|\psi_{\text{good}}\rangle\) and a "starting" reflection about the state \(|\psi_{0}\rangle\) that forms the starting point of the routine. If the starting state \(|\psi_0\rangle\) is prepared with some (potentially low) overlap with the target state \(|\psi_{\text{good}}\rangle\), repeatedly applying these two reflections \(\mathcal{O}(1/\sqrt{p})\) times should result in a final state which has \(\Omega(1)\) overlap with the target state.

These reflections can't be made blindly: if you pick a number of iterations that is too small, you "undercook" the state, and if you pick a number that is too high, you "overcook" the state, leading to low fidelities in both cases. The optimal number of iterations depends on the initial success probability p_succ, which you may or may not know a priori. AmpAmp requires p_succ to be passed as an argument in order to calculate the number of rounds needed and provides provision for two scenarios:

  1. If you know p_succ exactly a priori, you can realize the good state deterministically following the procedure in "Quantum Amplitude Amplification and Estimation" (arXiv:quant-ph/0005055).
  2. If you don't know p_succ, we can use fixed point amplitude amplification (the Workbench Algorithms implementation follows "Fixed-point quantum search with an optimal number of queries" (arXiv:1409.3305) along with a lower bound on the success probability as p_succ. Unlike vanilla AA, fixed point AA is guaranteed to succeed for any number of iterations greater than some threshold (calculated from the lower bound on the success probability). Thus, while it may use more resources than necessary, it is useful for when we can't determine p_succ exactly.
Note

The reflections that are passed to this Qubrick are entirely general - they may have additional parameters that need to be passed to them. These parameters can be passed through the kwargs as if the AmpAmp Qubrick has those parameters. For example, if you have a block encoding unitary which takes be_ancilla_reg as an argument, you can do AmpAmp(init_refl, good_refl).compute(sys_reg, p_succ, be_ancilla_reg=be_ancilla_reg).

Parameters:

Name Type Description Default
init_refl Qubrick

Reflection about the initial state.

required
good_refl Qubrick

Reflection about the good (target) state.

required
fixed_point bool

Whether to use fixed point amplitude amplification rather than vanilla amplitude amplification. Defaults to False (vanilla).

False
eps float

Desired error \(\epsilon\) such that \(|\langle\psi_{f}|\psi_{targ}\rangle|^2 \geq 1 - \epsilon\). Needed to calculate the fixed point rotation angles; not necessary if you use vanilla amplitude amplification. Defaults to 1e-3.

0.001
use_radians bool

(Deprecated) True if angles in Radians

False
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    sys_reg: Qubits,
    p_succ: float,
    ctrl: int | Qubits = 0,
    **kwargs,
)

Compute the amplitude amplification.

Parameters:

Name Type Description Default
sys_reg Qubits

Main register the computation is performed on.

required
p_succ float

The initial probability of obtaining the "good" state. If fixed_point is set in the initalizer, this can be a lower bound on the success probability, if not it must be the exact success probability.

required
ctrl int | Qubits

Register the amplitude amplification is controlled on. Defaults to 0.

0
**kwargs dict[str, Any]

Optional arguments that may be passed on to the reflection qubricks.

{}

Other Parameters:

Name Type Description
be_ancilla_reg Qubrick

Block encoding register.

data PauliSum or List[int]

Data for select qubricks.

AmplitudeAmplifiedQubrick

AmplitudeAmplifiedQubrick(
    base_qubrick: Qubrick,
    init_refl: Qubrick,
    good_refl: Qubrick,
    fixed_point: bool = False,
    eps: float = 0.001,
    use_radians: bool = False,
    **kwargs,
)

Bases: Qubrick

Performs amplitude amplification on the input Qubrick to provide an "amplified" Qubrick.

This Qubrick is intended to be used as a wrapper around a base Qubrick along with Amplitude Amplification (the AmpAmp Qubrick) in order to produce an amplitude amplified version of the base Qubrick.

Parameters:

Name Type Description Default
base_qubrick Qubrick

The base qubrick to be amplified.

required
init_refl Qubrick

Reflection about the initial state.

required
good_refl Qubrick

Reflection about the good (target) state.

required
fixed_point bool

Whether to use fixed point amplitude amplification rather than vanilla amplitude amplification. Defaults to False.

False
eps float

Desired error \(\epsilon\) such that \(|\langle\psi_{f}|\psi_{targ}\rangle|^2 \geq 1 - \epsilon\). Needed to calculate the fixed point rotation angles, not necessary for vanilla amp amp. Defaults to 1e-3.

0.001
use_radians bool

(Deprecated) True if angles in Radians

False
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    sys_reg: Qubits,
    p_succ: float,
    ctrl: int | Qubits = 0,
    **kwargs,
)

Compute the base qubrick along with amplitude amplification.

Parameters:

Name Type Description Default
sys_reg Qubits

Main register the computation is performed on.

required
p_succ float

The initial probability of obtaining the "good" state. If fixed_point is set in the initalizer, this can be a lower bound on the success probability, if not it must be the exact success probability.

required
ctrl int | Qubits

Register the amplitude amplification is controlled on. Defaults to 0.

0
**kwargs dict[str, Any]

Optional arguments that may be passed on to the AmpAmp Qubrick, reflection Qubricks, or the base Qubrick.

{}

Other Parameters:

Name Type Description
be_ancilla_reg Qubrick

Block encoding register.

data PauliSum or List[int]

Data for select qubricks.

GoodReflectionBlockEncoding

GoodReflectionBlockEncoding(**kwargs)

Bases: Qubrick

Reflection about a block encoded good state (i.e., all block encoding auxiliary qubits in \(\ket{0}\)).

Implements the reflection

\((I - (1 - e^{i\phi})|0^m\rangle\langle 0^m|)\)

Note

See references "Quantum Amplitude Amplification and Estimation" (arXiv:quant-ph/0005055) and "Fixed-point quantum search with an optimal number of queries" (arXiv:1409.3305) for details.

compute

compute(
    sys_reg: Qubits,
    ancillae: Qubits,
    angle: float = 180,
    ctrl: int | Qubits = 0,
    **kwargs,
)

Compute the reflection.

Parameters:

Name Type Description Default
sys_reg Qubits

Qubits register defining the system. Included to maintain compatibility with other Qubricks.

required
ancillae Qubits

Auxiliary qubits used to block encode the matrix.

required
angle float

Angle about which the generalized reflection is performed.

180
ctrl int | Qubits

Qubits to control the reflection on. Defaults to 0.

0
**kwargs dict[str, Any]

Additional keyword arguments included to maintain compatibility with other reflections.

{}

GoodReflectionGrover

GoodReflectionGrover(good_state: str, **kwargs)

Bases: Qubrick

Qubrick for reflecting about a good state in Grover.

Parameters:

Name Type Description Default
good_state str

Binary representation of the good state as the basis state, e.g. '101'

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    sys_reg: Qubits,
    angle: float,
    ctrl: int | Qubits = 0,
    **kwargs,
)

Compute the reflection.

Parameters:

Name Type Description Default
sys_reg Qubits

Register on which the state is prepared.

required
angle float

Angle about which the generalized reflection is performed, in degrees.

required
ctrl int | Qubits

Qubits to control the reflection on. Defaults to 0.

0
**kwargs dict[str, Any]

Additional keyword arguments included to maintain compatibility with other reflections.

{}

GroverDiffuser

GroverDiffuser(**kwargs)

Bases: Qubrick

Qubrick for Grover diffuser (reflection about the mean).

compute

compute(
    sys_reg: Qubits,
    angle: float = 180,
    ctrl: int | Qubits = 0,
    **kwargs,
)

Compute the reflection.

Parameters:

Name Type Description Default
sys_reg Qubits

Register on which the state is prepared.

required
angle float

Angle about which the generalized reflection is performed, in degrees.

180
ctrl int | Qubits

Qubits to control the reflection on. Defaults to 0.

0
**kwargs dict[str, Any]

Additional keyword arguments included to maintain compatibility with other reflections.

{}

InitReflectionBlockEncoding

InitReflectionBlockEncoding(unitary, **kwargs)

Bases: Qubrick

Reflection about the initial state given a unitary that prepares that state.

Parameters:

Name Type Description Default
unitary Qubrick

Qubrick implementing the unitary to reflect about.

required
**kwargs dict[str, Any]

Other key word arguments to pass to the Qubrick constructor.

{}

compute

compute(
    sys_reg: Qubits,
    angle: float = 180,
    ancillae: int | Qubits = 0,
    ctrl: int | Qubits = 0,
    **kwargs,
)

Compute the reflection.

Parameters:

Name Type Description Default
sys_reg Qubits

Register on which the state is prepared.

required
angle float

Angle about which the generalized reflection is performed, in degrees.

180
ancillae int | Qubits

Ancillae used to facillitate the implementation of the state. Defaults to 0.

0
ctrl int | Qubits

Qubits to control the reflection on. Defaults to 0.

0
**kwargs dict[str, Any]

Additional keyword arguments included to maintain compatibility with other reflections.

{}

InitReflectionFromUnitary

InitReflectionFromUnitary(unitary, **kwargs)

Bases: Qubrick

Reflection about the initial state given a unitary that prepares that state.

Parameters:

Name Type Description Default
unitary Qubrick

Qubrick implementing the unitary that prepares the state to reflect about.

required
**kwargs dict[str, Any]

Other key word arguments to pass to the Qubrick constructor.

{}

compute

compute(
    sys_reg: Qubits,
    angle: float = 180,
    ctrl: int | Qubits = 0,
    **kwargs,
)

Compute the reflection.

Parameters:

Name Type Description Default
sys_reg Qubits

Register on which the state is prepared.

required
angle float

Angle about which the generalized reflection is performed, in degrees.

180
ctrl int | Qubits

Qubits to control the reflection on. Defaults to 0.

0
**kwargs dict[str, Any]

Additional keyword arguments included to maintain compatibility with other reflections.

{}

Antisymmetrizer

Antisymmetrizer(prep_qbk, prob_knob=None, **kwargs)

Bases: Qubrick

Qubrick to antisymmetrize a register of qubits.

Parameters:

Name Type Description Default
prep_qbk Qubrick

A state preparation Qubrick.

required
prob_knob (Optional, int)

A value to use which determines the number of qubits to use per seed register, which influences the probability of needing to restart. Defaults to None, in which case, a default value which ensures >= 1/2 probability of success is used.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(system_reg: Qubits, ctrl: Qubits | int = 0)

Circuit for preparation of an antisymmetrized state.

The antisymmetrization procedure works as follows:

  1. We prepare an auxiliary "seed" register in an equal superposition state.
  2. We employ a sorting network on the seed register, keeping a record of all permutations made during the sort on another "record" register.
  3. The seed register is measured in order to post-select on the collision-free subspace. If we observe a collision, we go back to step 1. If not, continue.
  4. We apply Pauli Zs on each record qubit.
  5. We use the record to reverse the sorting operations on the input system register, resulting in an equal superpotision of all permutations of the input state.
  6. Because we applied Pauli Zs on each record qubit prior to the sort reversal, we also phase each permutation state according to its parity.

The above prepares the desired antisymmetrized state.

Parameters:

Name Type Description Default
system_reg Qubits

Register to prepare antisymmetrized state on.

required
ctrl (int, Qubits)

Control register for the routine. Defaults to 0.

0

PowerOfTwoBatchedHammingWeightPhasing

PowerOfTwoBatchedHammingWeightPhasing(
    hamming_weight_qubrick: Qubrick | None = None,
    n_hwp_batches: int = 1,
    rot_is_rz: bool = True,
    use_black_box: bool = False,
    **kwargs,
)

Bases: Qubrick

Implements Hamming weight phasing by splitting the target register into batches.

This Qubrick divides a large rotation tower into smaller batches, where the number of batches is a power of two. Each batch is processed with a smaller Hamming weight phasing circuit. This approach can significantly reduce the number of qubits and catalyst rotation requirements for large registers.

This is particularly useful for applications like Fermi-Hubbard simulation where the number of parallel Rz rotations is either L²/2 or L², where L is the lattice size.

Parameters:

Name Type Description Default
hamming_weight_qubrick Qubrick | None

Qubrick for computing the Hamming weight for the Hamming weight phasing operation. If None, a default method using ComputeHammingWeightGroupOfThrees with GidneyAdd will be used.

None
n_hwp_batches int

Number of batches to split the rotations into. Must be a power of 2. Larger values reduce resource costs but may increase circuit depth.

1
rot_is_rz bool

Whether to use RZ rotations (True) or phase rotations (False).

True
use_black_box bool

Uses black box AV counts if set to True. Default is False.

False
**kwargs dict[str, Any]

Additional arguments to pass to the Qubrick constructor.

{}

Raises:

Type Description
ValueError

If n_hwp_batches is not a power of 2.

hamming_weight_qubrick property

hamming_weight_qubrick

Returns the Hamming weight qubrick used for computation.

Returns:

Type Description
Qubrick

The Hamming weight calculation Qubrick.

compute

compute(
    rz_rotation_angle: float,
    target_register: Qubits,
    ctrl: Qubits | int = 0,
)

Computes the batched Hamming weight phasing operation.

This method splits the target register into batches, then applies a Hamming weight phasing operation to each batch separately. This approach can significantly reduce Toffoli gate counts and catalyst rotation requirements for large registers.

Parameters:

Name Type Description Default
rz_rotation_angle float

Rotation angle (in degrees) for the phase operations.

required
target_register Qubits

Register on which to apply the rotations.

required
ctrl Qubits | int

Controls for the operation. Can be an integer bitmask or a Qubits register. Default is 0 (uncontrolled).

0

Raises:

Type Description
ValueError

If the number of batches is greater than the number of qubits in the target register.

LCU

LCU(
    state_prep: StatePreparation,
    select: Select,
    **kwargs: dict[str, Any],
)

Bases: Qubrick

Implements a general block encoding using Linear Combination of Unitaries (LCU).

Constructs the block encoding as \(\text{PREP}-\text{SELECT}-\text{PREP}^\dagger\) using provided Qubrick implementations of SELECT and PREP.

Parameters:

Name Type Description Default
state_prep StatePreparation

A Qubrick implementing a state preparation (PREP) subroutine

required
select Select

A Qubrick implementing a select (SELECT) subroutine

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi: Qubits,
    be_ancilla_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
    **kwargs: dict[str, Any],
)

Compute the block encoding.

Parameters:

Name Type Description Default
psi Qubits

Target state register.

required
be_ancilla_reg Qubits

Block encoding auxiliary register.

required
data PauliSum | list[int]

Hamiltonian or bitstring values to be block-encoded.

required
ctrl Qubits | int

Register to control on. Defaults to None.

0
**kwargs dict[str, Any]

Extra kwargs to maintain compatibility with other Qubricks.

{}

CompressionGadget

CompressionGadget(
    strategy: CompressionGadgetStrategy,
    adder: Qubrick = None,
    **kwargs,
)

Bases: Qubrick

Compression gadget for block-encoding powers.

Given BE[H_i], applies a BE[Prod H_i] according to https://arxiv.org/pdf/2208.06941 Fig. 3.

Note

The block-encoding is successful in the subspace where counter == 0. The controlled version is such that the controlled unitary is applied accordingly when the block-encoding's ancillae qubits are in the zero state. However, the controlled-qubrick might still have an action in other subspace. This allows to reduce the cost of the implementation.

Parameters:

Name Type Description Default
strategy CompressionGadgetStrategy

block-encoding of the hamiltonian H

required
adder Qubrick

Adder qubrick

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

strategy property

strategy

Set the strategy property so it can't be modified.

Returns:

Type Description
CompressionGadgetStrategy

The Compression gadget strategy

compute

compute(
    system_reg,
    be_anc,
    idx_stop,
    idx_start: int = 0,
    counter=None,
    ctrl: int = 0,
) -> None

Compute CompressionGadget.

Parameters:

Name Type Description Default
system_reg Qubits

System qubits to apply to block-encodings.

required
be_anc int

Block-encoding ancilla register.

required
idx_stop int

Final index of the multiplication.

required
idx_start int

Starting index of the multiplication.

0
counter Qubits

Counter register to perform the compression, if None will be allocated at compute.

None
ctrl (Qubits, int)

Control register.

0

CompressionGadgetStrategy

Bases: Protocol

Interface for applying block-encodings in compression gadget.

apply_compression_gadget_block_encoding

apply_compression_gadget_block_encoding(
    system_reg: Qubits,
    be_anc: Qubits,
    idx: int,
    ctrl: Qubits | int = 0,
)

Method describing how to apply the block encodings.

Parameters:

Name Type Description Default
system_reg Qubits

System qubits.

required
be_anc Qubits

Block-encoding's ancillary qubits.

required
idx int

Iteration of the compression gadget.

required
ctrl Qubits | int

Control register.

0

DataLookupClean

DataLookupClean(
    select: Select,
    swap_up: SwapUpInterface,
    fallback_read=FallbackCoinToss,
    symbolic_mode: str = "worst",
    **kwargs,
)

Bases: Qubrick

Data lookup (QROM) circuit using the SELECT-SwapUp architecture.

Parameters:

Name Type Description Default
select Qubrick

SELECT unitary instance.

required
swap_up Qubrick

SwapUp unitary instance.

required
fallback_read FallbackReadGenerator

Constructor of an object providing results of read in case there's no state-vector simulator available.

FallbackCoinToss
symbolic_mode str

What kind of symbolic QREs should be provided. Can be either "worst" or "average".

'worst'
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg: Qubits,
    bits_of_precision: int,
    data: Iterable[int],
    lambda_val: int | None = None,
    ctrl: Qubits | int = 0,
    *,
    clean: Qubits | None = None,
)

Compute data lookup (QROM) circuit with clean auxiliary qubits.

This routine loads data conditioned by an index register. It makes use of the SELECT-SwapUp constructions introduced in "Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity" (arXiv:1805.03662), where we may tune a parameter (colloquially referred to as "lambda") that allows us to trade off between gates and qubits.

Depending on the input args and the chosen lambda value, we consider three cases:

  1. If "lambda" is equal to 1, this means we do not introduce any additional auxiliary qubits. This case reduces the QROM to a classic SELECT.

  2. If "lambda" is equal to the number of items we are loading, this case reduces to classically writing all data elements and using SwapUp to fetch a particular item and bring it to the top b "clean" qubits.

  3. All other cases make use of both SELECT and SwapUp to coherently write and fetch indexed data, respectively.

Parameters:

Name Type Description Default
index_reg Qubits

Index register.

required
bits_of_precision int

Number of bits to represent item in list.

required
data Iterable[int]

List of data to load.

required
lambda_val int | None

Power-of-two knob to trade off between gates and qubits. If None (default), then optimal lambda is calculated.

None
ctrl Qubits | int

Qreg to control on. Defaults to 0.

0
clean Qubits | None

If passed in, will be used as the output qubits. Useful for reusing registers.

None
Notes

With the introduction of a custom uncompute method for this class, the compute circuit is no longer fully coherent; if we are making use of additional junk registers, we measure them and record the read result to later be used during uncompute. This allows us to release auxiliary qubits that may otherwise constitute a significant space cost.

compute_phase_fixups

compute_phase_fixups()

Use QROM data to compute the addresses that require phase fixups.

Returns:

Type Description
list[int]

A list of each address (int) that requires a phase fixup.

compute_phase_fixups_symbolic

compute_phase_fixups_symbolic()

Use QROM data to compute the addresses that require phase fixups.

It models the worst-case scenario, where all the addresses need a fixup, or the average scenario when only half of them do, depending on self.symbolic_mode.

Returns:

Type Description
SymbolicArray

A list of each address (int) that requires a phase fixup.

DataLookupDirtyNaive

DataLookupDirtyNaive(select, swap_up, **kwargs)

Bases: Qubrick

Naive data lookup (QROM) oracle using dirty auxiliary qubits.

Introduced in Fig. 1D from "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954).

Note

This routine makes use of dirty, borrowable qubits. The auxiliary qubits in question can be any qubits on the entirety of the QPU, so long as they are not the qubits acted on by the routine itself. By "borrowable", we mean that after compute is called, the dirty auxiliary qubits are returned to their initial state; we do not need to wait until uncomputation for these qubits to be returned to their initial state.

The current implementation makes use of _dirty_qubits to find borrowable qubits; this will likely change in the future once a dirty auxiliary qubits management scheme is formally implemented in Workbench. A consequence of the current implementation is that when uncompute is called, the exact same dirty register will be used. This is technically correct and permissible, but absolutely not necessary.

Parameters:

Name Type Description Default
select Qubrick

Select unitary instance.

required
swap_up Qubrick

SwapUp unitary instance.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg,
    b,
    data,
    lambda_val=None,
    ctrl: int = 0,
    **kwargs,
) -> None

Compute data lookup (QROM) circuit with dirty auxiliary qubits.

Parameters:

Name Type Description Default
index_reg Qubits

Index register.

required
b int

Number of bits to represent item in list.

required
data list

List of data to load.

required
lambda_val int

Power-of-two knob to trade off between gates and qubits. If None (default), then optimal lambda is calculated.

None
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

DataLookupDirtyOptimized

DataLookupDirtyOptimized(select, swap_up, **kwargs)

Bases: Qubrick

Optimized data lookup (QROM) oracle using dirty auxiliary qubits.

Introduced in Fig. 4 from "Qubitization of Arbitrary Basis Quantum Chemistry Leveraging Sparsity and Low Rank Factorization" (arXiv:1902.02134).

Note

\(\text{SWAP}\) and \(\text{SWAP}^\dagger\) are switched in the code below from the drawing in Fig. 4 because \(\text{SWAP}\) and \(\text{SWAP}^\dagger\) in Workbench Algorithms are defined in the usual way as swapping the lth register up to the 0th, NOT the other way around.

This routine makes use of dirty, borrowable qubits. The auxiliary qubits in question can be any qubits on the entirety of the QPU so long as they are not the qubits acted on by the routine itself. By "borrowable", we mean that after compute is called, the dirty auxiliary qubits are returned to their initial state; we do not need to wait until uncomputation for these qubits to be returned to their initial state.

The current implementation makes use of _dirty_qubits to find borrowable qubits; this will likely change in the future once a dirty auxiliary qubits management scheme is formally implemented in Workbench. A consequence of the current implementation is that when uncompute is called, the exact same dirty register will be used. This is technically correct and permissible, but absolutely not necessary.

Parameters:

Name Type Description Default
select Qubrick

Select unitary instance.

required
swap_up Qubrick

SwapUp unitary instance.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg,
    b,
    data,
    lambda_val=None,
    ctrl: int = 0,
    **kwargs,
) -> None

Compute data lookup (QROM) circuit with dirty auxiliary qubits.

Parameters:

Name Type Description Default
index_reg Qubits

Index register.

required
b int

Number of bits to represent item in list.

required
data list

List of data to load.

required
lambda_val int

Power-of-two knob to trade off between gates and qubits. If None (default), then optimal lambda is calculated.

None
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

MultiplexedSparseDataLookup

MultiplexedSparseDataLookup(
    inner_qrom, outer_qrom, adder=None, **kwargs
)

Bases: Qubrick

Multiplexed data lookup oracle in Fig. (43) of arXiv:2007.14460.

The goal is to do a "multiplex of multiplexors", that is a quantum for loop over values \(k\) that index a second, inner for loop over \(k-\)dependent values \(j_k\), with the goal being to apply a series of bitstrings \(x_{j,k}\). This can be done efficiently by using a smaller QROM circuit (that also needs to be uncomputed), an adder and a larger "inner" QROM that actually outputs the values.

Parameters:

Name Type Description Default
inner_qrom Qubrick

Qubrick to implement the data loading over the flattened list of nested elements.

required
outer_qrom Qubrick

Qubrick to load the offsets for each set of nested data.

required
adder Qubrick

Qubrick to add the offsets to contiguize the indices. Defaults to GidneyAdd.

None
**kwargs dict[str, Any]

Other key word arguments to pass to the constructor.

{}

compute

compute(
    index_1,
    index_2,
    bits_of_precision,
    data,
    inner_lambda_val=None,
    outer_lambda_val=None,
) -> None

Compute the multiplexed data lookup.

Parameters:

Name Type Description Default
index_1 Qubits

Register for the outer loop in the multiplexed QROM.

required
index_2 Qubits

Register for the inner loop in the multiplexed QROM.

required
bits_of_precision int

Number of bits of precision for the inner QROM (the number of bits for the outer QROM is inferred).

required
data List[List[int]]

Nested list of data values to load; the first dimension corresponds to the outer QROM indices and the second to the inner QROM indices.

required
inner_lambda_val int

Power-of-two knob to trade off between gates and qubits. Defaults to None.

None
outer_lambda_val int

Power-of-two knob to trade off between gates and qubits. Defaults to None.

None

UnaryQROM

UnaryQROM(**kwargs)

Bases: Qubrick

A unary-encoded data-loader.

This class provides a unary QROM (Quantum Read-Only Memory) data loader, which can be used to encode data into quantum registers.

Parameters:

Name Type Description Default
**kwargs dict[str, Any]

Additional keyword arguments passed to the Qubrick superclass.

{}

compute

compute(
    index_reg: Qubits,
    b_of_p: int,
    data: list,
    ctrl: int | Qubits = 0,
    *,
    clean: Qubits | None = None,
)

This method loads the given data into the quantum register using unary encoding.

Parameters:

Name Type Description Default
index_reg Qubits

The index register, encoded in unary.

required
b_of_p int

The number of bits of precision per item to be loaded.

required
data list

A list of integers representing the data to be loaded.

required
ctrl int | Qubits

A control register for conditional loading. Defaults to 0.

0
clean Qubits | None

Qubits encoding the output data. If left as None, the register is allocated on the fly.

None

DysonSeriesLCU

DysonSeriesLCU(prepare, select, **kwargs)

Bases: Qubrick

A Dyson Series LCU Qubrick with a unary version of the truncation register.

Parameters:

Name Type Description Default
prepare Qubrick

a prepare qubrick for Dyson Series.

required
select Qubrick

a select qubrick for Dyson Series.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(register, data, ctrl: int = 0) -> None

Apply Dyson Series.

Parameters:

Name Type Description Default
register CompositeRegister

a composite register for Dyson Series.

required
data DysonSeriesData

Dataclass for the DysonSeries operator parameters.

required
ctrl (Qubits, int)

a register to control this operation on. Default to 0.

0

DysonSeriesPrepareBinary

DysonSeriesPrepareBinary(
    prepare=None, sort=None, usp=None, **kwargs
)

Bases: Qubrick

A modified version of the Dyson series expansion as in arXiv:1805.00675.

Parameters:

Name Type Description Default
sort Qubrick

a qubrick implementing quantum sort.

None
prepare Qubrick

prepare qubrick to implement the prepare oracle for t^k/k!

None
usp Qubrick

a qubrick that prepares a uniform state.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    register: DysonSeriesBinaryIndex, data, ctrl: int = 0
)

Apply the Dyson series prepare operator with binary version of the truncation register.

Parameters:

Name Type Description Default
register CompositeRegister

register for Dyson series indexing (binary).

required
data DysonSeriesData

Dataclass for the DysonSeries operator parameters.

required
ctrl (Qubits, int)

A register to control this operation on. Default to 0.

0
Note

The control version is an optimized version when an input register is 0. If the input register is not 0, the gates will be applied.

DysonSeriesPrepareUnary

DysonSeriesPrepareUnary(
    prepare=None, sort=None, usp=None, **kwargs
)

Bases: Qubrick

A modified version of the Dyson series expansion as in arXiv:1805.00675.

Uses the PrepareClockState Qubrick as its subroutine to encode probabilities.

Parameters:

Name Type Description Default
sort Qubrick

a qubrick implementing quantum sort.

None
prepare Qubrick

prepare qubrick to implement the prepare oracle for t^k/k!.

None
usp Qubrick

a qubrick that prepares a uniform state.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    register: DysonSeriesUnaryIndex, data, ctrl: int = 0
)

Apply the Dyson series prepare operator.

Parameters:

Name Type Description Default
register CompositeRegister

register for Dyson series indexing.

required
data DysonSeriesData

Dataclass for the DysonSeries operator parameters.

required
ctrl (Qubits, int)

A register to control this operation on. Default to 0.

0
Note

The control version is an optimized version when an input register is 0. If the input register is not 0, the gates will be applied.

DysonSeriesSelectBinary

DysonSeriesSelectBinary(
    strategy_cg: Qubrick, flag=None, adder=None, **kwargs
)

Bases: Qubrick

A modified version of the Dyson series expansion as in arXiv:1805.00675.

Note

If flagging time collisions, a flag qubrick is placed before the DysonSeriesSelectBinary in the binary version.

Parameters:

Name Type Description Default
strategy_cg class

strategy to apply compression gadget subroutine.

required
flag Qubrick

a binary version of a flag to mark time collisions in the time-discretization register. Flagging time collisions is optional.

None
adder Qubrick

a qubrick implementing add/subtract operation.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    register: CompositeRegister,
    data: DysonSeriesData,
    ctrl: Qubits | int = 0,
)

Apply the Dyson series select operator.

Parameters:

Name Type Description Default
register CompositeRegister

register (binary) for Dyson series indexing.

required
data DysonSeriesData

Dataclass for the DysonSeries operator parameters.

required
ctrl (Qubits, int)

A register to control this operation on. Default to 0.

0

DysonSeriesSelectUnary

DysonSeriesSelectUnary(
    fast_forward_exp, lcu, flag=None, **kwargs
)

Bases: Qubrick

A modified version of the Dyson series expansion as in arXiv:1805.00675.

Note

If flagging time collisions, a flag qubrick is placed after the DysonSeriesSelectUnary in the unary version.

Parameters:

Name Type Description Default
fast_forward_exp Qubrick

a qubrick implementing the time-evolution of the fast-forwardable part of the Hamiltonian.

required
lcu Qubrick

a block-encoding subroutine for appliying Hamiltonian to the sustem register.

required
flag Qubrick

a unary version of a flag to mark time collisions in the time-discretization register. Flagging time collisions is optional.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    register: CompositeRegister,
    data: DysonSeriesData,
    ctrl: Qubits | int = 0,
)

Apply the Dyson series select operator.

Parameters:

Name Type Description Default
register CompositeRegister

register for Dyson series indexing (unary version).

required
data DysonSeriesData

Dataclass for the DysonSeries operator parameters.

required
ctrl (Qubits, int)

A register to control this operation on. Default to 0.

0

FlagCollisionsBinary

FlagCollisionsBinary(**kwargs)

Bases: Qubrick

A FlagCollisionsBinary Qubrick to reflect (time) collisions.

Implementation of the collision functionality as described in "Optimized quantum algorithms for simulating the Schwinger effect" research paper (internal document).

Note

For the DysonSeriesBinary logic, the flag is to applied before the application of Hamiltonians, in contrast to DysonSeriesUnary logic.

compute

compute(
    discret_reg: Qubits,
    trunc_reg: Qubits,
    ctrl: Qubits | int = 0,
)

Construct the Qubrick.

Parameters:

Name Type Description Default
discret_reg Qubits

registers to be compared (registers where time collisions may occure).

required
trunc_reg Qubits

register indicating the value to compare up to.

required
ctrl (Qubits, int)

a register to control this operation on. Default to 0.

0
Note on convention

The resulting register, flag, stores 1 if at least one collision occured, 0 otherwise.

FlagCollisionsUnary

FlagCollisionsUnary(**kwargs)

Bases: Qubrick

A FlagCollisions Qubrick to reflect (time) collisions.

Implementation of the collision functionality as described in "Optimized quantum algorithms for simulating the Schwinger effect" research paper (internal document).

Note

for unary version of the DysonSeries (unary version of the truncation register).

compute

compute(
    discret_reg: Qubits,
    trunc_reg: Qubits,
    ctrl: Qubits | int = 0,
)

Construct the Qubrick.

Parameters:

Name Type Description Default
discret_reg Qubits

registers to be compared (registers where time collisions may occure).

required
trunc_reg Qubits

register indicating the value to compare up to.

required
ctrl (Qubits, int)

a register to control this operation on. Default to 0.

0
Note on convention

The resulting register, flag, stores 1 if at least one collision occured, 0 otherwise.

Rz

Rz(**kwargs)

Bases: Qubrick

Implementation of a direct Rz rotation using the built-in rz method.

This provides a simple interface for rotations that wraps the native rz gate.

RzAdder

RzAdder(adder: Adder = None, **kwargs)

Bases: Qubrick

Implementation of Rz rotation using an adder-based approach.

This uses the rotation catalyst state and an adder to implement an Rz rotation on the target register.

Parameters:

Name Type Description Default
adder Qubrick

Qubrick for implementing the addition in PGA.

None
**kwargs dict[str, Any]

Extra key word arguments for the Qubrick constructor.

{}

ComputeHammingWeightBinaryRecursion

ComputeHammingWeightBinaryRecursion(adder=None, **kwargs)

Bases: Qubrick

Quantum circuit to compute the Hamming Weight of a register that uses roughly O(N/2) ancillae and O(N) Toffoli.

This Qubrick computes the hamming weight of a quantum register (coherently) based on the algorithm outlined in this paper: Boyar, Joan, and René Peralta. "The exact multiplicative complexity of the Hamming weight function." This is a truly recursive algorithm that computes the hamming weight of a register by splitting it into three separate registers: U, V, and M. The third register, M, is of size 1 and is just an arbitrary qubit in the original register. Reigsters U and V are then an even split of qubits in the original register excluding the M qubit. The hamming weight is then computed as H(U) + H(V) + M where H(U) and H(V) are the hamming weight of U and V which are computed by calling the hamming weight computation function recursively.

Parameters:

Name Type Description Default
adder Qubrick

Qubrick to perform a quantum adder.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(target_register: Qubits, ctrl: Qubits | int = 0)

Compute the Hamming Weight.

Parameters:

Name Type Description Default
target_register Qubits

The target qubit register to compute the hamming weight of.

required
ctrl Qubits or int

Quantum control conditions

0
Note
  • Allocates a quantum register storing the hamming weight

ComputeHammingWeightGroupOfThrees

ComputeHammingWeightGroupOfThrees(
    use_black_box: bool = False, **kwargs
)

Bases: Qubrick

Quantum circuit to compute the Hamming Weight of a quantum register that uses roughly N ancillae and O(N) Toff.

This Qubrick computes the hamming weight of a quantum register (coherently). This is a recursive algorithm that groups qubits into batches of the 3 and computes the hamming weight of these qubits. The carry bit in this output is upgraded to the "next level" while the low-bit is tossed back into the current group of qubits. This process is repeated until all low-bits at the current level have been added and we are left with only one bit - this becomes the low bit in our hamming weight register. The process is then repeated on all of the carry bits that were upgraded to the "next level". This process is repeated until there are no more carry bits that get upgraded. This algorithm is described in arXiv:1709.06648.

compute

compute(target_register: Qubits, ctrl: Qubits | int = 0)

Compute the Hamming Weight.

Parameters:

Name Type Description Default
target_register Qubits

The target qubit register to compute the hamming weight of.

required
ctrl Qubits or int

Quantum control conditions

0
Note
  • Allocates a quantum register storing the hamming weight
  • If qubrick is controlled and the user wants black box cost, then the black box cost will be just naively counted from operations

ComputeHammingWeightNaive

ComputeHammingWeightNaive(adder=GidneyAdd(), **kwargs)

Bases: Qubrick

Naive/Qubit-efficient circuit to compute the Hamming Weight of a quantum register.

This Qubrick computes the hamming weight of a quantum register (coherently). The structure of this algorithm is to initialize a register of size log(N + 1) for an N qubit register and then traverse serially through the qubits in the target register and perform controlled adders onto the newly allocated ancilla register such that the value of the qubit in the target register is added into the value of the hamming weight register.

Parameters:

Name Type Description Default
adder Qubrick

Qubrick to perform a quantum adder.

GidneyAdd()
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(target_register: Qubits, ctrl: Qubits | int = 0)

Compute the Hamming Weight.

Parameters:

Name Type Description Default
target_register Qubits

The target qubit register to compute the hamming weight of.

required
ctrl Qubits or int

Quantum control conditions

0
Note
  • Allocates a quantum register storing the hamming weight

HammingWeightPhasing

HammingWeightPhasing(
    angle,
    rot_is_rz: bool = False,
    hamming_weight_qubrick=None,
    use_catalyst_state: bool = False,
    catalyst_state_reg=None,
    use_padding: bool = False,
    use_black_box: bool = False,
    **kwargs,
)

Bases: Qubrick

Implement a stack of rotations of the same angle using hamming weight phasing.

Parameters:

Name Type Description Default
angle float | RotationAngle

An angle specifying the angle of the rotations

required
rot_is_rz bool

Flag to determine if attempting to perform Rz rotations or phase gates

False
hamming_weight_qubrick Qubrick

A Qubrick that computes the hamming weight of a register

None
use_catalyst_state bool

A flag to determine if the Phasing circuit should be used to implement the growingtower of rotations.

False
catalyst_state_reg Qubits

The catalyst state for the PhaseC circuit

None
use_padding bool

A flag to determine if the Hamming Weight register should be padded with clean ancilla so that the size is consistent with the size of the catalyst state. If it is not padded, then a single phase gate needs to be applied during the PhaseC circuit. If it is padded, then the rotations should be completely decomposed via Toffolis when adding onto the catalyst state assuming the catalyst state is large enough to implement the angle passed in exactly. If the catalyst state is not large enough based on the precision of the angle, I believe a rotation is still required.

False
use_black_box bool

Uses black box AV counts if set to True. Default is False.

False
**kwargs dict[str, Any]

Additonal Qubrick kwargs

{}

angle property writable

angle

Angle specifying the angle of the rotations.

compute

compute(target_register: Qubits, ctrl: Qubits | int = 0)

Implement a stack of rotations using Hamming weight phasing.

Parameters:

Name Type Description Default
target_register Qubits

The register on which to apply the rotations

required
ctrl int or Qubits

The quantum control conditions.

0

PhasingCircuit

PhasingCircuit(
    base_angle,
    rot_is_rz: bool = False,
    use_black_box: bool = False,
    **kwargs,
)

Bases: Qubrick

Implement the phasing circuit.

Notes
  • See under section "Additional basis rotations."

Parameters:

Name Type Description Default
base_angle float | RotationAngle

An angle specifying the base angle of the growing tower of rotations

required
rot_is_rz bool

Flag to determine if attempting to perform Rz rotations or phase gates

False
use_black_box bool

Uses black box AV counts if set to True. Default is False.

False
**kwargs dict[str, Any]

Additonal Qubrick kwargs

{}

base_angle property writable

base_angle

Angle specifying the base angle of the growing tower of rotations.

compute

compute(
    target_reg: Qubits,
    catalyst_reg: Qubits,
    ctrl: Qubits | int = 0,
    final_qubits: Qubits | int = 0,
)

Use the phasing circuit to implement a tower of growing rotations.

Parameters:

Name Type Description Default
target_reg Qubits

The state to implement the rotations upon

required
catalyst_reg Qubits

The catalyst state to use which is specific to the base angle being implemented

required
ctrl int or Qubits

Classical or Quantum control conditions

0
final_qubits Qubits

If passed in, these are the three qubits on which we just perform Z, S, and T directly instead of adding on to the catalyst state.

0
Notes
  • The implemented circuit applies rotations of base_angle(2*i) for the i'th qubit of the target_reg where i runs from 0 to len(target_reg) - 1.

compute_subblock

compute_subblock(top, mid, bottom)

Compute half-adder-like block.

LKSMultiplexor

LKSMultiplexor(qrom, gate, **kwargs)

Bases: Qubrick

Multiplexor using data-lookup oracles.

The construction is detailed in arXiv:1812.00954 . Circuit described in Appendix D.

Parameters:

Name Type Description Default
qrom Qubrick

Data-loader for loading angles to bits_of_precision-bits of precision.

required
gate op

Rotation gate type to use in multiplexed rotations.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg,
    tgt,
    angles,
    bits_of_precision,
    lambda_val=None,
    **kwargs,
) -> None

Compute circuit for LKS multiplexor.

Parameters:

Name Type Description Default
index_reg Qubits

Index register.

required
tgt Qubits

Register to apply rotations onto.

required
angles list or None

List of angles to supply to rotations.

required
bits_of_precision int

Bits of precision for rotations.

required
lambda_val int

Power-of-two knob to trade off between gates and qubits. If None (default), then optimal lambda is calculated. If None (default), the clean decomposition will be used.

None
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}
Note

We want to apply single-qubit \(\text{RY}\) rotations conditioned on different significant bits. We truncate the exact angle and obtain an integer approximation of it, and so, each angle we apply is \(\frac{2\pi a_k} {2^{k + 1}}\). However, we express \(\text{RY}\) rotations as \(\text{RY}(\theta) = e^{iY \frac{\theta}{2}}\). If you account for this factor of 2 in the denominator, and also convert from radians to degrees \((\frac{180}{\pi})\), you end up using:

  • \(\text{angle} = \frac{\frac{2\pi a_k}{2^{k + 1}}}{2} \times \frac{180}{\pi}\)
  • Simplified: \(\text{angle} = \frac{180 a_k}{2^{k + 1}}\)

LKSStatePrep

LKSStatePrep(coeffs, mplxr, **kwargs)

Bases: Qubrick

State preparation detailed in arXiv:1812.00954 .

This routine works for real, positive coefficients.

Parameters:

Name Type Description Default
coeffs list or None

List of coefficients to load into state.

required
mplxr Qubrick

Multiplexor to use in state prep.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(qbits, **mplxr_kwargs) -> None

Compute circuit for LKS state prep.

Parameters:

Name Type Description Default
qbits Qubits

Qubits to prep state on.

required
**mplxr_kwargs dict

Dictionary with keyword arguments to pass to the multiplexor.

{}

Other Parameters:

Name Type Description
bits_of_precision int

Bits of precision for rotations.

lambda_val int

Power-of-two knob to trade off between gates and qubits. If None, then optimal lambda is calculated. If None, the clean decomposition will be used.

MajoranaFermionOperator

MajoranaFermionOperator(
    operator, multiplexor_cls, **kwargs
)

Bases: Qubrick

The Majorana Fermion Operator shown in Fig. 9 of arXiv:1805.03662 .

Parameters:

Name Type Description Default
operator callable

A function implementing an operator taking in two arguments: (1) the qubit register (2) the control conditions. Typically either the x or y method of a QPU instance

required
multiplexor_cls Qubrick

The class for a Qubrick that implements multiplexing

required
**kwargs dict[str, Any]

Additional Qubrick kwargs

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    ctrl: Qubits | int = 0,
)

Compute the Majorana Fermion Operation.

Parameters:

Name Type Description Default
index_reg Qubits

The qubit register that represents the indices to multiplex over

required
target_reg Qubits

The qubit register that the Majorana Fermion Operator gets applied onto.

required
ctrl Qubits or int

Additional classical or quantum control conditions. Defaults to 0 which performs the operation as if a control qubit were in the |1> state.

0

MultiplexedAliasSampling

MultiplexedAliasSampling(
    multiplexed_usp, multiplexed_qrom, **kwargs
)

Bases: Qubrick

Implements the multiplexed alias sampling subroutine for multiplexed arbitrary state preparation.

Overview

The goal of this protocol is to take a list of lists of coefficients (probabilities corresponding to the squares of statevector amplitudes), load these coefficients using QROM, and prepare the state formed as the superposition of the states defined by each list of coefficients. This method is heavily based on the Alias Sampling technique used in quantum computing.

Steps of the Routine

Assuming familiarity with regular alias sampling, the steps are:

  1. Superposition Preparation:

    • MultiplexedUSP is used to prepare a superposition of uniform superposition states multiplexed over indices \( i \).
    • The dimension of the \( i \)th USP state corresponds to the length of the coefficients for the \( i \)th state that we want to prepare.
  2. Computing alt and keep Values:

    • We calculate the alt and keep values for each set of coefficients.
    • The size of the alt register is buffered to fit the largest value for all states in superposition.
    • This is managed by bit-shifting the keep values by this maximum value, similar to regular alias sampling.
  3. Multiplexor of Multiplexors:

    • We load the alt and keep values in superposition using the construction from arXiv:2007.14460.
  4. Partitioning QROM Output:

    • The multiplexed QROM output is partitioned into alt and keep registers.
  5. Creating a Coin Flip State:

    • Hadamards are applied to create a uniform superposition in the coin flip register.
  6. Conditional Swapping:

    • A comparator checks whether coin_toss_reg is less than keep_reg.
    • If true, the input prep_reg is swapped with alt_reg.
Note
  • This construction is based on step 3 in the THC paper.
  • As implemented, this routine is deterministic. However, in the reference above, it only succeeds conditioned on a success flag.
  • The success flag comes from the comparator in MultiplexedUSP.
  • Currently, this always succeeds because rotations are directly implemented.
  • Once synthesis is introduced, alias sampling will succeed only conditionally based on the USP.

Parameters:

Name Type Description Default
multiplexed_usp Qubrick

A subroutine implementation for multiplexed USP.

required
multiplexed_qrom Qubrick

A subroutine implementation for multiplexed QROM.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    prep_reg,
    index,
    data_reg,
    data,
    bit_precision,
    inner_lambda_val=None,
    outer_lambda_val=None,
) -> None

Compute the multiplexed alias sampling.

Parameters:

Name Type Description Default
prep_reg Qubits

Register in which we want to prepare our superposition of states.

required
index Qubits

Register containing the coefficients for the multiplexing loop.

required
data_reg Qubits

Register with the different d values loaded in for computing the multiplexed USP.

required
data List[List[int]]

A list of lists of coefficients representing each of the states to be prepared in superposition.

required
bit_precision int

Number of bits of precision to be used in the alias sampling discretization procedure.

required
inner_lambda_val int

Power-of-two knob to trade off between gates and qubits for the inner loop in multiplexed QROM. Defaults to None.

None
outer_lambda_val int

Power-of-two knob to trade off between gates and qubits for the outer loop in multiplexed QROM. Defaults to None.

None

Contiguizer

Contiguizer(**kwargs)

Bases: Qubrick

Given an input register, produce a new register with 1s from the most significant bit down to 0.

This routine comes from:

"Even more efficient quantum computations of chemistry through tensor hypercontraction" (arxiv:2011.03494) See, see step 3.(a) of the double factorization compilation in Appendix C.

The motivation behind the routine is as follows: in regular USP, we apply Hadamard gates on the input register as the first step in the routine. The number of Hadamards is determined by the bit-length of the number of states \(d\), so \(d=10=1010\) would require Hadamards on 4 qubits in the first step of the USP protocol. When multiplexing, we could in principle have numbers with different bit lengths over which we multiplex, meaning that we would need different numbers of Hadamard gates. The solution to implement this is to initialize a new register (copy in this qubrick) and to prepare a state which has 1's on all the bits up to and including the bit-length of \(d\) (or more precisely, a superposition over such states for all \(d\) over which we are multiplexing). This register can then be used to apply a sequence of controlled Hadamards such that the appropriate number of Hadamards are applied for each value of \(d\).

As an example, say we are multiplexing over two values, \(d_1=2\) and \(d_2=10\). 2 has a bit length of 2 and 10 has a bit length of 4, so the contiguizer would realize a superposition \(|0011\rangle + |1111\rangle\). Notice that for each value \(d_i\), the value loaded into the state is (1 << d_i.bit_length()) - 1.

compute

compute(target_reg: Qubits, ctrl: Qubits | int = 0)

Compute the contiguizer.

Takes an target_reg register and produces a new register (copy_reg) with 1's corresponding to the bit lengths of the values encoded in the register (loaded in superposition).

Parameters:

Name Type Description Default
target_reg Qubits

Register encoding the data to be multiplexed over.

required
ctrl Qubits or int

Optional register to control on. Defaults to 0 (no control).

0

MultiplexedRealUSP

MultiplexedRealUSP(
    multiplexor=None, contiguizer=None, **kwargs
)

Bases: Qubrick

Qubrick to perform multiplexed USP.

Note
  • Uses the RealUSP flavor of USP from "Even more efficient quantum computations of chemistry through tensor hypercontraction" arxiv:2011.03494.

Parameters:

Name Type Description Default
contiguizer Qubrick

Qubrick instance to generate the contiguized register. Defaults to instance of Contiguizer.

None
multiplexor Qubrick

Qubrick class to perform the multiplexing. Defaults to ZeroAncMultiplexor.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi,
    index_reg,
    data_reg,
    data,
    rotator=None,
    succ_reg=None,
    error_param=None,
    ctrl: int = 0,
) -> None

Generate a superposition of USPs with values given by data.

The idea behind multiplexed USP is to take a list of dimensions d, and for each to prepare a d-dimensional uniform state in a coherent superposition. This superposition will be loaded into the psi register. Two additional registers must be passed in: index_reg, which is used to perform the multiplexing and data_reg, which contains an encoding of all of the d values (e.g. as loaded in via QROM).

To illustrate the idea, let's use a simple worked example. Say we have data=[2, 3]. We want to prepare a superposition of states

\[\frac{1}{\sqrt{2}}(|00\rangle + |01\rangle)\]

and

\[\frac{1}{\sqrt{3}}(|00\rangle + |01\rangle + |10\rangle)\]

Let us assume for simplicity that index_reg has been prepared in a uniform superposition state. Then our target is to prepare the state

\[ \frac{1}{\sqrt{2}}(\frac{1}{\sqrt{2}}(|00\rangle + |01\rangle) + \frac{1}{\sqrt{3}}(|00\rangle + |01\rangle + |10\rangle)) \]

or

\[\frac{1}{2\sqrt{6}}(|00\rangle + |01\rangle) + \frac{1}{\sqrt{6}}(|10\rangle)\]

Parameters:

Name Type Description Default
psi Qubits

The register on which the superposition of uniform states is to be prepared.

required
index_reg Qubits

The register used to load the indices for the multiplexing.

required
data_reg Qubits

A register with the different values of d for the USP calls loaded in superposition.

required
data List[int]

List of dimensions for each of the USPs we are multiplexing over.

required
rotator Qubits

Register to perform rotation on. Defaults to None, in which case, it is allocated by the Qubrick.

None
succ_reg Qubits

Qubit to herald success. Defaults to None, in which case, it is allocated by the Qubrick.

None
error_param float or int

Parameter determining the accuracy of truncated rotation angles. If None (default), angles are exact and no success qubit is output.

None
ctrl Qubits or int

Optional register to control on. Defaults to 0 (no control).

0
Note

The effect of setting various default args has not been tested.

MultiplexedUSP

MultiplexedUSP(
    multiplexor=None, contiguizer=None, **kwargs
)

Bases: Qubrick

Qubrick to perform multiplexed USP.

Note
  • Uses the USP flavor of USP from "Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity" (arXiv:1805.03662).

Parameters:

Name Type Description Default
multiplexor Qubrick

Qubrick class to perform the multiplexing. Defaults to ZeroAncMultiplexor.

None
contiguizer Qubrick

Qubrick instance to generate the contiguized register. Defaults to instance of Contiguizer.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi,
    index_reg,
    data_reg=None,
    data=None,
    ctrl: int = 0,
    data_bits=None,
) -> None

Generate a superposition of USPs with values given by data.

The idea behind multiplexed USP is to take a list of dimensions d, and for each to prepare a d-dimensional uniform state in a coherent superposition. This superposition will be loaded into the psi register. Two additional registers must be passed in: index_reg, which is used to perform the multiplexing and data_reg, which contains an encoding of all of the d values (e.g. as loaded in via QROM).

To illustrate the idea, let's use a simple worked example. Say we have data=[2, 3]. We want to prepare a superposition of states \(\frac{1}{\sqrt{2}}(|00\rangle + |01\rangle)\) and \(\frac{1}{\sqrt{3}}(|00\rangle + |01\rangle + |10\rangle)\). Let us assume for simplicity that index_reg has been prepared in a uniform superposition state. Then our target is to prepare the state $$ \frac{1}{\sqrt{2}}(\frac{1}{\sqrt{2}}(\ket{00} + \ket{01}) + \frac{1}{\sqrt{3}}(\ket{00} + \ket{01} + \ket{10}) $$ , or \(\frac{1}{2\sqrt{6}}(|00\rangle + |01\rangle) + \frac{1}{\sqrt{6}}(|10\rangle)\).

Parameters:

Name Type Description Default
psi Qubits

The register on which the superposition of uniform states is to be prepared.

required
index_reg Qubits

The register used to load the indices for the multiplexing.

required
data_reg Qubits

A register with the different values of d for the USP calls loaded in superposition.

None
data List[int]

List of dimensions for each of the USPs we are multiplexing over.

None
ctrl Qubits or int

Optional register to control on. Defaults to 0 (no control).

0
data_bits Qubits

Deprecated argument name for data_reg.

None
Note

The effect of setting various default args has not been tested.

BinaryTreeMultiplexor

BinaryTreeMultiplexor(**kwargs)

Bases: Qubrick

Optimized multiplexing based on Fig. 7 in arXiv:1805.03662.

compute

compute(
    index_reg: Qubits,
    multiplex_function: Callable,
    used_indices: list[int] | None = None,
    ctrl: Qubits | int = 0,
)

Compute the binary tree multiplexing circuit.

We account for various cases:

  1. There is no data to load (exit the routine).
  2. Loading a single item does not require this hefty machinery.
  3. Loading two items without a control is similarly cheap to the single-item-case.
  4. Loading n > 2 items without a control.
  5. Loading n > 1 items with a control.

The bottom two cases are handled by calling workhorse methods in this class.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register storing the values over which the multiplexing is performed.

required
multiplex_function Callable

A function which takes an index and then index register and performs the operation associated with that index.

required
used_indices list

List of indices corresponding to terms where the operators are actually being applied.

None
ctrl (int, Qubits)

Control for \(\text{SELECT}\). Defaults to 0.

0

ConditionallyCleanMultiplexor

Bases: Qubrick

Multiplexor utilizing conditionally clean construction as presented in arxiv:2407.17966.

See Figure 9 in reference. This qubrick works by constructing the first relevant index as aggregated conditions and then applies the corresponding data conditioned on this. Then it sequentially moves through the relevant indices by finding the MSB difference, undoing the structure to this point, and then redo-ing with the new condition utiliing the partial_compute() function.

Notes

This should be called with the filter '>>hermitian-window-filter>>' to take advantage of the cancellations that occur when you replace one condition with the next. This does the minimal work before calling the filter without hardcoding the cancellations with a maximum filter window required that is linear in the number of qubits in index register. Hardcoding like in the BinaryTreeMultiplexor requires more care as gates that begin each layer in the conditionally clean structure include adjacent bits such that the gate that switches branch for bit i, will need to be aware of the higher bit (i-1) to apply the correct cancellation.

compute

compute(
    index_reg: Qubits,
    multiplex_function: Callable,
    used_indices: list[int] | None = None,
    ctrl: Qubits | int = 0,
)

Compute the serial multiplexing circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register storing the values over which the multiplexing is performed.

required
multiplex_function callable

A function which takes an index and then index register and performs the operation associated with that index.

required
used_indices list

List of indices corresponding to terms where the operators are actually being applied.

None
ctrl (int, Qubits)

Control for \(\text{SELECT}\). Defaults to 0.

0

GeneralMultiplexedRotationNaive

GeneralMultiplexedRotationNaive(
    rot_qbk: RotationInterface
    | GivensRotation[float] = None,
    **kwargs,
)

Bases: Qubrick

Routine for implementing multiplexed rotations, allowing for various tradeoffs.

Attributes:

Name Type Description
rot_qbk RotationInterface

The rotation protocol compliant Qubrick used for rotation operations.

Parameters:

Name Type Description Default
rot_qbk RotationInterface

The rotation protocol compliant Qubrick used for rotation operations.

None
**kwargs dict[str, Any]

Additional keyword arguments.

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    rotation_specs: list[RotationSpec] | None = None,
    bits_of_precision: int | None = None,
    *,
    ctrl: Qubits | int = 0,
    **kwargs,
)

Compute circuit for a naive multiplexed rotation.

Implements the naive approach to multiplexed rotations by applying each rotation conditionally based on the index register matching the rotation's mux_idx. This implementation has no constraints on target qubits or rotation specifications, offering maximum flexibility at the cost of circuit efficiency.

Parameters:

Name Type Description Default
index_reg Qubits

Index register that selects which rotation to apply.

required
target_reg Qubits

Target register containing all qubits where rotations may be applied.

required
rotation_specs list[RotationSpec] | None

List of specifications for each rotation to be multiplexed.

None
bits_of_precision int | None

Precision for the rotation angles.

None
ctrl Qubits | int

Additional control for the entire operation (keyword-only parameter).

0
**kwargs dict[str, Any]

Additional keyword arguments.

{}

Raises:

Type Description
ValueError

If rotation_specs is not provided, or if a rotation spec doesn't have a rotation Qubrick specified and no default was provided.

GeneralMultiplexedRotationViaQROM

GeneralMultiplexedRotationViaQROM(
    qrom: QROM,
    rot_qbk: RotationInterface
    | GivensRotation[Qubits] = None,
    adder: Adder = PhaseGradientAdder(),
    is_unary: bool | None = None,
    **kwargs,
)

Bases: Qubrick

Optimized implementation of multiplexed rotations using QROM for angle loading.

This Qubrick implements multiplexed rotations using a QROM-based approach for efficient angle loading, significantly reducing the T-count compared to naive implementations when there are many rotations.

The implementation has specific constraints: within each multiplexer group: 1. All rotations must use the same rotation Qubrick 2. All rotations must target the same qubit indices

However, different multiplexer groups can have different target qubits and rotation Qubricks. This allows for efficient batching while maintaining some flexibility.

Attributes:

Name Type Description
qrom Incomplete

The Qubrick used for quantum ROM operations to load rotation angles.

rot_qbk Incomplete

Default rotation protocol compliant Qubrick used for all rotations unless overridden.

adder Incomplete

Adder Qubrick used in the rotation implementation.

bin_to_unary Incomplete

Converter for binary to unary encoding when required by the QROM.

Parameters:

Name Type Description Default
qrom QROM

The Qubrick instance used for quantum ROM operations.

required
rot_qbk RotationInterface | GivensRotation[Qubits]

Default rotation protocol compliant Qubrick to use if not specified in individual rotation specs. If None, each RotationSpec must provide its own.

None
adder Adder

Adder Qubrick used in the rotation implementation. Defaults to PhaseGradientAdder().

PhaseGradientAdder()
is_unary bool | None

Whether to use unary encoding for the index register. If None, auto-detects from the QROM implementation.

None
**kwargs dict[str, Any]

Additional keyword arguments passed to the Qubrick constructor.

{}

compute_rotations

compute_rotations(
    target_indices: list[list[int]],
    angle_reg: Qubits,
    target_reg: Qubits,
    rot_qbks_for_batch: list[RotationInterface],
    b_of_p: int,
) -> None

Apply rotation operations for each mux group using loaded angles.

Parameters:

Name Type Description Default
target_indices list[list[int]]

List of target qubit indices for each rotation.

required
angle_reg Qubits

Register containing loaded angle values.

required
target_reg Qubits

Target register containing qubits where rotations are applied.

required
rot_qbks_for_batch list[RotationInterface]

List of rotation Qubricks to use for each rotation.

required
b_of_p int

Bits of precision per rotation angle.

required

Raises:

Type Description
ValueError

If no rotation Qubrick is available for a rotation.

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    rotation_specs: list[RotationSpec] | None = None,
    mux_data: GeneralMultiplexedRotationViaQROMConfig
    | None = None,
    *,
    ctrl: Qubits | int = 0,
)

Compute circuit for multiplexed rotation using QROM-based implementation.

This method implements multiplexed rotations using QROM for efficient angle loading. It processes rotation specifications in batches, loads batched angle data from QROM, and applies rotations to target qubits according to the specifications.

The implementation requires that within each multiplexer group: 1. All rotations must use the same rotation Qubrick 2. All rotations must target the same qubit indices

Different multiplexer groups can have different target qubits and rotation Qubricks, allowing for flexibility while maintaining efficiency.

Note

This Qubrick supports Unary QROMs as well as Binary QROMs. If the QROM is unary it must have a is_unary attribute or you must set the is_unary flag in the init

Parameters:

Name Type Description Default
index_reg Qubits

The index register that selects which rotation to apply.

required
target_reg Qubits

The register where rotations are applied.

required
rotation_specs list[RotationSpec] | None

Specifications for each rotation.

None
mux_data GeneralMultiplexedRotationViaQROMConfig | None

Configuration data for the multiplexed rotation, including: - bits_of_precision: Precision bits per rotation angle - batches: Optional custom batching information. Ex. if you have three mux_groups ordered 0,1,2 then you can send in [[0],[1],[2]] which batches none of them together, or [[0,1],[2]] to just batch 0 and 1 together. [[0,1,2]] Would batch all of them together. Defaults to zero batching, which is [[0],[1],[2]] in the example. - lambda_val: Optional parameter for QROM optimization - ignore_last_batch_qrom_cleanup: Flag to skip final QROM cleanup

None
ctrl Qubits | int

Optional control for the entire operation.

0

Raises:

Type Description
ValueError

If mux_data is not provided or contains invalid specifications.

GeneralMultiplexedRotationViaQROMConfig dataclass

GeneralMultiplexedRotationViaQROMConfig(
    bits_of_precision: int,
    lambda_val: int | None = None,
    batches: list[list[int]] | None = None,
    ignore_last_batch_qrom_cleanup: bool = False,
)

Encapsulates configuration data for QROM-based multiplexed rotations.

This dataclass holds all the parameters needed to configure a QROM-based multiplexed rotation: precision settings, batching strategy, and other optimization parameters.

Attributes:

Name Type Description
bits_of_precision int

Number of bits used to represent each rotation angle.

lambda_val int | None

Optional lambda value parameter for the QROM implementation.

batches list[list[int]] | None

Optional custom batching of rotations by group indices. If None, default batching will be used based on group indices.

ignore_last_batch_qrom_cleanup bool

If True, skips the QROM cleanup step after the last batch for optimization purposes. Default is False.

GivensPPRs

GivensPPRs(**kwargs)

Bases: Qubrick

Applies the Givens rotation using Pauli Product Rotations.

This method implements the unitary:

\[ G(\theta) = e^{-i\frac{\theta}{2} (\mathbf{Y} \otimes \mathbf{X} - \mathbf{X} \otimes \mathbf{Y})} \]

which is equivalent to applying two single-qubit rotations, one with \( +\theta \) and the other with \( -\theta \).

compute

compute(
    rotation_encoding: float,
    target_reg: Qubits,
    ctrl: Qubits | int = 0,
) -> None

Apply the Givens rotation using Pauli Product Rotations.

Parameters:

Name Type Description Default
rotation_encoding float

Rotation angle in degrees.

required
target_reg Qubits

Two qubits to apply the rotation to.

required
ctrl Qubits | int

Control qubit (default: 0).

0

GivensRotationFusedAdder

GivensRotationFusedAdder(
    adder: Adder | None = None, **kwargs
)

Bases: Qubrick

Implements a Givens rotation using a fused quantum adder.

This method optimizes the standard two-adder approach by using a single fused adder, reducing qubit usage and circuit depth. Instead of requiring a full carry bit, it compresses the operation into a more compact form.

Note
  • This implementation requires only \( b - 1 \) bits for a \( b \)-bit approximation of \( \theta \).
  • The reduced bit count results from the fused adder structure, which avoids additional carry propagation.
  • However, current implementations may have basis states reversed, which requires correction.

Parameters:

Name Type Description Default
adder GidneyAdd or NaiveAdd

The quantum adder used to update phase values. Defaults to GidneyAdd(), but can be replaced with NaiveAdd() for alternative implementations.

None
**kwargs dict[str, Any]

Additional arguments passed to Qubrick.

{}

compute

compute(
    rotation_encoding: Qubits,
    target_reg: Qubits,
    ctrl: Qubits | int = 0,
) -> None

Apply the Givens rotation using phase gradient addition with a single fused adder.

Parameters:

Name Type Description Default
rotation_encoding Qubits

Rotation angle in degrees.

required
target_reg Qubits

Two qubits to apply the rotation to.

required
ctrl Qubits | int

Control qubit (default: 0).

0

GivensRotationTwoAdders

GivensRotationTwoAdders(
    adder: Adder | None = None, **kwargs
)

Bases: Qubrick

Implements a Givens rotation using two quantum adders.

This method applies a Givens rotation by using a phase gradient register and two quantum adders (GidneyAdd or NaiveAdd). It is particularly useful for multiplexed rotations, allowing for efficient conditional operations on quantum states.

Note
  • This implementation requires \( b + 1 \) bits for a \( b \)-bit approximation of \( \theta \).
  • The extra bit accounts for the additional carry bit required in the controlled addition.
  • If \( b \) bits are used, precision loss can occur due to truncation.

Parameters:

Name Type Description Default
adder GidneyAdd or NaiveAdd

The quantum adder used to update phase values. Defaults to GidneyAdd(), but can be replaced with NaiveAdd() for alternative implementations.

None
**kwargs dict[str, Any]

Additional arguments passed to Qubrick.

{}

compute

compute(
    rotation_encoding: Qubits,
    target_reg: Qubits,
    ctrl: Qubits | int = 0,
) -> None

Apply the Givens rotation using phase gradient addition with two adders.

Parameters:

Name Type Description Default
rotation_encoding Qubits

Rotation angle in degrees.

required
target_reg Qubits

Two qubits to apply the rotation to.

required
ctrl Qubits | int

Control qubit (default: 0).

0

GivensRZs

GivensRZs(**kwargs)

Bases: Qubrick

Implements a Givens rotation using RZ gates.

This class applies a Givens rotation using Pauli Z rotations (RZ) combined with Clifford gates. The operation targets two qubits and implements the unitary:

\[ G(\theta) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\theta) & \sin(\theta) & 0 \\ 0 & -\sin(\theta) & \cos(\theta) & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \]

This transformation can be decomposed into single-qubit RZ gates with Clifford conjugation:

  1. Apply a Clifford pre-rotation to transform the computational basis.
  2. Perform controlled RZ gates to introduce the phase shift.
  3. Apply a Clifford post-rotation to revert to the original basis.

This method is useful in multiplexed rotations and block encoding techniques.

Parameters:

Name Type Description Default
**kwargs dict[str, Any]

Additional arguments passed to Qubrick.

{}

compute

compute(
    rotation_encoding: float,
    target_reg: Qubits,
    ctrl: Qubits | int = 0,
) -> None

Apply the Givens rotation using Rz gates and Clifford basis change rotations.

Parameters:

Name Type Description Default
rotation_encoding float

Rotation angle in degrees.

required
target_reg Qubits

Two qubits to apply the rotation to.

required
ctrl Qubits | int

Control qubit (default: 0).

0

MultiplexedRotationInterface

Bases: Protocol

Protocol defining the interface for multiplexed rotation Qubricks.

MultiplexedRotation Qubricks should implement this protocol to ensure they have a consistent interface for controlling multiple rotations based on an index.

The protocol standardizes on a consistent parameter order with index register and target register as the first two parameters, followed by implementation-specific positional parameters, with the control parameter at the end. This allows for flexibility in how implementations handle their specific parameters.

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    rotation_specs: list[RotationSpec] | None,
    *,
    ctrl: Qubits | int = 0,
) -> None

Compute the multiplexed rotation.

OneAncMultiplexor

OneAncMultiplexor(**kwargs)

Bases: Qubrick

\(\text{SELECT}\) operator using a single, clean ancilla.

Circuit shown in Fig. (1.a) in arXiv:1812.00954.

compute

compute(
    index_reg: Qubits,
    multiplex_function: Callable,
    used_indices: list[int] | None = None,
    ctrl: Qubits | int = 0,
)

Compute a multiplexing circuit using a single, clean ancilla.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register storing the values over which the multiplexing is performed.

required
multiplex_function callable

A function which takes an index and then index register and performs the operation associated with that index.

required
used_indices list

List of indices corresponding to terms where the operators are actually being applied.

None
ctrl (int, Qubits)

Control for \(\text{SELECT}\). Defaults to 0.

0

RotationInterface

Bases: Protocol

Protocol defining the interface for rotation Qubricks.

Rotation Qubricks should implement this protocol to ensure they have a consistent interface for use in multiplexed rotations.

The protocol allows for additional custom arguments via **kwargs to accommodate different rotation implementations with specialized parameters.

compute

compute(
    rotation_encoding: Qubits | float,
    target_reg: Qubits,
    *,
    ctrl: Qubits | int = 0,
) -> None

Compute the rotation.

RotationSpec dataclass

RotationSpec(
    group_idx: int,
    mux_idx: int,
    target_qubits: list[int],
    angle: float,
    rot_qbk: RotationInterface | None = None,
)

Specification for a single rotation in a multiplexed rotation circuit.

This dataclass holds all information needed to define a single rotation operation within a multiplexed rotation circuit, including its group, multiplexing index, target qubits, angle, and optional custom rotation Qubrick.

Attributes:

Name Type Description
group_idx int

Index of the group this rotation belongs to. Groups allow batched execution of compatible rotations.

mux_idx int

Multiplexing select index - when the index register equals this value, the rotation will be applied.

target_qubits list[int]

List of qubit indices where the rotation should be applied.

angle float

Rotation angle in radians.

rot_qbk RotationInterface | None

Optional custom rotation Qubrick to use for this specific rotation. If None, the default rotation Qubrick from the parent class will be used.

SawtoothMultiplexor

SawtoothMultiplexor(max_index=None, **kwargs)

Bases: Qubrick

Unoptimized multiplexor from Fig. 5 in arXiv:1805.03662.

For some function, f, which returns an operator associated with an integer index, performs: \(\text{SELECT}|l\rangle|\psi\rangle \rightarrow |l\rangle f(l)|\psi\rangle\).

Parameters:

Name Type Description Default
max_index (Optional, int)

Integer corresponding to the maximum possible index that will be multiplexed over. Defaults to None.

None

Parameters:

Name Type Description Default
max_index (Optional, int)

Integer corresponding to the maximum possible index that will be multiplexed over. Defaults to None.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

set_max_index

set_max_index(index_val) -> None

Set the max index.

Sets the max_index attribute to the input arg.

Parameters:

Name Type Description Default
index_val int

The max possible index to iterate over, given as an int.

required

compute

compute(
    index_reg: Qubits,
    multiplex_function: Callable,
    used_indices: list[int] | None = None,
    ctrl: Qubits | int = 0,
)

Compute the sawtooth multiplexing circuit.

We account for four cases, and some sub-cases:

  1. There is no data to load (exit the routine).
  2. Loading a single item does not require this hefty machinery.
  3. Loading two items without a control is similarly cheap to the single-item-case.
  4. All other cases will proceed with unary iteration, removing controls on the index register when possible.

The last case above has a couple of sub-cases:

(i). We (rarely, but sometimes) may determine we needn't control on any qubit for a particular index value; consider this a free lunch!

(ii). The uncontrolled version of this routine is slightly cheaper than the controlled case. We actually have additional small sub-cases here: (a). If we determine we only need to control on a single qubit for a particular index, we can directly apply that element and exit the for loop. (b). In all other cases, the uncontrolled case uses one fewer ancilla than the controlled case (and also one fewer elbow).

(iii). After accounting for one fewer qubit for the uncontrolled case, the controlled and uncontrolled case than perform the same logic.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register storing the values over which the multiplexing is performed.

required
multiplex_function callable

A function which takes an index and then index register and performs the operation associated with that index.

required
used_indices list

List of indices corresponding to terms where the operators are actually being applied.

None
ctrl (int, Qubits)

Control for \(\text{SELECT}\). Defaults to 0.

0

ZeroAncMultiplexor

ZeroAncMultiplexor(**kwargs)

Bases: Qubrick

Most naïve version of multiplexing possible.

For some function, f, which returns an operator associated with an integer index performs: \(\text{SELECT}|l\rangle|\psi\rangle \rightarrow |l\rangle f(l)|\psi\rangle\).

compute

compute(
    index_reg: Qubits,
    multiplex_function: Callable,
    used_indices: list[int] | None = None,
    ctrl: Qubits | int = 0,
)

Compute the serial multiplexing circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register storing the values over which the multiplexing is performed.

required
multiplex_function callable

A function which takes an index and then index register and performs the operation associated with that index.

required
used_indices list

List of indices corresponding to terms where the operators are actually being applied.

None
ctrl (int, Qubits)

Control for \(\text{SELECT}\). Defaults to 0.

0

ArbitraryStatePrep

ArbitraryStatePrep(amps, multiplexor=None, **kwargs)

Bases: Qubrick

State preparation based on the routine in arXiv:quant-ph/0407010v1 .

Realizes:

\[ \text{PREP}\ket{0} \rightarrow \frac{\sum_i a_i}{\sum_i|a_i|^2}\ket{i} \]
Note

This routine prepares the desired state up to a global phase. When checking the validity of this routine, one should check fidelity rather than exact state vector matching. The other consequence is that controlling this routine will lead to (incorrect) relative phases.

Parameters:

Name Type Description Default
multiplexor (Qubrick, None)

Which multiplexing scheme to use in state prep. Defaults to NaiveMultiplexedRotations().

None
amps list or None

List of amplitudes to load into state.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

set_angles

set_angles(y_angles, z_angles=None) -> None

Set angles if none computed. Z angles defaults to None.

compute

compute(qbits, ctrl: int = 0, **kwargs) -> None

Compute the arbitrary state preparation circuit.

Parameters:

Name Type Description Default
qbits Qubits

Qubits to operate on.

required
ctrl Qubits or int

Register to control the on. Defaults to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

EfficientMultiplexedRotations

EfficientMultiplexedRotations(
    gate=None, angles=None, **kwargs
)

Bases: Qubrick

Decomposition of uniformly controlled rotations to single qubit rotation + CNOTs.

Corresponds to Figure 2 in arXiv:0407010 .

Parameters:

Name Type Description Default
gate op or None

Rotation gate type to use in multiplexed rotations. Defaults to None.

None
angles list or None

List of angles to supply to rotations. Defaults to None.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

set_gate

set_gate(gate) -> None

Choose which unitary to multiplex (qc.op function).

set_angles

set_angles(angles) -> None

Choose angles for multiplexed unitaries (list).

compute

compute(index_reg, tgt, ctrl: int = 0, **kwargs) -> None

Compute the multiplexed rotation.

Parameters:

Name Type Description Default
index_reg Qubits / int

Index qubits.

required
tgt Qubits / int

Target qubit.

required
ctrl (Qubits, int)

A register to control this operation on. Default to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

NaiveMultiplexedRotations

NaiveMultiplexedRotations(gate=None, angles=None, **kwargs)

Bases: Qubrick

Controlled rotations from arXiv:0407010 .

Parameters:

Name Type Description Default
gate op or None

Rotation gate type to use in multiplexed rotations. Defaults to None.

None
angles list or None

List of angles to supply to rotations. Defaults to None

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

set_gate

set_gate(gate) -> None

Choose which unitary to multiplex (qc.op function).

set_angles

set_angles(angles) -> None

Choose angles for multiplexed unitaries (list).

compute

compute(index_reg, tgt, ctrl: int = 0, **kwargs) -> None

Compute the multiplexed rotation.

Parameters:

Name Type Description Default
index_reg Qubits / int

Index qubits.

required
tgt Qubits / int

Target qubit.

required
ctrl (Qubits, int)

A register to control this operation on. Default to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

PrepareNaive

PrepareNaive(coeffs, multiplexor=None, **kwargs)

Bases: Qubrick

State preparation based on the routine in arXiv:quant-ph/0407010v1 .

Realizes:

\[\text{PREP}\ket{0} \rightarrow \frac{\sum_i \sqrt{a_i}}{\sum_i|a_i|}\ket{i}\]
Warning

This function only works for real and positive coefficients

Parameters:

Name Type Description Default
multiplexor Qubrick

Which multiplexing scheme to use in state prep. Defaults to NaiveMultiplexedRotations().

None
coeffs list or None

List of coefficients to load into state.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

set_angles

set_angles(y_angles) -> None

Set angles if none computed.

compute

compute(qbits, ctrl: int = 0, **kwargs) -> None

Compute the state preparation circuit.

Parameters:

Name Type Description Default
qbits Qubits

Qubits to operate on.

required
ctrl (Qubits, int)

A register to control this operation on. Default to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

BitonicPermutation

BitonicPermutation(**kwargs)

Bases: Qubrick

A routine that permutes qubit registers.

compute

compute(
    target_reg: Qubits,
    reg_size: int,
    register_permutation_function: Callable,
    ctrl: Qubits | int = 0,
)

Compute the circuit for the canonical swap-up-type permutation.

The sorting/permutation logic to perform a permutation of a register is independent of the particular quantum op used to effect a permutation. to use. This compute method exists so we can write down this logic just once and re-use it with your favorite "payload".

Parameters:

Name Type Description Default
target_reg (Qubits, list)

Register we apply the permutation to. This register can conceptually be interpreted as a single large register, or as several registers of equal size. To facilitate this dual use, we currently allow passing a list of Qubits objects (though this is likely to be refactored).

required
reg_size int

Number of bits in each target sub-register of target_reg.

required
register_permutation_function callable

Which quantum operation to use to effect the permutation of the target register.

required
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0
Note

target_reg is given as a single register or as a list of multiple registers.

PhaseGradientAdder

PhaseGradientAdder(**kwargs)

Bases: Qubrick

Optimized adder for use in phase gradient addition.

Parameters:

Name Type Description Default
**kwargs dict[str, Any]

Keyword arguments

{}

compute

compute(lhs: QUInt, rhs: QUInt, ctrl: Qubits | None = None)

Circuit for optimized phase gradient adder.

This construction comes from Fig. 13 in arXiv:2007.07391.

Parameters:

Name Type Description Default
lhs QUInt | None

The register with the phase gradient catalyst state. May be None when rhs is a single qubit and the implicit one-qubit catalyst is dropped.

required
rhs QUInt

The register we are adding into the phase gradient register.

required
ctrl (Optional, int | Qubits)

Control register. Defaults to 0 (i.e. no control).

None
Note
  • The phase gradient register is usually one qubit smaller than the rhs.
  • However, there exists at least one known case where they are equal in size (ex. when using GivensRotationTwoAdders).
  • When they are the same size, we can actually drop a CZ, and so, we distinguish these cases.
  • For rhs two qubits and lhs one qubit shorter than rhs, the Fig.~13 chain collapses to three bilinear gates (no temporary elbow). With no adder control, those are lhs.z(rhs[0]), lhs.x(rhs[0]), rhs[1].z(). With a control register ctrl (e.g. bidirectional rotation tests), merge ctrl into each gate as lhs[0].z(rhs[0] | ctrl), lhs[0].x(rhs[0] | ctrl), rhs[1].z(cond=ctrl).
  • For lhs and rhs both a single qubit, only the closing segment remains (matching GidneyAdd on one-qubit lhs).

PrepareClockState

PrepareClockState(**kwargs)

Bases: Qubrick

Prepares a clock state.

\[\text{PREP}|0\rangle^{\otimes n} = \sum_{k=0}^n \sqrt(p_k)|1\rangle^{\otimes k}|0\rangle^{\otimes n - k}\]
Example

The output state will be of the form \(\sqrt{p_0}|000\rangle + \sqrt{p_1}|100\rangle + \sqrt{p_2}|110\rangle + \sqrt{p_3}|111\rangle\).

The ket-states should be understood as a unary representation of an integer. For example, \(|1110\rangle\) is 3 in decimal \(|1000\rangle\) is 1 in decimal.

Note

The controlled version only ensures \(\text{c-PREP}|+\rangle|0\rangle^{\otimes n} = |0\rangle|0\rangle^{\otimes n}+|1\rangle \text{PREP}|0\rangle^{\otimes n}\) (a.k.a. if the input state is not zero, there is still an action of this Qubrick).

compute

compute(target, probs, ctrl: int = 0) -> None

Prepare the clock state according to given probabilities.

Parameters:

Name Type Description Default
target Qubits

Target qubits.

required
probs list

List of probability, such that the output state is of the form \(\sqrt{p_0}|000\rangle + \sqrt{p_1}|100\rangle + \sqrt{p_2}|110\rangle + \sqrt{p_3}|111\rangle\).

required
ctrl (Qubits, int)

Control register. Default to 0.

0

PrepareWState

PrepareWState(khot_prep=None, wpower2_prep=None, **kwargs)

Bases: Qubrick

Prepares a W state.

\[\text{PREP}|0\rangle^{\otimes n} = \sum_{k=0}^n |0\rangle^{\otimes k-1}|1\rangle|0\rangle^{\otimes n - k}\]
Note

The controlled version only ensures \(\text{c-PREP}|+\rangle|0\rangle^{\otimes n} = |0\rangle|0\rangle^{\otimes n} + |1\rangle\text{PREP}|0\rangle^{\otimes n}\) (a.k.a. if the input state is not zero, there is still an action of this Qubrick).

Parameters:

Name Type Description Default
khot_prep Qubrick

Qubrick to implement a Clock state.

None
wpower2_prep Qubrick

Qubrick to prepare a W state over a power-of-two number of amplitudes.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(target: Qubits, ctrl: Qubits | int = 0)

Prepares a W state.

Parameters:

Name Type Description Default
target Qubits

Target qubits.

required
ctrl (Qubits, int)

Control register. Default to 0.

0

PrepareWStatePowerTwo

PrepareWStatePowerTwo(**kwargs)

Bases: Qubrick

Prepares a W state for power of two target size.

\[\text{PREP}|0\rangle^{\otimes 2^n} =\sum_{k=0}^{2^n} |0\rangle^{\otimes k-1}|1\rangle|0\rangle^{\otimes 2^n - k}\]
Note

The controlled version only ensures \(\text{c-PREP}|+\rangle|0\rangle^{\otimes n} = |0\rangle|0\rangle^{\otimes n} + |1\rangle\text{PREP}|0\rangle^{\otimes 2^n}\) (a.k.a. if the input state is not zero, there is still an action of this Qubrick).

compute

compute(target: Qubits, ctrl: Qubits | int = 0)

Prepares a W state for power of two target size.

Parameters:

Name Type Description Default
target Qubits

Target qubits.

required
ctrl (Qubits, int)

Control register. Default to 0.

0

CosineWindow

CosineWindow(adder: Adder | None = None, **kwargs)

Bases: Qubrick

Cosine window from arxiv:2110.09590 .

compute

compute(
    phase_reg: Qubits, ctrl: Qubits | int = 0, **kwargs
)

Executes circuit for implementing cosine window.

Parameters:

Name Type Description Default
phase_reg Qubits

Phase qubit register

required
ctrl (Optional, int, Qubits)

Control register

0
**kwargs dict[str, Any]

Optional keyword arguments. Included to stay consistent with the arguments of window emulators.

{}

RectWindow

RectWindow(**kwargs)

Bases: Qubrick

Rectangular/Dirichlet window. This is the default window function for the textbook QPE.

compute

compute(
    phase_reg: Qubits, ctrl: Qubits | int = 0, **kwargs
)

Executes circuit for implementing rectangular window.

Parameters:

Name Type Description Default
phase_reg Qubits

Phase qubit register

required
ctrl (Optional, int, Qubits)

Control register

0
**kwargs dict[str, Any]

Optional positional arguments. Included to stay consistent with the arguments of window emulators.

{}

SineWindow

SineWindow(**kwargs)

Bases: Qubrick

Qubrick for window state with the sine function over the amplitudes.

This window state can be used to achieve an optimal Holevo variance as outlined in Section II B. of arxiv:1805.03662 . See \(\Xi_m\) state.

Note

The state prepared here has a global phase of pi. Additionally, if the user does not care about having purely real or purely imaginary values in the prepared state, the rz gates can be replaced by phase gates in which case the magnitudes will be the same as the expected state, but each amplitude will be rotated by some (global) phase.

compute

compute(
    target_reg,
    flag_reg,
    ctrl: int = 0,
    use_real_amps: bool = False,
    **kwargs,
) -> None

Computes sine window function.

Parameters:

Name Type Description Default
target_reg Qubits

register on which the sine window state is prepared

required
flag_reg Qubits

flag qubit when 0, the sine window state is prepared

required
ctrl Qubits

control qubit

0
use_real_amps bool

If True, prepares real amplitudes

False
**kwargs dict[str, Any]

Optional keyword arguments

{}
Note
  • Needs a round of amplitude amplification.

SineWindowPhaseCatalysis

SineWindowPhaseCatalysis(**kwargs)

Bases: Qubrick

Qubrick for window state with the sine function over the amplitudes.

Prepared via phase catalyst register.

This window state can be used to achieve an optimal Holevo variance as outlined in Section II B. of arxiv:1805.03662 . See \(\Xi_m\) state.

The phase catalyst implementation is outlined in Appendix B of arxiv:1805.03662

Note

The state prepared here will be the same as SineWindow up to a global phase.

compute

compute(
    target_reg: Qubits,
    flag_reg: Qubits,
    ctrl: Qubits | int = 0,
    **kwargs,
)

Computes sine window function via phase catalyst state.

Note
  • Needs a round of amplitude amplification.

SineWindowQubitEfficient

SineWindowQubitEfficient(**kwargs)

Bases: Qubrick

Qubrick for window state with the sine function over the amplitudes using only two active qubits at a time.

This window state can be used to achieve an optimal Holevo variance with the construction of the circuit outlined in Section IV of arxiv:2303.12505.

compute

compute(
    phase_reg: Qubits, ctrl: Qubits | int = 0, **kwargs
)

Computes sine window function.

Parameters:

Name Type Description Default
phase_reg Qubits

phase qubit register

required
ctrl (Optional, int, Qubits)

control register

0
**kwargs dict[str, Any]

optional keyword arguments

{}

WindowEmulator

WindowEmulator(
    emulator_func: Callable[Concatenate[int, P], NDArray],
    emulator_function_options: dict[str, Any] | None = None,
    **kwargs,
)

Bases: Qubrick

Constructor for window emulator.

Note
  • Check the window utils module for emulator_func options.
  • Note that this Qubrick does not execute quantum operations; it directly touches the state vector and is not meant to run on a real QPU program.

Parameters:

Name Type Description Default
emulator_func callable

method for computing amplitudes of a window state

required
emulator_function_options dict[str, Any]

Extra keyword arguments for the emulator_func

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

uncompute

uncompute() -> None

Override the default uncomputation.

compute

compute(phase_reg, psi, ctrl: int = 0, **kwargs) -> None

Compute amplitudes of taper state.

Note

Assumes Qubits in QC are ordered as: (1) Psi (2) Phase Register (3) All other qubits

Parameters:

Name Type Description Default
phase_reg Qubits

Phase qubit register

required
psi Qubits

System register

required
ctrl (Optional, int, Qubits)

Control register

0
**kwargs dict[str, Any]

Optional keyword arguments. Included to stay consistent with the arguments of window emulators.

{}
Note
  • Use emulators for a reasonably small number of phase qubits!
  • The control version is not currently implemented

WindowStatePrep

WindowStatePrep(amps, state_prep=None, **kwargs)

Bases: Qubrick

General class for simulating window state via state prep.

Parameters:

Name Type Description Default
amps ndarray

Amplitudes for window state.

required
state_prep Qubrick

Qubrick to implement the state preparation for the window function.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    phase_reg: Qubits, ctrl: Qubits | int = 0, **kwargs
)

Executes circuit for preparing window state.

Parameters:

Name Type Description Default
phase_reg Qubits

Phase qubit register.

required
ctrl (Optional, int, Qubits)

Control register.

0
**kwargs dict[str, Any]

Optional keyword arguments. Included to stay consistent with the arguments of window emulators.

{}

QPE

QPE(
    bits_of_precision,
    unitary,
    window_kwargs=None,
    window_func=RectWindow(),
    **kwargs,
)

Bases: Qubrick

Implements the standard quantum phase estimation routine using controlled unitaries and QFT.

Parameters:

Name Type Description Default
bits_of_precision int

The number of bits to estimate the phase to.

required
unitary Qubrick

The unitary for which we want to estimate the eigenphase.

required
window_kwargs dict

Keyword args for window func (e.g. in case it uses amplitude amplification). Defaults to None.

None
window_func Qubrick

Which window func to apply to the initial state of the phase register. Defaults to RectWindow.

RectWindow()
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi, phase_reg, ctrl: int = 0, **unitary_kwargs
) -> None

Compute quantum phase estimation.

Parameters:

Name Type Description Default
psi Qubits

State register for the computation.

required
phase_reg Qubits

Register to load the eigenphase into.

required
ctrl (Optional, int, Qubits)

Register to control the QPE on.

0
unitary_kwargs dict[str, Any]

Any additional kwargs that need to be passed to the unitary qubrick.

{}
Note

The control version makes no assumptions on the input states (phase register), and thus uses a naive control implementation (control on all operations). If the phase register is known to be in the zero state, one can control only phase window and the QFT or, if the RectWindow is used, one could only control the unitary.

CoherentIterativeQPE

CoherentIterativeQPE(
    bits_of_precision,
    unitary,
    window_kwargs=None,
    window_func=RectWindow(),
    **kwargs,
)

Bases: Qubrick

Performs iterative QPE as shown in Fig. 16 of arxiv:2105.02859.

Parameters:

Name Type Description Default
bits_of_precision int

The number of bits of precision to estimate the eigenphase to.

required
unitary Qubrick

The unitary to compute the eigenphase of.

required
window_kwargs dict[str, Any]

Key word arguments to pass to the window function.

None
window_func Qubrick

Which window func to apply to the initial state of the phase register. Defaults to RectWindow.

RectWindow()
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi, phase_reg, ctrl: int = 0, **unitary_kwargs
) -> None

Compute coherent iterative quantum phase estimation.

Parameters:

Name Type Description Default
psi Qubits

State register for the computation.

required
phase_reg Qubits

Register to load the eigenphase into.

required
ctrl (Optional, int, Qubits)

Register to control the QPE on.

0
unitary_kwargs dict[str, Any]

Any additional kwargs that need to be passed to the unitary qubrick.

{}
Note

The control version makes no assumptions on the input states (phase register), and thus uses a naive control implementation (control on all operations). If the phase register is known to be in the zero state, one can control only phase window and the QFT.

DoublePhaseKickbackQPE

DoublePhaseKickbackQPE(
    bits_of_precision,
    unitary: QubitizedWalkOperator,
    window_func=RectWindow(),
    window_kwargs=None,
    **kwargs,
)

Bases: Qubrick

Implements the double-phase kickback quantum phase estimation routine.

This version of QPE achieves m bits of precision using m qubits in the phase register, but uses approximately half the number of queries to the unitary than is necessary when using traditional QPE. It should be noted however that the input unitary for this approach must be in the form of a qubitized walk operator as outlined in Fig. 1 of arxiv:1805.03662 .

Parameters:

Name Type Description Default
bits_of_precision int

The number of bits to estimate the phase.

required
unitary QubitizedWalkOperator

The unitary for which we want to estimate the eigenphase. Must be in the form of a qubitized walk operator as outlined in Fig. 1 of arxiv:1805.03662 .

required
window_func Qubrick

Which window func to apply to the initial state of the phase register.

RectWindow()
window_kwargs dict

Keyword args for window func (e.g. in case it uses amplitude amplification). Defaults to None.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi, phase_reg, be_ancilla_reg, ctrl: int = 0, **kwargs
) -> None

Compute QPE based on Figure 2 of arxiv:1805.03662 .

Parameters:

Name Type Description Default
psi Qubits

State register for the computation.

required
phase_reg Qubits

Register to load the eigenphase into.

required
be_ancilla_reg Qubits

State register used to implement the block encoding on psi.

required
ctrl (Optional, int, Qubits)

Register to control the QPE on. Defaults to None. Note that we don't need to control the Hadamards or the inverse QFT as they will cancel on the branch that the controlled unitaries aren't applied on.

0
kwargs dict[str, Any]

Any additional kwargs that need to be passed to the unitary qubrick.

{}

IterativeQPE

IterativeQPE(
    bits_of_precision,
    unitary,
    window_kwargs=None,
    window_func=RectWindow(),
    **kwargs,
)

Bases: Qubrick

Implements incoherent (measurement-based) QPE.

Warning

Conceptually, iterative quantum phase estimation should be able to be performed using a single ancilla, and this Qubrick is capable of doing so -- however, since no values are returned from Qubricks, this functionality is currently broken.

Parameters:

Name Type Description Default
bits_of_precision int

The number of bits of precision to estimate the eigenphase to.

required
unitary Qubrick

The unitary to compute the eigenphase of.

required
window_kwargs dict[str, Any]

Key word arguments to pass to the window function.

None
window_func Qubrick

Which window func to apply to the initial state of the phase register. Defaults to RectWindow.

RectWindow()
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi, phase_reg, ctrl: int = 0, **unitary_kwargs
) -> None

Compute quantum phase estimation.

Parameters:

Name Type Description Default
psi Qubits

State register for the computation.

required
phase_reg (Qubits, Optional)

Register into which the eigenphase is loaded.

required
ctrl (Optional, int, Qubits)

Register to control the QPE on.

0
unitary_kwargs dict[str, Any]

Any additional kwargs that need to be passed to the unitary qubrick.

{}
Note
  • The control version makes no assumptions on the input states (phase register), and thus uses a naive control implementation (control on all operations). If the phase register is known to be in the zero state, one can control only phase window and the QFT.
  • Classical result is: list of binary values corresponding to the bits_of_precision bit representation of the estimated eigenphase.

OptimizedDoublePhaseKickbackQPE

OptimizedDoublePhaseKickbackQPE(
    bits_of_precision,
    unitary: QubitizedWalkOperator,
    window_func=RectWindow(),
    window_kwargs=None,
    **kwargs,
)

Bases: Qubrick

Implements an optimized version of the double-phase kickback quantum phase estimation routine.

There are two main optimizations we use here that lead to some minor gate-cost reductions:

  1. Subsequent applications of the controlled reflections (C-R_L) can be merged together with some simple qubit logic consisting of two CNOT gates. This means that in the middle of the circuit, we reduce the cost of applications of C-R_L (PREP^ - Refl - PREP) by approximately a factor of 2.
  2. Inspecting the naive DoublePhaseKickbackQPE circuit, there are often applications of PREP that are immediately followed by PREP^. With some classical logic, we can choose to not apply these gates as PREP is self-inverse.

In the same way as DoublePhaseKickbackQPE, this version of QPE achieves m bits of precision using m qubits in the phase register, but uses approximately half the number of queries to the unitary than is necessary when using traditional QPE. It should be noted however that the input unitary for this approach must be in the form of a qubitized walk operator as outlined in Fig. 1 of arxiv:1805.03662 .

Parameters:

Name Type Description Default
bits_of_precision int

The number of bits to estimate the phase.

required
unitary QubitizedWalkOperator

The unitary for which we want to estimate the eigenphase. Must be in the form of a qubitized walk operator as outlined in Fig. 1 of arxiv:1805.03662 .

required
window_func Qubrick

Which window func to apply to the initial state of the phase register.

RectWindow()
window_kwargs dict

Keyword args for window func (e.g. in case it uses amplitude amplification). Defaults to None.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi, phase_reg, be_ancilla_reg, ctrl: int = 0, **kwargs
) -> None

Compute QPE based on Figure 2 of arxiv:1805.03662 .

Parameters:

Name Type Description Default
psi Qubits

State register for the computation.

required
phase_reg Qubits

Register to load the eigenphase into.

required
be_ancilla_reg Qubits

State register used to implement the block encoding on psi.

required
ctrl (Optional, int, Qubits)

Register to control the QPE on. Defaults to None. Note that we don't need to control the Hadamards or the inverse QFT as they will cancel on the branch that the controlled unitaries aren't applied on.

0
kwargs dict[str, Any]

Any additional kwargs that need to be passed to the unitary qubrick.

{}

Qubitization

Qubitization(
    block_encoding: Qubrick, **kwargs: dict[str, Any]
)

Bases: Qubrick

Canonical qubitization iterate.

This Qubrick follows the canonical form of Qubitization introduced in "Hamiltonian Simulation by Qubitization" (arXiv:1610.06546) and used extensively in Lin Lin's lecture notes). This convention starts with a block encoding followed by an all-zero reflection.

Parameters:

Name Type Description Default
block_encoding Qubrick

Qubrick to apply the block encoding circuit.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi: Qubits,
    be_ancilla_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
    **kwargs: dict[str, Any],
)

Compute the qubitization.

Parameters:

Name Type Description Default
psi Qubits

Target state register.

required
be_ancilla_reg Qubits

Block encoding auxiliary register.

required
data PauliSum | list[int]

Hamiltonian or bitstring values to be qubitized.

required
ctrl Qubits | int

Register to control the qubitization on. Defaults to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

QubitizedWalkOperator

QubitizedWalkOperator(
    state_prep: Qubrick,
    select: Qubrick,
    **kwargs: dict[str, Any],
)

Bases: Qubrick

Qubitization iterate.

This Qubrick uses the form introduced in "Quantum Algorithm for Spectral Measurement with Lower Gate Count" (arxiv:1711.11025).

This form is also used by the Google group for their QPE-Qubitization papers. This form differs from the canonical Qubitization iterate (see Fig. 1 of "Even more efficient quantum computations of chemistry through tensor hypercontraction" (arXiv:2011.03494)), and effectively performs a qubitization of a quantum walk, hence the name QubitizedWalkOperator.

Note

Despite being a Qubitization iterate, this Qubrick has a different signature than the canonical Qubitization Qubrick, in that it is defined in terms of \(\text{PREP}\) and \(\text{SELECT}\) rather than arbitrary block encodings. Furthermore, when plugging it in to QPE, one must be careful with what initial state is passed to QPE. When using this Qubrick, one must first call \(\text{PREP}\)'s compute before calling QPE's compute, as this \(\text{PREP}\) effectively prepares a portion of an eigenstate of the QubitizedWalkOperator (or at least a state which has meaningful support on it).

Parameters:

Name Type Description Default
state_prep Qubrick

Qubrick to apply the state prep.

required
select Qubrick

Qubrick to select the Hamiltonian terms from.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    psi: Qubits,
    be_ancilla_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
    **kwargs: dict[str, Any],
)

Compute the qubitization.

Parameters:

Name Type Description Default
psi Qubits

Target state register.

required
be_ancilla_reg Qubits

Block encoding auxiliary register.

required
data PauliSum | list[int]

Hamiltonian or bitstring values to be qubitized.

required
ctrl Qubits | int

Register to control the qubitization on. Defaults to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

BinaryTreeSelect

BinaryTreeSelect(**kwargs)

Bases: Qubrick

Optimized select from Fig. 7 in "Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity" (arXiv:1805.03662).

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
)

Compute Select circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register determining which op in data to apply.

required
target_reg Qubits

Qubit register to apply the data to.

required
data PauliSum | list[int]

Hamiltonian terms expressed as a PauliSum to load or a list of bitvalues to load.

required
ctrl Qubits | int

Control register. Defaults to 0.

0

ConditionallyClean

ConditionallyClean(**kwargs)

Bases: Qubrick

Select utilizing conditionally clean construction as presented in arxiv:2407.17966.

Notes

This should be called with the filter '>>toffoli-window-filter>>' to take advantage of the cancellations that occur when you replace one condition with the next. This does the minimal work before calling the filter without hardcoding the cancellations with a maximum filter window required that is linear in the number of qubits in index register.

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
)

Compute Select circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register determining which op in data to apply.

required
target_reg Qubits

Qubit register to apply the data to.

required
data (PauliSum, List[int])

Hamiltonian terms expressed as a PauliSum to load or a list of bitvalues to load.

required
ctrl (int, Qubits)

Control register. Defaults to 0.

0

SawtoothSelect

SawtoothSelect(**kwargs)

Bases: Qubrick

Unoptimized select from Fig. 5 in "Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity" (arXiv:1805.03662).

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
)

Compute Select circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register determining which op in data to apply.

required
target_reg Qubits

Qubit register to apply the data to.

required
data PauliSum | list[int]

Hamiltonian terms expressed as a PauliSum to load or a list of bitvalues to load.

required
ctrl Qubits | int

Control register. Defaults to 0.

0

SelectNaive

SelectNaive(**kwargs)

Bases: Qubrick

Most naïve version of \(\text{SELECT}\) possible.

If the data to be loaded is given as a list of Hamiltonian terms, performs the transformation

\[|l\rangle |\psi\rangle \rightarrow |l\rangle U_l|\psi\rangle\]

If the data to be loaded as given as a list of bit values \(data\), performs the transformation

\[|l\rangle |\psi\rangle \rightarrow |l\rangle |\psi + data_l\rangle\]

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
)

Compute Select circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register determining which op in data to apply.

required
target_reg Qubits

Qubit register to apply the data to.

required
data PauliSum | list[int]

Hamiltonian terms expressed as a PauliSum to load or a list of bitvalues to load.

required
ctrl Qubits | int

Control register. Defaults to 0.

0

SelectOneAnc

SelectOneAnc(**kwargs)

Bases: Qubrick

\(\text{SELECT}\) operator using a single, clean auxiliary qubit.

Circuit shown in Fig. 1A in "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954).

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    data: PauliSum | list[int],
    ctrl: Qubits | int = 0,
)

Compute Select circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Qubit register determining which op in data to apply.

required
target_reg Qubits

Qubit register to apply the data to.

required
data PauliSum | list[int]

Hamiltonian terms expressed as a PauliSum to load or a list of bitvalues to load.

required
ctrl Qubits | int

Control register. Defaults to 0.

0

BitonicSort

BitonicSort(**kwargs)

Bases: Qubrick

Qubrick for performing a bitonic sort on a list of qubits.

unsort

unsort(regs_list, ctrl: int = 0) -> None

Uncompute sort a list of qubit registers.

This performs a measurement in the X basis for each record qubit. If the outcome is one, it will require a phase-fixup performed by a comparator.

Parameters:

Name Type Description Default
regs_list list[Qubits]

List of qubit registers to unsort.

required
ctrl (int, Qubits)

Control qubit for the routine.

0

compute

compute(
    regs_list: list[Qubits],
    direction: int,
    ctrl: Qubits | int = 0,
)

Sort a list of qubit registers.

Sort in ascending order if direction = 0, and descending otherwise. See : https://en.wikipedia.org/wiki/Bitonic_sorter#/media/File:BitonicSort.svg

Parameters:

Name Type Description Default
regs_list list[Qubits] or VectorRegister

List of qubit registers to sort.

required
direction int

Direction of the sort (0-ascending vs 1-descending).

required
ctrl (int, Qubits)

Control qubit for the routine. Defaults to 0.

0
Note

This assumes same size register for all registers in regs_list.

BinaryToUnaryUncomputation

BinaryToUnaryUncomputation(permutation_qbk=None, **kwargs)

Bases: Qubrick

Circuit which undoes a binary to unary conversion.

Suppose we have an index register which encodes some integer \(i\) between zero and \(N - 1\) in binary, but we wish to convert this to unary. One way to do this would be to allocate \(N - 1\) ancillae (starting in the zero state), perform a Pauli X on the topmost ancilla, and "swap it down" to the \(i^{\text{th}}\) position (i.e. perform the dagger of SwapUp). This gives us a unary encoding of \(i\) on the ancillae entangled with a binary encoding of \(i\) on the index reg.

If we are later tasked with uncomputing/disentangling the ancillary register from the index reg, we could simply use SwapUp to bring the ON bit back to the top ancilla qubit, and then turn it back OFF with a Pauli X again. In this situation, by construction, we are returning all the ancillae back to zero. In this situation, we needn't use the canonical SwapUp circuit from ... for the uncomputation; we can instead employ the use of measurement-based uncomputation, which instead uses right elbows and no non-Clifford gates. This method is discussed in Appendix C and depicted in Fig. 10 in arXiv:1902.02134 .

Parameters:

Name Type Description Default
permutation_qbk Qubrick

Qubrick to implement the bitonic permutations..

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    reg_size: int,
    ctrl: Qubits | int = 0,
)

Compute reversal of Binary to Unary conversion.

Parameters:

Name Type Description Default
index_reg Qubits

Input number state.

required
target_reg Qubits

Register we apply the swap network to.

required
reg_size int

Number of bits in each output register.

required
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0

InjectOp

InjectOp(swap_up, op, **kwargs)

Bases: Qubrick

Inject operation, defined as SwapUp \(^\dagger\) Op SwapUp.

This follows the construction introduced in Eq. 9 in "Exponentially faster implementations of Select(H) for fermionic Hamiltonians" (arXiv:2004.04170).

Parameters:

Name Type Description Default
swap_up Qubrick

SwapUp implementation.

required
op Qubrick

The unitary to inject.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    reg_size: int,
    ctrl: Qubits | int = 0,
)

Compute Inject circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Input number state.

required
target_reg Qubits or VectorRegister

Register to apply the operation to.

required
reg_size int

Number of bits in each item in the target register.

required
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0
Note

For single-qubit unitaries (reg_size = 1), you can pass Qubits as target_reg. For multi-qubit unitaries (reg_size > 1), use VectorRegister as target_reg.

SwapUp

SwapUp(permutation_qbk=None, **kwargs)

Bases: Qubrick

Canonical SwapUp circuit that acts on arbitrary input states.

Assuming an already-loaded list of \(n\) items, each \(b\) bits long, this routine "swaps up" item with index \(x\) from the loaded items to the top position, i.e., to the top \(b\) qubits. The other items remain in positions \(1, ..., n - 1\), permuted in some order.

This follows the construction introduced in "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954).

Parameters:

Name Type Description Default
permutation_qbk Qubrick

Qubrick to implement the bitonic permutations.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(
    index_reg: Qubits,
    target_reg: Qubits,
    reg_size: int,
    ctrl: Qubits | int = 0,
)

Compute SwapUp circuit.

Parameters:

Name Type Description Default
index_reg Qubits

Input number state.

required
target_reg Qubits

Register we apply the swap network to.

required
reg_size int

Number of bits in each item in the target register.

required
ctrl Optional[Qubits, int]

Qreg to control on. Defaults to 0.

0

PauliSumTrotterStrategy

PauliSumTrotterStrategy(
    hamiltonian: PauliSum, trotter_order: int = None
)

Implementation of a TrotterStrategy for the simplest case of looping through Hamiltonian terms.

Parameters:

Name Type Description Default
hamiltonian PauliSum

PauliSum representation of the Hamiltonian to be Trotterized. The order of the terms in the PauliSum determines the order in which the Trotterized terms will be applied, with the coefficients determining their magnitude.

required
trotter_order int

The order of the Trotterization.

None

apply_trotter_terms

apply_trotter_terms(
    factor, system, reverse: bool = False, ctrl: int = 0
)

Apply all the terms in the Hamiltonian, numerically or symbolically.

TrotterQuery

TrotterQuery(
    trotter_strategy: TrotterStrategy | None = None,
    trotter_order: int | None = None,
    hamiltonian: PauliSum | None = None,
    **kwargs,
)

Bases: Qubrick

Qubrick for implementing a Suzuki-Trotter approximation of an exponentiated Hamiltonian.

Parameters:

Name Type Description Default
trotter_strategy TrotterStrategy | None

A class that implements a TrotterStrategy for applying Trotter terms.

None
trotter_order int

The order of Trotterization.

None
hamiltonian PauliSum

The Hamiltonian expressed as a PauliSum.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

trotter_strategy property

trotter_strategy

Set the trotter_strategy property so it can't be modified.

compute

compute(
    system: Qubits,
    steps: int,
    evo_time: int,
    ctrl: Qubits | int = 0,
    trotter_order: int | None = None,
)

Execute the Suzuki-Trotter circuit.

Performs first and second order Trotterization directly. For higher orders, uses recursive calls to generate the appropriate product of operators.

Parameters:

Name Type Description Default
system Qubits

Qubits the Hamiltonian is acting on.

required
steps int

The number of Trotter steps.

required
evo_time int

(int): The total evolution time.

required
ctrl (Qubits, int)

Qubit register to control evolution on. Defaults to 0.

0
trotter_order int

The order of Trotterization. If not set, uses the Qubrick attribute self.trotter_order set at instantiation.

None

TrotterStrategy

Bases: Protocol

Interface for applying unitary terms in Trotterization.

apply_trotter_terms

apply_trotter_terms(
    factor: int | float | complex,
    system: Qubits,
    reverse: bool = False,
    ctrl: Qubits | int = 0,
)

Method describing how to apply the terms in Trotterization, to be implemented in concrete implementations.

USP

USP(**kwargs)

Bases: Qubrick

Qubrick for performing Uniform State Preparation.

From Fig. 12 in "Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity" (arXiv:1805.03662).

compute

compute(
    d,
    target_qreg,
    error_param=None,
    ctrl: int = 0,
    **kwargs,
) -> None

Prepare a uniformly distributed state.

Conceptually, starts by factoring \(d = 2^k L\), although this explicit calculation has been replaced by the num_trailing_zeros and highest_bit functions for better performance. Just applying Hadamard gates creates the desired equal superposition over k of the qubits. For the remaining qubits we need to also perform amplitude amplification to keep only basis states with value < d.

Parameters:

Name Type Description Default
d int

Desired number of uniform terms.

required
target_qreg Qubits

The register to operate on.

required
error_param float

Parameter determining the accuracy of truncated rotation angles. If None (default), angles are exact and no success qubit is output.

None
ctrl Qubits or int

Register to control the USP on. Defaults to None.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

Raises:

Type Description
ValueError

If the register passed in is too small.

Note

The effect of setting various default args has not been tested. Creates desired state up to global phase.

RealUSP

RealUSP(**kwargs)

Bases: Qubrick

Qubrick for performing Uniform State Preparation.

From "Even more efficient quantum computations of chemistry through tensor hypercontraction" (arxiv:2011.03494).

Note
  • This is the version based on the instructions (steps 1-7) under Eq. A15 of Appendix A.
  • A circuit diagram showing a similar implementation (but over two target registers) is shown in Fig. (3).

compute

compute(
    d,
    target_qreg,
    rotator=None,
    succ_reg=None,
    error_param=None,
    ctrl: int = 0,
    **kwargs,
) -> None

Prepare a uniformly distributed state.

Conceptually, starts by factoring \(d = 2^k L\), although this explicit calculation has been replaced by the num_trailing_zeros and highest_bit functions for better performance. Just applying Hadamard gates creates the desired equal superposition over k of the qubits. For the remaining qubits we need to also perform amplitude amplification to keep only basis states with value < d.

Utilizes one auxiliary qubit, the 'rotator', such that CZ gates perform the required reflections.

This routine uses RY rotations, resulting in only real amplitudes.

If no error_param is provided, the rotations are treated as ideal and the probability of success is 1.0. If an error_param is provided, the probability of success will be <=1.0 and a flag qubit will store the result via a comparator. This qubit can be optionally provided via succ_reg.

Parameters:

Name Type Description Default
d int

The number of nonzero terms required.

required
target_qreg Qubits

The register to operate on.

required
rotator Qubits

Register to perform rotation on. Defaults to None, in which case, it is allocated by the Qubrick.

None
succ_reg Qubits

Qubit to herald success. Defaults to None, in which case, it is allocated by the Qubrick.

None
error_param float

Parameter determining the accuracy of truncated rotation angles. If None (default), angles are exact and no success qubit is output.

None
ctrl Qubits or int

Register to control the USP on. Defaults to 0.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

Raises:

Type Description
RuntimeError

If the register passed in is too small.

Note

The effect of setting various default args has not been tested.

ZeroAncillaUSP

ZeroAncillaUSP(qc=None, **kwargs)

Bases: Qubrick

Qubrick for performing Uniform State Preparation without auxiliary qubits.

Adapted from "An efficient quantum algorithm for preparation of uniform quantum superposition states" (arxiv:2306.11747).

compute

compute(d, target_qreg, ctrl: int = 0, **kwargs) -> None

Prepare a uniformly distributed state.

Utilizes binary decomposition of \(d\), controlled Ry and Hadamard gates to avoid auxiliary qubit usage.

Parameters:

Name Type Description Default
d int

Desired number of uniform terms.

required
target_qreg Qubits

The register to operate on.

required
ctrl Qubits or int

Register to control the USP on. Defaults to None.

0
**kwargs dict[str, Any]

Other arguments to pass to the compute.

{}

Raises:

Type Description
RuntimeError

If the register passed in is too small.

AbsoluteDisplacement

AbsoluteDisplacement(
    orthogonal_dot_product, vector_sub, rsqrt, **kwargs
)

Bases: Qubrick

Qubrick for computing the reciprocal of the absolute value of the difference of two vectors.

Specifically, it computes \(\frac{1}{|r1 - r2|} = \frac{1}{\sqrt{(x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2}}\).

Note

Currently, it is on the user to set the constructor args for sub-Qubricks. A consequence of this is that if you want to allow negative values, this must be decided when you instantiate the square sub-Qubrick inside of orthogonal_dot_product rather than in this Qubrick's constructor. Discussions on where this decision should be made are ongoing.

Parameters:

Name Type Description Default
orthogonal_dot_product Qubrick

Qubrick for computing the square of a vector.

required
vector_sub Qubrick

Adder Qubrick for subtracting Qubit registers.

required
rsqrt Qubrick

Qubrick for performing the reciprocal square root operation.

required
kwargs dict[str, Any]

Other key word arguments for the Qubrick.

{}

compute

compute(
    q_vec1, q_vec2, high_precision: bool = False
) -> None

Compute circuit for taking the absolute value of the difference between two vectors.

Parameters:

Name Type Description Default
q_vec1 list

List of registers encoding vector components for one vector.

required
q_vec2 list

List of registers encoding vector components for the other vector.

required
high_precision (Optional, bool)

If True, returns high precision output from inverse square-root. Defaults to False.

False

OrthogonalDotProduct

OrthogonalDotProduct(
    release_ancillae, square, add, **kwargs
)

Bases: Qubrick

Qubrick for squaring an n-component vector, then adding the squared results.

Ex. for a 3-component vector computes \(x^2 + y^2 + z^3\).

Note

Currently, it is on the user to set the constructor args for sub-Qubricks. A consequence of this is that if you want to allow squaring negative values, this must be decided when you instantiate the square sub-Qubrick rather than in this Qubrick's constructor. Discussions on where this decision should be made are ongoing.

Parameters:

Name Type Description Default
release_ancillae bool

Whether to release ancillae in the squaring components.

required
square Qubrick

Qubrick that computes the square of a qubit register.

required
add Qubrick

Adder Qubrick.

required
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

compute

compute(q_vec: list[Qubits] | Qubits)

Compute circuit for squaring an n-component vector.

Parameters:

Name Type Description Default
q_vec Qubits or list[Qubits]

List of Qubits each storing a component of the vector or one big Qubits object with each component (ex. x | y | z).

required

VectorAddition

VectorAddition(
    add, subtract_condition: bool = False, **kwargs
)

Bases: Qubrick

Qubrick for adding (or subtracting) the components of two vectors of Qubits.

Parameters:

Name Type Description Default
add Qubrick

Adder Qubrick for adding Qubit registers.

required
subtract_condition (Optional, bool)

Whether to add or subtract the two vectors. Defaults to False (meaning, defaults to adding).

False

Parameters:

Name Type Description Default
add Qubrick

Adder Qubrick for adding Qubit registers.

required
subtract_condition (Optional, bool)

Whether to add or subtract the two vectors. Defaults to False (meaning, defaults to adding).

False
kwargs dict[str, Any]

Other key word arguments for the Qubrick.

{}

compute

compute(q_vec1: list[Qubits], q_vec2: list[Qubits])

Compute circuit for computing the sum (or difference) of two vectors.

Parameters:

Name Type Description Default
q_vec1 list

List of registers encoding vector components for one vector.

required
q_vec2 list

List of registers encoding vector components for the other vector.

required
Note

Two things: (i) The lengths of both vectors must be equal. (ii) Currently, WB cannot handle adding registers of different sizes correctly.

Currently, this method casts the results of addition to QInt objects in order to handle negative signs. This will be generalized.

BinaryToUnaryComputation

BinaryToUnaryComputation(
    **kwargs,
) -> BinaryToUnaryUncomputation

Factory function that creates a BinaryToUnaryUncomputation instance with dagger=True.

This is an alias to make the binary-to-unary conversion more intuitive by avoiding the double negative of "Uncomputation" with dagger=True. This function performs a binary-to-unary conversion by internally using BinaryToUnaryUncomputation with the dagger operation.

Parameters:

Name Type Description Default
**kwargs dict[str, Any]

Additional keyword arguments to pass to the BinaryToUnaryUncomputation constructor. The 'dagger' parameter will be set to True regardless of what is passed.

{}

Returns:

Type Description
BinaryToUnaryUncomputation

An instance configured for binary-to-unary conversion.

get_default_multiplex_function

get_default_multiplex_function(target_reg, data)

Factory to generate the default multiplexing function.

This default function assumes two kinds of input data
  • A PauliSum object.
  • A list of integers (to be loaded by, say, a QROM).

This function acts as a factory to return a multiplexing function that applies the element in data at the position given by the index onto the target register controlled on the index qubits being in the binary state representing the index value.

Note

All multiplexing functions must adhere to the contract of having a signature of index (int), index_qubits (Qubits), and ctrl (Qubits or int), such that the multiplexors that call them are promised a certain signature.

Parameters:

Name Type Description Default
target_reg Qubits

The target register to apply the operation on

required
data Union[PauliSum, List, Dict]

The object storing the operation that should be applied at the given index. Typically a PauliSum, List, or Dict. Examples also include a List/Dict of PauliMasks or a List/Dict of bitmasks

required

Returns:

Type Description
Callable

multiplexing function

get_multiplex_function_of_indexed_callables

get_multiplex_function_of_indexed_callables(
    target_reg, data
)

Factory to generate a multiplexing function when data contains a list of callable operators.

This function acts as a factory to return a multiplexing function that takes the callable given by the first element at the position in "data" given by "index" and calls that operation on the target register controlled on the index qubits being in the binary state representing the index value.

Note

All multiplexing functions must adhere to the contract of having a signature of index (int), index_qubits (Qubits), and ctrl (Qubits or int), such that the multiplexors that call them are promised a certain signature.

Parameters:

Name Type Description Default
target_reg Qubits

The target register to apply the operation on

required
data List or Dict

The List or Dict storing the callables (as the first element in the Tuple) and any kwargs needed for that callable (as the second element in the Tuple)

required

Returns:

Type Description
Callable

callable multiplexing function

get_default_register_permutation_function

get_default_register_permutation_function(index_reg=0)

Factory to generate the default register permutation function.

This function acts as a factory to return a callable that permutes two qubit registers according to the index passed into the returned callable, which indicates which iteration of the total permutation we are currently on.

All register permutation functions must adhere to the contract of having a signature of permutation_index (int), reg1 (Qubits), reg2 (Qubits), and ctrl (Qubits or int), such that the permutation Qubricks that call them are promised a certain signature.

Parameters:

Name Type Description Default
index_reg (Optional, Qubits)

An index register which coherently controls the application of quantum operations that effect a permutation of two qubit registers. Defaults to 0, in which case a permutation will occur regardless.

0

Returns:

Type Description
Callable

callable register permutation function.

get_reversed_binary_to_unary_permutation_function

get_reversed_binary_to_unary_permutation_function(
    index_reg=0,
)

Factory to generate permutation circuits which undo a binary-to-unary conversion.

This function acts as a factory to return a callable that permutes two qubit registers according to the index passed into the returned callable, which indicates which iteration of the total permutation we are currently on.

All register permutation functions must adhere to the contract of having a signature of permutation_index (int), reg1 (Qubits), reg2 (Qubits), and ctrl (Qubits or int), such that the permutation Qubricks that call them are promised a certain signature.

Parameters:

Name Type Description Default
index_reg (Optional, Qubits)

An index register which coherently controls the application of quantum operations that effect a permutation of two qubit registers. Defaults to 0, in which case a permutation will occur regardless.

0

Returns:

Type Description
Callable

callable register permutation function.