def test_reachable_disconnected_2(backend): nodes = [tn.Node(np.random.rand(2, 2, 2), backend=backend) for _ in range(4)] nodes[1][1] ^ nodes[2][0] #connect 2nd and third node assert set(tn.reachable([nodes[0], nodes[1]])) == {nodes[0], nodes[1], nodes[2]} nodes[2][1] ^ nodes[3][0] #connect third and fourth node assert set(tn.reachable([nodes[0], nodes[1]])) == set(nodes)
def test_real_physics_with_tensors(backend): # Calcuate the expected value in numpy a_vals = np.ones([2, 3, 4, 5]) b_vals = np.ones([4, 6, 7]) c_vals = np.ones([5, 6, 8]) contract1 = np.tensordot(a_vals, b_vals, [[2], [0]]) contract2 = np.tensordot(c_vals, contract1, [[0], [2]]) final_result = np.trace(contract2, axis1=0, axis2=4) # Build the network a = tn.Node(np.ones([2, 3, 4, 5]), name="T", backend=backend) b = tn.Node(np.ones([4, 6, 7]), name="A", backend=backend) c = tn.Node(np.ones([5, 6, 8]), name="B", backend=backend) e1 = tn.connect(a[2], b[0], "edge") e2 = tn.connect(c[0], a[3], "edge2") e3 = tn.connect(b[1], c[1], "edge3") tn.check_correct({a, b, c}) node_result = tn.contract(e1) np.testing.assert_allclose(node_result.tensor, contract1) tn.check_correct(tn.reachable(node_result)) node_result = tn.contract(e2) np.testing.assert_allclose(node_result.tensor, contract2) tn.check_correct(tn.reachable(node_result)) val = tn.contract(e3) tn.check_correct(tn.reachable(val)) np.testing.assert_allclose(val.tensor, final_result)
def test_reachable_2(backend): a = tn.Node(np.zeros((3, 5)), backend=backend) b = tn.Node(np.zeros((3, 4, 5)), backend=backend) e1 = tn.connect(a[0], b[0]) e2 = tn.connect(a[1], b[2]) nodes = [a, b] edges = [e1, e2] assert set(nodes) == tn.reachable(edges[0]) assert set(nodes) == tn.reachable(edges)
def test_replicate_nodes(backend): a = tn.Node(np.random.rand(10, 10), backend=backend) b = tn.Node(np.random.rand(10, 10), backend=backend) c = tn.Node(np.random.rand(10, 10), backend=backend) tn.connect(a[1], b[0]) tn.connect(b[1], c[0]) [a_copy, b_copy] = tn.replicate_nodes([a, b]) assert b_copy in tn.reachable([a_copy]) assert not set([a_copy, b_copy]).issubset(tn.reachable([c])) assert len(b_copy.get_all_dangling()) == 1
def test_with_tensors(backend): a = tn.Node(np.eye(2) * 2, name="T", backend=backend) b = tn.Node(np.eye(2) * 3, name="A", backend=backend) e1 = tn.connect(a[0], b[0], "edge") e2 = tn.connect(a[1], b[1], "edge2") tn.check_correct({a, b}) result = tn.contract(e1) tn.check_correct(tn.reachable(result)) val = tn.contract(e2) tn.check_correct(tn.reachable(val)) np.testing.assert_allclose(val.tensor, 12.0)
def test_reduced_density_contraction(backend): if backend == "pytorch": pytest.skip("pytorch doesn't support complex numbers") a = tn.Node(np.array([[0.0, 1.0j], [-1.0j, 0.0]], dtype=np.complex64), backend=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_split_node_qr(backend): a = tn.Node(np.random.rand(2, 3, 4, 5, 6), backend=backend) left_edges = [] for i in range(3): left_edges.append(a[i]) right_edges = [] for i in range(3, 5): right_edges.append(a[i]) left, _ = tn.split_node_qr(a, left_edges, right_edges) tn.check_correct(tn.reachable(left)) np.testing.assert_allclose(a.tensor, tn.contract(left[3]).tensor)
def test_split_node_full_svd(backend): unitary1 = np.array([[1.0, 1.0], [1.0, -1.0]]) / np.sqrt(2.0) unitary2 = np.array([[0.0, 1.0], [1.0, 0.0]]) singular_values = np.array([9.1, 7.5], dtype=np.float32) val = np.dot(unitary1, np.dot(np.diag(singular_values), (unitary2.T))) a = tn.Node(val, backend=backend) e1 = a[0] e2 = a[1] _, s, _, _, = tn.split_node_full_svd(a, [e1], [e2]) tn.check_correct(tn.reachable(s)) np.testing.assert_allclose(s.tensor, np.diag([9.1, 7.5]), rtol=1e-5)
def execute(self, probs_autocalc: bool = True) -> Execution_result: if not isinstance(probs_autocalc, bool): raise TypeError("probs_autocalc is a bool parametr") for i in range(len(self._edges) - 1): self.ci(i, i + 1) nodes = tn.reachable(self._edges[0]) result_node = tn.contractors.greedy(nodes, self._edges) result = Execution_result(result_node, probs_autocalc=probs_autocalc) for i in range(len(result_node.tensor.shape)): self._edges[i] = result_node.get_edge(i) return result
def test_real_physics(dtype, num_charges): # Calcuate the expected value in numpy t1 = get_random_symmetric((20, 20, 20, 20), [False, False, False, False], num_charges, dtype=dtype) t2 = get_random_symmetric((20, 20, 20), [True, False, True], num_charges, dtype=dtype) t3 = get_random_symmetric((20, 20, 20), [True, True, False], num_charges, dtype=dtype) t1_dense = t1.todense() t2_dense = t2.todense() t3_dense = t3.todense() adense = tn.Node(t1_dense, name="T", backend='numpy') bdense = tn.Node(t2_dense, name="A", backend='numpy') cdense = tn.Node(t3_dense, name="B", backend='numpy') e1 = tn.connect(adense[2], bdense[0], "edge") e2 = tn.connect(cdense[0], adense[3], "edge2") e3 = tn.connect(bdense[1], cdense[1], "edge3") node_result = tn.contract(e1) node_result = tn.contract(e2) final_result = tn.contract(e3) # Build the network a = tn.Node(t1, name="T", backend='symmetric') b = tn.Node(t2, name="A", backend='symmetric') c = tn.Node(t3, name="B", backend='symmetric') e1 = tn.connect(a[2], b[0], "edge") e2 = tn.connect(c[0], a[3], "edge2") e3 = tn.connect(b[1], c[1], "edge3") tn.check_correct(tn.reachable(a)) node_result = tn.contract(e1) tn.check_correct(tn.reachable(node_result)) node_result = tn.contract(e2) tn.check_correct(tn.reachable(node_result)) val = tn.contract(e3) tn.check_correct(tn.reachable(val)) np.testing.assert_allclose(val.tensor.todense(), final_result.tensor)
def test_complicated_edge_reordering(backend): a = tn.Node(np.zeros((2, 3, 4)), backend=backend) b = tn.Node(np.zeros((2, 5)), backend=backend) c = tn.Node(np.zeros((3, )), backend=backend) d = tn.Node(np.zeros((4, 5)), backend=backend) e_ab = tn.connect(a[0], b[0]) e_bd = tn.connect(b[1], d[1]) e_ac = tn.connect(a[1], c[0]) e_ad = tn.connect(a[2], d[0]) result = tn.contract(e_bd) a.reorder_edges([e_ac, e_ab, e_ad]) tn.check_correct(tn.reachable(result)) assert a.shape == (3, 2, 4)
def test_fft(): n = 3 initial_state = [complex(0)] * (1 << n) initial_state[1] = 1j initial_state[5] = -1 initial_node = tn.Node(np.array(initial_state).reshape((2, ) * n)) fft_out = fft.add_fft([initial_node[k] for k in range(n)]) result = tn.contractors.greedy(tn.reachable(fft_out[0].node1), fft_out) tn.flatten_edges(fft_out) actual = result.tensor expected = np.fft.fft(initial_state, norm="ortho") np.testing.assert_allclose(expected, actual)
def VRL_train(five_tuple, k, data, H, H_core, omega, lr=0.00001, epochs=int(1e4), lam=1): s, a, P_mat, R_vec, gamma = five_tuple energy_history = [] Pbar = pkbar.Pbar(name='progress', target=epochs) op = optim.SGD([data], lr=lr, momentum=0.9, weight_decay=5e-4) for e in range(epochs): spins = [] core = [] edge = [] energy = 0 regularity = 0 op.zero_grad() for i in range(k): H_core[i] = tensor_completion(H_core[i], H[i], omega[i]) core.append(tn.replicate_nodes(H_core[i])) edge.append([]) for c in core[i]: edge[i] += c.get_all_dangling() for i in range(k): spins.append(K_Spin(s, a, i + 1, data=data, softmax=True)) for j in range(i + 1): edge[i][j] ^ spins[i].qubits[j][0] for i in range(k): energy -= contractors.branch(tn.reachable(core[i]), nbranch=1).get_tensor() energy_history.append(energy) for j in range(s): regularity += (1 - torch.sum(data[j * a:(j + 1) * a], 0))**2 target = energy + lam * regularity target.backward() op.step() Pbar.update(e) return spins, energy_history
def test_solutions(): edge_order = sat_tensornetwork.sat_tn([ (1, 2, -3), ]) solutions = tensornetwork.contractors.greedy( tensornetwork.reachable(edge_order[0].node1), edge_order).tensor assert solutions[0][0][0] == 1 # Only unaccepted value. assert solutions[0][0][1] == 0 assert solutions[0][1][0] == 1 assert solutions[0][1][1] == 1 assert solutions[1][0][0] == 1 assert solutions[1][0][1] == 1 assert solutions[1][1][0] == 1 assert solutions[1][1][1] == 1
def get_state_vector(self): """ Returns resulting state vector as a tensor of rank 1. Round values to 3 decimal points. """ # connect all nodes and evaluate all tensors stored in it self.evaluate_patch() if len(self.network) > 1: for index in reversed(range(1, len(self.network) - 1)): self.network[index + 1][0] ^ self.network[index][1] self.network[1][0] ^ self.network[0][0] nodes = tn.reachable(self.network[1]) result = tn.contractors.greedy(nodes, ignore_edge_order=True) # round the result to three decimals state_vecor = np.round(result.tensor, 3) return state_vecor
def sat_count_tn(clauses: List[Tuple[int, int, int]]) -> Set[tn.BaseNode]: """Create a 3SAT Count TensorNetwork. After full contraction, the final node will be the count of all possible solutions to the given 3SAT problem. 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: nodes: The set of nodes """ var_edges1 = sat_tn(clauses) var_edges2 = sat_tn(clauses) for edge1, edge2 in zip(var_edges1, var_edges2): edge1 ^ edge2 # TODO(chaseriley): Support diconnected SAT graphs. return tn.reachable(var_edges1[0].node1)
def contract_network(nodes, contractor='auto', edge_order=None): """ Contract a tensor network that has already been 'wired' together Args: nodes: One or more nodes in the network of interest. All nodes connected to this one will get contracted contractor: Name of the TensorNetwork contractor used to contract the network. Options include 'greedy', 'optimal', 'bucket', 'branch', and 'auto' (default) edge_order: When expanding to a dense tensor, giving a list of the dangling edges of the tensor is required to set the order of the indices of the (large) output tensor Returns: output: Pytorch tensor containing the contracted network, which here will always be a scalar or batch vector """ contractor = getattr(tn.contractors, contractor) output = contractor(tn.reachable(nodes), output_edge_order=edge_order) return output.tensor
def test_reachable_raises_value_error(): with pytest.raises(ValueError): tn.reachable({})
# define network edges tn.connect(iso_l[0], iso_l_con[0]) tn.connect(iso_l[1], un_l[2]) tn.connect(iso_c[0], un_l[3]) tn.connect(iso_c[1], un_r[2]) tn.connect(iso_r[0], un_r[3]) tn.connect(iso_r[1], iso_r_con[1]) tn.connect(un_l[0], un_l_con[0]) tn.connect(un_l[1], op[3]) tn.connect(un_r[0], op[4]) tn.connect(un_r[1], op[5]) tn.connect(op[0], un_l_con[1]) tn.connect(op[1], un_r_con[0]) tn.connect(op[2], un_r_con[1]) tn.connect(un_l_con[2], iso_l_con[1]) tn.connect(un_l_con[3], iso_c_con[0]) tn.connect(un_r_con[2], iso_c_con[1]) tn.connect(un_r_con[3], iso_r_con[0]) # define output edges output_edge_order = [ iso_l_con[2], iso_c_con[2], iso_r_con[2], iso_l[2], iso_c[2], iso_r[2] ] # solve for optimal order and contract the network t0 = time.time() T2 = contractors.branch(tn.reachable(op), output_edge_order=output_edge_order).get_tensor() print("tn.contractors: time to contract = ", time.time() - t0)
def test_reachable_disconnected_1(backend): nodes = [ tn.Node(np.random.rand(2, 2, 2), backend=backend) for _ in range(4) ] nodes[0][1] ^ nodes[1][0] nodes[2][1] ^ nodes[3][0] assert set(tn.reachable([nodes[0], nodes[2]])) == set(nodes) assert set(tn.reachable([nodes[0]])) == {nodes[0], nodes[1]} assert set(tn.reachable([nodes[1]])) == {nodes[0], nodes[1]} assert set(tn.reachable([nodes[0], nodes[1]])) == {nodes[0], nodes[1]} assert set(tn.reachable([nodes[2]])) == {nodes[2], nodes[3]} assert set(tn.reachable([nodes[3]])) == {nodes[2], nodes[3]} assert set(tn.reachable([nodes[2], nodes[3]])) == {nodes[2], nodes[3]} assert set(tn.reachable([nodes[0], nodes[1], nodes[2]])) == set(nodes) assert set(tn.reachable([nodes[0], nodes[1], nodes[3]])) == set(nodes) assert set(tn.reachable([nodes[0], nodes[2], nodes[3]])) == set(nodes) assert set(tn.reachable([nodes[1], nodes[2], nodes[3]])) == set(nodes)
def test_reachable(backend): nodes = [ tn.Node(np.random.rand(2, 2, 2), backend=backend) for _ in range(10) ] _ = [nodes[n][0] ^ nodes[n + 1][1] for n in range(len(nodes) - 1)] assert set(nodes) == tn.reachable(nodes[0])
def f(input_vec, entanglers1, entanglers2, isometries1, isometries2, bias_var, kernel_dims): input_vv = [] step = int(kernel_dims // 4) for i in range(4): for ii in range(4): input_vv.append( tf.reshape( input_vec[i * step:i * step + step, ii * step:ii * step + step, 0], (1, step**2))) input_vec = tf.concat(input_vv, axis=0) input_vec = tf.reshape(input_vec, (16, step**2)) input_vec = tf.unstack(input_vec) input_nodes = [] for e_iv in input_vec: input_nodes.append(tn.Node(e_iv)) e_nodes1 = tn.Node(entanglers1) e_nodes2 = tn.Node(entanglers2) isometries_nodes1 = [] for eiso in isometries1: isometries_nodes1.append(tn.Node(eiso)) isometries_nodes2 = tn.Node(isometries2) e_nodes1[0] ^ input_nodes[5][0] e_nodes1[1] ^ input_nodes[6][0] e_nodes1[2] ^ input_nodes[9][0] e_nodes1[3] ^ input_nodes[10][0] e_nodes1[4] ^ isometries_nodes1[0][3] e_nodes1[5] ^ isometries_nodes1[1][2] e_nodes1[6] ^ isometries_nodes1[2][1] e_nodes1[7] ^ isometries_nodes1[3][0] input_nodes[0][0] ^ isometries_nodes1[0][0] input_nodes[1][0] ^ isometries_nodes1[0][1] input_nodes[4][0] ^ isometries_nodes1[0][2] input_nodes[2][0] ^ isometries_nodes1[1][0] input_nodes[3][0] ^ isometries_nodes1[1][1] input_nodes[7][0] ^ isometries_nodes1[1][3] input_nodes[8][0] ^ isometries_nodes1[2][0] input_nodes[12][0] ^ isometries_nodes1[2][2] input_nodes[13][0] ^ isometries_nodes1[2][3] input_nodes[11][0] ^ isometries_nodes1[3][1] input_nodes[14][0] ^ isometries_nodes1[3][2] input_nodes[15][0] ^ isometries_nodes1[3][3] isometries_nodes1[0][4] ^ e_nodes2[0] isometries_nodes1[1][4] ^ e_nodes2[1] isometries_nodes1[2][4] ^ e_nodes2[2] isometries_nodes1[3][4] ^ e_nodes2[3] e_nodes2[4] ^ isometries_nodes2[0] e_nodes2[5] ^ isometries_nodes2[1] e_nodes2[6] ^ isometries_nodes2[2] e_nodes2[7] ^ isometries_nodes2[3] nodes = tn.reachable(isometries_nodes2) result = tn.contractors.greedy(nodes) result = result.tensor return result + bias_var
def test_reachable_raises(backend): nodes = [tn.Node(np.random.rand(2, 2, 2), backend=backend), 5] with pytest.raises(TypeError): tn.reachable(nodes)
def binary_mera_energy(hamiltonian, state, isometry, disentangler): """Computes the energy using a layer of uniform binary MERA. Args: hamiltonian: The hamiltonian (rank-6 tensor) defined at the bottom of the MERA layer. state: The 3-site reduced state (rank-6 tensor) defined at the top of the MERA layer. isometry: The isometry tensor (rank 3) of the binary MERA. disentangler: The disentangler tensor (rank 4) of the binary MERA. Returns: The energy. """ backend = "jax" out = [] for dirn in ('left', 'right'): iso_l = tensornetwork.Node(isometry, backend=backend) iso_c = tensornetwork.Node(isometry, backend=backend) iso_r = tensornetwork.Node(isometry, backend=backend) iso_l_con = tensornetwork.conj(iso_l) iso_c_con = tensornetwork.conj(iso_c) iso_r_con = tensornetwork.conj(iso_r) op = tensornetwork.Node(hamiltonian, backend=backend) rho = tensornetwork.Node(state, backend=backend) un_l = tensornetwork.Node(disentangler, backend=backend) un_l_con = tensornetwork.conj(un_l) un_r = tensornetwork.Node(disentangler, backend=backend) un_r_con = tensornetwork.conj(un_r) tensornetwork.connect(iso_l[2], rho[0]) tensornetwork.connect(iso_c[2], rho[1]) tensornetwork.connect(iso_r[2], rho[2]) tensornetwork.connect(iso_l[0], iso_l_con[0]) tensornetwork.connect(iso_l[1], un_l[2]) tensornetwork.connect(iso_c[0], un_l[3]) tensornetwork.connect(iso_c[1], un_r[2]) tensornetwork.connect(iso_r[0], un_r[3]) tensornetwork.connect(iso_r[1], iso_r_con[1]) if dirn == 'right': tensornetwork.connect(un_l[0], un_l_con[0]) tensornetwork.connect(un_l[1], op[3]) tensornetwork.connect(un_r[0], op[4]) tensornetwork.connect(un_r[1], op[5]) tensornetwork.connect(op[0], un_l_con[1]) tensornetwork.connect(op[1], un_r_con[0]) tensornetwork.connect(op[2], un_r_con[1]) elif dirn == 'left': tensornetwork.connect(un_l[0], op[3]) tensornetwork.connect(un_l[1], op[4]) tensornetwork.connect(un_r[0], op[5]) tensornetwork.connect(un_r[1], un_r_con[1]) tensornetwork.connect(op[0], un_l_con[0]) tensornetwork.connect(op[1], un_l_con[1]) tensornetwork.connect(op[2], un_r_con[0]) tensornetwork.connect(un_l_con[2], iso_l_con[1]) tensornetwork.connect(un_l_con[3], iso_c_con[0]) tensornetwork.connect(un_r_con[2], iso_c_con[1]) tensornetwork.connect(un_r_con[3], iso_r_con[0]) tensornetwork.connect(iso_l_con[2], rho[3]) tensornetwork.connect(iso_c_con[2], rho[4]) tensornetwork.connect(iso_r_con[2], rho[5]) # FIXME: Check that this is giving us a good path! out.append( contractors.branch(tensornetwork.reachable(rho), nbranch=2).get_tensor()) return 0.5 * sum(out)
def contract_network(edges: Sequence[tn.Edge]) -> tn.Node: network = set() for edge in edges: network |= tn.reachable(edge) return cn.greedy(network, output_edge_order=edges)