11import numpy as np
22import tensorflow as tf
33import pytest
4+ from unittest .mock import patch
45from collections import namedtuple
56import h5py
67import re
78#pylint: disable=line-too-long
8- from tensornetwork .network_components import Node , CopyNode , Edge , NodeCollection
9+ from tensornetwork .network_components import Node , CopyNode , Edge , NodeCollection , BaseNode , _remove_trace_edge , _remove_edges
910import tensornetwork as tn
11+ from tensornetwork .backends .base_backend import BaseBackend
1012
1113string_type = h5py .special_dtype (vlen = str )
1214
1517 'node1 node2 edge1 edge12 tensor' )
1618
1719
20+ class TestNode (BaseNode ):
21+
22+ def get_tensor (self ): #pylint: disable=useless-super-delegation
23+ return super ().get_tensor ()
24+
25+ def set_tensor (self , tensor ): #pylint: disable=useless-super-delegation
26+ return super ().set_tensor (tensor )
27+
28+ @property
29+ def shape (self ):
30+ return super ().shape
31+
32+ @property
33+ def tensor (self ):
34+ return super ().tensor
35+
36+ @tensor .setter
37+ def tensor (self , tensor ):
38+ return super (TestNode , type (self )).tensor .fset (self , tensor )
39+
40+ def _load_node (self , node_data ):# pylint: disable=useless-super-delegation
41+ return super ()._load_node (node_data )
42+
43+ def _save_node (self , node_group ): #pylint: disable=useless-super-delegation
44+ return super ()._save_node (node_group )
45+
46+
47+
1848@pytest .fixture (name = 'single_node_edge' )
1949def fixture_single_node_edge (backend ):
2050 tensor = np .ones ((1 , 2 , 2 ))
@@ -249,6 +279,16 @@ def test_node_reorder_edges_raise_error_trace_edge(single_node_edge):
249279 assert "Edge reordering does not support trace edges." in str (e .value )
250280
251281
282+ def test_node_reorder_edges_raise_error_no_tensor (single_node_edge ):
283+ node = single_node_edge .node
284+ e2 = tn .connect (node [1 ], node [2 ])
285+ e3 = node [0 ]
286+ del node ._tensor
287+ with pytest .raises (AttributeError ) as e :
288+ node .reorder_edges ([e2 , e3 ])
289+ assert "Please provide a valid tensor for this Node." in str (e .value )
290+
291+
252292def test_node_magic_getitem (single_node_edge ):
253293 node = single_node_edge .node
254294 edge = single_node_edge .edge
@@ -279,13 +319,40 @@ def test_node_magic_lt(double_node_edge):
279319def test_node_magic_lt_raises_error_not_node (single_node_edge ):
280320 node = single_node_edge .node
281321 with pytest .raises (ValueError ):
282- assert node < 0
322+ node < 0
283323
284324
285325def test_node_magic_matmul_raises_error_not_node (single_node_edge ):
286326 node = single_node_edge .node
287327 with pytest .raises (TypeError ):
288- assert node @ 0
328+ node @ 0
329+
330+
331+ def test_node_magic_matmul_raises_error_no_tensor (single_node_edge ):
332+ node = single_node_edge .node
333+ del node ._tensor
334+ with pytest .raises (AttributeError ):
335+ node @ node
336+
337+
338+ def test_node_magic_matmul_raises_error_disabled_node (single_node_edge ):
339+ node = single_node_edge .node
340+ node .is_disabled = True
341+ with pytest .raises (ValueError ):
342+ node @ node
343+
344+
345+ def test_node_edges_getter_raises_error_disabled_node (single_node_edge ):
346+ node = single_node_edge .node
347+ node .is_disabled = True
348+ with pytest .raises (ValueError ):
349+ node .edges
350+
351+ def test_node_edges_setter_raises_error_disabled_node (single_node_edge ):
352+ node = single_node_edge .node
353+ node .is_disabled = True
354+ with pytest .raises (ValueError ):
355+ node .edges = []
289356
290357
291358def test_node_magic_matmul_raises_error_different_network (single_node_edge ):
@@ -918,4 +985,284 @@ def test_repr_for_Nodes_and_Edges(double_node_edge):
918985 assert "[[[1.,1.],[1.,1.]]]" in str (node1 ) and str (node2 )
919986 assert "Edge(DanglingEdge)[0]" in str (node1 ) and str (node2 )
920987 assert "Edge('test_node1'[1]->'test_node2'[1])" in str (node1 ) and str (node2 )
921- assert "Edge(DanglingEdge)[2]" in str (node1 ) and str (node2 )
988+ assert "Edge(DanglingEdge)[2]" in str (node1 ) and str (node2 )
989+
990+
991+ def test_base_node_name_list_throws_error ():
992+ with pytest .raises (TypeError ,):
993+ TestNode (name = ["A" ], axis_names = ['a' , 'b' ]) # pytype: disable=wrong-arg-types
994+
995+
996+ def test_base_node_name_int_throws_error ():
997+ with pytest .raises (TypeError ):
998+ TestNode (name = 1 , axis_names = ['a' , 'b' ]) # pytype: disable=wrong-arg-types
999+
1000+
1001+ def test_base_node_axis_names_int_throws_error ():
1002+ with pytest .raises (TypeError ):
1003+ TestNode (axis_names = [0 , 1 ]) # pytype: disable=wrong-arg-types
1004+
1005+
1006+ def test_base_node_no_axis_names_no_shapes_throws_error ():
1007+ with pytest .raises (ValueError ):
1008+ TestNode (name = 'a' )
1009+
1010+
1011+ def test_node_add_axis_names_int_throws_error ():
1012+ n1 = Node (np .eye (2 ), axis_names = ['a' , 'b' ])
1013+ with pytest .raises (TypeError ):
1014+ n1 .add_axis_names ([0 , 1 ]) # pytype: disable=wrong-arg-types
1015+
1016+
1017+ def test_node_axis_names_setter_throws_shape_large_mismatch_error ():
1018+ n1 = Node (np .eye (2 ), axis_names = ['a' , 'b' ])
1019+ with pytest .raises (ValueError ):
1020+ n1 .axis_names = ['a' , 'b' , 'c' ]
1021+
1022+
1023+ def test_node_axis_names_setter_throws_shape_small_mismatch_error ():
1024+ n1 = Node (np .eye (2 ), axis_names = ['a' , 'b' ])
1025+ with pytest .raises (ValueError ):
1026+ n1 .axis_names = ['a' ]
1027+
1028+
1029+ def test_node_axis_names_setter_throws_value_error ():
1030+ n1 = Node (np .eye (2 ), axis_names = ['a' , 'b' ])
1031+ with pytest .raises (TypeError ):
1032+ n1 .axis_names = [0 , 1 ]
1033+
1034+
1035+ def test_node_dtype (backend ):
1036+ n1 = Node (np .random .rand (2 ), backend = backend )
1037+ assert n1 .dtype == n1 .tensor .dtype
1038+
1039+
1040+ @pytest .mark .parametrize ("name" , [1 , ['1' ]])
1041+ def test_node_set_name_raises_type_error (backend , name ):
1042+ n1 = Node (np .random .rand (2 ), backend = backend )
1043+ with pytest .raises (TypeError ):
1044+ n1 .set_name (name )
1045+
1046+
1047+ @pytest .mark .parametrize ("name" , [1 , ['1' ]])
1048+ def test_node_name_setter_raises_type_error (backend , name ):
1049+ n1 = Node (np .random .rand (2 ), backend = backend )
1050+ with pytest .raises (TypeError ):
1051+ n1 .name = name
1052+
1053+
1054+ def test_base_node_get_tensor ():
1055+ n1 = TestNode (name = "n1" , axis_names = ['a' ], shape = (1 ,))
1056+ assert n1 .get_tensor () is None
1057+
1058+
1059+ def test_base_node_set_tensor ():
1060+ n1 = TestNode (name = "n1" , axis_names = ['a' ], shape = (1 ,))
1061+ assert n1 .set_tensor (np .random .rand (2 )) is None
1062+ assert n1 .tensor is None
1063+
1064+
1065+ def test_base_node_shape ():
1066+ n1 = TestNode (name = "n1" , axis_names = ['a' ], shape = (1 ,))
1067+ n1 ._shape = None
1068+ with pytest .raises (ValueError ):
1069+ n1 .shape
1070+
1071+
1072+ def test_base_node_tensor_getter ():
1073+ n1 = TestNode (name = "n1" , axis_names = ['a' ], shape = (1 ,))
1074+ assert n1 .tensor is None
1075+
1076+
1077+ def test_base_node_tensor_setter ():
1078+ n1 = TestNode (name = "n1" , axis_names = ['a' ], shape = (1 ,))
1079+ n1 .tensor = np .random .rand (2 )
1080+ assert n1 .tensor is None
1081+
1082+
1083+ def test_node_has_dangling_edge_false (double_node_edge ):
1084+ node1 = double_node_edge .node1
1085+ node2 = double_node_edge .node2
1086+ tn .connect (node1 ["a" ], node2 ["a" ])
1087+ tn .connect (node1 ["c" ], node2 ["c" ])
1088+ assert not node1 .has_dangling_edge ()
1089+
1090+
1091+ def test_node_has_dangling_edge_true (single_node_edge ):
1092+ assert single_node_edge .node .has_dangling_edge ()
1093+
1094+
1095+ def test_node_get_item (single_node_edge ):
1096+ node = single_node_edge .node
1097+ edge = single_node_edge .edge
1098+ node .add_edge (edge , axis = 0 )
1099+ assert node [0 ] == edge
1100+ assert edge in node [0 :2 ]
1101+
1102+
1103+ def test_node_signature_getter_disabled_throws_error (single_node_edge ):
1104+ node = single_node_edge .node
1105+ node .is_disabled = True
1106+ with pytest .raises (ValueError ):
1107+ node .signature
1108+
1109+
1110+ def test_node_signature_setter_disabled_throws_error (single_node_edge ):
1111+ node = single_node_edge .node
1112+ node .is_disabled = True
1113+ with pytest .raises (ValueError ):
1114+ node .signature = "signature"
1115+
1116+
1117+ def test_node_disabled_disabled_throws_error (single_node_edge ):
1118+ node = single_node_edge .node
1119+ node .is_disabled = True
1120+ with pytest .raises (ValueError ):
1121+ node .disable ()
1122+
1123+
1124+ def test_node_disabled_shape_throws_error (single_node_edge ):
1125+ node = single_node_edge .node
1126+ node .is_disabled = True
1127+ with pytest .raises (ValueError ):
1128+ node .shape
1129+
1130+
1131+ def test_copy_node_get_partners_with_trace (backend ):
1132+ node1 = CopyNode (4 , 2 , backend = backend )
1133+ node2 = Node (np .random .rand (2 , 2 ), backend = backend , name = "node2" )
1134+ tn .connect (node1 [0 ], node1 [1 ])
1135+ tn .connect (node1 [2 ], node2 [0 ])
1136+ tn .connect (node1 [3 ], node2 [1 ])
1137+ assert node1 .get_partners () == {node2 : {0 , 1 }}
1138+
1139+
1140+ @pytest .mark .parametrize ("name" , [1 , ['1' ]])
1141+ def test_edge_name_throws_type_error (single_node_edge , name ):
1142+ with pytest .raises (TypeError ):
1143+ Edge (node1 = single_node_edge .node , axis1 = 0 , name = name )
1144+
1145+
1146+ def test_edge_name_setter_disabled_throws_error (single_node_edge ):
1147+ edge = Edge (node1 = single_node_edge .node , axis1 = 0 )
1148+ edge .is_disabled = True
1149+ with pytest .raises (ValueError ):
1150+ edge .name = 'edge'
1151+
1152+
1153+ def test_edge_name_getter_disabled_throws_error (single_node_edge ):
1154+ edge = Edge (node1 = single_node_edge .node , axis1 = 0 )
1155+ edge .is_disabled = True
1156+ with pytest .raises (ValueError ):
1157+ edge .name
1158+
1159+
1160+ @pytest .mark .parametrize ("name" , [1 , ['1' ]])
1161+ def test_edge_name_setter_throws_type_error (single_node_edge , name ):
1162+ edge = Edge (node1 = single_node_edge .node , axis1 = 0 )
1163+ with pytest .raises (TypeError ):
1164+ edge .name = name
1165+
1166+
1167+ def test_edge_signature_getter_disabled_throws_error (single_node_edge ):
1168+ edge = Edge (node1 = single_node_edge .node , axis1 = 0 )
1169+ edge .is_disabled = True
1170+ with pytest .raises (ValueError ):
1171+ edge .signature
1172+
1173+
1174+ def test_edge_signature_setter_disabled_throws_error (single_node_edge ):
1175+ edge = Edge (node1 = single_node_edge .node , axis1 = 0 )
1176+ edge .is_disabled = True
1177+ with pytest .raises (ValueError ):
1178+ edge .signature = "signature"
1179+
1180+
1181+ def test_edge_node1_throws_value_error (single_node_edge ):
1182+ edge = Edge (node1 = single_node_edge .node , axis1 = 0 , name = "edge" )
1183+ edge ._node1 = None
1184+ err_msg = "node1 for edge 'edge' no longer exists."
1185+ with pytest .raises (ValueError , match = err_msg ):
1186+ edge .node1
1187+
1188+
1189+
1190+ def test_edge_node2_throws_value_error (single_node_edge ):
1191+ edge = tn .connect (single_node_edge .node [1 ], single_node_edge .node [2 ])
1192+ edge .name = 'edge'
1193+ edge ._node2 = None
1194+ err_msg = "node2 for edge 'edge' no longer exists."
1195+ with pytest .raises (ValueError , match = err_msg ):
1196+ edge .node2
1197+
1198+
1199+ @pytest .mark .parametrize ("name" , [1 , ['1' ]])
1200+ def test_edge_set_name_throws_type_error (single_node_edge , name ):
1201+ edge = Edge (node1 = single_node_edge .node , axis1 = 0 )
1202+ with pytest .raises (TypeError ):
1203+ edge .set_name (name )
1204+
1205+
1206+ @patch .object (Edge , "name" , None )
1207+ def test_edge_str (single_node_edge ):
1208+ single_node_edge .edge .name = None
1209+ assert str (single_node_edge .edge ) == "__unnamed_edge__"
1210+
1211+
1212+ def test_get_all_dangling_single_node (single_node_edge ):
1213+ node = single_node_edge .node
1214+ assert set (tn .get_all_dangling ({node })) == set (node .edges )
1215+
1216+
1217+ def test_get_all_dangling_double_node (double_node_edge ):
1218+ node1 = double_node_edge .node1
1219+ node2 = double_node_edge .node2
1220+ assert set (tn .get_all_dangling ({node1 , node2 })) == {node1 [0 ], node1 [2 ],
1221+ node2 [0 ], node2 [2 ]}
1222+
1223+
1224+ def test_flatten_edges_different_backend_raises_value_error (single_node_edge ):
1225+ node1 = single_node_edge .node
1226+ node2 = tn .Node (np .random .rand (2 , 2 , 2 ))
1227+ node2 .backend = BaseBackend ()
1228+ with pytest .raises (ValueError ):
1229+ tn .flatten_edges (node1 .get_all_edges ()+ node2 .get_all_edges ())
1230+
1231+
1232+ def test_split_edge_trivial (single_node_edge ):
1233+ edge = single_node_edge .edge
1234+ assert tn .split_edge (edge , (1 ,)) == [edge ]
1235+
1236+
1237+ def test_split_edge_different_backend_raises_value_error (single_node_edge ):
1238+ if single_node_edge .node .backend .name == "numpy" :
1239+ pytest .skip ("numpy comparing to all the others" )
1240+ node1 = single_node_edge .node
1241+ node2 = tn .Node (np .random .rand (2 , 2 , 2 ), backend = "numpy" )
1242+ edge = tn .connect (node1 [1 ], node2 [1 ])
1243+ with pytest .raises (ValueError , match = "Not all backends are the same." ):
1244+ tn .split_edge (edge , (2 , 1 ))
1245+
1246+
1247+ def test_remove_trace_edge_dangling_edge_raises_value_error (single_node_edge ):
1248+ node = single_node_edge .node
1249+ edge = node [0 ]
1250+ edge .name = "e"
1251+ with pytest .raises (ValueError , match = "Attempted to remove dangling edge 'e" ):
1252+ _remove_trace_edge (edge , node )
1253+
1254+
1255+ def test_remove_trace_edge_non_trace_raises_value_error (double_node_edge ):
1256+ node1 = double_node_edge .node1
1257+ node2 = double_node_edge .node2
1258+ edge = tn .connect (node1 [0 ], node2 [0 ])
1259+ edge .name = "e"
1260+ with pytest .raises (ValueError , match = "Edge 'e' is not a trace edge." ):
1261+ _remove_trace_edge (edge , node1 )
1262+
1263+
1264+ def test_remove_edges_trace_raises_value_error (single_node_edge ):
1265+ node = single_node_edge .node
1266+ edge = tn .connect (node [1 ], node [2 ])
1267+ with pytest .raises (ValueError ):
1268+ _remove_edges (edge , node , node , node ) # pytype: disable=wrong-arg-types
0 commit comments