| from __future__ import annotations |
|
|
| import numpy as np |
| from numpy.typing import ArrayLike, NDArray |
|
|
|
|
| def complex_statevector_to_ri(psi: ArrayLike) -> NDArray[np.float64]: |
| psi_c = np.asarray(psi, dtype=np.complex128) |
| if psi_c.ndim != 1: |
| raise ValueError("psi must be a 1D complex array of length 2^n") |
| out = np.empty((psi_c.shape[0], 2), dtype=np.float64) |
| out[:, 0] = psi_c.real |
| out[:, 1] = psi_c.imag |
| return out |
|
|
|
|
| def ri_to_complex_statevector(psi_ri: ArrayLike) -> NDArray[np.complex128]: |
| arr = np.asarray(psi_ri, dtype=np.float64) |
| if arr.ndim != 2 or arr.shape[1] != 2: |
| raise ValueError("psi_ri must have shape (2^n, 2)") |
| return arr[:, 0].astype(np.complex128) + 1j * arr[:, 1] |
|
|
|
|
| def complex_matrix_to_ri(mat: ArrayLike) -> NDArray[np.float64]: |
| mat_c = np.asarray(mat, dtype=np.complex128) |
| if mat_c.ndim != 2: |
| raise ValueError("mat must be a 2D complex array") |
| out = np.empty((mat_c.shape[0], mat_c.shape[1], 2), dtype=np.float64) |
| out[:, :, 0] = mat_c.real |
| out[:, :, 1] = mat_c.imag |
| return out |
|
|
|
|
| def ri_to_complex_matrix(mat_ri: ArrayLike) -> NDArray[np.complex128]: |
| arr = np.asarray(mat_ri, dtype=np.float64) |
| if arr.ndim != 3 or arr.shape[2] != 2: |
| raise ValueError("mat_ri must have shape (N, M, 2)") |
| return arr[:, :, 0].astype(np.complex128) + 1j * arr[:, :, 1] |
|
|
|
|
| def kraus_1q_to_ri(kraus_ops: ArrayLike) -> NDArray[np.float64]: |
| """ |
| Convert a set of 1-qubit Kraus operators into the Rust-kernel format. |
| |
| Input shape: (k, 2, 2) complex |
| Output shape: (k, 2, 2, 2) float64 with last dim [re, im] |
| """ |
| k = np.asarray(kraus_ops, dtype=np.complex128) |
| if k.ndim != 3 or k.shape[1:] != (2, 2): |
| raise ValueError("kraus_ops must have shape (k, 2, 2) complex") |
| out = np.empty((k.shape[0], 2, 2, 2), dtype=np.float64) |
| out[:, :, :, 0] = k.real |
| out[:, :, :, 1] = k.imag |
| return out |
|
|
|
|
|
|