From 402b31c0e20fc2379f4b7791c9cffa96d408b136 Mon Sep 17 00:00:00 2001 From: Arash Badie-Modiri Date: Wed, 17 Jul 2024 17:29:08 +0200 Subject: [PATCH] use hash on complete invariants instead of str --- pymnet/graphlets/graphlet_measures.py | 23 +++--- pymnet/graphlets/graphlets.py | 96 +++++++++++------------ pymnet/graphlets/independent_equations.py | 28 +++---- pyproject.toml | 2 +- 4 files changed, 71 insertions(+), 78 deletions(-) diff --git a/pymnet/graphlets/graphlet_measures.py b/pymnet/graphlets/graphlet_measures.py index 1813bc6..e1500e6 100644 --- a/pymnet/graphlets/graphlet_measures.py +++ b/pymnet/graphlets/graphlet_measures.py @@ -20,7 +20,7 @@ def orbit_counts_all(net, n, nets, invs, auts, orbit_list, allowed_aspects="all" max number of nodes nets : dict (key: n_nodes, value: list of networks) Graphlets, as produced by graphlets - invs : dict (key: str(complete invariant), value: tuple(n_nodes, net_index in nets)) + invs : dict (key: complete invariant, value: tuple(n_nodes, net_index in nets)) complete invariants of the graphlets, as produced by graphlet auts : dd (key: (n_nodes, net_index, node), value: node) automorphisms, as produced by automorphism_orbits @@ -71,17 +71,21 @@ def orbit_counts_all(net, n, nets, invs, auts, orbit_list, allowed_aspects="all" processed.add(node0) for node_comb in node_sets: sub_net = pymnet.subnet(net, node_comb, layers) - ci_sub = str( - pymnet.get_complete_invariant(sub_net, allowed_aspects=allowed_aspects) - ) + ci_sub = pymnet.get_complete_invariant( + sub_net, allowed_aspects=allowed_aspects) if ci_sub not in invs: raise KeyError( - "The network contains a graphlet not found in the pre-constructed complete invariant dictionary (invs). This can be caused by invs creation not being compatible with the attributes of the network. For example, the network might not be fully interconnected." + "The network contains a graphlet not found in the " + "pre-constructed complete invariant dictionary (invs). " + "This can be caused by invs creation not being compatible " + "with the attributes of the network. For example, the " + "network might not be fully interconnected." ) i = invs[ci_sub][0] j = invs[ci_sub][1] nw = nets[i][j] - iso = pymnet.get_isomorphism(sub_net, nw, allowed_aspects=allowed_aspects) + iso = pymnet.get_isomorphism( + sub_net, nw, allowed_aspects=allowed_aspects) for node in node_comb: if node in iso[0]: orbits[node, (i, j, auts[i, j, iso[0][node]])] += 1 @@ -165,7 +169,7 @@ def orbit_counts( dictionary where the counts will be stored auts : dd (key: (n_nodes, net_index, node), value: node) automorphism orbits - invs : dict (key: str(complete invariant), value: tuple(n_nodes, net_index in nets)) + invs : dict (key: complete invariant, value: tuple(n_nodes, net_index in nets)) complete invariants of the graphlets orbit_list : list of orbits allowed_aspects : list, string @@ -179,9 +183,8 @@ def orbit_counts( node_sets = touching_orbit_nodes(node0, net, n) for nodes_s in node_sets: sub_net = pymnet.subnet(net, nodes_s, layers) - ci_sub = str( - pymnet.get_complete_invariant(sub_net, allowed_aspects=allowed_aspects) - ) + ci_sub = pymnet.get_complete_invariant( + sub_net, allowed_aspects=allowed_aspects) i = invs[ci_sub][1] n_nodes = invs[ci_sub][0] nw = nets[n_nodes][i] diff --git a/pymnet/graphlets/graphlets.py b/pymnet/graphlets/graphlets.py index 0717852..3ace970 100644 --- a/pymnet/graphlets/graphlets.py +++ b/pymnet/graphlets/graphlets.py @@ -29,10 +29,10 @@ def graphlets(n, layers, n_l=None, couplings=None, allowed_aspects="all"): ------- nets : dict (key: n_nodes, value: list of MultiplexNetwork objects) graphlets - invariants : dict (key: str(complete invariant), value: tuple(index in 'nets': n_nodes, index in the list of multiplex networks)) + invariants : dict (key: complete invariant, value: tuple(index in 'nets': n_nodes, index in the list of multiplex networks)) complete invariants of the graphlets, the values can be used to match the graphlets in 'nets' """ - if n_l == None: + if n_l is None: n_l = len(layers) nets = {} @@ -42,17 +42,18 @@ def graphlets(n, layers, n_l=None, couplings=None, allowed_aspects="all"): for net_layers in itertools.combinations(layers, n_l): layer_combs = layer_combinations(net_layers) for layer_comb in layer_combs: - net = pymnet.MultiplexNetwork(couplings=couplings, fullyInterconnected=True) + net = pymnet.MultiplexNetwork( + couplings=couplings, fullyInterconnected=True) for layer in layer_comb: net[0, 1, layer] = 1 for layer in net_layers: net.add_layer(layer) - ci = pymnet.get_complete_invariant(net, allowed_aspects=allowed_aspects) - ci_s = str(ci) - if not ci_s in invariants: - invariants[ci_s] = (2, len(nets2)) + ci = pymnet.get_complete_invariant( + net, allowed_aspects=allowed_aspects) + if ci not in invariants: + invariants[ci] = (2, len(nets2)) nets2.append(net) nets[2] = nets2 @@ -77,13 +78,13 @@ def graphlets(n, layers, n_l=None, couplings=None, allowed_aspects="all"): for layer in net_layers: new_net.add_layer(layer) - # check if isomorphic with a previous graph & add only if not isomorphic + # check if isomorphic with a previous graph & add only + # if not isomorphic ci = pymnet.get_complete_invariant( new_net, allowed_aspects=allowed_aspects ) - ci_s = str(ci) - if not ci_s in invariants: - invariants[ci_s] = (i + 1, len(nets_i_1)) + if ci not in invariants: + invariants[ci] = (i + 1, len(nets_i_1)) nets_i_1.append(new_net) nets[i + 1] = nets_i_1 @@ -106,8 +107,9 @@ def automorphism_orbits(nets, allowed_aspects="all"): ------- auts : dict (key: (n_nodes, net_index, node), value: node_orbit_index) Automorphism orbits. 'n_nodes' is the key in 'nets'. 'net_index' is the - index in the list of networks. 'node' is the node name in the given network. - 'node_orbit_index' gets the same value for nodes that are in the same orbit. + index in the list of networks. 'node' is the node name in the given + network. 'node_orbit_index' gets the same value for nodes that are in + the same orbit. """ auts = dd() @@ -189,7 +191,7 @@ def orbit_equations(n, nets, auts, invs, allowed_aspects="all"): graphlets, as returned by graphlets auts : dd (key: (n_nodes, net_index, node), value: node) automorphisms, as returned by automorphism_orbits - invs : dict (key: str(complete invariant), value: tuple(n_nodes, net_index in nets)) + invs : dict (key: complete invariant, value: tuple(n_nodes, net_index in nets)) complete invariants of the graphlets, as returned by graphlets allowed_aspects : list, string the aspects that can be permutated when computing isomorphisms @@ -248,10 +250,8 @@ def orbit_equations(n, nets, auts, invs, allowed_aspects="all"): comb_nets += add_e_nets for comb_net in comb_nets: - ci_comb = str( - pymnet.get_complete_invariant( - comb_net[0], allowed_aspects=allowed_aspects - ) + ci_comb = pymnet.get_complete_invariant( + comb_net[0], allowed_aspects=allowed_aspects ) iso_net = invs[ci_comb] iso = pymnet.get_isomorphism( @@ -269,7 +269,7 @@ def orbit_equations(n, nets, auts, invs, allowed_aspects="all"): iso_net[1], auts[iso_net[0], iso_net[1], node_o], ) - if not new_orbit in new_orbits: + if new_orbit not in new_orbits: new_orbits.add(new_orbit) new_nets[new_orbit] = comb_net @@ -337,9 +337,8 @@ def subtrahend(orbit1, orbit2, nets, auts, invs, allowed_aspects="all"): for nodes_s in partition: nodes_g = set(nodes_s) | set([the_node]) sub_net = pymnet.subnet(net1, nodes_g, layers) - ci_sub = str( - pymnet.get_complete_invariant(sub_net, allowed_aspects=allowed_aspects) - ) + ci_sub = pymnet.get_complete_invariant( + sub_net, allowed_aspects=allowed_aspects) if ci_sub in invs and invs[ci_sub] == (n_nodes2, orbit2[1]): iso = pymnet.get_isomorphism( sub_net, net2, allowed_aspects=allowed_aspects @@ -439,7 +438,8 @@ def combine_orbits(orbit1, orbit2, nets, allowed_aspects="all"): new_net[e[0], e[1], e[2], e[3]] = e[4] new_nets.append(new_net) - ci = str(pymnet.get_complete_invariant(new_net, allowed_aspects=allowed_aspects)) + ci = pymnet.get_complete_invariant( + new_net, allowed_aspects=allowed_aspects) new_invs.add(ci) if allowed_aspects != [0]: @@ -453,10 +453,9 @@ def combine_orbits(orbit1, orbit2, nets, allowed_aspects="all"): if e[0] != e[1]: new_net[e[0], e[1], e[2], e[3]] = e[4] - ci = str( - pymnet.get_complete_invariant(new_net, allowed_aspects=allowed_aspects) - ) - if not ci in new_invs: + ci = pymnet.get_complete_invariant( + new_net, allowed_aspects=allowed_aspects) + if ci not in new_invs: new_nets.append(new_net) new_invs.add(ci) @@ -532,10 +531,9 @@ def merge_nodes(both_orbit_nodes, net, allowed_aspects="all"): if neighbor[0] != node2: new_net[node1, neighbor[0], layer, neighbor[1]] = 1 - ci = str( - pymnet.get_complete_invariant(new_net, allowed_aspects=allowed_aspects) - ) - if not ci in new_invs: + ci = pymnet.get_complete_invariant( + new_net, allowed_aspects=allowed_aspects) + if ci not in new_invs: new_nets.append(new_net) new_nets_and_nodes.append((new_net, both_orbit_nodes + [node1])) new_invs.add(ci) @@ -711,25 +709,27 @@ def coefficient_help( net2 = nets[orbit2[0]][orbit2[1]] n_nodes1 = len(net1.slices[0]) - for node_comb in itertools.combinations(nodes, n_nodes1 - len(both_orbit_nodes)): + node_combs = itertools.combinations( + nodes, n_nodes1 - len(both_orbit_nodes)) + for node_comb in node_combs: nodes_s2 = nodes_a - set(node_comb) nodes_s1 = (nodes_a - nodes_s2) | set(both_orbit_nodes) sub1 = pymnet.subnet(net, nodes_s1, layers) sub2 = pymnet.subnet(net, nodes_s2, layers) - ci_sub1 = str( - pymnet.get_complete_invariant(sub1, allowed_aspects=allowed_aspects) - ) - ci_sub2 = str( - pymnet.get_complete_invariant(sub2, allowed_aspects=allowed_aspects) - ) - if not ci_sub1 in invs or not ci_sub2 in invs: + ci_sub1 = pymnet.get_complete_invariant( + sub1, allowed_aspects=allowed_aspects) + ci_sub2 = pymnet.get_complete_invariant( + sub2, allowed_aspects=allowed_aspects) + if ci_sub1 not in invs or ci_sub2 not in invs: continue if invs[ci_sub1] == (orbit1[0], orbit1[1]) and invs[ci_sub2] == ( orbit2[0], orbit2[1], ): - iso1 = pymnet.get_isomorphism(sub1, net1, allowed_aspects=allowed_aspects) - iso2 = pymnet.get_isomorphism(sub2, net2, allowed_aspects=allowed_aspects) + iso1 = pymnet.get_isomorphism(sub1, net1, + allowed_aspects=allowed_aspects) + iso2 = pymnet.get_isomorphism(sub2, net2, + allowed_aspects=allowed_aspects) if the_node in iso1[0]: iso_node1 = iso1[0][the_node] else: @@ -754,7 +754,7 @@ def orbit_name(node, net, nets, invs, auts, allowed_aspects="all"): finds the name of the orbit given node and net """ - ci = str(pymnet.get_complete_invariant(net, allowed_aspects=allowed_aspects)) + ci = pymnet.get_complete_invariant(net, allowed_aspects=allowed_aspects) i, j = invs[ci] net_i = nets[i][j] iso = pymnet.get_isomorphism( @@ -765,9 +765,8 @@ def orbit_name(node, net, nets, invs, auts, allowed_aspects="all"): return (i, j, k) -def partitions( - s, r -): # Gareth Rees https://stackoverflow.com/questions/14559946/producing-all-groups-of-fixed-length-combinations +# Gareth Rees https://stackoverflow.com/questions/14559946/producing-all-groups-of-fixed-length-combinations +def partitions(s, r): """ Generate partitions of the iterable `s` into subsets of size `r`. @@ -787,9 +786,8 @@ def partitions( yield (first_subset,) + p -def partitions_with_remainder( - s, r -): # Gareth Rees https://stackoverflow.com/questions/14559946/producing-all-groups-of-fixed-length-combinations +# Gareth Rees https://stackoverflow.com/questions/14559946/producing-all-groups-of-fixed-length-combinations +def partitions_with_remainder(s, r): """ Generate partitions of the iterable `s` into subsets of size `r` plus a remainder. @@ -800,7 +798,7 @@ def partitions_with_remainder( [((0, 1, 2),), ((1, 2), (0,)), ((0, 2), (1,)), ((0, 1), (2,))] """ s = set(s) - for n in xrange(len(s), -1, -r): # n is size of remainder. + for n in range(len(s), -1, -r): # n is size of remainder. if n == 0: for p in partitions(s, r): yield p diff --git a/pymnet/graphlets/independent_equations.py b/pymnet/graphlets/independent_equations.py index 72a6613..41b682a 100644 --- a/pymnet/graphlets/independent_equations.py +++ b/pymnet/graphlets/independent_equations.py @@ -34,7 +34,8 @@ def independent_equations(n, n_l, layers, allowed_aspects="all"): Implemented for up to 4-node graphlets """ - nets, invs = graphlets.graphlets(n, layers, n_l, allowed_aspects=allowed_aspects) + nets, invs = graphlets.graphlets( + n, layers, n_l, allowed_aspects=allowed_aspects) auts = graphlets.automorphism_orbits(nets, allowed_aspects=allowed_aspects) orbit_lists = graphlets.list_orbits(auts) eqs = graphlets.orbit_equations( @@ -54,7 +55,8 @@ def independent_equations(n, n_l, layers, allowed_aspects="all"): continue eqNet = eq_network( - undefined, set_eqs, n, nets, auts, invs, allowed_aspects=allowed_aspects + undefined, set_eqs, n, nets, auts, invs, + allowed_aspects=allowed_aspects ) for eq in eqs_sub: @@ -285,7 +287,7 @@ def eq_network(undefined, set_eqs, max_nodes, nets, auts, invs, allowed_aspects= graphlets auts : dd (key: (n_nodes, net_index, node), value: node) automorphisms - invs : dict (key: str(complete invariant), value: tuple(n_nodes, net_index in nets)) + invs : dict (key: complete invariant, value: tuple(n_nodes, net_index in nets)) complete invariants of the graphlets allowed_aspects : list, string the aspects that can be permutated when computing isomorphisms @@ -359,7 +361,6 @@ def eq_network(undefined, set_eqs, max_nodes, nets, auts, invs, allowed_aspects= def too_many_nodes(eq, orbit, max_nodes): - n = orbit[0] if len(eq[0]) != 3: @@ -382,12 +383,11 @@ def too_many_nodes(eq, orbit, max_nodes): def find_equations(orbit, eq, set_eqs): - eqs = set() for orbit_eq in set_eqs[eq]: key = find_key(orbit, orbit_eq, set_eqs) - if key != None: + if key is not None: eqs.add(key) else: eqs = set() @@ -397,7 +397,6 @@ def find_equations(orbit, eq, set_eqs): def find_key(orbit1, orbit2, eqs): - if orbit1 == orbit2 and (orbit1, 2) in eqs: return (orbit1, 2) @@ -442,7 +441,8 @@ def three_orbit_equations( else: sub = graphlets.subtrahend( - orbit, orbit1, nets, auts, invs, allowed_aspects=allowed_aspects + orbit, orbit1, nets, auts, invs, + allowed_aspects=allowed_aspects ) key = find_key(orbit, orbit1, set_eqs) if sub == 0: @@ -498,7 +498,6 @@ def three_orbit_equations( def all_inds_and_deps(eq_net): - eqs = [] eq_is = [] eq_edges = [] @@ -530,13 +529,10 @@ def all_inds_and_deps(eq_net): eq_net_best = eq_net.copy() max_deps = len(dependent) - # break # remove this!!! only for 4-node 3-layer vertex isomorphism - return inds, deps, eq_net_best def SCCs(net): - net_r = reverse(net) post = DFS(net_r) @@ -556,7 +552,6 @@ def SCCs(net): def reverse(eq_net): - net_r = {} for eq in eq_net: @@ -570,12 +565,11 @@ def reverse(eq_net): def explore(v, net, visited, post): - visited_c = visited.copy() visited_c.add(v) if len(net[v]) > 0: for u in net[v]: - if not u in visited_c: + if u not in visited_c: visited_c, post = explore(u, net, visited_c, post) post.append(v) @@ -584,18 +578,16 @@ def explore(v, net, visited, post): def DFS(net): - visited = set() post = [] for v in net: - if not v in visited: + if v not in visited: visited, post = explore(v, net, visited, post) return post def independents_and_dependents(SCC, eq_net): - independent = set() dependent = set() diff --git a/pyproject.toml b/pyproject.toml index c99907d..33b4ab6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "numpy >= 1.23.0", "scipy >= 1.10.0", "networkx >= 2.0, < 4.0", - "bliss-bind >= 0.2.0 ; (sys_platform == 'darwin' or ( (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32') )) and python_version >= '3.8'" + "bliss-bind >= 0.3.0 ; (sys_platform == 'darwin' or ( (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32') )) and python_version >= '3.8'" ] [project.urls]