Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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