diff --git a/tensornetwork/backends/backend_test.py b/tensornetwork/backends/backend_test.py index e1a96071a..3e30dcffe 100644 --- a/tensornetwork/backends/backend_test.py +++ b/tensornetwork/backends/backend_test.py @@ -4,6 +4,7 @@ import pytest import numpy as np from tensornetwork import connect, contract, Node +from tensornetwork.backends.base_backend import BaseBackend def clean_tensornetwork_modules(): @@ -146,3 +147,200 @@ def test_basic_network_without_backends_raises_error(): Node(np.ones((2, 2)), backend="tensorflow") with pytest.raises(ImportError): Node(np.ones((2, 2)), backend="pytorch") +[] + +def test_base_backend_name(): + backend = BaseBackend() + assert backend.name == "base backend" + + +def test_base_backend_tensordot_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.tensordot(np.ones((2, 2)), np.ones((2, 2)), axes=[[0], [0]]) + + +def test_base_backend_reshape_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.reshape(np.ones((2, 2)), (4, 1)) + + +def test_base_backend_transpose_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.transpose(np.ones((2, 2)), [0, 1]) + + +def test_base_backend_svd_decompositon_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.svd_decomposition(np.ones((2, 2)), 0) + + +def test_base_backend_qr_decompositon_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.qr_decomposition(np.ones((2, 2)), 0) + + +def test_base_backend_rq_decompositon_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.rq_decomposition(np.ones((2, 2)), 0) + + +def test_base_backend_shape_concat_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.shape_concat([np.ones((2, 2)), np.ones((2, 2))], 0) + + +def test_base_backend_shape_tensor_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.shape_tensor(np.ones((2, 2))) + + +def test_base_backend_shape_tuple_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.shape_tuple(np.ones((2, 2))) + + +def test_base_backend_shape_prod_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.shape_prod(np.ones((2, 2))) + + +def test_base_backend_sqrt_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.sqrt(np.ones((2, 2))) + + +def test_base_backend_diag_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.diag(np.ones((2, 2))) + + +def test_base_backend_convert_to_tensor_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.convert_to_tensor(np.ones((2, 2))) + + +def test_base_backend_trace_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.trace(np.ones((2, 2))) + + +def test_base_backend_outer_product_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.outer_product(np.ones((2, 2)), np.ones((2, 2))) + + +def test_base_backend_einsul_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.einsum("ii", np.ones((2, 2))) + + +def test_base_backend_norm_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.norm(np.ones((2, 2))) + + +def test_base_backend_eye_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.eye(2, dtype=np.float64) + + +def test_base_backend_ones_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.ones((2, 2), dtype=np.float64) + + +def test_base_backend_zeros_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.zeros((2, 2), dtype=np.float64) + + +def test_base_backend_randn_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.randn((2, 2)) + + +def test_base_backend_random_uniforl_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.random_uniform((2, 2)) + + +def test_base_backend_conj_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.conj(np.ones((2, 2))) + + +def test_base_backend_eigh_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.eigh(np.ones((2, 2))) + + +def test_base_backend_eigs_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.eigs(np.ones((2, 2))) + + +def test_base_backend_eigs_lanczos_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.eigsh_lanczos(np.ones((2, 2))) + + +def test_base_backend_addition_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.addition(np.ones((2, 2)), np.ones((2, 2))) + + +def test_base_backend_subtraction_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.subtraction(np.ones((2, 2)), np.ones((2, 2))) + + +def test_base_backend_multiply_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.multiply(np.ones((2, 2)), np.ones((2, 2))) + + +def test_base_backend_divide_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.divide(np.ones((2, 2)), np.ones((2, 2))) + + +def test_base_backend_index_update_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.index_update(np.ones((2, 2)), np.ones((2, 2)), np.ones((2, 2))) + + +def test_base_backend_inv_not_implemented(): + backend = BaseBackend() + with pytest.raises(NotImplementedError): + backend.inv(np.ones((2, 2))) diff --git a/tensornetwork/backends/jax/jax_backend_test.py b/tensornetwork/backends/jax/jax_backend_test.py index 330dbe224..4c2868734 100644 --- a/tensornetwork/backends/jax/jax_backend_test.py +++ b/tensornetwork/backends/jax/jax_backend_test.py @@ -271,3 +271,27 @@ def index_update(dtype): tensor = np.array(tensor) tensor[tensor > 0.1] = 0.0 np.testing.assert_allclose(tensor, out) + + +def test_base_backend_eigs_not_implemented(): + backend = jax_backend.JaxBackend() + tensor = backend.randn((4, 2, 3), dtype=np.float64) + with pytest.raises(NotImplementedError): + backend.eigs(tensor) + + +def test_base_backend_eigsh_lanczos_not_implemented(): + backend = jax_backend.JaxBackend() + tensor = backend.randn((4, 2, 3), dtype=np.float64) + with pytest.raises(NotImplementedError): + backend.eigsh_lanczos(tensor) + + +@pytest.mark.parametrize("dtype", np_dtypes) +def test_index_update(dtype): + backend = jax_backend.JaxBackend() + tensor = backend.randn((4, 2, 3), dtype=dtype, seed=10) + out = backend.index_update(tensor, tensor > 0.1, 0.0) + np_tensor = np.array(tensor) + np_tensor[np_tensor > 0.1] = 0.0 + np.testing.assert_allclose(out, np_tensor) diff --git a/tensornetwork/backends/numpy/numpy_backend_test.py b/tensornetwork/backends/numpy/numpy_backend_test.py index fe73271e8..6a8068c41 100644 --- a/tensornetwork/backends/numpy/numpy_backend_test.py +++ b/tensornetwork/backends/numpy/numpy_backend_test.py @@ -3,6 +3,7 @@ import numpy as np import pytest from tensornetwork.backends.numpy import numpy_backend +from unittest.mock import Mock np_randn_dtypes = [np.float32, np.float16, np.float64] np_dtypes = np_randn_dtypes + [np.complex64, np.complex128] @@ -310,6 +311,35 @@ def __call__(self, x): np.testing.assert_allclose(v1, v2) +@pytest.mark.parametrize("dtype", [np.float64, np.complex128]) +def test_eigsh_lanczos_reorthogonalize(dtype): + backend = numpy_backend.NumPyBackend() + D = 24 + np.random.seed(10) + tmp = backend.randn((D, D), dtype=dtype, seed=10) + H = tmp + backend.transpose(backend.conj(tmp), (1, 0)) + + class LinearOperator: + + def __init__(self, shape, dtype): + self.shape = shape + self.dtype = dtype + + def __call__(self, x): + return np.dot(H, x) + + mv = LinearOperator(shape=((D,), (D,)), dtype=dtype) + eta1, U1 = backend.eigsh_lanczos(mv, reorthogonalize=True, ndiag=1, + tol=10**(-12), delta=10**(-12)) + eta2, U2 = np.linalg.eigh(H) + v2 = U2[:, 0] + v2 = v2 / sum(v2) + v1 = np.reshape(U1[0], (D)) + v1 = v1 / sum(v1) + np.testing.assert_allclose(eta1[0], min(eta2)) + np.testing.assert_allclose(v1, v2, rtol=10**(-5), atol=10**(-5)) + + def test_eigsh_lanczos_raises(): backend = numpy_backend.NumPyBackend() with pytest.raises(AttributeError): @@ -320,6 +350,37 @@ def test_eigsh_lanczos_raises(): backend.eigsh_lanczos(lambda x: x, numeig=2, reorthogonalize=False) +def test_eigsh_lanczos_raises_error_for_incompatible_shapes(): + backend = numpy_backend.NumPyBackend() + A = backend.randn((4, 4), dtype=np.float64) + init = backend.randn((3, ), dtype=np.float64) + with pytest.raises(ValueError): + backend.eigsh_lanczos(A, initial_state=init) + + +def test_eigsh_lanczos_raises_error_for_untyped_A(): + backend = numpy_backend.NumPyBackend() + A = Mock(spec=[]) + A.shape = Mock(return_value=(2, 2)) + err_msg = "`A` has no attribute `dtype`. Cannot initialize lanczos. " \ + "Please provide a valid `initial_state` with a `dtype` attribute" + with pytest.raises(AttributeError, match=err_msg): + backend.eigsh_lanczos(A) + + +def test_eigsh_lanczos_raises_error_for_bad_initial_state(): + backend = numpy_backend.NumPyBackend() + D = 16 + init = [1]*D + M = backend.randn((D, D), dtype=np.float64) + + def mv(x): + return np.dot(M, x) + + with pytest.raises(TypeError): + backend.eigsh_lanczos(mv, initial_state=init) + + @pytest.mark.parametrize("a, b, expected", [ pytest.param(1, 1, 2), pytest.param(1., np.ones((1, 2, 3)), 2*np.ones((1, 2, 3))), @@ -430,6 +491,84 @@ def mv(x): np.testing.assert_allclose(v1, v2) +@pytest.mark.parametrize("dtype", [np.float64, np.complex128]) +@pytest.mark.parametrize("which", ['LM', 'LR', 'SM', 'SR']) +def test_eigs_no_init(dtype, which): + backend = numpy_backend.NumPyBackend() + D = 16 + np.random.seed(10) + H = backend.randn((D, D), dtype=dtype, seed=10) + + class LinearOperator: + + def __init__(self, shape, dtype): + self.shape = shape + self.dtype = dtype + + def __call__(self, x): + return np.dot(H, x) + + mv = LinearOperator(shape=((D,), (D,)), dtype=dtype) + eta1, U1 = backend.eigs(mv, numeig=1, which=which) + eta2, U2 = np.linalg.eig(H) + val, index = find(which, eta2) + v2 = U2[:, index] + v2 = v2 / sum(v2) + v1 = np.reshape(U1[0], (D)) + v1 = v1 / sum(v1) + np.testing.assert_allclose(find(which, eta1)[0], val) + np.testing.assert_allclose(v1, v2) + + +@pytest.mark.parametrize("which", ['SI', 'LI']) +def test_eigs_raises_error_for_unsupported_which(which): + backend = numpy_backend.NumPyBackend() + A = backend.randn((4, 4), dtype=np.float64) + with pytest.raises(ValueError): + backend.eigs(A=A, which=which) + + +def test_eigs_raises_error_for_incompatible_shapes(): + backend = numpy_backend.NumPyBackend() + A = backend.randn((4, 4), dtype=np.float64) + init = backend.randn((3, ), dtype=np.float64) + with pytest.raises(ValueError): + backend.eigs(A, initial_state=init) + + +def test_eigs_raises_error_for_unshaped_A(): + backend = numpy_backend.NumPyBackend() + A = Mock(spec=[]) + print(hasattr(A, "shape")) + err_msg = "`A` has no attribute `shape`. Cannot initialize lanczos. " \ + "Please provide a valid `initial_state`" + with pytest.raises(AttributeError, match=err_msg): + backend.eigs(A) + + +def test_eigs_raises_error_for_untyped_A(): + backend = numpy_backend.NumPyBackend() + A = Mock(spec=[]) + A.shape = Mock(return_value=(2, 2)) + err_msg = "`A` has no attribute `dtype`. Cannot initialize lanczos. " \ + "Please provide a valid `initial_state` with a `dtype` attribute" + with pytest.raises(AttributeError, match=err_msg): + backend.eigs(A) + + +def test_eigs_raises_error_for_bad_initial_state(): + backend = numpy_backend.NumPyBackend() + D = 16 + init = [1]*D + M = backend.randn((D, D), dtype=np.float64) + + def mv(x): + return np.dot(M, x) + + with pytest.raises(TypeError): + backend.eigs(mv, initial_state=init) + + @pytest.mark.parametrize("dtype", [np.float64, np.complex128]) def test_eigh(dtype): backend = numpy_backend.NumPyBackend() diff --git a/tensornetwork/backends/pytorch/pytorch_backend_test.py b/tensornetwork/backends/pytorch/pytorch_backend_test.py index e25542ac8..f03dc26a3 100644 --- a/tensornetwork/backends/pytorch/pytorch_backend_test.py +++ b/tensornetwork/backends/pytorch/pytorch_backend_test.py @@ -3,6 +3,7 @@ from tensornetwork.backends.pytorch import pytorch_backend import torch import pytest +from unittest.mock import Mock torch_dtypes = [torch.float32, torch.float64, torch.int32] torch_eye_dtypes = [torch.float32, torch.float64, torch.int32, torch.int64] @@ -237,7 +238,7 @@ def test_conj(): def test_eigsh_lanczos_1(): dtype = torch.float64 backend = pytorch_backend.PyTorchBackend() - D = 16 + D = 24 init = backend.randn((D,), dtype=dtype) tmp = backend.randn((D, D), dtype=dtype) H = tmp + backend.transpose(backend.conj(tmp), (1, 0)) @@ -255,10 +256,11 @@ def mv(x): np.testing.assert_allclose(v1, v2) -def test_eigsh_lanczos_2(): +def test_eigsh_lanczos_reorthogonalize(): dtype = torch.float64 backend = pytorch_backend.PyTorchBackend() D = 16 + init = backend.randn((D,), dtype=dtype) tmp = backend.randn((D, D), dtype=dtype) H = tmp + backend.transpose(backend.conj(tmp), (1, 0)) @@ -272,7 +274,7 @@ def __call__(self, x): return H.mv(x) mv = LinearOperator(shape=((D,), (D,)), dtype=dtype) - eta1, U1 = backend.eigsh_lanczos(mv) + eta1, U1 = backend.eigsh_lanczos(mv, init) eta2, U2 = H.symeig() v2 = U2[:, 0] v2 = v2 / sum(v2) @@ -282,6 +284,34 @@ def __call__(self, x): np.testing.assert_allclose(v1, v2) +def test_eigsh_lanczos_2(): + dtype = torch.float64 + backend = pytorch_backend.PyTorchBackend() + D = 16 + tmp = backend.randn((D, D), dtype=dtype) + H = tmp + backend.transpose(backend.conj(tmp), (1, 0)) + + class LinearOperator: + + def __init__(self, shape, dtype): + self.shape = shape + self.dtype = dtype + + def __call__(self, x): + return H.mv(x) + + mv = LinearOperator(shape=((D,), (D,)), dtype=dtype) + eta1, U1 = backend.eigsh_lanczos(mv, reorthogonalize=True, ndiag=1, + tol=10**(-12), delta=10**(-12)) + eta2, U2 = H.symeig() + v2 = U2[:, 0] + v2 = v2 / sum(v2) + v1 = np.reshape(U1[0], (D)) + v1 = v1 / sum(v1) + np.testing.assert_allclose(eta1[0], min(eta2)) + np.testing.assert_allclose(v1, v2, rtol=10**(-5), atol=10**(-5)) + + def test_eigsh_lanczos_raises(): backend = pytorch_backend.PyTorchBackend() with pytest.raises(AttributeError): @@ -388,3 +418,27 @@ def test_matrix_inv_raises(dtype): matrix = backend.randn((4, 4, 4), dtype=dtype, seed=10) with pytest.raises(ValueError): backend.inv(matrix) + + +def test_eigs_not_implemented(): + backend = pytorch_backend.PyTorchBackend() + with pytest.raises(NotImplementedError): + backend.eigs(np.ones((2, 2))) + + +def test_eigsh_lanczos_raises_error_for_incompatible_shapes(): + backend = pytorch_backend.PyTorchBackend() + A = backend.randn((4, 4), dtype=torch.float64) + init = backend.randn((3, ), dtype=torch.float64) + with pytest.raises(ValueError): + backend.eigsh_lanczos(A, initial_state=init) + + +def test_eigsh_lanczos_raises_error_for_untyped_A(): + backend = pytorch_backend.PyTorchBackend() + A = Mock(spec=[]) + A.shape = Mock(return_value=(2, 2)) + err_msg = "`A` has no attribute `dtype`. Cannot initialize lanczos. " \ + "Please provide a valid `initial_state` with a `dtype` attribute" + with pytest.raises(AttributeError, match=err_msg): + backend.eigsh_lanczos(A) diff --git a/tensornetwork/backends/tensorflow/tensorflow_backend_test.py b/tensornetwork/backends/tensorflow/tensorflow_backend_test.py index 8073a61e2..4916301ce 100644 --- a/tensornetwork/backends/tensorflow/tensorflow_backend_test.py +++ b/tensornetwork/backends/tensorflow/tensorflow_backend_test.py @@ -342,3 +342,14 @@ def test_matrix_inv_raises(dtype): matrix = backend.randn((4, 4, 4), dtype=dtype, seed=10) with pytest.raises(ValueError): backend.inv(matrix) + +def test_eigs_not_implemented(): + backend = tensorflow_backend.TensorFlowBackend() + with pytest.raises(NotImplementedError): + backend.eigs(np.ones((2, 2))) + + +def test_eigsh_lanczos_not_implemented(): + backend = tensorflow_backend.TensorFlowBackend() + with pytest.raises(NotImplementedError): + backend.eigsh_lanczos(np.ones((2, 2))) diff --git a/tensornetwork/tests/backend_contextmanager_test.py b/tensornetwork/tests/backend_contextmanager_test.py index 60f6e833b..644c055d0 100644 --- a/tensornetwork/tests/backend_contextmanager_test.py +++ b/tensornetwork/tests/backend_contextmanager_test.py @@ -3,23 +3,27 @@ import pytest import numpy as np + def test_contextmanager_simple(): with tn.DefaultBackend("tensorflow"): a = tn.Node(np.ones((10,))) b = tn.Node(np.ones((10,))) assert a.backend.name == b.backend.name + def test_contextmanager_default_backend(): tn.set_default_backend("pytorch") with tn.DefaultBackend("numpy"): assert _default_backend_stack.default_backend == "pytorch" + def test_contextmanager_interruption(): tn.set_default_backend("pytorch") with pytest.raises(AssertionError): with tn.DefaultBackend("numpy"): tn.set_default_backend("tensorflow") + def test_contextmanager_nested(): with tn.DefaultBackend("tensorflow"): a = tn.Node(np.ones((10,))) @@ -32,15 +36,24 @@ def test_contextmanager_nested(): d = tn.Node(np.ones((10,))) assert d.backend.name == "numpy" + def test_contextmanager_wrong_item(): a = tn.Node(np.ones((10,))) with pytest.raises(ValueError): with tn.DefaultBackend(a): # pytype: disable=wrong-arg-types pass + def test_contextmanager_BaseBackend(): tn.set_default_backend("pytorch") a = tn.Node(np.ones((10,))) with tn.DefaultBackend(a.backend): b = tn.Node(np.ones((10,))) assert b.backend.name == "pytorch" + + +def test_set_default_backend_value_error(): + tn.set_default_backend("pytorch") + with pytest.raises(ValueError, match="Item passed to set_default_backend " + "must be Text or BaseBackend"): + tn.set_default_backend(-1) # pytype: disable=wrong-arg-types