def test_crazy_linear_graph_builder(): """ Tests a 10-node crazy linear graph correctly built """ l, n = 5, 3 g = linear_graph(l) cg = make_crazy(g, n) cg_nodes, cg_edges = process_graph_nodes_edges(cg) nodes = {(i, 0): [((i, 0), j) for j in range(n)] for i in range(l)} edges = [((i, 0), (i + 1, 0)) for i in range(l - 1)] edges = sorted(flatten([it.product(nodes[u], nodes[v]) for u, v in edges])) nodes = sorted(flatten(nodes.values())) assert cg_nodes == nodes assert cg_edges == edges
def make_crazy(graph, n): """ Converts a graph into it's crazily encoded version """ # Defines groupings of crazy nodes and edges between them crazy_nodes = {node: [(node, i) for i in range(n)] for node in graph.nodes()} crazy_edges = flatten([it.product(crazy_nodes[u], crazy_nodes[v]) for u, v in graph.edges()]) # Creates graph and adds edges and nodes crazy_graph = nx.Graph() crazy_graph.add_nodes_from(flatten(crazy_nodes.values())) crazy_graph.add_edges_from(crazy_edges) # Assigns encoded attribute for to_GraphState crazy_graph.encoded = True return crazy_graph
def square_lattice(n, m, boundary=True): """ Creates a square lattice with 2D coordinates """ mod_n = n + 1 if boundary else n mod_m = m + 1 if boundary else m g = nx.Graph() nodes = list(it.product(range(n), range(m))) edges = flatten([[((i, j), ((i + 1) % mod_n, j)), ((i, j), (i, (j + 1) % mod_m))] for i, j in nodes]) edges = [((u_x, u_y), (v_x, v_y)) for (u_x, u_y), (v_x, v_y) in edges if max([u_x, v_x]) < n and max([u_y, v_y]) < m] g.add_edges_from(edges) return g
def make_ghz_like(graph, n): """ Converts a graph into it's GHZ-encoded version """ # Defines groupings of GHZ-like nodes and edges between them ghz_nodes = {node: [(node, i) for i in range(n)] for node in graph.nodes()} ghz_edges = [((u, 0), (v, 0)) for u, v in graph.edges()] + \ [((node, 0), (node, i)) for node in graph.nodes() for i in range(1, n)] # Creates graph and adds edges and nodes ghz_graph = nx.Graph() ghz_graph.add_nodes_from(flatten(ghz_nodes.values())) ghz_graph.add_edges_from(ghz_edges) # Assigns encoded attribute for to_GraphState ghz_graph.encoded = True return ghz_graph
def are_lc_equiv(g1, g2): """ Tests whether two graphs are equivalent up to local complementation. If True, also returns every unitary such that |g2> = U|g1>. """ # Gets adjacency matrices and returns false if differing bases am1, k1 = get_adjacency_matrix(g1) am2, k2 = get_adjacency_matrix(g2) dim1, dim2 = len(k1), len(k2) if k1 != k2 or am1.shape != (dim1, dim1) or am2.shape != (dim2, dim2): return False, None # Defines binary matrices Id = sp.eye(dim1) S1 = sp.Matrix(am1).col_join(Id) S2 = sp.Matrix(am2).col_join(Id) # Defines symbolic variables A = sp.symbols('a:' + str(dim1), bool=True) B = sp.symbols('b:' + str(dim1), bool=True) C = sp.symbols('c:' + str(dim1), bool=True) D = sp.symbols('d:' + str(dim1), bool=True) # Defines solution matrix basis abcd = flatten(list(zip(A, B, C, D))) no_vars = len(abcd) no_qubits = no_vars // 4 # Creates symbolic binary matrix A, B, C, D = sp.diag(*A), sp.diag(*B), sp.diag(*C), sp.diag(*D) Q = A.row_join(B).col_join(C.row_join(D)) P = sp.zeros(dim1).row_join(Id).col_join(Id.row_join(sp.zeros(dim1))) # Constructs matrix to solve X = [i for i in S1.T * Q.T * P * S2] X = np.array([[x.coeff(v) for v in abcd] for x in X], dtype=int) # Removes any duplicated and all-zero rows X = np.unique(X, axis=0) X = X[~(X == 0).all(1)] # Finds the solutions (the nullspace of X) V = list(GF2nullspace(X)) if len(V) > 4: V = [(v1 + v2) % 2 for v1, v2 in it.combinations(V, 2)] else: V = [sum(vs) % 2 for vs in powerset(V)] V = [np.reshape(v, (no_qubits, 4)) for v in V] V = [v for v in V if all((a * d + b * c) % 2 == 1 for a, b, c, d in v)] if V: V = [[bin2gate[tuple(r)] for r in v] for v in V] return True, V else: return False, None