Skip to content
Construct PsiQDK Algorithms

experimental

experimental

Subpackage for experimental WBA functions and Qubricks.

This directory is designed to allow for free-form experimentation and prototyping while keeping core development constrained to the WBA repo. The idea is that new interfaces, refactors or otherwise experimental Qubricks will be implemented here, to be imported as from psiqdk.algorithms.experimental import ... so that they can be used by other developers without them having to align disparate branches (that may have become stale).

NOTES FOR USERS: - The code contained within this directory should be considered unstable and subject to breaking changes. It should be used with appropriate caution. - Code implemented here may have less documentation than code implemented in the main package, and may also have more uncaught bugs. - Experimental Qubricks live as flat underscore-prefixed modules in this package and are re-exported from from psiqdk.algorithms.experimental import x.

NOTES FOR DEVELOPERS: - Experimental code will have a relaxed, but not totally eliminated, set of requirements to be merged. Specifically: - Code is still expected to be tested, but requirements won't be as robust as for the main branch (i.e. if the main functionality works on expected inputs, this should be sufficient) - Documentation requirements will be relaxed - docstrings and usage notebooks are still recommended to make usage clearer, but robust documentation will not be enforced. - Breaking changes can be made to experimental interfaces without requiring a major version bump, but devs should be conscious of the effects on users of doing so - if you're implementing a number of alternative APIs to choose from, consider using versioning as MyAPIV1, MyAPIV2 to minimise churn - Code merged into experimental should be considered as transient and short-lived. It should either be merged into the main repo once the API is stabilized or deleted if the feature is not needed. - MRs are still subject to review, but we should err a little more on the side of rapid development rather than robust checks.

FrequencyInterpreter module-attribute

FrequencyInterpreter = Callable[[float], float]

AliasSampling

AliasSampling(
    qrom: QROM,
    usp: UniformStatePreparation,
    lambda_val: int | None = None,
    **kwargs,
)

Bases: Qubrick

Qubrick for implementing alias sampling.

Parameters:

Name Type Description Default
qrom QROM

Data lookup instance.

required
usp UniformStatePreparation

Uniform state preparation instance.

required
lambda_val int | None

SEL-SWAP tunable parameter for QROM, default to None where optimal lambda (based on Toffoli counts) is calculated.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

qrom instance-attribute

qrom: Incomplete = qrom

usp instance-attribute

usp: Incomplete = usp

lambda_val instance-attribute

lambda_val: Incomplete = lambda_val

compute

compute(
    prep_reg: BaseQubits,
    data: StatePrepDataInterface,
    ctrl: BaseQubits[Any] | int = 0,
    *,
    coin_toss_reg: BaseQubits | None = None,
)

State preparation by alias sampling.

Note
  • Uses the circuit in Fig. 11 of "Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity" (arXiv:1805.03662 ⧉).
  • This qubrick stores the coin_toss_reg register as a persistent auxiliary. The register will not be released upon uncompute. You must call the release_persistent_qregs method when you wish to release the register.

Parameters:

Name Type Description Default
prep_reg BaseQubits

Register to prepare coefficients onto.

required
data StatePrepDataInterface

A data storage interface that holds all the classical precomputation numbers.

required
ctrl BaseQubits[Any] | int

Control register.

0
coin_toss_reg BaseQubits | None

Qubits register used to load the coin toss state (uniform state) in for the alias sampling protocol. Needs to be supplied if this Qubrick is used with a coherent uncomputation (such as in LCU), but will be allocated on the fly if not supplied.

None

ArbitraryStatePrep

ArbitraryStatePrep(
    amplitude_prep: AmplitudePreparation,
    phase_prep: PhasePreparation | None = None,
    **kwargs,
)

Bases: Qubrick

Qubrick for preparing states with arbitrary coefficients.

The strategy used is straightforward: first we prepare the amplitudes for the state such that the probabilities for each basis state are correct, then we prepare the phases to get the full state.

Parameters:

Name Type Description Default
amplitude_prep AmplitudePreparation

Qubrick to prepare the amplitudes for the state.

required
phase_prep PhasePreparation | None

Qubrick to prepare the phases given the amplitudes have already been prepared.

None
kwargs dict[str, Any]

Other keyword arguments to pass to the constructor.

{}

amplitude_prep instance-attribute

amplitude_prep: Incomplete = amplitude_prep

phase_prep instance-attribute

phase_prep: Incomplete = phase_prep

compute

compute(
    prep_reg: BaseQubits,
    data: StatePrepDataInterface,
    ctrl: BaseQubits[Any] | int = 0,
)

Compute the arbitrary state prep.

Note

This Qubrick makes no assumptions about how the amplitudes and phases are prepared and so all data processing is delegated to those Qubricks.

Parameters:

Name Type Description Default
prep_reg BaseQubits

Register to prepare the state on.

required
data StatePrepDataInterface

Dataclass encoding the specification of the state.

required
ctrl BaseQubits[Any] | int

Register to control the state preparation.

0

GrayCodeMultiplexedSingleQubitRotation

GrayCodeMultiplexedSingleQubitRotation(**kwargs)

Bases: Qubrick

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

Figure 2 in "Transformation of quantum states using uniformly controlled rotations" (arXiv:quant-ph/0407010 ⧉).

compute

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

Compute the multiplexed rotation.

Parameters:

Name Type Description Default
index_reg Qubits

Index qubits.

required
target_reg Qubits

Target qubit.

required
rot_data MultiplexedRotationDataInterface

Encodes the data needed to implement the uniformly controlled rotations.

required
ctrl Qubits | int

Register to control on. Defaults to 0.

0

HouseholderMPSLoading

HouseholderMPSLoading(unitary_synth_qbk=None, **kwargs)

Bases: Qubrick

Qubrick for loading the MPS on a quantum computer, based on HouseholderUnitarySynthesis.

unitary_synth_qbk instance-attribute

unitary_synth_qbk: Incomplete = (
    HouseholderUnitarySynthesis()
)

compute

compute(prep_reg, data, ctrl: Qubits | int = 0)

Compute circuit for loading an MPS.

Parameters:

Name Type Description Default
prep_reg Qubits

Register where we are to prepare the desired state.

required
data MPSPrepData

Dataclass encoding the specification of the MPS.

required
ctrl Qubits

Control qubits.

0
Note

Ref: see "Initial state preparation for quantum chemistry on quantum computers" (arXiv:2310.18410 ⧉).

HouseholderUnitarySynthesis

HouseholderUnitarySynthesis(
    inverse_state_prep=None,
    merge_qroms: bool = False,
    **kwargs,
)

Bases: Qubrick

Qubrick synthesizing an isometry using the Householder-based decomposition.

Parameters:

Name Type Description Default
inverse_state_prep Qubrick

State preperation protocol to utilise.

None
merge_qroms Bool

Choice to utilise QROM merging between two consecutive column loading on same physical site.

False
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}
Note
  • Ref: see "Initial state preparation for quantum chemistry on quantum computers" (arXiv:2310.18410 ⧉).
  • Currently the QRE is inaccurate due to compute of the daggered LKS state prep acting oddly.
  • QROM merging will only be accurate for sufficient b_of_p in rotation angles.

merge_qroms instance-attribute

merge_qroms: Incomplete = merge_qroms

inverse_state_prep instance-attribute

inverse_state_prep: Incomplete = ArbitraryStatePrep(
    mux_rot, mux_rot_phase, dagger=True
)

compute

compute(
    virtual_reg, physical_reg, data, ctrl: Qubits | int = 0
)

Compute function for the Householder-based synthesis of a given isometry matrix isometry.

Parameters:

Name Type Description Default
virtual_reg Qubits

Virtual reg used in synthesis. Must have dimension at least isometry.shape[1].

required
physical_reg Qubits

Physical reg used in synthesis.

required
data HouseHolderUnitarySynthesisData

Dataclass containing unitary synthesis info.

required
ctrl Qubits

Control qubits.

0

QROM

Bases: Protocol

NOTE: Not final implementation, just to get things working for now.

compute

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

Compute the Qubrick.

Parameters:

Name Type Description Default
index_reg Qubits

Qubits encoding the indices to load the data from.

required
bits_of_precision int

Encodes the accuracy of the data being loaded.

required
data Iterable[int]

Contains the data to be loaded.

required
lambda_val int | None

Space/time tradeoff parameter.

None
ctrl Qubits | int

Qubits to control the operation.

0

AmplitudePreparation

Bases: Protocol

Interface for state preparation Qubricks that only prepare real, positive amplitudes.

compute

compute(
    psi: Qubits,
    data: StatePrepDataInterface,
    ctrl: Qubits | int = 0,
) -> None

Compute the Qubrick.

Parameters:

Name Type Description Default
psi Qubits

Qubits to prepare the state on.

required
data StatePrepDataInterface

Classical parameters needed to specify the state.

required
ctrl Qubits | int

Qubits to control the operation.

0

Antisymmetrization

Bases: Protocol

NOTE: Not final implementation, just to get things working for now.

compute

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

Compute the Qubrick.

Parameters:

Name Type Description Default
system_reg Qubits

Register to prepare antisymmetrized state on.

required
ctrl Qubits | int

Control register for the routine. Defaults to 0.

0

BasisTransform

Bases: Protocol

Interface for Qubricks that compute Basis Transform.

compute

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

Computes Basis Transform.

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 Qubits | int

Classical or Quantum control conditions

0
final_qubits Qubits | int

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.

BinaryToUnaryUncomputationInterface

Bases: Protocol

Interface for Qubricks that compute reversal of Binary to Unary conversion.

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 Qubits | int

Qreg to control on. Defaults to None.

0

DotProduct

Bases: Protocol

Interface for Qubricks that compute dot products of vectors.

compute

compute(q_vec: list[Qubits] | Qubits)

Compute dot products of vectors.

Parameters:

Name Type Description Default
q_vec list[Qubits] | Qubits

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

required

DysonSeriesSelect

Bases: Protocol

Interface for Qubricks that apply the Dyson series select operator.

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 None.

0

EncodingChange

Bases: Protocol

Interface for Qubricks that compute the encoding change.

compute

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

Compute the encoding change.

Takes a 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 | int

Optional register to control on. Defaults to None.

0

FlagCollisions

Bases: Protocol

Interface for Qubricks that compute Flag Collision.

compute

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

Compute Flag Collision.

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 None.

0
Note on convention

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

FlaggedQPEWindowFunction

Bases: Protocol

Interface for Qubricks that compute window function.

compute

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

Computes 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 | int

control qubit

0
**kwargs dict[str, Any]

other keyword arguments

{}
Note
  • Needs a round of amplitude amplification.

GivensRotation

Bases: Protocol, Generic[T]

Interface for Qubricks that compute Givens Rotation.

compute

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

Computes Givens Rotation.

Parameters:

Name Type Description Default
rotation_encoding T

data type that encodes the rotation angle defining the PPR. This can be encoded in either a classical or a quantum datatype depending on the implementation, hence the protocol is generic in this argument.

required
target_reg Qubits

the quantum register that we wish to rotate via the Givens rotation.

required
ctrl Qubits | int

Qreg to control on. Defaults to None.

0

HammingWeight

Bases: Protocol

Interface for Qubricks that compute Hamming Weight.

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 | int

Quantum control conditions defaults to 0.

0
Note
  • Allocates a quantum register storing the hamming weight

HammingWeightPhasingInterface

Bases: Protocol

Interface for Qubricks that apply Hamming weight phasing.

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 Qubits | int

The quantum control conditions.

0

InjectOpInterface

Bases: Protocol

Interface for Qubricks that compute Inject circuit.

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

Register to apply operation to.

required
reg_size int

Number of bits in each output register.

required
ctrl Qubits | int

Qreg to control on. Defaults to 0.

0

MajoranaFermionOperator

Bases: Protocol

Interface for Qubricks that compute the Majorana Fermion Operator.

compute

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

Compute the Majorana Fermion Operator.

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 | 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

MultiplexedRotationDataInterface

Interface for dataclasses being passed to multiplexed rotation Qubricks.

opcode instance-attribute

opcode: str

angles instance-attribute

angles: Iterable[float]

epsilon instance-attribute

epsilon: float

bits_of_precision class-attribute instance-attribute

bits_of_precision: int | None = None

MultiplexedRotations

Bases: Protocol

Interface for Qubricks that handle multiplexing over a series of rotations.

compute

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

Compute the Qubrick.

Parameters:

Name Type Description Default
index_reg Qubits

Index qubits.

required
target_reg Qubits

Target qubit.

required
rot_data MultiplexedRotationDataInterface

Encodes the data needed to implement the uniformly controlled rotations.

required
ctrl Qubits | int

Register to control on. Defaults to 0.

0

Multiplexor

Bases: Protocol

NOTE: Not final implementation, just to get things working for now.

compute

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

Compute the Qubrick.

Parameters:

Name Type Description Default
index_reg Qubits

Encodes the indices we're multiplexing over.

required
multiplex_function Callable

Defines the operation that performs the multiplexing.

required
used_indices list[int] | None

Encodes whether we skip any indices.

None
ctrl Qubits | int

Qubits to control the operation on.

0

Permutation

Bases: Protocol

Interface for Qubricks that apply permutation to register.

compute

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

Apply permutation to register.

Parameters:

Name Type Description Default
target_reg Qubits

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 Qubits | int

Qreg to control on. Defaults to None.

0
Note

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

PhasePreparation

Bases: Protocol

Interface for Qubricks that apply phase corrections to prepared amplitudes.

compute

compute(
    psi: Qubits,
    data: StatePrepDataInterface,
    ctrl: Qubits | int = 0,
) -> None

Compute the Qubrick.

Parameters:

Name Type Description Default
psi Qubits

Qubits to prepare the state on.

required
data StatePrepDataInterface

Classical parameters needed to specify the state.

required
ctrl Qubits | int

Qubits to control the operation.

0

PrepareWState

Bases: Protocol

Interface for Qubricks that Prepares a W state.

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 None.

0

QPEWindowFunction

Bases: Protocol

Interface for Qubricks that compute QPE Window Function.

compute

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

Compute QPE Window Function.

Parameters:

Name Type Description Default
phase_reg Qubits

Phase qubit register

required
ctrl Qubits | int

Control register

0
**kwargs dict[str, Any]

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

{}

Select

Bases: Protocol, Generic[IndexReg, TargReg]

Interface for Qubricks that implement a SELECT operation.

compute

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

Compute Select circuit.

Parameters:

Name Type Description Default
index_reg IndexReg

Qubit register determining which op in data to apply.

required
target_reg TargReg

System qubits.

required
ctrl Qubits | int

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

0

Sort

Bases: Protocol

Interface for Qubricks that sort qubit register.

compute

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

Sort qubit registers.

Parameters:

Name Type Description Default
regs_list list[Qubits]

List of qubit registers to sort.

required
direction int

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

required
ctrl Qubits | int

Control qubit for the routine. Defaults to None.

0
Note

This assumes same size register for all registers in regs_list.

StatePreparation

Bases: Protocol, Generic[StateReg, StateData]

Interface for arbitrary state preparation Qubricks.

compute

compute(
    prep_reg: StateReg,
    data: StateData,
    ctrl: BaseQubits | int = 0,
)

Compute the Qubrick.

Parameters:

Name Type Description Default
prep_reg StateReg

Qubits to prepare the state on.

required
data StateData

Classical parameters needed to specify the state.

required
ctrl BaseQubits | int

Qubits to control the operation.

0

StatePrepDataInterface

Interface for dataclasses being passed to state preparation Qubricks.

coefficients instance-attribute

coefficients: Iterable[float | complex]

epsilon instance-attribute

epsilon: float

SuperpositionRotations

Bases: Protocol

Interface for Qubricks that apply a number of rotations in superposition simultaneously.

compute

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

Compute the Qubrick.

Parameters:

Name Type Description Default
angle_reg Qubits

Qubits encoding the angles for the rotations.

required
target_reg Qubits

Qubits to apply the multiplexed rotations on.

required
rot_data MultiplexedRotationDataInterface

Classical parameters needed to specify the superposition rotations.

required
ctrl Qubits | int

Qubits to control the operation.

0

SwapUpInterface

Bases: Protocol

Interface for Qubricks that compute the SwapUp circuit.

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 output register.

required
ctrl Qubits | int

Qreg to control on. Defaults to None.

0

Trotterization

Bases: Protocol

Interface for Qubricks that execute the Suzuki-Trotter circuit.

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

The total evolution time.

required
ctrl Qubits | int

Qubit register to control evolution on. Defaults to 0.

0
trotter_order int | None

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

None

UniformStatePreparation

Bases: Protocol

NOTE: Not final implementation, just to get things working for now.

compute

compute(
    d: int, target_qreg: Qubits, ctrl: Qubits | int = 0
)

Compute the Qubrick.

Parameters:

Name Type Description Default
d int

Dimension of the USP.

required
target_qreg Qubits

Register to prepare the uniform state onto.

required
ctrl Qubits | int

Qubits to control the operation on.

0

VectorAdder

Bases: Protocol

Interface for Qubricks that compute the sum (or difference) of two vectors.

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[Qubits]

List of registers encoding vector components for one vector.

required
q_vec2 list[Qubits]

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.

HouseHolderUnitarySynthesisData dataclass

HouseHolderUnitarySynthesisData(
    isometry: list | ndarray,
    bits_of_precision: int,
    physical_dim: int | None,
)

Data for specifying a Householder unitary synthesis.

Only meant to be a container for a couple of attributes for the sake of simplifying the compute signature of the HouseHolderUnitarySynthesis Qubrick.

Parameters:

Name Type Description Default
isometry [list, numpy]

The isometry matrix to be synthesized.

required
bits_of_precision int

The number of precision bits to use in synthesizing each column of unitary matrix (per site).

required
physical_dim (None, int)

If None, the physical register dimension will be used. Must be specified if used in the context of an MPS with non-power of two physical dimension.

required

isometry instance-attribute

isometry: list | ndarray

bits_of_precision instance-attribute

bits_of_precision: int

physical_dim instance-attribute

physical_dim: int | None

MPSPrepData dataclass

MPSPrepData(mps_tensors: Iterable, bits_of_precision: int)

Data for specifying a matrix product state.

Parameters:

Name Type Description Default
mps_tensors Iterable

MPS tensors from DMRG calculations

required
bits_of_precision int

The number of precision bits to use in synthesizing each column of unitary matrix (per site)

required
Note

Input MPS tensors need to be reshaped to be fed into a loading circuit.

mps_tensors instance-attribute

mps_tensors: Iterable

bits_of_precision instance-attribute

bits_of_precision: int

n_sites property

n_sites: int

Returns number of sites.

physical_dim property

physical_dim: int

Returns physical leg dimension of each site.

maximum_bond_dim property

maximum_bond_dim: int

Returns maximum bond dimension.

MultiplexedSingleQubitRotationViaQROM

MultiplexedSingleQubitRotationViaQROM(
    qrom: QROM,
    rotation_qbk: SuperpositionRotations,
    controlled_on: bool | None = None,
    lambda_val: int | None = None,
    **kwargs,
)

Bases: Qubrick

Multiplexor using data-lookup oracles.

Detailed in "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954 ⧉) (circuit described in Appendix D).

This technique for multiplexed rotations works by first loading a truncated, integerized, b-bit approximation of rotation angles onto an ancillary register and then performing the rotations coherently in superposition controlled on this register.

Parameters:

Name Type Description Default
qrom QROM

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

required
rotation_qbk SuperpositionRotations

Qubrick to implement the actual rotations (e.g. via phase gradient addition).

required
controlled_on bool | None

Whether the prep circuit is controlled on, default to None.

None
lambda_val int | None

the SEL-SWAP tunable parameter, default to None and optimized Toffoli version is used.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

qrom instance-attribute

qrom: Incomplete = qrom

rotation_qbk instance-attribute

rotation_qbk: Incomplete = rotation_qbk

lambda_val instance-attribute

lambda_val: Incomplete = lambda_val

controlled_on property

controlled_on: Qubrick

Flag to determine which component to control the Qubrick on, QROM or the rotations.

compute

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

Compute circuit for Data-lookup multiplexor.

Parameters:

Name Type Description Default
index_reg Qubits

Index register.

required
target_reg Qubits

Register to apply rotations onto.

required
rot_data MultiplexedRotationDataInterface

Dataclass that containerizes the classical input data needed for the multiplexed rotations.

required
ctrl Qubits | int

Control register.

0

NaiveMultiplexedSingleQubitRotation

NaiveMultiplexedSingleQubitRotation(
    multiplexor: Multiplexor = None, **kwargs
)

Bases: Qubrick

Controlled rotations from "Transformation of quantum states using uniformly controlled rotations" (arXiv:quant-ph/0407010 ⧉).

Parameters:

Name Type Description Default
multiplexor Multiplexor

Qubrick for implementing the multiplexing over the rotations.

None
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

multiplexor property

multiplexor

Getter for the multiplexor.

compute

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

Compute the multiplexed rotation.

Parameters:

Name Type Description Default
index_reg Qubits

Index qubits.

required
target_reg Qubits

Target qubits.

required
rot_data MultiplexedRotationDataInterface

Dataclass that containerizes the classical input data needed for the multiplexed rotations.

required
ctrl Qubits | int

Register to control on.

0

FlattenedRotArray

FlattenedRotArray(mplxr: MultiplexedRotations, **kwargs)

Bases: Qubrick

Implements a state sub-preparation using a single set of multiplexed rotations.

Note
  • This only works with PHASE ops, so can only be used for a phase fixup, and can't be used with the Gray code multiplexor, which relies on the structure of RZ gates to work.
  • There is no global phase correction to do with this Qubrick.

Parameters:

Name Type Description Default
mplxr MultiplexedRotations

The Qubrick that will implement the individual multiplexed rotations

required
kwargs dict[str, Any]

Other keyword arguments to pass to the constructor.

{}

mplxr property

mplxr: MultiplexedRotations

Getter for the multiplexor Qubrick.

compute

compute(
    psi: Qubits,
    data: StatePrepDataInterface,
    ctrl: Qubits | int = 0,
)

Compute the multiplexor.

Parameters:

Name Type Description Default
psi Qubits

The qubits to apply the rotations onto.

required
data StatePrepDataInterface

A dataclass encoding the rotation data

required
ctrl Qubits | int

Qubits to control the operation on.

0

MultiplexedRotationData dataclass

MultiplexedRotationData(
    opcode: str,
    angles: Iterable[float],
    epsilon: float,
    bits_of_precision: int | None = None,
)

Data class for handling data for multiplexed rotations.

Parameters:

Name Type Description Default
opcode str

Encodes the type of rotation op to be applied, one of SupportedOps.

required
angles Iterable[float]

The list of rotation angles to be applied.

required
epsilon float

The accuracy that the multiplexed rotations are to be applied to.

required
bits_of_precision int | None

For QROM-based multiplexors, the number of bits of precision to be used in the rotations.

None

opcode instance-attribute

opcode: str

angles instance-attribute

angles: Iterable[float]

epsilon instance-attribute

epsilon: float

bits_of_precision class-attribute instance-attribute

bits_of_precision: int | None = None

ProgrammableRotArray

ProgrammableRotArray(
    op,
    mplxr: MultiplexedRotations,
    fix_global_phase: bool = False,
    **kwargs,
)

Bases: Qubrick

Implements a state sub-preparation using a cascade of uniformly controlled rotations.

Based on the implementation published in "Quantum computing enhanced computational catalysis" (arXiv:2007.14460 ⧉) (see appendix VII, section B, subsection 1) where we need a 2D array of angles (each row of size 1, 2, 4, 8, ...), similar to the multiplexed Givens rotation.

Parameters:

Name Type Description Default
op SupportedOps

Encodes the type of rotation op to be applied, one of SupportedOps.

required
mplxr MultiplexedRotations

The Qubrick that will implement the individual multiplexed rotations

required
fix_global_phase bool

Whether to fix up the global phase (for statevector validation) or prepare the state up to global phase. This correction is always applied when the Qubrick is controlled.

False
kwargs dict[str, Any]

Other keyword arguments to pass to the constructor.

{}

op property

op: SupportedOps

Getter for the op in the programmable rot array.

mplxr property

mplxr: MultiplexedRotations

Getter for the multiplexor qubrick.

fix_global_phase property

fix_global_phase: bool

Getter for the fix global phase attribute.

compute

compute(
    psi: Qubits,
    data: StatePrepDataInterface,
    ctrl: Qubits | int = 0,
)

Compute the rotation array.

ProgrammableRotArrayData dataclass

ProgrammableRotArrayData(
    opcode: str,
    coefficients: Iterable[float],
    epsilon: float,
    _bits_of_precision: int | None = None,
)

Data class for handling data for multiplexed rotations.

Parameters:

Name Type Description Default
opcode str

Encodes the type of rotation op to be applied, one of SupportedOps.

required
coefficients Iterable[float]

The coefficients of the state to be loaded.

required
epsilon float

The accuracy that the multiplexed rotations are to be applied to.

required
_bits_of_precision int | None

Override the default bits of precision argument with a custom value. NOTE: this may result in loss of fidelity if the value is not chosen carefully - users are recommended to leave this unset unless they know what they are doing.

None

opcode instance-attribute

opcode: str

coefficients instance-attribute

coefficients: Iterable[float]

epsilon instance-attribute

epsilon: float

angles cached property

angles: list[float]

Get the angles corresponding to the particular set of rotations to be applied.

bits_of_precision cached property

bits_of_precision: int

Get the number of bits of precision for QROM-based multiplexors.

PauliToPauliBasisTransform

PauliToPauliBasisTransform(**kwargs)

Bases: Qubrick

Transforms quantum operations between different Pauli bases (X, Y, Z).

Used to simplify or standardize quantum computations.

y_to_z

y_to_z(qbits: Qubits, ctrl: Qubits | int = 0)

Convert y to z.

x_to_z

x_to_z(qbits: Qubits, ctrl: Qubits | int = 0)

Convert x to z.

pauli_product_to_z

pauli_product_to_z(
    x_qbits: Qubits, z_qbits: Qubits, ctrl: Qubits | int = 0
)

Convert PPO to z.

z_to_y

z_to_y(qbits: Qubits, ctrl: Qubits | int = 0)

Convert z to y.

z_to_x

z_to_x(qbits: Qubits, ctrl: Qubits | int = 0)

Convert z to x.

z_to_pauli_product

z_to_pauli_product(
    x_qbits: Qubits, z_qbits: Qubits, ctrl: Qubits | int = 0
)

Convert z to PPO.

compute

compute(
    qbits: Qubits,
    opcode: SupportedOps,
    ctrl: Qubits | int = 0,
)

RotationViaPhaseGradientAddition

RotationViaPhaseGradientAddition(
    adder_qbk: Adder | None = None, **kwargs
)

Bases: Qubrick

Coherently-applies WB qc.phase rotations via phase gradient addition.

This method originated from Appendix A in "Compilation of Fault-Tolerant Quantum Heuristics for Combinatorial Optimization" (arXiv:2007.07391 ⧉). (See Appendix D.1.2 in "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954 ⧉) for how this is used to form a multiplexor.)

The PGA circuit is defined with respect to phase rotations; as such, implementing any other-axis rotation in a coherent superposition typically requires rotating to the Z basis, in-place adding with a phase gradient, and then rotating back to the original basis.

This Qubrick is a stand-in for that base-case of phase gate.

Parameters:

Name Type Description Default
adder_qbk Adder | None

Qubrick for implementing the addition in the phase gradient addition.

None
kwargs dict[str, Any]

Other keyword arguments to pass to the constructor.

{}

adder_qbk instance-attribute

adder_qbk: Incomplete = (
    adder_qbk
    if adder_qbk is not None
    else PhaseGradientAdder()
)

basis_change_qbk instance-attribute

basis_change_qbk: Incomplete = PauliToPauliBasisTransform()

compute

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

Compute circuit for rotations via phase gradient addition.

Parameters:

Name Type Description Default
angle_reg Qubits

Register where rotation angles have been written.

required
target_reg Qubits

Single qubit where rotations are applied.

required
rot_data MultiplexedRotationDataInterface

Discretized rotation angles data for the multiplexor.

required
ctrl Qubits | int

Control register.

0

RotationViaSingleQubitUnitaries

RotationViaSingleQubitUnitaries(**kwargs)

Bases: Qubrick

Compute circuit for rotations via controlled single-qubit rotations.

See Appendix D.1.1 in "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954 ⧉) for how this is used to form a multiplexor.

Note

Here we note some conventions used in the literature and its correspondence in this Qubrick:

  • In "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954 ⧉), a multiplexed Y rotation is written as \(\text{RY}(\theta_x) = e^{i2\pi \theta_x Y}\), with \(\theta_x\) in radians.
  • With an explicit factor of \(2\pi\) in the exponent, this implies the angles range from zero to one.
  • Workbench does not include this factor of \(2\pi\) in its definition of Pauli rotations, so it must be accounted for.
  • Additionally, the default units in Workbench are degrees, and thus, this is why the angle args below have a factor of 360 in the numerator.
  • This routine makes use of an integer approximation of \(\theta_x\) by truncating its binary expansion to \(b\) bits.
  • For these reasons, the integer angle approximations written to a register in this routine take values from zero to \(2^b - 1\).

compute

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

Compute circuit for rotations via controlled single qubit rotations.

Parameters:

Name Type Description Default
angle_reg Qubits

Register where rotation angles have been written.

required
target_reg Qubits

Single qubit where rotations are applied.

required
rot_data MultiplexedRotationDataInterface

discretized rotation angles data for the multiplexor

required
ctrl Qubits | int

Control register.

0

QubitizationIterate

QubitizationIterate(
    state_prep: StatePreparation[
        BlockEncodingReg, PrepData
    ],
    select: SelectWithData[
        BlockEncodingReg, StateReg, SelData
    ]
    | Select[BlockEncodingReg, StateReg],
    basis: QubitizationBases = QubitizationBases.COMPUTATIONAL,
    **kwargs,
)

Bases: Qubrick, Generic[StateReg, BlockEncodingReg, PrepData, SelData]

Qubrick for implementing qubitization iterates.

There are two different conventions for implementing qubitization iterates that appear in the literature: one applies the block encoding, followed by a reflection in the all-zero subspace of the block encoding ancillae (this can be seen explicitly in Fig. 3 of Hamiltonian Simulation Using Linear Combinations of Unitary Operations ⧉ or more clearly in Fig. 9.3 of Lin Lin's Lecture Notes on Quantum Algorithms for Scientific Computation ⧉). The other applies a SELECT operation, followed by reflection about the state defined by the PREP operation (as seen in the construction given in Fig. 1 of Encoding Electronic Spectra in Quantum Circuits with Linear T Complexity ⧉).

Both of these are actually the same operation performed in different bases. The former applies a qubitization iterate in the computational basis, while the other performs it in the basis defined by the PREP operation. In order to correctly apply the operation, the appropriate basis state should be supplied (i.e. |0> for the computational basis, and PREP|0> for the qubitization basis).

Notes
  • Qubitization is technically more general than this, since here we're assuming a linear combination of unitaries construction. The distinction between a block encoding and a qubitization iterate is simply a reflection about the qubitized basis, so separating the abstractions at this level would result in very thin qubitization classes. By contrast, assuming an LCU construction allows us to exploit this structure to easily implement constructions like directional phase kickback QPE. Since the vast majority of our use cases for qubitization also follow the LCU construction, we treat this as the default and iterates that break this construction are treated as specal cases that need their own class (and interface).
  • Users are responsible for ensuring the basis of the supplied state matches what the Qubrick expects. That is, if QubitizationBases.QUBITIZED is selected, the user must prepare this state before calling compute.

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
basis QubitizationBases

Determines the expected basis the operation is to be applied in. For example, we could apply it in the computational basis (i.e. starting from the |0> state) or from the basis defined by the qubitization iterate itself (i.e. starting from the state defined by the action of PREP|0>).

COMPUTATIONAL
**kwargs dict[str, Any]

Other arguments to pass to the init.

{}

state_prep instance-attribute

state_prep: Incomplete = state_prep

select instance-attribute

select: Incomplete = select

basis instance-attribute

basis: Incomplete = basis

compute

compute(
    psi: StateReg,
    be_ancilla_reg: BlockEncodingReg,
    data: LCUData[PrepData, SelData] | SelData,
    ctrl: Qubits | SymbolicQubits | int = 0,
)

Compute the qubitization.

Parameters:

Name Type Description Default
psi StateReg

State register.

required
be_ancilla_reg BlockEncodingReg

Block encoding ancilla register.

required
data LCUData[PrepData, SelData] | SelData

Data to pass to the Qubrick. NOTE that for the experimental implementations, the data is of type LCUData and is passed to both the prep and select subroutines, but to maintain compatability with the legacy implementations of the state prep routines we also support passing lists or PauliSums directly, in which case the data will only be passed to the select subroutine.

required
ctrl Qubits | SymbolicQubits | int

Register to control the qubitization on. Defaults to 0.

0

BitwiseQPEConfig dataclass

BitwiseQPEConfig(
    *,
    num_time_samples: int | None = None,
    bits_of_precision: int | None = None,
)

Bases: QPEConfig

Configuration for bitwise QPE programs.

num_time_samples class-attribute instance-attribute

num_time_samples: int | None = None

bits_of_precision class-attribute instance-attribute

bits_of_precision: int | None = None

iterations_per_time_step cached property

iterations_per_time_step

BitwiseTimeSampler

Bases: TimeSampler

Yields samples of the time-frequency register where each bit in the register is set.

Explicitly, this just means that we yield each qubit in the time-frequency register and use that to obtain samples for multiple times in superposition.

For example, yielding the qubit corresponding to the least significant bit will correspond to sampling all odd times simultaneously. Yielding the second least significant bit will correspond to sampling all times with a set bit in the second least significant position (i.e. 2 = 0b10, 3 = 0b11, 6 = 0b110, 7 = 0b111, etc.) and so on for the other bits.

Note

This is the "standard" sampling protocol that you see in, e.g. Nielsen and Chuang.

ComputationalBasisStateFactory

ComputationalBasisStateFactory(
    num_qubits: int | Parameter, basis_state: int = 0
)

Initialize a register holding the signal source state in computational basis \(|basis\rangle\).

num_qubits instance-attribute

num_qubits: Incomplete = num_qubits

basis_state instance-attribute

basis_state: Incomplete = basis_state

get_signal_source_state

get_signal_source_state(qpu: BaseQPU) -> BaseQubits

ControlQubit

ControlQubit(
    *args,
    defer_rotations: bool = False,
    skip_rotations: bool = False,
    **kwargs,
)

Bases: Qubits

Type for a control qubit.

Note
  • This inherits all the standard Qubits methods but allows us to explicitly mark qubits that are used as controls.
  • We override rotation operations so that we can (optionally) either defer them to the end of a series of such rotations or skip them entirely.

Parameters:

Name Type Description Default
defer_rotations bool

If True, tracks rotations instead of applying them

False
skip_rotations bool

If True, skips rotations instead of applying them

False
args list

args

()
kwargs dict

keyword args

{}

defer_rotations instance-attribute

defer_rotations: Incomplete = defer_rotations

skip_rotations instance-attribute

skip_rotations: Incomplete = skip_rotations

phase_rots instance-attribute

phase_rots: Incomplete = []

rz_rots instance-attribute

rz_rots: Incomplete = []

phase

phase(theta, *args, **kwargs) -> None

Apply phase rotation.

Parameters:

Name Type Description Default
theta float or Units

Rotation angle, in degrees by default

required
args list

args

()
kwargs dict

keyword args

{}

reflect

reflect(theta: float = None, *args, **kwargs)

Apply reflect operation (which is a phase gate for single qubit).

Parameters:

Name Type Description Default
theta float or Units

rotation angle, in degrees by default

None
args list

args

()
kwargs dict

keyword args

{}
Notes
  • This means that ControlQubit has to be a single qubit currently, since it's included in the phase rotation list.

rz

rz(theta, *args, **kwargs) -> None

Apply RZ rotation.

Parameters:

Name Type Description Default
theta float or Units

Rotation angle, in degrees by default

required
args list

args

()
kwargs dict

keyword args

{}

resolve_rotations

resolve_rotations(
    merge_phase_and_rz: bool = False, *args, **kwargs
) -> None

Resolve rotations by either executing them as one (or two) merged rotations or skipping them.

Parameters:

Name Type Description Default
merge_phase_and_rz bool

If True, merges phase and RZ rotations into one RZ rotation (which can be done up to a global phase)

False
args list

args

()
kwargs dict

keyword args

{}

CosineWindowV2

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

Bases: Qubrick

Cosine window from arxiv:2110.09590  ⧉.

adder instance-attribute

adder: Incomplete = adder

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

Executes circuit for implementing cosine window.

Parameters:

Name Type Description Default
time_frequency_register Qubits

Phase qubit register

required
num_time_steps int | None

The number of time steps to include in the window function

None
ctrl (Optional, int, Qubits)

Control register

0

DebugQFTQPEFrequencyResolver dataclass

DebugQFTQPEFrequencyResolver(
    frequency_interpreter: FrequencyInterpreter = default_frequency_interpreter,
)

Class to handle QPE data accumulation.

This class specifically handles the cases where we use classical "cheat" methods to pull out information about probabilities etc rather than using measurements as you'd have to do for a real QPU.

frequency_interpreter class-attribute instance-attribute

frequency_interpreter: FrequencyInterpreter = (
    default_frequency_interpreter
)

measurement_outcomes property

measurement_outcomes: dict[float, float]

fixed_point_measurement_outcomes property

fixed_point_measurement_outcomes: dict[float, float]

Get the measurement outcomes interpreted as raw fixed point numbers.

phases class-attribute instance-attribute

phases = ...

probabilities class-attribute instance-attribute

probabilities = ...

iterate

iterate() -> Iterator[None]

Iteration for building up QFT QPE statistics.

Since we're debugging, this is effectively just a dummy method that just yields None once. The statistics we're going to get are going to come from read probabilities instead of repeated measurements.

resolve

resolve(time_frequency_register: Qubits)

calculate_holevo_variance

calculate_holevo_variance() -> float

get_most_probable_phase

get_most_probable_phase() -> float

reset

reset() -> None

Reset the frequency resolver.

Allows the same qpe_program to be used with different variables without reinitialising it. Since this is debugging this doesn't need to do anything here.

DiagonalMatrixSignalSampler

DiagonalMatrixSignalSampler(matrix_diag: Iterable[complex])

Bases: SignalSampler

Signal sampler where the signal unitary is a classically-defined diagonal matrix.

matrix_diag instance-attribute

matrix_diag: Incomplete = np.asarray(matrix_diag)

DirectionalControlQubit

DirectionalControlQubit(
    *args,
    defer_rotations: bool = False,
    skip_rotations: bool = False,
    **kwargs,
)

Bases: ControlQubit

Wrapper for directional control qubit.

from_control classmethod

from_control(q: ControlQubit)

Helper to retain lists of rotations when they are deferred.

EmptyStateFactory

get_signal_source_state

get_signal_source_state(qpu: QPU) -> None

FastForwardPhaseSignalSampler

FastForwardPhaseSignalSampler(
    angle: float | RotationAngle | None = None,
)

Bases: SignalSampler[Qubits]

Signal sampler that just applies phase gates directly onto the time-frequency register.

Note that for interface compatibility, this signal sampler accepts a signal_source_register, but it is ignored.

angle instance-attribute

angle: Incomplete = angle

FourierBasisStateFactory

FourierBasisStateFactory(
    num_qubits: int, basis_state: int = 0
)

Prepare the signal source state in a Fourier basis.

num_qubits instance-attribute

num_qubits: Incomplete = num_qubits

basis_state instance-attribute

basis_state: Incomplete = basis_state

get_signal_source_state

get_signal_source_state(qpu: QPU) -> BaseQubits

FrequencyResolver

Bases: Protocol

iterate

iterate() -> Iterable

resolve

resolve(time_frequency_register: Qubits)

GenericUnitarySignalSampler

GenericUnitarySignalSampler(
    op: Qubrick | GenericUnitaryCallable,
)

Bases: SignalSampler[Qubits]

This is an adaptor for handling generic, arbitrary unitaries for QPE.

The op is either a callable taking the signal source register and the time sample register and nothing else, or a Qubrick that already has that shape: its _compute needs a ctrl parameter for the time sample register, and at most one other parameter without a default, for the signal source register.

Any other unitary has to have its remaining arguments frozen first, with bind_generic_unitary_arguments. The generic_unitary preset does this for you.

While this is pretty generic and flexible, there are unitaries that can't easily be fit into this structure. The suggested API is to write a custom adaptor for whatever specific unitary you have in mind.

Note
  • For high performance applications, this is probably not the way to go.
  • We are not doing bidirectional phase kickback, as there is no generic way to do so.
  • This is only intended to support textbook (e.g. Nielsen and Chuang) QPE, with the exponentiation achieved by applying the unitary exponentially many times.

Parameters:

Name Type Description Default
op Qubrick | GenericUnitaryCallable

The operation to sample the signal from, taking the signal source register and the time sample register.

required

Raises:

Type Description
ValueError

if a Qubrick is supplied whose _compute still needs other arguments.

TypeError

if the op is neither a Qubrick nor callable.

fn instance-attribute

fn: Incomplete = bind_generic_unitary_arguments(op)

HadamardBasisStateFactory

HadamardBasisStateFactory(
    num_qubits: int, basis_state: int = 0
)

Prepare the signal source state in a Hadamard basis.

num_qubits instance-attribute

num_qubits: Incomplete = num_qubits

basis_state instance-attribute

basis_state: Incomplete = basis_state

get_signal_source_state

get_signal_source_state(qpu: QPU) -> BaseQubits

PushStateVectorFactory

PushStateVectorFactory(state: Iterable[complex])

Initialize a register with the provided signal source state injected (state vector sim only).

state instance-attribute

state: Incomplete = state

get_signal_source_state

get_signal_source_state(qpu) -> BaseQubits

QFTBasedQPE

QFTBasedQPE(
    signal_source_state_factory: SignalSourceStateFactory,
    qpe_subroutine: QPESubroutine,
    frequency_resolver: FrequencyResolver | None = None,
    config: QPEConfig | None = None,
)

Quantum program for running QFT based QPE.

signal_source_state_factory instance-attribute

signal_source_state_factory: Incomplete = (
    signal_source_state_factory
)

qpe_subroutine instance-attribute

qpe_subroutine: Incomplete = qpe_subroutine

frequency_resolver instance-attribute

frequency_resolver: Incomplete = frequency_resolver

config instance-attribute

config: Incomplete = config

pre_allocated_qubits instance-attribute

pre_allocated_qubits: Incomplete = None

QFTQPEFrequencyResolver dataclass

QFTQPEFrequencyResolver(
    num_shots: int = 1,
    all_measurement_outcomes: list[float] = list(),
    frequency_interpreter: FrequencyInterpreter = default_frequency_interpreter,
    early_exit_function: Callable[
        [QFTQPEFrequencyResolver, int], bool
    ] = _default_exit_function,
)

Frequency resolver for "standard" measurement-based QFT QPE.

num_shots class-attribute instance-attribute

num_shots: int = 1

all_measurement_outcomes class-attribute instance-attribute

all_measurement_outcomes: list[float] = field(
    default_factory=list
)

frequency_interpreter class-attribute instance-attribute

frequency_interpreter: FrequencyInterpreter = (
    default_frequency_interpreter
)

early_exit_function class-attribute instance-attribute

early_exit_function: Callable[
    [QFTQPEFrequencyResolver, int], bool
] = _default_exit_function

measurement_outcomes property

measurement_outcomes: dict[float, float]

Create dictionary of phases and their probabilities.

fixed_point_measurement_outcomes property

fixed_point_measurement_outcomes: dict[float, float]

Get the measurement outcomes interpreted as raw fixed point numbers.

exit_condition class-attribute instance-attribute

exit_condition = ...

phases class-attribute instance-attribute

phases = ...

iterate

iterate() -> Iterator[None]

Iteration for building up QFT QPE statistics.

resolve

resolve(time_frequency_register: Qubits)

Collect measurement data.

get_most_probable_phase

get_most_probable_phase() -> float

Get the most likely phase.

calculate_holevo_variance

calculate_holevo_variance() -> float

reset

reset() -> None

Reset the all_measurement_outcomes list.

Allows the same qpe_program to be used with different variables without reinitialising it.

QPEBuilder dataclass

QPEBuilder(
    *,
    signal_source_state_factory: SignalSourceStateFactory,
    config: QPEConfig,
    window_function: WindowFunction | None = None,
    time_frequency_transformation: TimeFrequencyTransformation
    | None = None,
    frequency_resolver: FrequencyResolver | None = None,
    signal_sampler: SignalSampler | None = None,
    time_sampler: TimeSampler | None = None,
    signal_generator: SignalGeneratorInterface
    | None = None,
    frequency_interpreter: FrequencyInterpreter = default_frequency_interpreter,
)

Builder class for instantiating QPE programs.

Designed to make it easy to build QPE programs for common cases without sacrificing flexibility for advanced users.

The core idea is that this class serves as a single entry point for composing the different parts of a quantum phase estimation program, and provides functionality for using that program in different contexts. For example, using this class instantiated with a signal sampler and time sampler, you can define the quantum program for a particular instantiation of QPE, but you might want to do different things with it. For example, you might want to run it with the debug frequency resolver for validation, then run it with the sampling based frequency resolver to generate QREs (or run on a real QPU). Using this class, you can do both of those things with the same setup using the with_resolver functionality.

A deep dive into this class and the functionality it exposes is given in [TODO: ADD TUTORIAL FOR THIS IN DOCS PASS!]

Parameters:

Name Type Description Default
signal_source_state_factory SignalSourceStateFactory

Factory for the register that holds the signal source state (e.g. textbook QPE eigenstate).

required
config QPEConfig

Dataclass containing the configuration for the QPE.

required
window_function WindowFunction | None

Qubrick for applying a window function on the time/frequency register.

None
time_frequency_transformation TimeFrequencyTransformation | None

Qubrick for transforming between time and frequency domains.

None
frequency_resolver FrequencyResolver | None

Class for collating and analyzing the output from QPE shots.

None
signal_sampler SignalSampler | None

Class for sampling the signal at a single point in time.

None
time_sampler TimeSampler | None

Class for returning time samples throughout the QPE routine.

None
signal_generator SignalGeneratorInterface | None

Qubrick that implements the entire signal generation and sampling step of QPE. Not needed if signal_sampler and time_sampler are independently supplied.

None
frequency_interpreter FrequencyInterpreter

Callable that determines how a measured frequency should be interpreted (e.g. as an energy or simply as a phase multiplied by 2 pi).

default_frequency_interpreter

signal_source_state_factory instance-attribute

signal_source_state_factory: SignalSourceStateFactory

config instance-attribute

config: QPEConfig

window_function class-attribute instance-attribute

window_function: WindowFunction | None = None

time_frequency_transformation class-attribute instance-attribute

time_frequency_transformation: (
    TimeFrequencyTransformation | None
) = None

frequency_resolver class-attribute instance-attribute

frequency_resolver: FrequencyResolver | None = None

signal_sampler class-attribute instance-attribute

signal_sampler: SignalSampler | None = None

time_sampler class-attribute instance-attribute

time_sampler: TimeSampler | None = None

signal_generator class-attribute instance-attribute

signal_generator: SignalGeneratorInterface | None = None

frequency_interpreter class-attribute instance-attribute

frequency_interpreter: FrequencyInterpreter = (
    default_frequency_interpreter
)

qpe_subroutine property

qpe_subroutine: QPESubroutine

The QPE subroutine that forms the core of the QPE algorithm.

with_debug_resolver

with_debug_resolver() -> QPEBuilder

Return a QPEBuilder with a debug frequency resolver bound to it.

with_measurement_based_resolver

with_measurement_based_resolver(
    num_shots: int = 1,
) -> QPEBuilder

Return a QPEBuilder with a measurement-based frequency resolver bound to it.

with_resolver

with_resolver(
    frequency_resolver: FrequencyResolver,
) -> QPEBuilder

Return a QPEBuilder with a supplied frequency resolver bound to it.

build

build() -> QFTBasedQPE

Build the QPE program.

QPEConfig

Bases: Protocol

Configuration for QPE programs.

bits_of_precision property

bits_of_precision: int

Number of qubits needed to represent the phase in QPE.

num_time_samples property

num_time_samples: int | None

Total number of times sampled in QPE.

iterations_per_time_step property

iterations_per_time_step: Iterable[int]

Number of time samples at each time step in QPE.

get_num_iterations_per_time_step

get_num_iterations_per_time_step(time_step: int) -> int

Given a specific time step, return the number of time samples that need to be taken.

QPESubroutine

QPESubroutine(
    signal_generator: SignalGeneratorInterface,
    window_function: WindowFunction,
    time_frequency_transformation: TimeFrequencyTransformation
    | None = None,
    **kwargs,
)

Bases: Qubrick

Qubrick for the core QPE subroutine.

signal_generator instance-attribute

signal_generator: Incomplete = signal_generator

window_function instance-attribute

window_function: Incomplete = window_function

time_frequency_transformation instance-attribute

time_frequency_transformation: Incomplete = (
    time_frequency_transformation
)

compute

compute(
    time_frequency_reg: Qubits,
    signal_source_reg: Qubits,
    config: QPEConfig,
    ctrl: Qubits | int = 0,
)

RectWindowV2

RectWindowV2(name=None, **kwargs)

Bases: Qubrick

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

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

Executes circuit for implementing rectangular window.

Parameters:

Name Type Description Default
time_frequency_register Qubits

Phase qubit register

required
num_time_steps int | None

The number of time steps to include in the window function

None
ctrl (Optional, int, Qubits)

Control register

0

SamplingStrategy dataclass

SamplingStrategy(
    time_sampler: TimeSampler, signal_sampler: SignalSampler
)

Bases: Generic[SigReg]

Utility class for combining time and signal sampling iterators.

Users should be able to take this class and use it without modification with any compatible time_sampler and signal_sampler.

time_sampler instance-attribute

time_sampler: TimeSampler

signal_sampler instance-attribute

signal_sampler: SignalSampler

sample_from

sample_from(
    time_frequency_register: Qubits, qpe_config: QPEConfig
) -> Iterator[
    tuple[Qubits, Callable[[SigReg, Qubits], None]]
]

SignalGenerator

SignalGenerator(
    sampling_strategy: SamplingStrategy[SigReg], **kwargs
)

Bases: Qubrick, Generic[SigReg]

Qubrick for generating the signal for QPE.

sampling_strategy instance-attribute

sampling_strategy: Incomplete = sampling_strategy

compute

compute(
    time_frequency_register: Qubits,
    signal_source_register: SigReg,
    config: QPEConfig,
    ctrl: Qubits | int = 0,
)

SignalGeneratorInterface

Bases: Protocol

Interface for QPE signal generators.

compute

compute(
    time_frequency_register: Qubits,
    signal_source_register: Qubits,
    config: QPEConfig,
    ctrl: Qubits | int = 0,
)

SignalSampler

Bases: ABC, Generic[SigReg]

Base class for signal samplers in QPE.

MAX_SAMPLE_SIZE class-attribute instance-attribute

MAX_SAMPLE_SIZE: int = 10000000

sample_signal

sample_signal(
    qpe_config: QPEConfig,
) -> Iterator[Callable[[SigReg, Qubits], None]]

SignalSourceStateFactory

Bases: Protocol

Allocates the register that holds the signal source state for QPE.

The factory receives a QPU so it can allocate the correct qubit register on that machine.

get_signal_source_state

get_signal_source_state(qpu: QPU) -> Qubits | None

SineWindowPhaseCatalysisRUSV2

SineWindowPhaseCatalysisRUSV2(
    use_real_amps: bool = True, **kwargs
)

Bases: SineWindowRUSV2

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

Prepared via phase catalyst register using repeat-until-success.

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
  • This version uses repeat until success to avoid the need for amplitude amplification at the cost of the routine not being coherently invertible.
  • The state prepared here will be the same as SineWindowV2 up to a global phase.

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

Computes sine window function.

Parameters:

Name Type Description Default
time_frequency_register Qubits

register on which the sine window state is prepared

required
num_time_steps int | None

The number of time steps to include in the window function

None
ctrl Qubits

control qubit

0
Note
  • This version uses repeat until success to avoid the need for amplitude amplification at the cost of the routine not being coherently invertible.

SineWindowPhaseCatalysisV2

SineWindowPhaseCatalysisV2(
    use_real_amps: bool = True,
    fixed_point: bool = False,
    eps: float = 0.0001,
    **kwargs,
)

Bases: SineWindowV2

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 SineWindowV2 up to a global phase.

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

SineWindowQubitEfficientV2

SineWindowQubitEfficientV2(name=None, **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(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

Computes sine window function.

Parameters:

Name Type Description Default
time_frequency_register Qubits

phase qubit register

required
num_time_steps int | None

The number of time steps to include in the window function

None
ctrl (Optional, int, Qubits)

control register

0

SineWindowRUSV2

SineWindowRUSV2(use_real_amps: bool = True, **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.

use_real_amps instance-attribute

use_real_amps: Incomplete = use_real_amps

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

Computes sine window function.

Parameters:

Name Type Description Default
time_frequency_register Qubits

register on which the sine window state is prepared

required
num_time_steps int | None

The number of time steps to include in the window function

None
ctrl Qubits

control qubit

0
Note
  • This version uses repeat until success to avoid the need for amplitude amplification at the cost of the routine not being coherently invertible.

SineWindowV2

SineWindowV2(
    use_real_amps: bool = True,
    fixed_point: bool = False,
    eps: float = 0.0001,
    **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.

The state is prepared coherently via amplitude amplification on :class:_SineWindow.

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.

use_real_amps instance-attribute

use_real_amps: Incomplete = use_real_amps

fixed_point instance-attribute

fixed_point: Incomplete = fixed_point

eps instance-attribute

eps: Incomplete = eps

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

TimeFrequencyTransformation

Bases: Protocol

Interface for time-frequency transformations in QPE.

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | None = None,
)

TimeSampler

Bases: ABC

Base class for time sampling in QPE.

sample_from

sample_from(
    time_frequency_register: Qubits, qpe_config: QPEConfig
) -> Iterator[Qubits]

WindowEmulatorV2

WindowEmulatorV2(
    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.

{}

emulator_func instance-attribute

emulator_func: Incomplete = emulator_func

emulator_func_kwargs instance-attribute

emulator_func_kwargs: Incomplete = (
    emulator_function_options or {}
)

modifies_state_vector_directly instance-attribute

modifies_state_vector_directly: bool = True

uncompute

uncompute() -> None

Override the default uncomputation.

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

Compute amplitudes of taper state.

Parameters:

Name Type Description Default
time_frequency_register Qubits

Phase qubit register

required
num_time_steps int | None

The number of time steps to include in the window function

None
ctrl (Optional, int, Qubits)

Control register

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

WindowFunction

Bases: Protocol

Interface for QPE window functions.

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

WindowStatePrepV2

WindowStatePrepV2(
    amps,
    state_prep: StatePreparation | None = 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.

{}

amps instance-attribute

amps: Incomplete = amps

state_prep instance-attribute

state_prep: Incomplete = ArbitraryStatePrep(
    amps_rot, phases_rot
)

prep_data instance-attribute

prep_data: Incomplete = StatePrepData(self.amps, 1e-06)

compute

compute(
    time_frequency_register: Qubits,
    num_time_steps: int | None = None,
    ctrl: Qubits | int = 0,
)

Executes circuit for preparing window state.

Parameters:

Name Type Description Default
time_frequency_register Qubits

Phase qubit register.

required
num_time_steps int | None

The number of time steps to include in the window function

None
ctrl (Optional, int, Qubits)

Control register.

0

is_positive_real

is_positive_real(coeffs: Iterable[float | complex]) -> bool

Checks whether the coefficients are all positive real.

ceillog

ceillog(s)

Ceiling log.

Parameters:

Name Type Description Default
s float

Value to take ceil log of.

required

find_physical_locations

find_physical_locations(mps)

Find basis state indices corresponding to the physical registers.

Parameters:

Name Type Description Default
mps list

List of MPS tensors.

required

get_random_mps

get_random_mps(
    d: int,
    n: int,
    maxbond: int,
    is_complex: bool,
    random_number_generator: Generator | None = None,
)

Get random MPS.

Parameters:

Name Type Description Default
d int

Physical dimension.

required
n int

Number of sites.

required
maxbond int

Max bond dimension.

required
is_complex bool

If True, returns MPS tensors with complex values.

required
random_number_generator Generator | None

Generator for the random numbers used in the mps. If not passed, a new generator will be instantiated using the default numpy seed.

None

get_random_tensor

get_random_tensor(
    shape: tuple,
    is_complex: bool,
    random_number_generator: Generator | None = None,
)

Get random MPS tensor.

Parameters:

Name Type Description Default
shape tuple

Shape of tensor.

required
is_complex bool

If True, elements of tensors are complex.

required
random_number_generator Generator | None

Generator for the random numbers used in the mps. If not passed, a new generator will be instantiated using the default numpy seed.

None

make_left_canonical

make_left_canonical(mps)

Make MPS tensors into left canonical form.

Parameters:

Name Type Description Default
mps array

Input MPS tensors.

required

reconstruct_state

reconstruct_state(Ms, d, n_sites)

Convert MPS tensors into state vector.

reshape_last_tensor

reshape_last_tensor(mps)

Fuse the physical-bond indices of every MPS tensor into 2-D matrices and pad the final site.

The routine converts a left-canonical matrix-product state \(mps = [A_0, A_1, ..., A_{n-1}]\), where each tensor has shape \((χ_{left}, d, χ_{right})\), into a list of two-dimensional arrays \([M_0, M_1, ..., M_{n-1}]\) suitable for subsequent right-to-left contractions or for a loader that expects this layout:

  • \(M_0\) - column vector of shape \((d \cdot χ_1, 1)\) obtained by squeezing \(A_0\) and fusing its physical (size \(d\)) and right-bond indices.
  • \(M_i\) - for each interior site \(1 \le i < n-1\), a matrix of shape \((d \cdot χ_{i+1}, χ_i)\) equal to \(A_i.reshape(χ_i, d \cdot χ_{i+1}).T\).
  • \(M_{n-1}\) - the last tensor, first reshaped/transposed as above, \((d', χ_{last})\), and then expanded to \((d' \cdot χ_{last}, χ_{last})\) by inserting \(χ_{last} - 1\) rows of zeros between successive physical rows. This zero-padding ensures that each physical basis block starts at an address that is an integer multiple of the virtual bond dimension, which is required by downstream loading routines.

Parameters:

Name Type Description Default
mps list[ndarray]

List of \(n\) left-canonical MPS tensors with shapes \([(1, d, χ_1), (χ_1, d, χ_2), ..., (χ_{n-1}, d, 1)]\).

required

Returns:

Type Description
list[ndarray]

List \([M_0, ..., M_{n-1}]\), where every element is a 2-D NumPy array as described above.

Notes

The transformation leaves the (virtual) bond dimensions unchanged and does not alter the represented many-body quantum state; it merely repackages the tensors to match the memory layout expected by other utilities in this module, e.g. reconstruct_state.

split

split(M, d, bond_dim)

Split a matrix M via SVD and keep only the bond_dim largest entries.

Parameters:

Name Type Description Default
M array

Input array.

required
d int

Physical dimension.

required
bond_dim int

Bond dimension.

required

splitleft

splitleft(M, d, bond_dim)

Split a matrix M via SVD and keep only the bond_dim largest entries.

Parameters:

Name Type Description Default
M array

Input array.

required
d int

Physical dimension.

required
bond_dim int

Bond dimension.

required

default_frequency_interpreter

default_frequency_interpreter(phase: float) -> float

Interprets the phase as an undifferentiated frequency in the range [0, 2pi].

Assumes the phase is represented in the range [0, 1] rather than [-1, 1].