|
1 | 1 | from __future__ import annotations
|
2 | 2 |
|
| 3 | +import math |
| 4 | +from functools import reduce |
3 | 5 | from numbers import Complex, Real
|
4 | 6 | from typing import TYPE_CHECKING
|
5 | 7 |
|
6 | 8 | import numpy as np
|
7 | 9 | import numpy.typing as npt
|
8 | 10 | import sympy as sp
|
| 11 | +from qiskit import quantum_info |
| 12 | +from scipy.linalg import inv, sqrtm |
9 | 13 | from sympy import Expr, I, pi # pyright: ignore[reportUnusedImport]
|
10 | 14 | from typeguard import typechecked
|
11 | 15 |
|
@@ -41,7 +45,7 @@ def normalize(v: npt.NDArray[np.complex64]) -> npt.NDArray[np.complex64]:
|
41 | 45 |
|
42 | 46 | @typechecked
|
43 | 47 | def matrix_eq(lhs: Matrix, rhs: Matrix) -> bool:
|
44 |
| - r"""Checks whether two matrix are element-wise equal, within a tolerance. |
| 48 | + r"""Checks whether two matrix (including vectors) are element-wise equal, within a tolerance. |
45 | 49 |
|
46 | 50 | For respectively each elements `a` and `b` of both inputs, we check this
|
47 | 51 | specific condition: `|a - b| \leq (atol + rtol * |b|)`.
|
@@ -182,3 +186,75 @@ def exp(angle: Expr | Complex) -> sp.Expr | complex:
|
182 | 186 | res = sp.exp(angle)
|
183 | 187 | assert isinstance(res, Expr)
|
184 | 188 | return res
|
| 189 | + |
| 190 | + |
| 191 | +def rand_orthogonal_matrix_seed(size: int, seed: int) -> npt.NDArray[np.complex64]: |
| 192 | + """Generate a random orthogonal matrix with a given seed. |
| 193 | +
|
| 194 | + Args: |
| 195 | + size: Size (number of columns, or rows) of the squared matrix to generate. |
| 196 | + seed: Seed used to control the random generation of the matrix. |
| 197 | +
|
| 198 | + Returns: |
| 199 | + A random orthogonal Matrix. |
| 200 | + """ |
| 201 | + # TODO: example |
| 202 | + np.random.seed(seed) |
| 203 | + m = np.random.rand(size, size) |
| 204 | + return m.dot(inv(sqrtm(m.T.dot(m)))) |
| 205 | + |
| 206 | + |
| 207 | +def rand_orthogonal_matrix(size: int) -> npt.NDArray[np.complex64]: |
| 208 | + """Generate a random orthogonal matrix without a given seed""" |
| 209 | + # TODO: to comment + examples |
| 210 | + m = np.random.rand(size, size) |
| 211 | + return m.dot(inv(sqrtm(m.T.dot(m)))) |
| 212 | + |
| 213 | + |
| 214 | +def rand_clifford_matrix(nb_qubits: int) -> npt.NDArray[np.complex64]: |
| 215 | + """Generate a random Clifford matrix""" |
| 216 | + # TODO: to comment + examples |
| 217 | + return quantum_info.random_clifford( |
| 218 | + nb_qubits |
| 219 | + ).to_matrix() # pyright: ignore[reportReturnType] |
| 220 | + |
| 221 | + |
| 222 | +def rand_unitary_2x2_matrix() -> npt.NDArray[np.complex64]: |
| 223 | + """Generate a random one-qubit unitary matrix""" |
| 224 | + # TODO: to comment + examples |
| 225 | + theta, phi, gamma = np.random.rand(3) * 2 * math.pi |
| 226 | + c, s, eg, ep = ( |
| 227 | + np.cos(theta / 2), |
| 228 | + np.sin(theta / 2), |
| 229 | + np.exp(gamma * 1j), |
| 230 | + np.exp(phi * 1j), |
| 231 | + ) |
| 232 | + return np.array([[c, -eg * s], [eg * s, eg * ep * c]]) |
| 233 | + |
| 234 | + |
| 235 | +def rand_product_local_unitaries(nb_qubits: int) -> npt.NDArray[np.complex64]: |
| 236 | + """ |
| 237 | + Generate a random tensor product of unitary matrices |
| 238 | +
|
| 239 | + Args: |
| 240 | + nb_qubits: Number of qubits on which the product of unitaries will act. |
| 241 | + """ |
| 242 | + return reduce( |
| 243 | + np.kron, |
| 244 | + [rand_unitary_2x2_matrix() for _ in range(nb_qubits - 1)], |
| 245 | + np.eye(1, dtype=np.complex64), |
| 246 | + ) |
| 247 | + |
| 248 | + |
| 249 | +def rand_hermitian_matrix(size: int) -> npt.NDArray[np.complex64]: |
| 250 | + """Generate a random Hermitian matrix. |
| 251 | +
|
| 252 | + Args: |
| 253 | + size: Size (number of columns, or rows) of the squared matrix to generate. |
| 254 | +
|
| 255 | + Returns: |
| 256 | + A random orthogonal Matrix. |
| 257 | + """ |
| 258 | + # TODO: examples |
| 259 | + m = np.random.rand(size, size).astype(np.complex64) |
| 260 | + return m + m.conjugate().transpose() |
0 commit comments