def qubit_LC(graph, node, copy=True): """ Returns the graph for local complementation applied to node """ neighs = graph.neighbors(node) neigh_k_edges = it.combinations(neighs, 2) lc_graph = copy_graph(graph) if copy else graph for u, v in neigh_k_edges: if lc_graph.has_edge(u, v): lc_graph.remove_edge(u, v) else: lc_graph.add_edge(u, v, weight=1) return lc_graph
def qudit_graph_map(nx_wg, partition=None): """ Maps an edge-weighted NX graph to a node-colored NX graph. For prime-power graph states, can colour by member or family. """ # Gets list of all nodes by layer us, vs, weights = zip(*nx_wg.edges.data('weight')) n_layers = int(log(max(weights), 2)) + 1 layers = range(n_layers) # If node is prime power, applies colouring across same member-nodes if nx_wg.__dict__.get('power', 1) > 1: _, m, f = nx_wg.prime, nx_wg.power, nx_wg.families # Partitions based on which member of the family node is if partition == 'member': coloring = [[(l, (n, i)) for n in range(f)] for l in layers for i in range(m)] # Partitions based on which family => must make colourings equiv. elif partition == 'family': # Adds extra nodes to represent exchangeable colours # (see page 60 of nauty user guide v26) nx_wg = copy_graph(nx_wg) for u in range(f): node = (u, m) nx_wg.add_node(node) nx_wg.add_weighted_edges_from([(node, (u, i), 1) for i in range(m)]) coloring = [[(l, (n, i)) for n in range(f) for i in range(m)] for l in layers] + \ [[(l, (n, m)) for n in range(f)] for l in layers] else: raise Exception("Unknown colour scheme provided") else: coloring = [[(l, n) for n in nx_wg.nodes()] for l in layers] # Creates layered graph with vertical edges nx_cg = nx.Graph() v_nodes = [(l, n) for l in layers for n in nx_wg.nodes()] nx_cg.add_nodes_from(v_nodes) v_edges = [((l, n), (l + 1, n)) for n in nx_wg.nodes() for l in layers[:-1]] nx_cg.add_edges_from(v_edges) # Add edges within layers for u, v, w in nx_wg.edges.data('weight'): # Gets binary rep. of weight, padded with zeros (written L to R) bin_w = int_to_bits(w)[::-1] bin_w = bin_w + (n_layers - len(bin_w)) * [0] # Converts binary weight to list of layers and adds edges to graph edge_layers = [l for l, b in enumerate(bin_w) if b] edges = [((l, u), (l, v)) for l in edge_layers] nx_cg.add_edges_from(edges) return nx_cg, coloring
def prime_power_qudit_CC(graph, node, t, a, copy=True): """ Returns graph after controlled complementation """ # Creates new graph if needed new_graph = copy_graph(graph) if copy else graph n, c = node # Adds edge between control and target node if c != t: new_graph.add_edge((n, c), (n, t), weight=1) # Applies LC to control new_graph = prime_qudit_LC(new_graph, (n, c), a, copy=False) # Removes any intra-family edges family_edges = [((u, i), (v, j)) for (u, i), (v, j) in new_graph.edges() if u == v] new_graph.remove_edges_from(family_edges) return new_graph
def prime_qudit_EM(graph, node, b, copy=True): """ Returns the graph for edge multiplication operation applied on node n with weight b """ em_graph = copy_graph(graph) if copy else graph p = graph.prime neighs = em_graph.neighbors(node) for u in neighs: if em_graph.has_edge(node, u): nv_weight = em_graph[node][u]['weight'] new_weight = (b * nv_weight) % p em_graph[node][u]['weight'] = new_weight if em_graph[node][u]['weight'] == 0: em_graph.remove_edge(node, u) return em_graph
def prime_qudit_LC(graph, node, a, copy=True): """ Returns the graph for generalised local complementation applied to node n with weight a """ p = graph.prime neighs = list(graph.neighbors(node)) neigh_k_edges = it.combinations(neighs, 2) lc_graph = copy_graph(graph) if copy else graph for u, v in neigh_k_edges: nu_weight = lc_graph[node][u]['weight'] nv_weight = lc_graph[node][v]['weight'] if lc_graph.has_edge(u, v): uv_weight = lc_graph[u][v]['weight'] new_weight = (uv_weight + a * nv_weight * nu_weight) % p lc_graph[u][v]['weight'] = new_weight else: weight = (a * nv_weight * nu_weight) % p lc_graph.add_edge(u, v, weight=weight) if lc_graph[u][v]['weight'] == 0: lc_graph.remove_edge(u, v) return lc_graph
def apply_qubit_LCs(graph, nodes): """ Applies a sequence of local complementations """ lc_graph = copy_graph(graph) for node in nodes: lc_graph = qubit_LC(lc_graph, node, copy=False) return lc_graph