Repository URL to install this package:
|
Version:
5.0.3.post1 ▾
|
import numpy as np
from numpy.random import SeedSequence, default_rng
import scipy.sparse as sp
import scipy.linalg as la
import pytest
from qutip import qeye, num, to_kraus, kraus_to_choi, CoreOptions, Qobj
from qutip import data as _data
from qutip.random_objects import (
rand_herm,
rand_unitary,
rand_dm,
rand_ket,
rand_stochastic,
rand_super,
rand_super_bcsz,
rand_kraus_map,
)
@pytest.fixture(params=[
12,
[8],
[2, 2, 3],
[[2], [2]]
], ids=["int", "list", "tensor", "super"])
def dimensions(request):
return request.param
@pytest.fixture(
params=list(_data.to.dtypes),
ids=lambda dtype: str(dtype)[:-2].split(".")[-1]
)
def dtype(request):
return request.param
def _assert_density(qobj, density):
N = np.sum(qobj.full() != 0)
density = N / np.prod(qobj.shape)
assert density == pytest.approx(density, abs=0.2)
def _assert_metadata(random_qobj, dims, dtype=None, super=False, ket=False):
if isinstance(dims, int):
dims = [dims]
N = np.prod(dims)
if super and not isinstance(dims[0], list):
target_dims_0 = [dims, dims]
shape0 = N**2
else:
target_dims_0 = dims
shape0 = N
if ket:
target_dims_1 = [1]
shape1 = 1
else:
target_dims_1 = target_dims_0
shape1 = shape0
assert random_qobj.dims[0] == target_dims_0
assert random_qobj.dims[1] == target_dims_1
assert random_qobj.shape == (shape0, shape1)
if dtype:
assert isinstance(random_qobj.data, dtype)
@pytest.mark.repeat(3)
@pytest.mark.parametrize('density', [0.2, 0.8], ids=["sparse", "dense"])
@pytest.mark.parametrize('distribution', ["fill", "pos_def"])
def test_rand_herm(dimensions, density, distribution, dtype):
"""
Random Qobjs: Hermitian matrix
"""
random_qobj = rand_herm(
dimensions,
density=density,
distribution=distribution,
dtype=dtype
)
if distribution == "pos_def":
assert all(random_qobj.eigenenergies() > -1e14)
assert random_qobj.isherm
assert _data.isherm(random_qobj.data)
_assert_metadata(random_qobj, dimensions, dtype)
_assert_density(random_qobj, density)
@pytest.mark.repeat(3)
@pytest.mark.parametrize('density', [0.2, 0.8], ids=["sparse", "dense"])
def test_rand_herm_Eigs(dimensions, density):
"""
Random Qobjs: Hermitian matrix - Eigs given
"""
N = np.prod(dimensions)
eigs = np.random.random(N)
eigs /= np.sum(eigs)
eigs.sort()
random_qobj = rand_herm(dimensions, density, "eigen", eigenvalues=eigs)
np.testing.assert_allclose(random_qobj.eigenenergies(), eigs)
# verify hermitian
assert random_qobj.isherm
assert _data.isherm(random_qobj.data)
_assert_metadata(random_qobj, dimensions)
_assert_density(random_qobj, density)
@pytest.mark.repeat(5)
@pytest.mark.parametrize('distribution', ["haar", "exp"])
@pytest.mark.parametrize('density', [0.2, 0.8])
def test_rand_unitary(dimensions, distribution, density, dtype):
"""
Random Qobjs: Tests that unitaries are actually unitary.
"""
N = np.prod(dimensions)
random_qobj = rand_unitary(
dimensions, distribution=distribution,
density=density, dtype=dtype
)
I = qeye(dimensions)
assert random_qobj * random_qobj.dag() == I
_assert_metadata(random_qobj, dimensions, dtype)
if distribution == "exp":
_assert_density(random_qobj, density)
@pytest.mark.repeat(3)
@pytest.mark.parametrize(["distribution", "kw"], [
pytest.param("ginibre", {"rank": 3}),
pytest.param("ginibre", {"rank": 1}),
pytest.param("hs", {"rank": 0}),
pytest.param("pure", {"rank": 1, "density": 0.5}),
pytest.param("eigen", {"eigenvalues": True}),
pytest.param("herm", {"density": 0.7}),
pytest.param("herm", {"density": 0.3}),
])
def test_rand_dm(dimensions, kw, dtype, distribution):
"""
Random Qobjs: Density matrix
"""
N = np.prod(dimensions)
print(N, kw)
if "eigenvalues" in kw:
eigs = np.random.random(N)
eigs /= np.sum(eigs)
eigs.sort()
kw["eigenvalues"] = eigs
random_qobj = rand_dm(
dimensions,
distribution=distribution,
dtype=dtype,
**kw
)
assert abs(random_qobj.tr() - 1.0) < 1e-14
# verify all eigvals are >=0
assert all(random_qobj.eigenenergies() >= -1e-14)
# verify hermitian
assert random_qobj.isherm
assert _data.isherm(random_qobj.data)
_assert_metadata(random_qobj, dimensions, dtype)
eigenvalues = random_qobj.eigenenergies()
if "rank" in kw:
print(kw["rank"], N, kw["rank"] or N)
desired_rank = kw["rank"] or N # 'hs' is full rank.
rank = sum([abs(E) >= 1e-10 for E in eigenvalues])
assert rank == desired_rank
if "eigenvalues" in kw:
np.testing.assert_allclose(eigenvalues, kw["eigenvalues"])
if "density" in kw:
_assert_density(random_qobj, kw["density"])
@pytest.mark.repeat(5)
@pytest.mark.parametrize('kind', ["left", "right"])
def test_rand_stochastic(dimensions, kind, dtype):
"""
Random Qobjs: Test random stochastic
"""
random_qobj = rand_stochastic(dimensions, kind=kind, dtype=dtype)
axis = {"left":0, "right":1}[kind]
np.testing.assert_allclose(
np.sum(random_qobj.full(), axis=axis),
1, atol=1e-14
)
_assert_metadata(random_qobj, dimensions, dtype)
@pytest.mark.repeat(5)
@pytest.mark.parametrize('distribution', ["haar", "fill"])
def test_rand_ket(dimensions, distribution, dtype):
"""
Random Qobjs: Test random ket type and norm.
"""
random_qobj = rand_ket(dimensions, distribution=distribution, dtype=dtype)
target_type = "ket"
if isinstance(dimensions, list) and isinstance(dimensions[0], list):
target_type = "operator-ket"
assert random_qobj.type == target_type
assert abs(random_qobj.norm() - 1) < 1e-14
if isinstance(dimensions, int):
dims = [dimensions]
N = np.prod(dimensions)
_assert_metadata(random_qobj, dimensions, dtype, ket=True)
@pytest.mark.repeat(2)
@pytest.mark.parametrize('superrep', ["choi", "super"])
def test_rand_super(dimensions, dtype, superrep):
"""
Random Qobjs: Super operator.
"""
random_qobj = rand_super(dimensions, dtype=dtype, superrep=superrep)
assert random_qobj.issuper
with CoreOptions(atol=2e-9):
assert random_qobj.iscptp
assert random_qobj.superrep == superrep
_assert_metadata(random_qobj, dimensions, dtype, super=True)
@pytest.mark.repeat(2)
@pytest.mark.parametrize('rank', [None, 4])
@pytest.mark.parametrize('superrep', ["choi", "super"])
def test_rand_super_bcsz(dimensions, dtype, rank, superrep):
"""
Random Qobjs: Tests that BCSZ-random superoperators are CPTP.
"""
random_qobj = rand_super_bcsz(dimensions, rank=rank,
dtype=dtype, superrep=superrep)
assert random_qobj.issuper
with CoreOptions(atol=1e-9):
assert random_qobj.iscptp
assert random_qobj.superrep == superrep
_assert_metadata(random_qobj, dimensions, dtype, super=True)
if (
not rank
and isinstance(dimensions, list)
and isinstance(dimensions[0], list)
):
# dimensions = [[a], [a]], qobj.dims = [[[a], [a]], [[a], [a]]]
rank = np.prod(dimensions)
elif not rank:
# dimensions = [a], qobj.dims = [[[a], [a]], [[a], [a]]]
rank = np.prod(dimensions)**2
rank = rank or N
obtained_rank = len(to_kraus(random_qobj, tol=1e-13))
assert obtained_rank == rank
@pytest.mark.parametrize("function", [
pytest.param(rand_herm, id="rand_herm"),
pytest.param(rand_unitary, id="rand_unitary"),
pytest.param(rand_dm, id="rand_dm"),
pytest.param(rand_ket, id="rand_ket"),
pytest.param(rand_stochastic, id="rand_stochastic"),
pytest.param(rand_super, id="rand_super"),
pytest.param(rand_super_bcsz, id="rand_super_bcsz"),
])
@pytest.mark.parametrize("seed", [
pytest.param(lambda : 123, id="int"),
pytest.param(lambda : SeedSequence(123), id="SeedSequence"),
pytest.param(lambda : default_rng(123), id="Generator")
])
def test_random_seeds(function, seed):
"""
Random Qobjs: Random number generator seed
"""
U0 = function(5, seed=seed())
U1 = function(5, seed=None)
U2 = function(5, seed=seed())
assert U0 != U1
assert U0 == U2
def test_kraus_map(dimensions, dtype):
if isinstance(dimensions, list) and isinstance(dimensions[0], list):
# Each element of a kraus map cannot be a super operators
with pytest.raises(TypeError) as err:
kmap = rand_kraus_map(dimensions, dtype=dtype)
assert "super operator" in str(err.value)
else:
kmap = rand_kraus_map(dimensions, dtype=dtype)
_assert_metadata(kmap[0], dimensions, dtype)
with CoreOptions(atol=1e-9):
assert kraus_to_choi(kmap).iscptp
dtype_names = list(_data.to._str2type.keys()) + list(_data.to.dtypes)
dtype_types = list(_data.to._str2type.values()) + list(_data.to.dtypes)
@pytest.mark.parametrize(['alias', 'dtype'], zip(dtype_names, dtype_types),
ids=[str(dtype) for dtype in dtype_names])
@pytest.mark.parametrize('func', [
rand_herm,
rand_unitary,
rand_dm,
rand_ket,
rand_stochastic,
rand_super,
rand_super_bcsz,
rand_kraus_map,
])
def test_random_dtype(func, alias, dtype):
with CoreOptions(default_dtype=alias):
object = func(2)
if isinstance(object, Qobj):
assert isinstance(object.data, dtype)
else:
for obj in object:
assert isinstance(obj.data, dtype)