Quantum State Preparation#
- prepare(qv, target_array, reversed: bool = False, method: str = 'auto')[source]#
Prepare a quantum state on
qvfrom a target amplitude vector.Given a vector \(b=(b_0,\dotsc,b_{N-1})\) (corresponding to
target_array), this routine prepares the quantum state:\[\sum_{i=0}^{N-1} b_i \ket{i}.\]The
target_arrayinput vector is normalized internally, i.e.\[\tilde b_i = \frac{b_i}{\|b\|}, \qquad \ket{0} \;\mapsto\; \sum_{i=0}^{N-1} \tilde b_i \ket{i}.\]By default, the little-endian convention is used for the computational basis ordering. For example, for a 2-qubit system, the basis states are ordered as
\[\ket{0} \equiv \ket{q_0 = 0, q_1 = 0}, \quad \ket{1} \equiv \ket{q_0 = 1, q_1 = 0}, \dotsc\]- Parameters:
- qvQuantumVariable
Quantum variable to prepare.
- target_arraynumpy.ndarray or jax.numpy.ndarray
Target amplitude vector \(b\). Must have length \(2^n\) where \(n\) is the size of
qv(validated for concrete arrays).- reversedbool, optional
If
True, applies a bit-reversal permutation (big-endian ordering). Default isFalse.- method{‘qiskit’, ‘qswitch’, ‘auto’}, optional
Compilation method for state preparation. Possible values are:
'qiskit': requires concrete arrays (e.g. NumPy).'qswitch': supports traced arrays (e.g. JAX tracers in Jasp mode). Note that shape validation is not performed in Jasp mode.'auto': automatically selects between the above.
Default is
'auto'.
Examples
In this example, we create a QuantumFloat and prepare the normalized state \(\sum_{i=0}^3 \tilde b_i\ket{i}\) for \(\tilde b=(0,1,2,3)/\sqrt{14}\).
import numpy as np from qrisp import QuantumFloat, prepare b = np.array([0, 1, 2, 3], dtype=float) b /= np.linalg.norm(b) qf = QuantumFloat(2) prepare(qf, b)
We can verify that the state has been correctly prepared.
For example, we can use the
statevectormethod to get a function that maps basis states to amplitudes:sv_function = qf.qs.statevector("function") print(f"b[1]: {b[1]:.6f} -> {sv_function({qf: 1}):.6f}") # b[1]: 0.267261 -> 0.267261-0.000000j print(f"b[2]: {b[2]:.6f} -> {sv_function({qf: 2}):.6f}") # b[2]: 0.534522 -> 0.534522-0.000000j
where index 1 in little-endian corresponds to the basis state \(\ket{q_0=1, q_1=0}\) and index 2 to \(\ket{q_0=0, q_1=1}\). With
reversed=True, we can switch to big-endian ordering. That is, we can mapb[1]tosv_function({qf: 2})instead, and so on.We can perform a similar verification even if the statevector is not directly accessible (for example when running on hardware), by using measurement results:
qf = QuantumFloat(2) prepare(qf, b) res_dict = qf.get_measurement() ref = np.sqrt(res_dict[1]) amps = {k: round(np.sqrt(v) / ref) for k, v in res_dict.items()} print(amps) # Yields: {3: 3, 2: 2, 1: 1}
The output indicates that the magnitudes of the amplitudes for the basis states \(\ket{1}\), \(\ket{2}\), and \(\ket{3}\) are in the ratio \(1 : 2 : 3\), exactly matching the input vector \(b = (0,1,2,3)\) up to normalization.
Note
This primitive is not yet compatible with QuantumEnvironments (e.g.
invertorcontrol) in Jasp mode when using theqswitchmethod. Trying to use it within such environments, for example by writing:from qrisp.jasp.evaluation_tools import terminal_sampling @terminal_sampling def circuit(): (...) with invert(): prepare(..., method="qswitch")
currently results in an error.
Furthermore, it is currently not possible to prepare a state with 64 or more qubits using the
qswitchmethod.