From 035b1688b09c2d8498fcf331167c70317f97e72e Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 23 Nov 2019 11:38:43 +0100 Subject: [PATCH 01/18] added test for mps switch backend --- tensornetwork/matrixproductstates/base_mps_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tensornetwork/matrixproductstates/base_mps_test.py b/tensornetwork/matrixproductstates/base_mps_test.py index 1426963eb..7a9bd6fd3 100644 --- a/tensornetwork/matrixproductstates/base_mps_test.py +++ b/tensornetwork/matrixproductstates/base_mps_test.py @@ -142,3 +142,13 @@ def test_apply_two_site_gate(backend_dtype_values): res = tn.contract_between(mps.nodes[5], mps.nodes[6]) res.reorder_edges(order) np.testing.assert_allclose(res.tensor, actual) + + +def test_mps_switch_backend(backend): + D, d, N = 10, 2, 10 + tensors = [get_random_np((1, d, D), np.float64)] + [ + get_random_np((D, d, D), np.float64) for _ in range(N - 2) + ] + [get_random_np((D, d, 1), np.float64)] + mps = BaseMPS(tensors, center_position=0, backend="numpy") + mps.switch_backend(backend) + assert mps.backend.name == backend From cd6558da6dcc3dcf6be4faf30d1abbc03543fda5 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 23 Nov 2019 11:40:58 +0100 Subject: [PATCH 02/18] added switch backend method to MPS --- tensornetwork/matrixproductstates/base_mps.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tensornetwork/matrixproductstates/base_mps.py b/tensornetwork/matrixproductstates/base_mps.py index de96c7d71..5963731c6 100644 --- a/tensornetwork/matrixproductstates/base_mps.py +++ b/tensornetwork/matrixproductstates/base_mps.py @@ -16,11 +16,10 @@ from __future__ import division from __future__ import print_function import numpy as np -import functools # pylint: disable=line-too-long from tensornetwork.network_components import Node, contract, contract_between, BaseNode # pylint: disable=line-too-long -from tensornetwork.network_operations import split_node_qr, split_node_rq, split_node_full_svd, norm, conj +from tensornetwork.network_operations import split_node_qr, split_node_rq, split_node_full_svd, norm, conj, switch_backend from typing import Any, List, Optional, Text, Type, Union, Dict, Sequence from tensornetwork.backends.base_backend import BaseBackend Tensor = Any @@ -199,6 +198,15 @@ def physical_dimensions(self) -> List: return [node.shape[1] for node in self.nodes] + def switch_backend(self, new_backend: Text) -> None: + """ + Change the backend of all the nodes in the MPS. + + Args: + new_backend (str): The new backend. + """ + switch_backend(self.nodes, new_backend) + def right_envs(self, sites: Sequence[int]) -> Dict: raise NotImplementedError() From 304a0e5d9a05171ee9910c3e6f17bdc3a0b7cd38 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 23 Nov 2019 11:41:18 +0100 Subject: [PATCH 03/18] added test for network operations switch backend --- tensornetwork/tests/network_operations_test.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tensornetwork/tests/network_operations_test.py b/tensornetwork/tests/network_operations_test.py index fb398b7d2..189c08594 100644 --- a/tensornetwork/tests/network_operations_test.py +++ b/tensornetwork/tests/network_operations_test.py @@ -15,10 +15,6 @@ import tensornetwork as tn import pytest import numpy as np -import tensorflow as tf -import torch -import jax -from jax.config import config def test_split_node_full_svd_names(backend): @@ -329,3 +325,12 @@ def test_reduced_density_contraction(backend): tn.reduced_density([a[0]]) result = tn.contractors.greedy(tn.reachable(a), ignore_edge_order=True) np.testing.assert_allclose(result.tensor, np.eye(2)) + + +def test_switch_backend(backend): + a = tn.Node(np.random.rand(3, 3, 3), name="A", backend="numpy") + b = tn.Node(np.random.rand(3, 3, 3), name="B", backend="numpy") + c = tn.Node(np.random.rand(3, 3, 3), name="C", backend="numpy") + nodes = [a, b, c] + tn.switch_backend(nodes, backend) + assert nodes[0].backend.name == backend From 7a11d58e7eed657b92faa8bab6b639f5c9eb1f19 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 23 Nov 2019 11:41:42 +0100 Subject: [PATCH 04/18] make sure switch_backend not only fixes tensor but also node property --- tensornetwork/network_operations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tensornetwork/network_operations.py b/tensornetwork/network_operations.py index 040a82ebb..ef1673553 100644 --- a/tensornetwork/network_operations.py +++ b/tensornetwork/network_operations.py @@ -789,3 +789,4 @@ def switch_backend(nodes: Iterable[BaseNode], new_backend: Text) -> None: "backend is 'numpy'. Current backend " "is '{}'".format(node.backend)) node.tensor = backend.convert_to_tensor(node.tensor) + node.backend = backend \ No newline at end of file From fcfb3ce53e9195bce25b9438e9355ad3153f4c70 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 23 Nov 2019 11:42:00 +0100 Subject: [PATCH 05/18] added switch_backend to init --- tensornetwork/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensornetwork/__init__.py b/tensornetwork/__init__.py index 18e652c63..fd6269031 100644 --- a/tensornetwork/__init__.py +++ b/tensornetwork/__init__.py @@ -1,7 +1,7 @@ #pylint: disable=line-too-long from tensornetwork.network_components import Node, Edge, CopyNode, BaseNode, NodeCollection #pylint: disable=line-too-long -from tensornetwork.network_operations import norm, conj, copy, transpose, split_node, split_node_qr, split_node_rq, split_node_full_svd, reachable, check_connected, check_correct, get_all_nodes, get_all_edges, remove_node, contract_trace_edges, get_subgraph_dangling, reduced_density +from tensornetwork.network_operations import norm, conj, copy, transpose, split_node, split_node_qr, split_node_rq, split_node_full_svd, reachable, check_connected, check_correct, get_all_nodes, get_all_edges, remove_node, contract_trace_edges, get_subgraph_dangling, reduced_density, switch_backend #pylint: disable=line-too-long from tensornetwork.network_components import contract, contract_copy_node, contract_between, outer_product, outer_product_final_nodes, contract_parallel, flatten_edges, split_edge, get_all_nondangling, get_all_dangling, flatten_all_edges, flatten_edges_between, get_parallel_edges, get_shared_edges from tensornetwork.backends.base_backend import BaseBackend From a1c527b594266bd1638ee2233c9a4338b969faf0 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 09:42:50 +0100 Subject: [PATCH 06/18] missing test for backend contextmanager --- tensornetwork/tests/backend_contextmanager_test.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tensornetwork/tests/backend_contextmanager_test.py b/tensornetwork/tests/backend_contextmanager_test.py index 60f6e833b..7a8faf90e 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) From 631477f9747d8bedfb1cfabbbaa96df19a743b69 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 10:05:54 +0100 Subject: [PATCH 07/18] notimplemented tests for base backend --- tensornetwork/backends/backend_test.py | 192 +++++++++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/tensornetwork/backends/backend_test.py b/tensornetwork/backends/backend_test.py index e1a96071a..d372343a3 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,194 @@ 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_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))) From a0a942366df340d2f6cdd341127ef19d82cc2219 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 10:07:08 +0100 Subject: [PATCH 08/18] added subtraction test notimplemented --- tensornetwork/backends/backend_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tensornetwork/backends/backend_test.py b/tensornetwork/backends/backend_test.py index d372343a3..2b86718e9 100644 --- a/tensornetwork/backends/backend_test.py +++ b/tensornetwork/backends/backend_test.py @@ -316,6 +316,12 @@ def test_base_backend_addition_not_implemented(): 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): From 45381be0179fe7e2a68c7167e2290cdcecb471d5 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 10:13:38 +0100 Subject: [PATCH 09/18] added jax backend index_update test --- .../backends/jax/jax_backend_test.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) 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) From 90356c0387347cb9900df8711406786be69f947a Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 10:36:32 +0100 Subject: [PATCH 10/18] first missing tests for numpy --- .../backends/numpy/numpy_backend_test.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tensornetwork/backends/numpy/numpy_backend_test.py b/tensornetwork/backends/numpy/numpy_backend_test.py index fe73271e8..e98271373 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] @@ -430,6 +431,42 @@ def mv(x): 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) + + @pytest.mark.parametrize("dtype", [np.float64, np.complex128]) def test_eigh(dtype): backend = numpy_backend.NumPyBackend() From 6676520e622de7e0729418119ef6d7b6ec682da9 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 10:49:44 +0100 Subject: [PATCH 11/18] actually catched an error in numpy_backend eigs method! --- tensornetwork/backends/numpy/numpy_backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensornetwork/backends/numpy/numpy_backend.py b/tensornetwork/backends/numpy/numpy_backend.py index 7a1606f9d..515bce646 100644 --- a/tensornetwork/backends/numpy/numpy_backend.py +++ b/tensornetwork/backends/numpy/numpy_backend.py @@ -218,7 +218,7 @@ def eigs(self, "lanczos. Please provide a valid `initial_state` with " "a `dtype` attribute") - initial_state = self.randn(A.shape[1], A.dtype) + initial_state = self.randn((A.shape[1],), A.dtype) if not isinstance(initial_state, self.np.ndarray): raise TypeError("Expected a `np.array`. Got {}".format( From 15012029bdf89b7cad5557d80fcee159efddbd6e Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 10:52:36 +0100 Subject: [PATCH 12/18] more eigs tests --- .../backends/numpy/numpy_backend_test.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tensornetwork/backends/numpy/numpy_backend_test.py b/tensornetwork/backends/numpy/numpy_backend_test.py index e98271373..c3216d403 100644 --- a/tensornetwork/backends/numpy/numpy_backend_test.py +++ b/tensornetwork/backends/numpy/numpy_backend_test.py @@ -431,6 +431,40 @@ 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) + M = backend.randn((D, D), dtype=dtype, seed=10) + + class MyOperator: + def __init__(self, M): + self.M = M + + def __call__(self, x): + return np.dot(self.M, x) + + @property + def shape(self): + return self.M.shape + + @property + def dtype(self): + return self.M.dtype + + eta1, U1 = backend.eigs(MyOperator(M), numeig=1, which=which) + eta2, U2 = np.linalg.eig(M) + 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() @@ -467,6 +501,19 @@ def test_eigs_raises_error_for_untyped_A(): 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() From 2e8b86b4bc6a5d9a91a2e5891f6dc21a92f9e5b2 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 11:23:54 +0100 Subject: [PATCH 13/18] didnt catch an error, unexpected convention --- tensornetwork/backends/numpy/numpy_backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensornetwork/backends/numpy/numpy_backend.py b/tensornetwork/backends/numpy/numpy_backend.py index 515bce646..7a1606f9d 100644 --- a/tensornetwork/backends/numpy/numpy_backend.py +++ b/tensornetwork/backends/numpy/numpy_backend.py @@ -218,7 +218,7 @@ def eigs(self, "lanczos. Please provide a valid `initial_state` with " "a `dtype` attribute") - initial_state = self.randn((A.shape[1],), A.dtype) + initial_state = self.randn(A.shape[1], A.dtype) if not isinstance(initial_state, self.np.ndarray): raise TypeError("Expected a `np.array`. Got {}".format( From 942a1d368085294df210aec9f3259988378a60e0 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 11:24:07 +0100 Subject: [PATCH 14/18] more tests for eigsh_lancszos --- .../backends/numpy/numpy_backend_test.py | 85 +++++++++++++++---- 1 file changed, 70 insertions(+), 15 deletions(-) diff --git a/tensornetwork/backends/numpy/numpy_backend_test.py b/tensornetwork/backends/numpy/numpy_backend_test.py index c3216d403..6a8068c41 100644 --- a/tensornetwork/backends/numpy/numpy_backend_test.py +++ b/tensornetwork/backends/numpy/numpy_backend_test.py @@ -311,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): @@ -321,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))), @@ -437,25 +497,20 @@ def test_eigs_no_init(dtype, which): backend = numpy_backend.NumPyBackend() D = 16 np.random.seed(10) - M = backend.randn((D, D), dtype=dtype, seed=10) - - class MyOperator: - def __init__(self, M): - self.M = M + H = backend.randn((D, D), dtype=dtype, seed=10) - def __call__(self, x): - return np.dot(self.M, x) + class LinearOperator: - @property - def shape(self): - return self.M.shape + def __init__(self, shape, dtype): + self.shape = shape + self.dtype = dtype - @property - def dtype(self): - return self.M.dtype + def __call__(self, x): + return np.dot(H, x) - eta1, U1 = backend.eigs(MyOperator(M), numeig=1, which=which) - eta2, U2 = np.linalg.eig(M) + 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) From 8473aa4d1dbeb70d4a51b627b4d9c1f9ad70e91c Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 11:53:52 +0100 Subject: [PATCH 15/18] added missing pytorch backend tests --- .../backends/pytorch/pytorch_backend_test.py | 60 ++++++++++++++++++- 1 file changed, 57 insertions(+), 3 deletions(-) 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) From 3b7b3ce39d60e497f3d1983141736fc3d1da350d Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 11:58:43 +0100 Subject: [PATCH 16/18] added missing tf backend tests --- .../backends/tensorflow/tensorflow_backend_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) 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))) From f5b20b8da5447278efe78e51819b64e4b0195327 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 12:16:00 +0100 Subject: [PATCH 17/18] pytype --- tensornetwork/backends/backend_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensornetwork/backends/backend_test.py b/tensornetwork/backends/backend_test.py index 2b86718e9..3e30dcffe 100644 --- a/tensornetwork/backends/backend_test.py +++ b/tensornetwork/backends/backend_test.py @@ -157,7 +157,7 @@ def test_base_backend_name(): 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]) + backend.tensordot(np.ones((2, 2)), np.ones((2, 2)), axes=[[0], [0]]) def test_base_backend_reshape_not_implemented(): From 2a33a4de3d85939614f9514199e84955574a5541 Mon Sep 17 00:00:00 2001 From: michaelmarien Date: Sat, 25 Jan 2020 12:38:06 +0100 Subject: [PATCH 18/18] suppress pytype --- tensornetwork/tests/backend_contextmanager_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensornetwork/tests/backend_contextmanager_test.py b/tensornetwork/tests/backend_contextmanager_test.py index 7a8faf90e..644c055d0 100644 --- a/tensornetwork/tests/backend_contextmanager_test.py +++ b/tensornetwork/tests/backend_contextmanager_test.py @@ -56,4 +56,4 @@ 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) + tn.set_default_backend(-1) # pytype: disable=wrong-arg-types