def test_prime_power_hash_examples(): # Tests that two C-shaped prime power graphs are equivalent prime, power = 2, 2 e1 = [((0, 1), (1, 1), 1), ((1, 0), (0, 0), 1), ((0, 0), (0, 1), 1)] e2 = [((0, 1), (1, 1), 1), ((1, 0), (0, 0), 1), ((1, 0), (1, 1), 1)] g1 = create_prime_power_graph(e1, prime, power) g2 = create_prime_power_graph(e2, prime, power) assert hash_graph(g1) == hash_graph(g2) # Tests upper ququart bar and lower ququart bar inequivalent e1 = [((1, 0), (0, 0), 1)] e2 = [((0, 1), (1, 1), 1)] g1 = create_prime_power_graph(e1, prime, power) g2 = create_prime_power_graph(e2, prime, power) assert hash_graph(g1) == hash_graph(g2) # Tests both ququart zigzags are equivalent e1 = [((0, 1), (1, 1), 1), ((1, 0), (0, 0), 1), ((0, 0), (1, 1), 1)] e2 = [((0, 1), (1, 1), 1), ((1, 0), (0, 0), 1), ((0, 1), (1, 0), 1)] g1 = create_prime_power_graph(e1, prime, power) g2 = create_prime_power_graph(e2, prime, power) assert hash_graph(g1) == hash_graph(g2) # Checks two-bar and rotated two-bar ququarts are inequivalent e1 = [((0, 1), (1, 1), 1), ((0, 0), (1, 0), 1)] e2 = [((0, 0), (0, 1), 1), ((1, 0), (1, 1), 1)] g1 = create_prime_power_graph(e1, prime, power) g2 = create_prime_power_graph(e2, prime, power) assert hash_graph(g1) == hash_graph(g2)
def queued_orbit_search(init_graph, local_ops, save_edges, verbose): # Initialises class graph with init_graph init_edges = list(init_graph.edges()) init_hash = hash_graph(init_graph) class_graph = nx.Graph() class_graph.add_node(0, nx_graph=init_graph, edges=init_edges, hash=init_hash) class_graph.member_hash_table = {init_hash: 0} # Loops over queue members until empty queue = [0] visited = 0 while queue: # Prints live count of explored/known if verbose: out = \ str(visited) + '/' + str(len(queue) + visited) + ' visited (' \ + str(int(100 * float(visited)/(len(queue) + visited))) + '%)' sys.stdout.write('%s\r' % out) sys.stdout.flush() visited += 1 # Gets next graph on queue and finds representative nodes graph_label = queue.pop() graph = class_graph.node[graph_label]['nx_graph'] node_equivs = find_rep_nodes(graph) # Applies set of local ops to each representative node for rep_node, equiv_nodes in node_equivs.iteritems(): for op_label, local_op in local_ops: new_graph = local_op(graph, rep_node) new_edges = list(new_graph.edges()) new_hash = hash_graph(new_graph) # Checks new graph is difference to original if sorted(new_graph.edges(data='weight')) == \ sorted(graph.edges(data='weight')): continue # If different, tries to find new graph in class try: old_label = class_graph.member_hash_table[new_hash] if save_edges: # If new edge adds new edge between members if not class_graph.has_edge(graph_label, old_label): class_graph.add_edge(graph_label, old_label, equivs=[equiv_nodes], ops=[op_label]) # Else adds any new local ops to edge label elif op_label not in \ class_graph[graph_label][old_label]['ops']: class_graph[graph_label][old_label]['ops']\ .append(op_label) class_graph[graph_label][old_label]['equivs']\ .append(equiv_nodes) continue # If not in class, creates new class graph node except KeyError: new_label = max(class_graph.nodes()) + 1 class_graph.add_node(new_label, nx_graph=new_graph, edges=new_edges, hash=new_hash) if save_edges: class_graph.add_edge(graph_label, new_label, equivs=[equiv_nodes], ops=[op_label]) class_graph.member_hash_table.update({new_hash: new_label}) queue.append(new_label) return class_graph
def test_hash_graph(): for _ in range(100): g = gen_random_connected_graph(10) relab_g = random_relabel(g) assert hash_graph(g) == hash_graph(relab_g)
def find_all_classes(directory, power, prime): """ Finds all members of all classes """ # Gets edge indices and state params and generates edge map filename = directory + '/edge_index.csv' with open(filename, 'r') as file: reader = csv.reader(file) edge_index = [tuple(map(int, edge)) for edge in reader] filename = directory + '/state_params.csv' with open(filename, 'r') as file: reader = csv.reader(file) p, m, n = map(int, next(reader)) c_map = gen_psuedo_graph_edge_map(p, m) # Creates function to produce config isomorphs isomorph_configs = make_isomorph_func(edge_index, n) pprint(c_map) pprint(edge_index) # Initialises progress bar rg_file = directory + '/remaining_graphs.csv' rem_graphs_size = os.path.getsize(rg_file) pbar = tqdm(total=rem_graphs_size) while True: rem_update = rem_graphs_size - os.path.getsize(rg_file) if rem_update >= 0: pbar.update(rem_update) rem_graphs_size = os.path.getsize(rg_file) # Waits until a graph is available to process edge_config = get_next_graph(directory) if not edge_config: break tqdm.write("Psuedo edge config: %s" % (edge_config, )) # Create initial graph c_edges = [(u, v, w) for (u, v), w in zip(edge_index, edge_config)] init_graph = create_psuedo_graph(c_edges, p, m, c_map) # Checks if graph is connected if not nx.is_connected(init_graph.to_undirected()): tqdm.write("Disconnected. Removing isomorphs... ") # Removes any isomorphic graphs from remaining remove_disconnected_configs(directory, edge_config, isomorph_configs) tqdm.write("Done") continue init_graph = psuedo_to_real(init_graph) # Check if graph has already been found for hash test graph_hash = hash_graph(init_graph) if found_hash(directory, graph_hash): tqdm.write("Already found %d" % graph_hash) iso_configs = isomorph_configs(edge_config) remove_found_graphs(directory, iso_configs) continue # Explore class graph tqdm.write("Exploring class...") class_graph = explore_lc_orbit(init_graph, False, False) class_register = [[ node, attrs['edges'], attrs['hash'], attrs['nx_graph'] ] for node, attrs in class_graph.node.iteritems()] nodes, edges, hashes, graphs = zip(*class_register) # Formats edge list based on state parameters if power == 1: edges = [[(u, v, c) for (u, i), (v, j), c in edge_set] for edge_set in edges] if prime == 2: edges = [[(u, v) for u, v, c in edge_set] for edge_set in edges] # Exports class_register to file tqdm.write("Writing register to file...") class_register = zip(nodes, edges, hashes) config_label = '_'.join(map(str, edge_config)) filename = directory + '/classes/' + config_label + '.csv' with open(filename, 'w') as csvfile: writer = csv.writer(csvfile) writer.writerows(class_register) # Finds and removes any isomorphs tqdm.write("Removing isomorphs...") psu_edges = [ real_graph_to_psu_edges(graph, c_map, edge_index) for graph in graphs ] edge_configs = [[c for u, v, c in w_edges] for w_edges in psu_edges] iso_configs = [ iso_config for config in edge_configs for iso_config in isomorph_configs(config) ] remove_found_graphs(directory, iso_configs) # Adds hashes to found hash directory write_hashes(directory, hashes) tqdm.write("Done") pbar.close()