Source code for toqito.rand.random_unitary
"""Generates a random unitary matrix."""
import numpy as np
[docs]
def random_unitary(dim: list[int] | int, is_real: bool = False, seed: int | None = None) -> np.ndarray:
r"""Generate a random unitary or orthogonal matrix [@Ozols_2009_RandU].
Calculates a random unitary matrix (if `is_real = False`) or a random real orthogonal
matrix (if `is_real = True`), uniformly distributed according to the Haar measure.
Examples:
We may generate a random unitary matrix. Here is an example of how we may be able to generate a
random \(2\)-dimensional random unitary matrix with complex entries.
```python exec="1" source="above" session="complex_dm"
from toqito.rand import random_unitary
complex_dm = random_unitary(2)
print(complex_dm)
```
We can verify that this is in fact a valid unitary matrix using the `is_unitary` function
from `|toqito⟩` as follows
```python exec="1" source="above" session="complex_dm"
from toqito.matrix_props import is_unitary
print(is_unitary(complex_dm))
```
We can also generate random unitary matrices that are real-valued as follows.
```python exec="1" source="above" session="real_dm"
from toqito.rand import random_unitary
real_dm = random_unitary(2, True)
print(real_dm)
```
Again, verifying that this is a valid unitary matrix can be done as follows.
```python exec="1" source="above" session="real_dm"
from toqito.matrix_props import is_unitary
print(is_unitary(real_dm))
```
We may also generate unitaries such that the dimension argument provided is a `list` as
opposed to an `int`. Here is an example of a random unitary matrix of dimension \(4\).
```python exec="1" source="above" session="mat"
from toqito.rand import random_unitary
mat = random_unitary([4, 4], True)
print(mat)
```
As before, we can verify that this matrix generated is a valid unitary matrix.
```python exec="1" source="above" session="mat"
from toqito.matrix_props import is_unitary
print(is_unitary(mat))
```
It is also possible to pass a seed to this function for reproducibility.
```python exec="1" source="above" session="seeded"
from toqito.rand import random_unitary
seeded = random_unitary(2, seed=42)
print(seeded)
```
And once again, we can verify that this matrix generated is a valid unitary matrix.
```python exec="1" source="above" session="seeded"
from toqito.matrix_props import is_unitary
print(is_unitary(seeded))
```
Args:
dim: The number of rows (and columns) of the unitary matrix.
is_real: Boolean denoting whether the returned matrix has real entries or not. Default is `False`.
seed: A seed used to instantiate numpy's random number generator.
Returns:
A `dim`-by-`dim` random unitary matrix.
"""
gen = np.random.default_rng(seed=seed)
if isinstance(dim, int):
dim = [dim, dim]
if dim[0] != dim[1]:
raise ValueError("Unitary matrix must be square.")
# Construct the Ginibre ensemble.
gin = gen.standard_normal((dim[0], dim[1]))
if not is_real:
gin = gin + 1j * gen.standard_normal((dim[0], dim[1]))
# QR decomposition of the Ginibre ensemble.
q_mat, r_mat = np.linalg.qr(gin)
# Compute U from QR decomposition.
r_mat = np.sign(np.diag(r_mat))
# Protect against potentially zero diagonal entries.
r_mat[r_mat == 0] = 1
return q_mat @ np.diag(r_mat)