Skip to content
Construct PsiQDK Algorithms

utils

utils

AliasSamplingStatePrepDataProtocol

Bases: Protocol

Protocol for alias sampling state preparation data containers.

is_positive_real property

is_positive_real: bool

Determines whether coefficients are all positive, real values.

probabilities property

probabilities: list[float] | SymbolicArray

Converts coefficients to corresponding probabilities.

validate_inputs

validate_inputs() -> None

Check that all input coefficients and types are valid for alias sampling.

trim_register_if_needed

trim_register_if_needed(qbits: Qubits | SymbolicQubits) -> Qubits | SymbolicQubits

Trim register to appropriate size if too many qubits were provided.

combined_data_list

combined_data_list(max_shift: int | Parameter | None = None) -> list[int] | SymbolicArray

Helper to combine data output by QROM in alias sampling.

compute_num_states

compute_num_states() -> tuple[int | Parameter, int | Parameter]

Helper to compute number of states to prepare in alias sampling.

NumericAliasSamplingStatePrepData dataclass

NumericAliasSamplingStatePrepData(coeffs: Iterable[float | complex], bits_of_precision: int | None = None, lambda_val: int | None = None, error_param: int | None = None)

Numeric implementation of alias sampling state preparation data.

coeffs instance-attribute

coeffs: Iterable[float | complex]

bits_of_precision class-attribute instance-attribute

bits_of_precision: int | None = None

lambda_val class-attribute instance-attribute

lambda_val: int | None = None

error_param class-attribute instance-attribute

error_param: int | None = None

is_positive_real property

is_positive_real: bool

Determines whether self.coeffs are all positive, real values.

probabilities cached property

probabilities: list[float]

Converts self.coeffs to the corresponding probabilities.

validate_inputs

validate_inputs() -> None

Check that all input coefficients and types are valid for alias sampling.

trim_register_if_needed

trim_register_if_needed(qbits: Qubits) -> Qubits

Trim register to appropriate size if too many qubits were provided.

combined_data_list

combined_data_list(max_shift: int | None = None) -> list[int]

Helper to combine data output by QROM in alias sampling.

compute_num_states

compute_num_states() -> tuple[int, int]

Helper to compute number of states to prepare in alias sampling.

SymbolicAliasSamplingStatePrepData dataclass

SymbolicAliasSamplingStatePrepData(coeffs: SymbolicArray, bits_of_precision: Parameter | None = None, lambda_val: Parameter | None = None, error_param: Parameter | None = None)

Symbolic implementation of alias sampling state preparation data.

coeffs instance-attribute

coeffs: SymbolicArray

bits_of_precision class-attribute instance-attribute

bits_of_precision: Parameter | None = None

lambda_val class-attribute instance-attribute

lambda_val: Parameter | None = None

error_param class-attribute instance-attribute

error_param: Parameter | None = None

is_positive_real property

is_positive_real: bool

Determines whether self.coeffs are all positive, real values.

probabilities cached property

probabilities: SymbolicArray

Converts self.coeffs to the corresponding probabilities.

validate_inputs

validate_inputs() -> None

Check that all input coefficients and types are valid for alias sampling.

trim_register_if_needed

trim_register_if_needed(qbits: SymbolicQubits) -> SymbolicQubits

Trim register to appropriate size if too many qubits were provided.

combined_data_list

combined_data_list(max_shift: Parameter | None = None) -> SymbolicArray

Helper to combine data output by QROM in alias sampling.

compute_num_states

compute_num_states() -> tuple[Parameter, Parameter]

Helper to compute number of states to prepare in alias sampling.

ArbitraryStatePrepData dataclass

ArbitraryStatePrepData(coefficients: Iterable[float | complex], bits_of_precision: int)

Data for specifying an arbitrary state to prepare via LKS state prep.

coefficients instance-attribute

coefficients: Iterable[float | complex]

bits_of_precision instance-attribute

bits_of_precision: int

epsilon property

epsilon: float

Accuracy of the state prep protocol, determined using Eq. 49 from "Trading T gates for dirty qubits in state preparation and unitary synthesis" (arXiv:1812.00954 ⧉).

StatePrepData dataclass

StatePrepData(coefficients: Iterable[float | complex], epsilon: float)

Data for specifying an arbitrary state to prepare.

coefficients instance-attribute

coefficients: Iterable[float | complex]

epsilon instance-attribute

epsilon: float

SupportedOps

Bases: Enum

Specifies which rotation ops the multiplexed rotations support.

RX class-attribute instance-attribute

RX = 0

RY class-attribute instance-attribute

RY = 1

RZ class-attribute instance-attribute

RZ = 2

PHASE class-attribute instance-attribute

PHASE = 3

PPR class-attribute instance-attribute

PPR = 4

alias_sampling_get_b_from_epsilon

alias_sampling_get_b_from_epsilon(inputs: Iterable[float], epsilon: float, b_upper_bound: int = 1000, return_theory_bound_and_actual_diff: bool = False) -> int | tuple[int, float, float]

Get the number of bits of precision needed for alias sampling to achieve an accuracy epsilon.

Finds the minimum bit precision required such that the 2-norm difference between the normalized input and its discretized version is below an epsilon threshold.

Parameters:

Name Type Description Default
inputs Iterable[float]

Input list of values to be normalized and discretized.

required
epsilon float

Threshold for acceptable 2-norm difference.

required
b_upper_bound int

Maximum bit precision to search. Default is 1000.

1000
return_theory_bound_and_actual_diff bool

Set to True to return the theory bound and actual l2-norm difference.

False

Returns:

Type Description
tuple

(bit_precision, norm_diff) if a suitable precision is found.

Raises:

Type Description
ValueError

If no suitable bit precision is found within the range.

AliasSamplingStatePrepData

alias_sampling_state_prep_data(coeffs: SymbolicArray, bits_of_precision: Parameter | None = None, lambda_val: Parameter | None = None, error_param: Parameter | None = None) -> SymbolicAliasSamplingStatePrepData
alias_sampling_state_prep_data(coeffs: Iterable[float | complex], bits_of_precision: int | None = None, lambda_val: int | None = None, error_param: int | None = None) -> NumericAliasSamplingStatePrepData
AliasSamplingStatePrepData(coeffs: Iterable[float | complex] | SymbolicArray, bits_of_precision: int | Parameter | None = None, lambda_val: int | Parameter | None = None, error_param: int | Parameter | None = None) -> AliasSamplingStatePrepDataProtocol

Create appropriate alias sampling state prep data based on input type.

alias_sampling_state_prep_data

alias_sampling_state_prep_data(coeffs: SymbolicArray, bits_of_precision: Parameter | None = None, lambda_val: Parameter | None = None, error_param: Parameter | None = None) -> SymbolicAliasSamplingStatePrepData
alias_sampling_state_prep_data(coeffs: Iterable[float | complex], bits_of_precision: int | None = None, lambda_val: int | None = None, error_param: int | None = None) -> NumericAliasSamplingStatePrepData
alias_sampling_state_prep_data(coeffs: Iterable[float | complex] | SymbolicArray, bits_of_precision: int | Parameter | None = None, lambda_val: int | Parameter | None = None, error_param: int | Parameter | None = None) -> AliasSamplingStatePrepDataProtocol

Create appropriate alias sampling state prep data based on input type.

discretized_prob_distribution_improved

discretized_prob_distribution_improved(probabilities_list: Iterable[float], bit_precision: int) -> np.array

Discretizes a probability distribution while preserving the total sum using a rounding correction.

Warning: this function now takes the input parameter in the form of the probabilities (amplitude square) rather than the state vector. This is compatible with the implementation in the experimental branch, and will cause conflict with the original Alias Sampling implementation

Parameters:

Name Type Description Default
probabilities_list Iterable[float]

List of non-negative values representing probabilities of coefficients (don't have to be normalized)

required
bit_precision int

Number of bits to determine the number of discrete levels.

required

Returns:

Type Description
array

Discretized values that sum to the expected total.

Raises:

Type Description
ValueError

If input contains negative values.

LKS_get_b_from_epsilon

LKS_get_b_from_epsilon(inputs: Iterable[float], epsilon: float, b_upper_bound: int = 1000, return_theory_bound_and_actual_diff: bool = False) -> int | tuple[int, float, float]

Get a numerically-optimized number of bits of precision for LKS state prep.

Finds the minimum bit precision such that the L2-norm difference between the normalized input and its discretized version is below a given epsilon threshold.

Parameters:

Name Type Description Default
epsilon float

Acceptable L2-norm threshold.

required
inputs Iterable[float]

Real or complex input values.

required
b_upper_bound int

Max bit precision to check.

1000
return_theory_bound_and_actual_diff bool

Whether to return (bit_precision, theory_eps, actual_eps)

False

Returns:

Type Description
int | tuple[int, float, float]

Best bit precision, or (bit_precision, expected_eps, norm_diff).

Raises:

Type Description
ValueError

If no suitable bit precision is found.

compute_ry_angle_array

compute_ry_angle_array(coeffs: Iterable[float]) -> list[list[float]]

Calculate rotation angles needed to prepare an arbitrary pure state.

In particular, for a state \(\frac{e^{i \theta}}{\|a\|_2}\sum_i a_i \ket{i}\), with complex coefficients \(a_i\), where \(e^{i \theta}\) is the global phase and \(\|a\|_2\) is the two-norm, this function finds angles for rotations which prepare the magnitude component of each coefficient in the state vector.

We follow equation 8 in "Transformation of quantum states using uniformly controlled rotations" (arXiv:quant-ph/0407010 ⧉).

Note

The output rotations are in degrees to coincide with the convention used elsewhere in Workbench.

Returns:

Type Description
list[list[float]]

Nested list of \(Y\) rotation angles that prepare the magnitudes per term in the input target coefficients.

Notes
  • The reference above actually presents the calculation of these angles with the inverse goal of state preparation; assume you start in an arbitrary state, and now must apply specific-angle + axis rotations to return to the all-zero state.
  • This function corresponds to equations in the text for determining angles meant to zero out the magnitudes of an input arbitrary superposition state.
  • We simply return the reverse-order list of the angles we calculate.

compute_rz_angle_array

compute_rz_angle_array(coeffs: Iterable[float]) -> list[list[float]]

Calculate rotation angles needed to prepare an arbitrary pure state.

In particular, for a state \(\frac{e^{i \theta}}{\|a\|_2}\sum_i a_i \ket{i}\), with complex coefficients \(a_i\), where \(e^{i \theta}\) is the global phase and \(\|a\|_2\) is the two-norm, this function finds angles for rotations which prepare the phase component of each coefficient in the state vector.

We follow equation 5 in "Transformation of quantum states using uniformly controlled rotations" (arXiv:quant-ph/0407010 ⧉).

Note: rotations default to degrees, as it is now used in all the implementations here

Returns:

Type Description
tuple[list[list[float]], float]

We return a tuple with two different items:

  • A nested list of \(Z\) rotation angles that prepare the correct phases for each coefficient in target_state_coeffs.
  • A float between 0 and 1 that corresponds to the angle \(\theta\) in the global phase \(e^{i \theta}\).
Notes
  • The reference above actually presents the calculation of these angles with the inverse goal of state preparation; assume you start in an arbitrary state, and now must apply specific-angle + axis rotations to return to the all-zero state.
  • This function corresponds to equations in the text for determining angles meant to equalize the phases in an input arbitrary superposition state.
  • We simply return the reverse-order list of the angles we calculate.

get_amp_array_from_angle_array

get_amp_array_from_angle_array(angles_2d_list: list[list[float]]) -> list[float]

Takes a list of angles used in Grover-Rudolph state prep and converts them to a list of resulting amplitudes.

Compute amplitude array from a 2D list of angles qubit by qubit, in a tree-like structure. For each qubit layer, we grab the previous layer amps and calculate the cos and sin values parameterized by the current qubit layer angles, and put the two values for each of the angles in the current qubit layer's amp_list.

Parameters:

Name Type Description Default
angles_2d_list list[list[float]]

Each sublist represents angles for a qubit layer.

required

Returns:

Type Description
list[float]

The last computed amplitude list.

get_approximated_weight_using_angle_truncation_function

get_approximated_weight_using_angle_truncation_function(weights: Iterable[float], b: int) -> np.ndarray

Computes the approximated weight using angle truncation.

Parameters:

Name Type Description Default
weights Iterable[float]

Input weight values (real or complex).

required
b int

Truncation precision for the rotation angle.

required

Returns:

Type Description
ndarray

Approximated weight after angle truncation.

pauli_rotation_helper

pauli_rotation_helper(angle: float, opcode: SupportedOps, target_reg: Qubits, ctrl: Qubits | int = 0)

Parses the specification of an op given by opcode to a QPU rotation op which is applied on target_reg.

ppr_to_rz_compute

ppr_to_rz_compute(qc: QPU, x_qbits: Qubits | int, z_qbits: Qubits | int, ctrl: Qubits | int = 0)

PPR as standard gates.

Parameters:

Name Type Description Default
qc QPU

QPU instance.

required
x_qbits Qubits | int

Qubit register where Pauli Xs act (or zero if none).

required
z_qbits Qubits | int

Qubit register where Pauli Zs act (or zero if none).

required
ctrl Qubits | int

Qubits register to control the ppr on.

0

generate_complex_array

generate_complex_array(n: int, real_range: tuple[int, int] = (-1, 1), imag_range: tuple[int, int] = (-1, 1), random_number_generator: Generator | None = None) -> np.ndarray

Generate an array of n complex numbers.

The array is generated with real and imaginary parts sampled from uniform distributions within specified ranges.

Parameters:

Name Type Description Default
n int

Number of complex numbers to generate.

required
real_range tuple[int, int]

Range (min, max) for real parts.

(-1, 1)
imag_range tuple[int, int]

Range (min, max) for imaginary parts.

(-1, 1)
random_number_generator Generator | None

Generator for the random numbers.

None

Returns:

Type Description
ndarray

Array of complex numbers.

l1_normalize

l1_normalize(input_list: Iterable[float]) -> list[float]

Normalize an input list with respect to the L1-norm of the elements.

l2_norm_diff

l2_norm_diff(arr1: ndarray, arr2: ndarray) -> float

Computes the L2-norm (Euclidean distance) between two real or complex arrays.

Parameters:

Name Type Description Default
arr1 ndarray

First input array (real or complex).

required
arr2 ndarray

Second input array (real or complex).

required

Returns:

Type Description
float

L2-norm distance between arr1 and arr2.

Raises:

Type Description
ValueError

If array shapes don't match or types don't match.

l2_normalize

l2_normalize(input_list: Iterable[float], allow_complex: bool = False, eps: float = 1e-15) -> np.ndarray

Normalize a 1D array so that the sum of squares equals 1 (L2 norm).

Parameters:

Name Type Description Default
input_list Iterable[float]

Input array

required
allow_complex bool

Whether to allow complex numbers

False
eps float

Tolerance for zero norm

1e-15

Returns:

Type Description
ndarray

L2-normalized array