def test_copy_node_add_to_node_collection(): container = set() with NodeCollection(container): a = tn.CopyNode(rank=4, dimension=3, name='copier1', axis_names=[str(n) for n in range(4)]) b = tn.CopyNode(rank=2, dimension=3, name='copier2', axis_names=[str(n) for n in range(2)]) assert container == {a, b}
def batch_node(num_inputs, batch_dim): """ Return a network of small CopyNodes which emulates a large CopyNode This network is used for reproducing the standard batch functionality available in Pytorch, and requires connecting the `num_inputs` edges returned by batch_node to the respective batch indices of our inputs. The sole remaining dangling edge will then give the batch index of whatever contraction occurs later with the input. Args: num_inputs: The number of batch indices to contract together batch_dim: The batch dimension we intend to reproduce Returns: edge_list: List of edges of our composite CopyNode object """ # For small numbers of edges, just use a single CopyNode num_edges = num_inputs + 1 if num_edges < 4: node = tn.CopyNode(rank=num_edges, dimension=batch_dim) return node.get_all_edges() # Initialize list of free edges with output of trivial identity mats input_node = tn.Node(torch.eye(batch_dim)) edge_list, dummy_list = zip( *[input_node.copy().get_all_edges() for _ in range(num_edges)]) # Contract dummy edges as a binary tree via third-order tensors dummy_len = len(dummy_list) while dummy_len > 4: odd = dummy_len % 2 == 1 half_len = dummy_len // 2 # Apply third order tensor to contract two dummy indices together temp_list = [] for i in range(half_len): temp_node = tn.CopyNode(rank=3, dimension=batch_dim) temp_node[1] ^ dummy_list[2 * i] temp_node[2] ^ dummy_list[2 * i + 1] temp_list.append(temp_node[0]) if odd: temp_list.append(dummy_list[-1]) dummy_list = temp_list dummy_len = len(dummy_list) # Contract the 3 or less dummy indices together last_node = tn.CopyNode(rank=dummy_len, dimension=batch_dim) [last_node[i] ^ dummy_list[i] for i in range(dummy_len)] return edge_list
def test_copy_node_load(tmp_path, backend): node = tn.CopyNode( rank=4, dimension=3, name='copier', axis_names=[str(n) for n in range(4)], backend=backend) with h5py.File(tmp_path / 'node', 'w') as node_file: node_group = node_file.create_group('node_data') node_group.create_dataset('signature', data=node.signature) node_group.create_dataset('backend', data=node.backend.name) node_group.create_dataset( 'copy_node_dtype', data=np.dtype(node.copy_node_dtype).name) node_group.create_dataset('name', data=node.name) node_group.create_dataset('shape', data=node.shape) node_group.create_dataset( 'axis_names', data=np.array(node.axis_names, dtype=object), dtype=string_type) node_group.create_dataset( 'edges', data=np.array([edge.name for edge in node.edges], dtype=object), dtype=string_type) loaded_node = CopyNode._load_node(node_data=node_file["node_data/"]) assert loaded_node.name == node.name assert loaded_node.signature == node.signature assert set(loaded_node.axis_names) == set(node.axis_names) assert (set(edge.name for edge in loaded_node.edges) == set( edge.name for edge in node.edges)) assert loaded_node.get_dimension(axis=1) == node.get_dimension(axis=1) assert loaded_node.get_rank() == node.get_rank() assert loaded_node.shape == node.shape assert loaded_node.copy_node_dtype == node.copy_node_dtype
def test_add_copy_node(backend): net = tensornetwork.TensorNetwork(backend=backend) a = net.add_node( tensornetwork.CopyNode(3, 3, name="TestName", axis_names=['a', 'b', 'c'])) assert a in net
def test_add_copy_node_from_node_object(backend): a = tn.CopyNode( 3, 3, name="TestName", axis_names=['a', 'b', 'c'], backend=backend) assert a.shape == (3, 3, 3) assert isinstance(a, tn.CopyNode) assert a.name == "TestName" assert a.axis_names == ['a', 'b', 'c'] b = tn.Node(np.eye(3), backend=backend) e = a[0] ^ b[0] c = tn.contract(e) np.testing.assert_allclose(c.tensor, a.tensor)
def test_contract_copy_node_dangling_edge_value_error(backend): a = tn.Node(np.array([1, 2, 3]), backend=backend) b = tn.Node(np.array([10, 20, 30]), backend=backend) c = tn.Node(np.array([5, 6, 7]), backend=backend) cn = tn.CopyNode(rank=4, dimension=3, backend=backend) tn.connect(a[0], cn[0]) tn.connect(b[0], cn[1]) tn.connect(c[0], cn[2]) with pytest.raises(ValueError): tn.contract_copy_node(cn)
def sat_tn(clauses: List[Tuple[int, int, int]]) -> List[tn.Edge]: """Create a 3SAT TensorNetwork of the given 3SAT clauses. After full contraction, this network will be a tensor of size (2, 2, ..., 2) with the rank being the same as the number of variables. Each element of the final tensor represents whether the given assignment satisfies all of the clauses. For example, if final_node.get_tensor()[0][1][1] == 1, then the assiment (False, True, True) satisfies all clauses. Args: clauses: A list of 3 int tuples. Each element in the tuple corresponds to a variable in the clause. If that int is negative, that variable is negated in the clause. Returns: net: The 3SAT TensorNetwork. var_edges: The edges for the given variables. Raises: ValueError: If any of the clauses have a 0 in them. """ for clause in clauses: if 0 in clause: raise ValueError("0's are not allowed in the clauses.") var_set = set() for clause in clauses: var_set |= {abs(x) for x in clause} num_vars = max(var_set) var_nodes = [] var_edges = [] # Prepare the variable nodes. for _ in range(num_vars): new_node = tn.Node(np.ones(2, dtype=np.int32)) var_nodes.append(new_node) var_edges.append(new_node[0]) # Create the nodes for each clause for clause in clauses: a, b, c, = clause clause_tensor = np.ones((2, 2, 2), dtype=np.int32) clause_tensor[(-np.sign(a) + 1) // 2, (-np.sign(b) + 1) // 2, (-np.sign(c) + 1) // 2] = 0 clause_node = tn.Node(clause_tensor) # Connect the variable to the clause through a copy tensor. for i, var in enumerate(clause): copy_tensor_node = tn.CopyNode(3, 2) clause_node[i] ^ copy_tensor_node[0] var_edges[abs(var) - 1] ^ copy_tensor_node[1] var_edges[abs(var) - 1] = copy_tensor_node[2] return var_edges
def test_copy_node_save_structure(tmp_path, backend): node = tn.CopyNode(rank=4, dimension=3, name='copier', axis_names=[str(n) for n in range(4)], backend=backend) with h5py.File(tmp_path / 'nodes', 'w') as node_file: node_group = node_file.create_group('test_node') node._save_node(node_group) assert set(list(node_file.keys())) == {"test_node"} assert set(list(node_file['test_node'])) == { "signature", 'name', 'edges', 'backend', 'shape', 'axis_names', 'copy_node_dtype', "type" }
def test_contract_copy_node(backend): a = tn.Node(np.array([1, 2, 3]), backend=backend) b = tn.Node(np.array([10, 20, 30]), backend=backend) c = tn.Node(np.array([5, 6, 7]), backend=backend) d = tn.Node(np.array([1, -1, 1]), backend=backend) cn = tn.CopyNode(rank=4, dimension=3, backend=backend) tn.connect(a[0], cn[0]) tn.connect(b[0], cn[1]) tn.connect(c[0], cn[2]) tn.connect(d[0], cn[3]) val = tn.contract_copy_node(cn) result = val.tensor assert list(result.shape) == [] np.testing.assert_allclose(result, 50 - 240 + 630)
def test_copy_copynode_method(backend): a = tn.CopyNode(3, 3, 'mynode', axis_names=['a', 'b', 'c'], backend=backend) a.add_edge(tn.Edge(a, 0, name='named_edge1'), 0) a.add_edge(tn.Edge(a, 1, name='named_edge2'), 1) a.add_edge(tn.Edge(a, 2, name='named_edge3'), 2) b = a.copy() assert a.name == b.name assert a.shape == b.shape assert a.axis_names == b.axis_names assert a.rank == b.rank assert a.backend == b.backend assert a.dtype == b.dtype for i in range(len(a.edges)): assert a[i].name == b[i].name np.testing.assert_allclose(a.tensor, b.tensor)
def test_add_copy_node_from_node_object(backend): net = tensornetwork.TensorNetwork(backend=backend) a = net.add_node( tensornetwork.CopyNode(3, 3, name="TestName", axis_names=['a', 'b', 'c'])) assert a in net assert a.shape == (3, 3, 3) assert isinstance(a, tensornetwork.CopyNode) assert a.name == "TestName" assert a.axis_names == ['a', 'b', 'c'] b = net.add_node(np.eye(3)) e = a[0] ^ b[0] c = net.contract(e) np.testing.assert_allclose(c.tensor, a.tensor)
def test_copy_tensor_parallel_edges(backend): a = tn.Node(np.diag([1., 2, 3]), backend=backend) b = tn.Node(np.array([10, 20, 30], dtype=np.float64), backend=backend) cn = tn.CopyNode(rank=3, dimension=3, backend=backend) edge1 = tn.connect(a[0], cn[0]) edge2 = tn.connect(a[1], cn[1]) edge3 = tn.connect(b[0], cn[2]) result = cn.compute_contracted_tensor() assert list(result.shape) == [] np.testing.assert_allclose(result, 10 + 40 + 90) for edge in [edge1, edge2, edge3]: val = tn.contract(edge) result = val.tensor assert list(result.shape) == [] np.testing.assert_allclose(result, 10 + 40 + 90)
def test_contract_copy_node_connected_neighbors(backend): a = tn.Node(np.array([[1, 2, 3], [10, 20, 30]]), backend=backend) b = tn.Node(np.array([[2, 1, 1], [2, 2, 2]]), backend=backend) c = tn.Node(np.array([3, 4, 4]), backend=backend) cn = tn.CopyNode(rank=3, dimension=3, backend=backend) tn.connect(a[0], b[0]) tn.connect(a[1], cn[0]) tn.connect(b[1], cn[1]) tn.connect(c[0], cn[2]) n = tn.contract_copy_node(cn) assert len(n.edges) == 2 assert n.edges[0] == n.edges[1] val = tn.contract_parallel(n.edges[0]) result = val.tensor assert list(result.shape) == [] np.testing.assert_allclose(result, 26 + 460)
def test_copy_node_save_data(tmp_path, backend): node = tn.CopyNode(rank=4, dimension=3, name='copier', axis_names=[str(n) for n in range(4)], backend=backend) with h5py.File(tmp_path / 'nodes', 'w') as node_file: node_group = node_file.create_group('copier') node._save_node(node_group) assert node_file['copier/signature'][()] == node.signature assert node_file['copier/backend'][()] == node.backend.name assert node_file['copier/type'][()] == type(node).__name__ assert node_file['copier/name'][()] == node.name assert node_file['copier/copy_node_dtype'][()] == np.dtype( node.copy_node_dtype).name assert set(node_file['copier/shape'][()]) == set(node.shape_tensor) assert set(node_file['copier/axis_names'][()]) == set(node.axis_names) assert (set(node_file['copier/edges'][()]) == set( edge.name for edge in node.edges))
def test_copy_tensor(backend): a = tn.Node(np.array([1, 2, 3], dtype=np.float64), backend=backend) b = tn.Node(np.array([10, 20, 30], dtype=np.float64), backend=backend) c = tn.Node(np.array([5, 6, 7], dtype=np.float64), backend=backend) d = tn.Node(np.array([1, -1, 1], dtype=np.float64), backend=backend) cn = tn.CopyNode(rank=4, dimension=3, backend=backend) edge1 = tn.connect(a[0], cn[0]) edge2 = tn.connect(b[0], cn[1]) edge3 = tn.connect(c[0], cn[2]) edge4 = tn.connect(d[0], cn[3]) result = cn.compute_contracted_tensor() assert list(result.shape) == [] np.testing.assert_allclose(result, 50 - 240 + 630) for edge in [edge1, edge2, edge3, edge4]: val = tn.contract(edge) result = val.tensor assert list(result.shape) == [] np.testing.assert_allclose(result, 50 - 240 + 630)
def test_node_mul_input_error(): #pylint: disable=unused-variable #pytype: disable=unsupported-operands node1 = Node(tensor=2, backend='numpy') node2 = Node(tensor=np.array([[10, 10], [10, 10]]), backend='numpy') del node1._tensor with pytest.raises(AttributeError): result = node1 * node2 result = node2 * node1 node1.tensor = 1 node2 = 'str' copynode = tn.CopyNode(rank=4, dimension=3) with pytest.raises(TypeError): result = node1 * node2 result = node1 * copynode node2 = Node(tensor=np.array([[10, 10], [10, 10]]), backend='pytorch') with pytest.raises(TypeError): result = node1 * node2
def test_default_names_add_node_object(backend): net = tensornetwork.TensorNetwork(backend=backend) a = net.add_node(tensornetwork.CopyNode(3, 3)) assert a.name is not None assert len(a.axis_names) == 3
def test_add_node_twice_raise_value_error(backend): net = tensornetwork.TensorNetwork(backend=backend) a = net.add_node(tensornetwork.CopyNode(3, 3)) with pytest.raises(ValueError): net.add_node(a)
def test_default_names_add_node_object(backend): a = tn.CopyNode(3, 3, backend=backend) assert a.name is not None assert len(a.axis_names) == 3
def regauge_B_symm_linear_problem_v1(B, AL, AR, p=0): Bn = tn.Node(B, axis_names=["p", "L", "R"]) ALn = tn.Node(AL, axis_names=["p", "L", "R"]) ARn = tn.Node(AR * np.exp(-1.j * p), axis_names=["p", "L", "R"]) D = B.shape[2] ALn_c = tn.conj(ALn) ALn["L"] ^ ALn_c["L"] ALn["R"] ^ ALn_c["R"] PLn = tn.contract_between(ALn, ALn_c, output_edge_order=[ALn_c["p"], ALn["p"]], axis_names=["p_in", "p_out"]) ARn_c = tn.conj(ARn) ARn["L"] ^ ARn_c["L"] ARn["R"] ^ ARn_c["R"] PRn = tn.contract_between(ARn, ARn_c, output_edge_order=[ARn_c["p"], ARn["p"]], axis_names=["p_in", "p_out"]) PLRn = tn.Node(PLn.get_tensor() + PRn.get_tensor(), axis_names=["p_in", "p_out"]) E = tn.CopyNode(2, D, dtype=B.dtype) PLRn["p_out"] ^ ALn_c["p"] MLn = tn.contract_between( PLRn, ALn_c, output_edge_order=[PLRn["p_in"], ALn_c["L"], ALn_c["R"]], axis_names=["p_in", "L_in", "L_out"]) MLn = tn.contract_between( MLn, E, output_edge_order=[MLn["L_out"], E[0], MLn["p_in"], MLn["L_in"], E[1]], axis_names=["L_out", "R_out", "p_in", "L_in", "R_in"], allow_outer_product=True) PLRn["p_out"] ^ ARn_c["p"] MRn = tn.contract_between( PLRn, ARn_c, output_edge_order=[PLRn["p_in"], ARn_c["L"], ARn_c["R"]], axis_names=["p_in", "R_out", "R_in"]) MRn = tn.contract_between( MRn, E, output_edge_order=[E[0], MRn["R_out"], MRn["p_in"], E[1], MRn["R_in"]], axis_names=["L_out", "R_out", "p_in", "L_in", "R_in"], allow_outer_product=True) MLRn = tn.Node(MLn.get_tensor() - MRn.get_tensor(), axis_names=["L_out", "R_out", "p_in", "L_in", "R_in"]) MLRn["p_in"] ^ Bn["p"] MLRn["L_in"] ^ Bn["L"] MLRn["R_in"] ^ Bn["R"] target_n = tn.contract_between( MLRn, Bn, output_edge_order=[MLRn["L_out"], MLRn["R_out"]]) target_vec = target_n.get_tensor().ravel() ARn["p"] ^ MLRn["p_in"] ARn["R"] ^ MLRn["R_in"] bigM_Rn = tn.contract_between(ARn, MLRn, output_edge_order=[ MLRn["L_out"], MLRn["R_out"], MLRn["L_in"], ARn["L"] ]) ALn["p"] ^ MLRn["p_in"] ALn["L"] ^ MLRn["L_in"] bigM_Ln = tn.contract_between(ALn, MLRn, output_edge_order=[ MLRn["L_out"], MLRn["R_out"], ALn["R"], MLRn["R_in"] ]) bigMn = tn.Node(bigM_Rn.get_tensor() - bigM_Ln.get_tensor(), axis_names=["L_out", "R_out", "L_in", "R_in"]) mat = bigMn.get_tensor().reshape((D**2, D**2)) return mat, target_vec