workbench_algorithms.subroutines.multiplexing
Submodule for multiplexing.
BinaryTreeMultiplexor
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:
- There is no data to load (exit the routine).
- Loading a single item does not require this hefty machinery.
- Loading two items without a control is similarly cheap to the single-item-case.
- Loading n > 2 items without a control.
- 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
|
OneAncMultiplexor
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
|
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
Bases: Qubrick
Applies the Givens rotation using Pauli Product Rotations.
This method implements the unitary:
which is equivalent to applying two single-qubit rotations, one with \( +\theta \) and the other with \( -\theta \).
compute
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
|
GivensRotationFusedAdder
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 |
None
|
**kwargs
|
dict[str, Any]
|
Additional arguments passed to |
{}
|
compute
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
|
GivensRotationTwoAdders
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 |
None
|
**kwargs
|
dict[str, Any]
|
Additional arguments passed to |
{}
|
compute
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
|
GivensRZs
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:
This transformation can be decomposed into single-qubit RZ gates with Clifford conjugation:
- Apply a Clifford pre-rotation to transform the computational basis.
- Perform controlled
RZgates to introduce the phase shift. - 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 |
{}
|
compute
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
|
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.
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.
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
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 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:
- There is no data to load (exit the routine).
- Loading a single item does not require this hefty machinery.
- Loading two items without a control is similarly cheap to the single-item-case.
- 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
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
|
get_default_multiplex_function
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
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 |
BinaryToUnaryComputation
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. |