State Preparation¶
Most quantum applications start with preparing a state in a quantum register. For example, in finance the state may represent price distribution of some assets. In chemistry, it may be an initial guess for the ground state of a molecule and in a quantum machine learning, feature vector to be analyzed.
The state preparation function creates a quantum circuit which outputs either a probability distribution \(p_{i}\) or a real amplitudes vector \(a_{i}\) in the computational basis, with \(i\) denoting the corresponding basis state. The amplitudes should be given in the form of list of float numbers. The probabilities can be described as a list or positive numbers or a mixture of a gaussian distributions. The resulting wave function is given by
in the case of probability and by
in the case of amplitude
In general, state preparation is hard. Only a very small portion of the Hilbert space can be prepared efficiently (in \(O(poly(n))\) steps) on a quantum circuit. Therefore, in practice, an approximation is often used to lower the complexity. The approximation is specified by an error metric and error range.
For a circuit consisting of error-less gates, there are several options for the error metric:
- Kullback–Leibler divergence (KL)
- \(L_p\) norms: \(L_1\), \(L_2\), and \(L_\infty\)(max probability)
- Loss of fidelity (FL), defined by \(\rm{FL} = 1 - \left|\left\langle \tilde{\psi} \right|\left.\vphantom {\tilde{\psi}}\psi\right\rangle \right|^{2}\), where \({\psi}\), \(\tilde {\psi}\) is the exact, approximated state, respectively.
- Total variation (half the \(L_1\) norm).
- Hellinger distance
- Bhattacharyya distance
For the amplitude preparation only The \(L_p\) norms are available.
The higher the specified error tolerance, the smaller the output circuit will be. Not specifying an error will result in an attempt to build the exact circuit.
Syntax¶
Function: StatePreparation
Parameters:
-
probabilities: [pmf, GaussianMixture, List, Tuple, Ndarray]
or amplitudes: [ List, Tuple, Ndarray]
- error_metric: Optional[[KL, L1, L2, MAX_PROBABILITY, LOSS_OF_FIDELITY, TOTAL_VARIATION, HELLINGER, BHATTACHARYYA], NonNegativeFloatRange]]
- is_uniform_start: Optional[bool] = true
{
"function": "StatePreparation",
"function_params": {
"probabilities": [0.05, 0.11, 0.13, 0.23, 0.27, 0.12, 0.03, 0.06],
"error_metric": { "KL": { "upper_bound": 0.01 } }
}
}
Example 1: Loading Point Mass Function(PMF)¶
{
"constraints": {
"max_depth": 91
},
"logic_flow": [{
"function": "StatePreparation",
"function_params": {
"probabilities": [0.05, 0.11, 0.13, 0.23, 0.27, 0.12, 0.03, 0.06],
"error_metric": {"KL": {"upper_bound": 0.01}}
}
}]
}
from classiq import Model
from classiq.model import Constraints
from classiq.builtin_functions import StatePreparation
probabilities = (0.05, 0.11, 0.13, 0.23, 0.27, 0.12, 0.03, 0.06)
params = StatePreparation(
probabilities=probabilities,
error_metric={"KL": {"upper_bound": 0.01}},
)
constraints = Constraints(max_depth=91)
model = Model(constraints=constraints)
model.StatePreparation(params)
circuit = model.synthesize()
This example generates a circuit whose output state probabilities are an approximation to the pmf given. That is, the probability to measure the state \(\ket{000}\) is 0.05, \(\ket{001}\) is 0.11,... ,and the probability to measure \(\ket{111}\) is 0.06. The error metric used is Kullback–Leibler.
To execute the circuit, you may run the following code:
Create the following file: execution_preferences.exct
{
"preferences": {
"num_shots": 4000,
"backend_preferences": {
"backend_service_provider": "IBM Quantum",
"backend_name": "aer_simulator"
}
}
}
Classiq: Execute Quantum Program
), choose a file containing the program and pick it's instruction set (e.g. QASM or ionq) and the outptut path.
from classiq import Executor
from classiq import execution
res = Executor(
num_shots=4000,
backend_preferences=execution.IBMBackendPreferences(backend_name="aer_simulator"),
).execute(circuit)
To print the result on the SDK, use the code below:
counts = sorted(res.counts.items())
print(
f"probabilities are:\n{dict([(bit_string, count/NUM_SHOT) for bit_string, count in counts])}"
)
which results in the following values:
probabilities are:
{'0000': 0.048, '0001': 0.133, '0010': 0.129, '0011': 0.228, '0100': 0.255, '0101': 0.114, '0110': 0.047, '0111': 0.046}
Example 2: Loading Gaussian Mixture¶
{
"constraints": {
"max_depth": 91
},
"logic_flow": [
{
"function": "StatePreparation",
"function_params": {
"probabilities": {
"gaussian_moment_list": [
{
"mu": 1,
"sigma": 1
},
{
"mu": 3,
"sigma": 1
},
{
"mu": -3,
"sigma": 1
}
],
"num_qubits": 8
},
"error_metric": {
"L2": {
"upper_bound": 0.023
}
}
}
}
]
}
from classiq import Model
from classiq.model import Constraints
from classiq.builtin_functions import StatePreparation
from classiq.builtin_functions.state_preparation import (
GaussianMixture,
GaussianMoments,
)
params = StatePreparation(
probabilities=GaussianMixture(
gaussian_moment_list=(
GaussianMoments(mu=1, sigma=1),
GaussianMoments(mu=3, sigma=1),
GaussianMoments(mu=-3, sigma=1),
),
num_qubits=8,
),
error_metric={"L2": {"upper_bound": 0.023}},
)
constraints = Constraints(max_depth=91)
model = Model(constraints=constraints)
model.StatePreparation(params)
circuit = model.synthesize()
This example generates a circuit whose output state probabilities
correspond to a gaussian mixture.
GaussianMixture
includes a list of gaussian functions to describe the total
distribution, and num_qubits
field to determine the sampling.
Each gaussian function is described by mean (mu) and standard deviation (sigma).
The underlying pmf is calculated in the following way:
first, the support of the gaussian mixture cdf is
truncated at 5 sigma from the gaussian at each edge, second, the
support is divided into an equal size grid containing \(2^8+ 1\)
points and lastly the pmf is calculated by taking the difference
between the cdf values of consecutive grid points. The error
metric used is L2. Note that 4 qubits do not undergo any operation.
This is due to the selected error bound (these qubits correspond
to the least significant bits). A tighter error bound would result
in a circuit operating on more qubits.
To execute the circuit, you may run the following code:
Create the following file: execution_preferences.exct
{
"preferences": {
"num_shots": 4000,
"backend_preferences": {
"backend_service_provider": "IBM Quantum",
"backend_name": "aer_simulator"
}
}
}
Classiq: Execute Quantum Program
), choose a file containing the program and pick it's instruction set (e.g. QASM or ionq) and the outptut path.
from classiq import Executor
from classiq import execution
res = Executor(
num_shots=4000,
backend_preferences=execution.IBMBackendPreferences(backend_name="aer_simulator"),
).execute(circuit)
The resulting plot and the code to generate it using the SDK are shown below.
from matplotlib import pyplot as plt
sorted_counts = dict(sorted(res.counts.items()))
bit_strings, counts = sorted_counts.keys(), sorted_counts.values()
plt.title("Gaussian Mixtures graph")
plt.xlabel("State")
plt.ylabel("Measurement Probability [%]")
plt.plot(
[int(bit_str, 2) for bit_str in bit_strings], [count / NUM_SHOT for count in counts]
)
plt.show()
Example 3 - Amplitudes Preparation¶
{
"constraints": {
"max_depth": 120
},
"logic_flow": [{
"function": "StatePreparation",
"function_params": {
"amplitudes": [-0.540061731, -0.38575837, -0.23145502, -0.07715167, 0.07715167,
0.23145502, 0.385758371, 0.540061731],
"error_metric": {"L2": {"upper_bound": 0.1}}
}
}]
}
from classiq import Model
from classiq.model import Constraints
from classiq.builtin_functions import StatePreparation
import numpy as np
amp = np.linspace(-1, 1, 8)
amp = amp / np.linalg.norm(amp)
params = StatePreparation(
amplitudes=amp,
error_metric={"L2": {"upper_bound": 0.1}},
)
constraints = Constraints(max_depth=120)
model = Model(constraints=constraints)
model.StatePreparation(params)
circuit = model.synthesize()
In this example, we load a normalized linear space between -1 to 1. The load state has an accuracy of 90 present under the L2 norm.
Note
When amplitudes are loaded, probabilities shouldn't pass as an argument. StatePreparation
must get either probabilities or amplitudes but not both of them.