Пример #1
0
def test_empty_graph_hash():
    G1 = nx.empty_graph()
    G2 = nx.empty_graph()

    h1 = nx.weisfeiler_lehman_graph_hash(G1)
    h2 = nx.weisfeiler_lehman_graph_hash(G2)

    assert h1 == h2
Пример #2
0
def test_directed():
    G1 = nx.DiGraph()
    G1.add_edges_from([(1, 2), (2, 3), (3, 1), (1, 5)])

    h_directed = nx.weisfeiler_lehman_graph_hash(G1)

    G2 = G1.to_undirected()
    h_undirected = nx.weisfeiler_lehman_graph_hash(G2)

    assert h_directed != h_undirected
Пример #3
0
def test_relabel():
    G1 = nx.Graph()
    G1.add_edges_from([(1, 2, {'label': 'A'}),
                       (2, 3, {'label': 'A'}),
                       (3, 1, {'label': 'A'}),
                       (1, 4, {'label': 'B'})])
    h_before = nx.weisfeiler_lehman_graph_hash(G1, edge_attr='label')

    G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()})

    h_after = nx.weisfeiler_lehman_graph_hash(G2, edge_attr='label')

    assert h_after == h_before
def test_directed():
    """
    A directed graph with no bi-directional edges should yield different a graph hash
    to the same graph taken as undirected if there are no hash collisions.
    """
    r = 10
    for i in range(r):
        G_directed = nx.gn_graph(10 + r, seed=100 + i)
        G_undirected = nx.to_undirected(G_directed)

        h_directed = nx.weisfeiler_lehman_graph_hash(G_directed)
        h_undirected = nx.weisfeiler_lehman_graph_hash(G_undirected)

        assert h_directed != h_undirected
def test_isomorphic():
    """
    graph hashes should be invariant to node-relabeling (when the output is reindexed
    by the same mapping)
    """
    n, r = 100, 10
    p = 1.0 / r
    for i in range(1, r + 1):
        G1 = nx.erdos_renyi_graph(n, p * i, seed=200 + i)
        G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()})

        g1_hash = nx.weisfeiler_lehman_graph_hash(G1)
        g2_hash = nx.weisfeiler_lehman_graph_hash(G2)

        assert g1_hash == g2_hash
def test_reversed():
    """
    A directed graph with no bi-directional edges should yield different a graph hash
    to the same graph taken with edge directions reversed if there are no hash collisions.
    Here we test a cycle graph which is the minimal counterexample
    """
    G = nx.cycle_graph(5, create_using=nx.DiGraph)
    nx.set_node_attributes(G, {n: str(n) for n in G.nodes()}, name="label")

    G_reversed = G.reverse()

    h = nx.weisfeiler_lehman_graph_hash(G, node_attr="label")
    h_reversed = nx.weisfeiler_lehman_graph_hash(G_reversed, node_attr="label")

    assert h != h_reversed
def test_digest_size():
    """
    The hash string lengths should be as expected for a variety of graphs and
    digest sizes
    """
    n, r = 100, 10
    p = 1.0 / r
    for i in range(1, r + 1):
        G = nx.erdos_renyi_graph(n, p * i, seed=1000 + i)

        h16 = nx.weisfeiler_lehman_graph_hash(G)
        h32 = nx.weisfeiler_lehman_graph_hash(G, digest_size=32)

        assert h16 != h32
        assert len(h16) == 16 * 2
        assert len(h32) == 32 * 2
def test_isomorphic_edge_attr():
    """
    Isomorphic graphs with differing edge attributes should yield different graph
    hashes if the 'edge_attr' argument is supplied and populated in the graph,
    and there are no hash collisions.
    The output should still be invariant to node-relabeling
    """
    n, r = 100, 10
    p = 1.0 / r
    for i in range(1, r + 1):
        G1 = nx.erdos_renyi_graph(n, p * i, seed=300 + i)

        for a, b in G1.edges:
            G1[a][b]["edge_attr1"] = f"{a}-{b}-1"
            G1[a][b]["edge_attr2"] = f"{a}-{b}-2"

        g1_hash_with_edge_attr1 = nx.weisfeiler_lehman_graph_hash(
            G1, edge_attr="edge_attr1"
        )
        g1_hash_with_edge_attr2 = nx.weisfeiler_lehman_graph_hash(
            G1, edge_attr="edge_attr2"
        )
        g1_hash_no_edge_attr = nx.weisfeiler_lehman_graph_hash(G1, edge_attr=None)

        assert g1_hash_with_edge_attr1 != g1_hash_no_edge_attr
        assert g1_hash_with_edge_attr2 != g1_hash_no_edge_attr
        assert g1_hash_with_edge_attr1 != g1_hash_with_edge_attr2

        G2 = nx.relabel_nodes(G1, {u: -1 * u for u in G1.nodes()})

        g2_hash_with_edge_attr1 = nx.weisfeiler_lehman_graph_hash(
            G2, edge_attr="edge_attr1"
        )
        g2_hash_with_edge_attr2 = nx.weisfeiler_lehman_graph_hash(
            G2, edge_attr="edge_attr2"
        )

        assert g1_hash_with_edge_attr1 == g2_hash_with_edge_attr1
        assert g1_hash_with_edge_attr2 == g2_hash_with_edge_attr2
Пример #9
0
def fa2_layout(nx_graph, iters=500):
    if (not os.path.exists(CACHE_FOLDER)):
        os.makedirs(CACHE_FOLDER)
    g_hash = nx.weisfeiler_lehman_graph_hash(nx_graph)
    fa2_cached_layout = f"{CACHE_FOLDER}/{g_hash}.fa2"
    if (os.path.isfile(fa2_cached_layout)):
        with open(fa2_cached_layout, 'rb') as fin:
            return pickle.load(fin)

    forceatlas2 = ForceAtlas2(
        # Behavior alternatives
        outboundAttractionDistribution=True,  # Dissuade hubs
        linLogMode=False,  # NOT IMPLEMENTED
        adjustSizes=False,  # Prevent overlap (NOT IMPLEMENTED)
        edgeWeightInfluence=0,

        # Performance
        jitterTolerance=1.0,  # Tolerance
        barnesHutOptimize=True,
        barnesHutTheta=1.2,
        multiThreaded=False,  # NOT IMPLEMENTED

        # Tuning
        scalingRatio=2.0,
        strongGravityMode=False,
        gravity=1.0,

        # Log
        verbose=True)

    positions = forceatlas2.forceatlas2_networkx_layout(nx_graph,
                                                        pos=None,
                                                        iterations=iters)
    with open(fa2_cached_layout, 'wb+') as fout:
        pickle.dump(positions, fout)
    return positions
def test_empty_graph_hash():
    """
    empty graphs should give hashes regardless of other params
    """
    G1 = nx.empty_graph()
    G2 = nx.empty_graph()

    h1 = nx.weisfeiler_lehman_graph_hash(G1)
    h2 = nx.weisfeiler_lehman_graph_hash(G2)
    h3 = nx.weisfeiler_lehman_graph_hash(G2, edge_attr="edge_attr1")
    h4 = nx.weisfeiler_lehman_graph_hash(G2, node_attr="node_attr1")
    h5 = nx.weisfeiler_lehman_graph_hash(
        G2, edge_attr="edge_attr1", node_attr="node_attr1"
    )
    h6 = nx.weisfeiler_lehman_graph_hash(G2, iterations=10)

    assert h1 == h2
    assert h1 == h3
    assert h1 == h4
    assert h1 == h5
    assert h1 == h6
Пример #11
0
    def designated_gate(self):

        # Collect all node-set
        node_combination = []
        n_nodes = len(self.dag.op_nodes())
        node_list_sorted = list(self.dag.op_nodes())

        for i, node in enumerate(reversed(node_list_sorted)):
            if node.type == 'out' or node.name == 'measure':
                continue
            node_list = self.get_node_list(self.dag, node,
                                           self.max_longest_path_length - 1)
            node_combination.extend(node_list)

        if self._debug:
            print("total num of graphs = ", len(node_combination))

        # Nodeset to DAG
        from collections import defaultdict
        subdag_dict = defaultdict(list)
        for i, node_list in enumerate(node_combination):
            if self._debug and i % 100 == 0:
                print(f"node-set to graph... {i}/{len(node_combination)}")
            dag_sub = self.nodeset_to_graph(node_list, self.dag, self.level)
            if nx.dag_longest_path_length(
                    dag_sub) >= self.max_longest_path_length:
                continue
            if self.level in [2, 3]:
                dag_sub_hash = nx.weisfeiler_lehman_graph_hash(
                    dag_sub, node_attr="node_attr", edge_attr="edge_attr"
                )  # Graph hash. Use for graph counting
            else:
                dag_sub_hash = nx.weisfeiler_lehman_graph_hash(
                    dag_sub, node_attr="node_attr"
                )  # Graph hash. Use for graph counting
            subdag_dict[dag_sub_hash].append(dag_sub)

        # Frequency of node_sets(graph_hashs)
        max_independent_set = {}
        for graph_hash, graphs in subdag_dict.items():
            n_graphs = len(graphs)
            if self._not_calc_overlapping:
                max_independent_set[graph_hash] = n_graphs
            else:
                # Get Maximum independent set for each graph hash
                G = nx.Graph()
                for i in range(n_graphs):
                    G.add_node(i)
                for (i, j) in itertools.combinations(range(n_graphs), 2):
                    if len(set(graphs[i].nodes())
                           & set(graphs[j].nodes())) > 0:
                        G.add_edge(i, j)
                max_independent_set[graph_hash] = len(
                    maximal_independent_set(G))

        for key, value in list(max_independent_set.items(
        )):  # Only node_sets which repeated more than n times
            if value < self.min_n_repetition:
                del subdag_dict[key]
                del max_independent_set[key]

        # Identify first to N-th node-set as recurring gate-sets
        subdag_dict_filtered = {}
        for i in range(self.n_patterns):
            if self._debug:
                print(f"Extracting maximum patterns... {i}/{self.n_patterns}")

            max_index = 0
            max_key = None
            for k, v in max_independent_set.items():
                g = subdag_dict[k][0]
                if v * len(g.nodes()) > max_index:
                    max_index = v * len(g.nodes())
                    max_key = k

            if max_key is None:
                break

            g0 = subdag_dict[max_key][0]
            subdag_dict_filtered[max_key] = g0

            # Remove related graph with the main reccuring graph
            for k in list(max_independent_set.keys()):
                g = subdag_dict[k][0]

                from networkx.algorithms import isomorphism
                if self.level in [2, 3]:
                    GM1 = isomorphism.DiGraphMatcher(
                        g0,
                        g,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]),
                        edge_match=isomorphism.categorical_edge_match(
                            ['edge_attr'], [None]))
                    GM2 = isomorphism.DiGraphMatcher(
                        g,
                        g0,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]),
                        edge_match=isomorphism.categorical_edge_match(
                            ['edge_attr'], [None]))

                else:
                    GM1 = isomorphism.DiGraphMatcher(
                        g0,
                        g,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]))
                    GM2 = isomorphism.DiGraphMatcher(
                        g,
                        g0,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]))

                if GM1.subgraph_is_isomorphic(
                ):  # check if g is a subgraph of g0
                    del subdag_dict[k]
                    del max_independent_set[k]

                elif GM2.subgraph_is_isomorphic(
                ):  # check if g0 is a subgraph of g
                    del subdag_dict[k]
                    del max_independent_set[k]

            g_sub1 = g0.copy()
            g_sub2 = g0.copy()
            g_sub3 = g0.copy()
            for _ in range(int(len(g0) - 4)):  # "4" can be changed !!
                g_sub1.remove_node(list(g_sub1.nodes)[len(g_sub1.nodes) - 1])
                g_sub2.remove_node(list(g_sub2.nodes)[0])

            for _ in range(int((len(g0) - 3) / 2)):  # "3" can be changed !!
                g_sub3.remove_node(list(g_sub3.nodes)[len(g_sub3.nodes) - 1])
                g_sub3.remove_node(list(g_sub3.nodes)[0])

            for k in list(max_independent_set.keys()):
                g = subdag_dict[k][0]

                from networkx.algorithms import isomorphism
                if self.level in [2, 3]:
                    GM3 = isomorphism.DiGraphMatcher(
                        g,
                        g_sub1,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]),
                        edge_match=isomorphism.categorical_edge_match(
                            ['edge_attr'], [None]))
                    GM4 = isomorphism.DiGraphMatcher(
                        g,
                        g_sub2,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]),
                        edge_match=isomorphism.categorical_edge_match(
                            ['edge_attr'], [None]))
                    GM5 = isomorphism.DiGraphMatcher(
                        g,
                        g_sub3,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]),
                        edge_match=isomorphism.categorical_edge_match(
                            ['edge_attr'], [None]))

                else:
                    GM3 = isomorphism.DiGraphMatcher(
                        g,
                        g_sub1,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]))
                    GM4 = isomorphism.DiGraphMatcher(
                        g,
                        g_sub2,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]))
                    GM5 = isomorphism.DiGraphMatcher(
                        g,
                        g_sub3,
                        node_match=isomorphism.categorical_node_match(
                            ['node_attr'], [None]))

                if GM3.subgraph_is_isomorphic(
                ):  # check if g_sub1 is a subgraph of g
                    del subdag_dict[k]
                    del max_independent_set[k]

                elif GM4.subgraph_is_isomorphic(
                ):  # check if g_sub2 is a subgraph of g
                    del subdag_dict[k]
                    del max_independent_set[k]

                elif GM5.subgraph_is_isomorphic(
                ):  # check if g_sub3 is a subgraph of g
                    del subdag_dict[k]
                    del max_independent_set[k]

        # Find recurring gates in the circuit
        gate_list = []
        for _ in range(len(subdag_dict_filtered)):
            gate_list.append([])

        for i, node_list in enumerate(node_combination):

            dag_sub = self.nodeset_to_graph(node_list, self.dag, self.level)
            if nx.dag_longest_path_length(
                    dag_sub) >= self.max_longest_path_length:
                continue
            if self.level in [2, 3]:
                dag_sub_hash = nx.weisfeiler_lehman_graph_hash(
                    dag_sub, node_attr="node_attr", edge_attr="edge_attr")
            else:
                dag_sub_hash = nx.weisfeiler_lehman_graph_hash(
                    dag_sub, node_attr="node_attr")

            for k, value in enumerate(subdag_dict_filtered.items()):
                small_list = []
                sub_list = []
                a = nx.weisfeiler_lehman_graph_hash(value[1],
                                                    node_attr="node_attr",
                                                    edge_attr="edge_attr")
                if a == dag_sub_hash:
                    gate_index = 0
                    for node in self.dag.op_nodes():
                        if (node.name == node_list[0].name) & (
                                node.qargs == node_list[0].qargs):
                            gate_index += 1
                        if str(node.op) == str(node_list[0].op):
                            small_list.append(gate_index)
                            small_list.append(len(node_list))
                            small_list.append(node.name)
                            small_list.append(node.qargs)
                            sub_list.append(small_list)
                            sub_list.append(list(node_list))
                            gate_list[k].append(sub_list)
                            break

        return subdag_dict_filtered, gate_list