Skip to content

Commit

Permalink
sample random states: raise ValueError if dim is zero
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinsung committed Nov 3, 2024
1 parent 2d3823d commit 20a389e
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 4 deletions.
14 changes: 13 additions & 1 deletion python/ffsim/random/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ def random_state_vector(dim: int, *, seed=None, dtype=complex) -> np.ndarray:
Returns:
The sampled state vector.
Raises:
ValueError: Dimension must be at least one.
"""
if dim < 1:
raise ValueError("Dimension must be at least one.")

rng = np.random.default_rng(seed)
vec = rng.standard_normal(dim).astype(dtype, copy=False)
if np.issubdtype(dtype, np.complexfloating):
Expand All @@ -42,7 +48,7 @@ def random_state_vector(dim: int, *, seed=None, dtype=complex) -> np.ndarray:
def random_density_matrix(dim: int, *, seed=None, dtype=complex) -> np.ndarray:
"""Returns a random density matrix distributed with Hilbert-Schmidt measure.
A density matrix is Hermitian and has eigenvalues between 0 and 1.
A density matrix is positive semi-definite and has trace equal to one.
Args:
dim: The width and height of the matrix.
Expand All @@ -52,11 +58,17 @@ def random_density_matrix(dim: int, *, seed=None, dtype=complex) -> np.ndarray:
Returns:
The sampled density matrix.
Raises:
ValueError: Dimension must be at least one.
References:
- `arXiv:0909.5094`_
.. _arXiv:0909.5094: https://arxiv.org/abs/0909.5094
"""
if dim < 1:
raise ValueError("Dimension must be at least one.")

rng = np.random.default_rng(seed)

mat = rng.standard_normal((dim, dim)).astype(dtype, copy=False)
Expand Down
29 changes: 26 additions & 3 deletions tests/python/random_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,40 @@ def test_random_antihermitian_matrix(dim: int):
assert ffsim.linalg.is_antihermitian(mat)


@pytest.mark.parametrize("dim", range(10))
@pytest.mark.parametrize("dim", range(1, 10))
def test_random_state_vector(dim: int):
"""Test random state vector."""
vec = ffsim.random.random_state_vector(dim, seed=rng)
assert vec.dtype == complex
np.testing.assert_allclose(np.linalg.norm(vec), 1)

vec = ffsim.random.random_state_vector(dim, seed=rng, dtype=float)
assert vec.dtype == float
np.testing.assert_allclose(np.linalg.norm(vec), 1)


@pytest.mark.parametrize("dim", range(1, 10))
def test_random_density_matrix(dim: int):
"""Test random density matrix."""
mat = ffsim.random.random_density_matrix(dim, seed=rng)
assert mat.dtype == complex
assert ffsim.linalg.is_hermitian(mat)
eigs, _ = np.linalg.eigh(mat)
assert all(0 <= e <= 1 for e in eigs)
assert all(eigs >= 0)
np.testing.assert_allclose(np.trace(mat), 1)

mat = ffsim.random.random_density_matrix(dim, seed=rng, dtype=float)
assert mat.dtype == float
assert ffsim.linalg.is_hermitian(mat)
eigs, _ = np.linalg.eigh(mat)
assert all(0 <= e <= 1 for e in eigs)
assert all(eigs >= 0)
np.testing.assert_allclose(np.trace(mat), 1)


def test_raise_errors():
"""Test errors are raised as expected."""
with pytest.raises(ValueError, match="Dimension"):
_ = ffsim.random.random_state_vector(0, seed=rng)

with pytest.raises(ValueError, match="Dimension"):
_ = ffsim.random.random_density_matrix(0, seed=rng)

0 comments on commit 20a389e

Please sign in to comment.