Skip to content
Construct PsiQDK Algorithms

data_loading

data_loading

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.

{}

swap_up instance-attribute

swap_up: Incomplete = swap_up

select instance-attribute

select: Incomplete = select

fallback_read instance-attribute

fallback_read: Incomplete = fallback_read

symbolic_mode instance-attribute

symbolic_mode: Incomplete = symbolic_mode

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 "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954 ⧉), 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.

{}

swap_up instance-attribute

swap_up: Incomplete = swap_up

select instance-attribute

select: Incomplete = select

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

{}

swap_up instance-attribute

swap_up: Incomplete = swap_up

select instance-attribute

select: Incomplete = select

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 "Quantum computing enhanced computational catalysis" (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 keyword arguments to pass to the constructor.

{}

inner_qrom instance-attribute

inner_qrom: Incomplete = inner_qrom

outer_qrom instance-attribute

outer_qrom: Incomplete = outer_qrom

adder instance-attribute

adder: Incomplete = adder

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.

{}

is_unary instance-attribute

is_unary: bool = True

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