Beispiel #1
0
def find_rep_nodes(nx_g):
    """
    Takes a NetworkX graph and finds groups of nodes that are equivalent
    up to automorphism
    """
    # Creates PyNauty graph and passes it to PyNauty to get orbits
    partition = 'member' if nx_g.__dict__.get('power', 1) > 1 else None
    pyn_g, node_map = convert_nx_to_pyn(nx_g, partition=partition)
    _, _, _, orbits, _ = pyn.autgrp(pyn_g)
    # Finds node equivalency dictionary
    node_equivs = defaultdict(list)
    for node, equiv in enumerate(orbits):
        node_equivs[node_map[equiv]].append(node_map[node])
    # If multigraph, returns orbits of nodes in first layer
    if nx_g.__dict__.get('dimension', 2) > 2:
        node_equivs = {
            u: [v for l_v, v in equivs if l_v == 0]
            for (l_u, u), equivs in list(node_equivs.items()) if l_u == 0
        }
    else:
        node_equivs = {
            node: equivs
            for node, equivs in node_equivs.items() if nx_g.degree(node) > 1
        }
    return node_equivs
Beispiel #2
0
def bindByOrbits(graph1, graph2):
    bondedGraphs = []
    orbits1 = autgrp(graph1)[3]
    orbits2 = autgrp(graph2)[3]

    verticesByOrbit1 = getVerticesByOrbit(orbits1)
    verticesByOrbit2 = getVerticesByOrbit(orbits2)
    for vertex1 in verticesByOrbit1.values():
        for vertex2 in verticesByOrbit2.values():
            g1VertexDegree = graph1.getVertexDegree(vertex1)
            g2VertexDegree = graph2.getVertexDegree(vertex2)
            if g1VertexDegree != g2VertexDegree:
                continue

            g1 = deepcopy(graph1)
            g2 = deepcopy(graph2)

            g1.setBindVertex(vertex1)
            g2.setBindVertex(vertex2)

            bondedGraphs.append(bindGraph(g1, g2))
    return bondedGraphs
def apply_to_all_ged_k(G, k, f, statistic=np.mean):
    """                              
    f is the function to apply. Must take (G,aut)
    """
    results = []
    edges = [(u, v) for u, v in G.edges()]
    for edges_to_remove in combinations(edges, k):
        G1 = copy.deepcopy(G)
        for e in edges_to_remove:
            assert (len(e) == 2)
            G1.remove_edge(*e)
        g = pynauty.Graph(number_of_vertices=G1.number_of_nodes(),
                          directed=nx.is_directed(G1),
                          adjacency_dict=get_adjacency_dict(G1))
        aut = pynauty.autgrp(g)
        results.append(f(G1, aut))
    return statistic(results)
Beispiel #4
0
def compute_orbits(node_list, A):
    '''
    WARN:
      node_list & A should be a connected component. Don't input multiple connected components.
    args:
      node_list e.g. ['C', 'N', 'N', 'C', 'C', 'O', 'P', 'O', 'C']
      A adj mat n x n np array. 0 edge absent. >0 edge present. Edge colors & edge weights are ignored.
    returns:
      orbit labels. 1 label per atom.
      number of orbit partitions. scalar.
    '''
    A = adj_mat_2_adj_dict(A)
    vertex_coloring = node_list_2_vertex_coloring(node_list)
    G = pynauty.Graph(number_of_vertices=len(node_list), 
                    directed=False,
                    adjacency_dict=A,
                    vertex_coloring=vertex_coloring)
    automorphism_group = pynauty.autgrp(G)  #return -> (generators, grpsize1, grpsize2, orbits, numorbits)
    # print('automorphism_group', automorphism_group)
    n_orbits = automorphism_group[-1] # e.g. 3
    orbits = automorphism_group[-2]   # e.g. [0 1 2 2 1 0]
    return orbits, n_orbits
 print(args.files)
 for fname in progressbar.progressbar(glob.glob(args.files)):
     # TODO: check if the row is already there. If it is, check what fields it already has
     name = Path(fname).name
     if name in precomputed_names:
         # if it's already there, update
         s = df.loc[name]
         existing_columns = set(s.where(s.notna()).dropna().index)
         columns_to_compute = expected_features - existing_columns
         elist = s['elist']
         G = nx.OrderedGraph()
         G.add_edges_from(elist)
         g = pynauty.Graph(number_of_vertices=G.number_of_nodes(),
                           directed=nx.is_directed(G),
                           adjacency_dict=get_adjacency_dict(G))
         aut = pynauty.autgrp(g)
         for feature_name in columns_to_compute:
             df.at[name, feature_name] = float(
                 feature_getter_dispatcher(feature_name, G, aut))
     else:
         # if it's not there yet, build a dictionary with all the stuff
         elist, p, res = pickle.load(open(fname, "rb"))
         d = {
             'name': name,
             'p': float(p),
             'elist': copy.deepcopy(elist),
             'res': copy.deepcopy(res)
         }
         G = nx.OrderedGraph()
         G.add_edges_from(elist)
         g = pynauty.Graph(number_of_vertices=G.number_of_nodes(),
Beispiel #6
0
def calculate_platform_symmetries(cfg):
    """Calculate the Automorphism Group of a Platform Graph

    This task expects three hydra parameters to be available.


    **Hydra Parameters**:
        * **platform:** the input platform. The task expects a configuration
          dict that can be instantiated to a
          :class:`~mocasin.common.platform.Platform` object.
        * **out:** the output file (extension will be added)
        * **mpsym:** a boolean value selecting mpsym as backend (and JSON as output)
        Otherwise it outputs plaintext from the python implementation.
    """
    platform = hydra.utils.instantiate(cfg["platform"])
    log.info("start converting platform to edge graph for automorphisms.")
    plat_graph = platform.to_adjacency_dict(include_proc_type_labels=True)
    use_mpsym = cfg["mpsym"]

    (
        adjacency_dict,
        num_vertices,
        coloring,
        nodes_correspondence,
    ) = aut.to_labeled_edge_graph(plat_graph)
    log.info("done converting platform to edge graph for automorphisms.")
    # print(nodes_correspondence)
    # print(coloring)
    # print(len(coloring))
    # print(str(edge_graph))
    log.info(
        "start calculating the automorphism group of the (edge) graph with " +
        str(num_vertices) + " nodes using nauty.")
    nautygraph = pynauty.Graph(num_vertices, True, adjacency_dict, coloring)
    autgrp_edges = pynauty.autgrp(nautygraph)
    log.info(
        "done calculating the automorphism group of the (edge) graph using nauty."
    )

    log.info("start coverting automorhpism of edges to nodes.")
    autgrp, new_nodes_correspondence = aut.edge_to_node_autgrp(
        autgrp_edges[0], nodes_correspondence)
    permutations_lists = map(aut.list_to_tuple_permutation, autgrp)
    # permutations = map(perm.Permutation,permutations_lists)
    # permgrp = perm.PermutationGroup(list(permutations))
    # print(permgrp.point_orbit(0))
    log.info("done coverting automorhpism of edges to nodes.")

    log.info("start writing to file.")
    if use_mpsym:
        try:
            mpsym
        except NameError:
            log.error(
                "Configured for mpsym output but could not load mpsym. Fallback to python implementation"
            )
            use_mpsym = False

    if use_mpsym:
        out_filename = str(cfg["out_file"])
        mpsym_autgrp = mpsym.ArchGraphAutomorphisms(
            [mpsym.Perm(g) for g in autgrp])
        json_out = mpsym_autgrp.to_json()
        with open(out_filename, "w") as f:
            f.write(json_out)
    else:
        out_filename = cfg["out_file"]
        with open(out_filename, "w") as f:
            f.write("Platform Graph:")
            f.write(str(plat_graph))
            # f.write("Edge Group with ~" + str(autgrp_edges[1]) + " * 10^" + str(autgrp_edges[2]) + " elements.\n")
            f.write("Symmetry group generators:")
            f.write(str(list(permutations_lists)))
            f.write("\nCorrespondence:")
            f.write(str(new_nodes_correspondence))

    log.info("done writing to file.")
Beispiel #7
0
            adjacency_dict[variable_index].append(intermediate_vertex_index)
            num_vertices += 1

# So, in building the adjacency dict, we want to colour constraints in one colour (maybe this changes in the future).
# We then want to partition the variables by their upper bound, lower bound and their value (if any) in the objective function

# Inefficient to itereate through yet again but want it to be as obvious as possible what's going on
# I think that we may also need to consider constraint colourings!
variable_colouring_dict = defaultdict(set)
for n, variable in model.vd.items():
    variable_index = graph_indices[variable.name]
    obj_coef = obj_var_coefs[
        variable.name] if variable.name in obj_var_coefs else 0
    variable_colouring_dict[(variable.lb, variable.ub,
                             obj_coef)].add(variable_index)

# Let's look at some constraint colourings
constraint_colouring_dict = defaultdict(set)
for n, constraint in model.c.items():
    constraint_index = graph_indices[constraint.name]
    constraint_colouring_dict[(constraint.lb, constraint.ub,
                               constraint.rhs)].add(constraint_index)

vertex_colourings = []
vertex_colourings.extend(variable_colouring_dict.values())
vertex_colourings.extend(constraint_colouring_dict.values())

# We haven't yet done the vertex_colourings yet but let's just see what we get for now
graph = pynauty.Graph(num_vertices, False, adjacency_dict, vertex_colourings)
aut = pynauty.autgrp(graph)
print(aut[3])
Beispiel #8
0
#   [[name, Graph, numorbit, grpsize, generators]]
#
# numorbit, grpsize, generators was calculated by dreadnut
#

from data_graphs import graphs


if __name__ == '__main__':
    print('Testing pynauty.autgrp()')
    print('Python version: ' + sys.version)
    print('Starting ...')
    passed = 0
    failed = 0
    for gname, g, numorbit, grpsize, gens in graphs:
        print('%-17s ...' % gname, end=' ')
        sys.stdout.flush()
        generators, order, o2, orbits, orbit_no = autgrp(g)
        if generators == gens and orbit_no == numorbit and order == grpsize:
            print('OK')
            passed += 1
        else:
            print('failed')
            failed +=1
    print('... done.')
    if failed > 0:
        print('passed = %d   failed = %d' % (passed, failed))
    else:
        print('All tests passed.')

Beispiel #9
0
    def __init__(
        self,
        graph,
        platform,
        channels=False,
        periodic_boundary_conditions=False,
        norm_p=2,
        canonical_operations=True,
        disable_mpsym=False,
        disable_symmetries_test=False,
    ):
        self._topologyGraph = platform.to_adjacency_dict(
            include_proc_type_labels=True)
        self.graph = graph
        self.platform = platform
        self._d = len(graph.processes())
        init_app_ncs(self, graph)
        self._arch_nc_inv = {}
        self.channels = channels
        self.boundary_conditions = periodic_boundary_conditions
        self.p = norm_p
        com_mapper = ComFullMapper(graph, platform)
        self.list_mapper = ProcPartialMapper(graph, platform, com_mapper)
        self.canonical_operations = canonical_operations

        n = len(self.platform.processors())
        correct = None

        if disable_mpsym:
            self.sym_library = False
        else:
            try:
                mpsym
            except NameError:
                self.sym_library = False
            else:
                self.sym_library = True
                if hasattr(platform, "ag"):
                    self._ag = platform.ag
                    log.info(
                        "Symmetries initialized with mpsym: Platform Generator."
                    )
                elif hasattr(platform, "ag_json"):
                    if exists(platform.ag_json):
                        self._ag = mpsym.ArchGraphSystem.from_json_file(
                            platform.ag_json)
                        if disable_symmetries_test:
                            log.warning(
                                "Using symmetries JSON without testing.")
                            correct = True
                        else:
                            try:
                                correct = checkSymmetries(
                                    platform.to_adjacency_dict(),
                                    self._ag.automorphisms(),
                                )
                            except Exception as e:
                                log.warning(
                                    "An unknown error occurred while reading "
                                    "the embedding JSON file. Did you provide "
                                    "the correct file for the given platform? "
                                    f"({e})")
                                correct = False
                        if not correct:
                            log.warning(
                                "Symmetries json does not fit platform.")
                            del self._ag
                        else:
                            log.info(
                                "Symmetries initialized with mpsym: JSON file."
                            )
                    else:
                        log.warning(
                            "Invalid symmetries JSON path (file does not exist)."
                        )

                if not hasattr(self, "_ag"):
                    # only calculate this if not already present
                    log.info("No pre-comupted mpsym symmetry group available."
                             " Initalizing architecture graph...")
                    (
                        adjacency_dict,
                        num_vertices,
                        coloring,
                        self._arch_nc,
                    ) = to_labeled_edge_graph(self._topologyGraph)
                    nautygraph = pynauty.Graph(num_vertices, True,
                                               adjacency_dict, coloring)
                    log.info("Architecture graph initialized. Calculating "
                             "automorphism group using Nauty...")
                    autgrp_edges = pynauty.autgrp(nautygraph)
                    autgrp, _ = edge_to_node_autgrp(autgrp_edges[0],
                                                    self._arch_nc)
                    self._ag = mpsym.ArchGraphAutomorphisms(
                        [mpsym.Perm(g) for g in autgrp])
                    for node in self._arch_nc:
                        self._arch_nc_inv[self._arch_nc[node]] = node
                        # TODO: ensure that nodes_correspondence fits simpleVec

        if not self.sym_library:
            log.info(
                "Using python symmetries: Initalizing architecture graph...")
            (
                adjacency_dict,
                num_vertices,
                coloring,
                self._arch_nc,
            ) = to_labeled_edge_graph(self._topologyGraph)
            nautygraph = pynauty.Graph(num_vertices, True, adjacency_dict,
                                       coloring)
            log.info("Architecture graph initialized. Calculating "
                     "automorphism group using Nauty...")
            autgrp_edges = pynauty.autgrp(nautygraph)
            autgrp, _ = edge_to_node_autgrp(autgrp_edges[0], self._arch_nc)
            permutations_lists = map(list_to_tuple_permutation, autgrp)
            permutations = [
                Permutation.fromLists(p, n=n) for p in permutations_lists
            ]
            self._G = PermutationGroup(permutations)
            log.info("Initialized automorphism group with internal symmetries")
Beispiel #10
0
def find_symmetries(model):
    num_vertices = 0
    obj_var_coefs = {}

    # Going to make this really easy initially by iterating through once initially and building up an index map
    graph_indices = {}
    variable_names = {}

    def add_vertex(name, num):
        graph_indices[name] = num
        variable_names[num] = name
        return num + 1

    for n, constraint in model.c.items():
        num_vertices = add_vertex(constraint.name, num_vertices)
        #graph_indices[constraint.name] = num_vertices
        #num_vertices += 1

    for n, variable in model.vd.items():
        num_vertices = add_vertex(variable.name, num_vertices)
        #graph_indices[variable.name] = num_vertices
        #num_vertices += 1

    # The number of vertices before the inclusion of intermediate vertices
    num_model_vertices = num_vertices

    # I think that first, we go through the objective function build a map from variable->onj_coeff
    standard_objective = generate_standard_repn(model.o)
    for i, (variable, coefficient) in enumerate(
            zip(standard_objective.linear_vars,
                standard_objective.linear_coefs)):
        obj_var_coefs[variable.name] = coefficient

    # Should probably look up a slightly nicer way to do this?
    adjacency_dict = defaultdict(list)

    for name, constraint in model.c.items():
        # variables that share a coefficient within a constraint can coalesce their intermediate vertices
        coalesce_dict = {}
        repn = generate_standard_repn(constraint.body)
        constraint_index = graph_indices[constraint.name]
        for coefficient, variable in zip(repn.linear_coefs, repn.linear_vars):
            # So, first we want an intermediate vertex
            variable_index = graph_indices[variable.name]
            if coefficient == 1:
                # For now, if the coefficient is one, we will not use an intermediate vertex
                adjacency_dict[constraint_index].append(variable_index)
            elif coefficient in coalesce_dict:
                intermediate_vertex_index = coalesce_dict[coefficient]
                # The intermediate vertex is already connected to the constraint vertex, so here we just need to connect it to this variable
                adjacency_dict[variable_index].append(
                    intermediate_vertex_index)
            else:
                # We do not yet have an intermediate vertex for this coefficient and vertex, let's make one
                intermediate_vertex_index = num_vertices
                coalesce_dict[coefficient] = intermediate_vertex_index
                adjacency_dict[constraint_index].append(
                    intermediate_vertex_index)
                adjacency_dict[variable_index].append(
                    intermediate_vertex_index)
                num_vertices += 1

    # So, in building the adjacency dict, we want to colour constraints in one colour (maybe this changes in the future).
    # We then want to partition the variables by their upper bound, lower bound and their value (if any) in the objective function

    # Inefficient to itereate through yet again but want it to be as obvious as possible what's going on
    # I think that we may also need to consider constraint colourings!
    variable_colouring_dict = defaultdict(set)
    for n, variable in model.vd.items():
        variable_index = graph_indices[variable.name]
        obj_coef = obj_var_coefs[
            variable.name] if variable.name in obj_var_coefs else 0
        variable_colouring_dict[(variable.lb, variable.ub,
                                 obj_coef)].add(variable_index)

    # Let's look at some constraint colourings
    constraint_colouring_dict = defaultdict(set)
    for n, constraint in model.c.items():
        constraint_index = graph_indices[constraint.name]
        constraint_colouring_dict[(constraint.lb, constraint.ub,
                                   constraint.rhs)].add(constraint_index)

    vertex_colourings = []
    vertex_colourings.extend(variable_colouring_dict.values())
    vertex_colourings.extend(constraint_colouring_dict.values())

    # We haven't yet done the vertex_colourings yet but let's just see what we get for now
    graph = pynauty.Graph(num_vertices, False, adjacency_dict,
                          vertex_colourings)
    aut = pynauty.autgrp(graph)

    symmetry_groups = defaultdict(set)
    for index, min_vertex in enumerate(aut[3][:num_model_vertices]):

        # I think that we're doing it slightly wrong here, we should use the constraint names here
        symmetry_groups[min_vertex].add(variable_names[index])

    return set(map(lambda s: frozenset(s), symmetry_groups.values()))
Beispiel #11
0
    1: [0, 7],
    2: [3, 1],
    3: [2, 5],
    4: [2, 5],
    5: [4, 6],
    6: [0, 7],
    7: [4, 6],
}

if __name__ == "__main__":
    print(list_to_tuple_permutation([0, 1, 2, 4, 3, 5]))  # [[3, 4]]
    print(list_to_tuple_permutation([5, 4, 3, 2, 1,
                                     0]))  # [[0, 5], [1, 4], [2, 3]]
    print(list_to_tuple_permutation([1, 2, 3, 4, 5,
                                     0]))  # [[0, 1, 2, 3, 4, 5]]
    square_aut_grp = pynauty.autgrp(pynauty.Graph(8, True, edge_graph_square))
    print(str(list(map(list_to_tuple_permutation, square_aut_grp[0]))))


def platform_graph_to_num_dict(platform_graph):
    core_to_int = {}
    for i, core in enumerate(platform_graph):
        core_to_int[core] = i
    res = {}
    for core in platform_graph:
        vals = []
        for val in platform_graph[core]:
            vals.append(core_to_int[val[0]])
        res[core_to_int[core]] = set(vals)
    return res