Exemple #1
0
    def _recursive_position_for_row(
        G: nx.classes.graph.Graph,
        result: dict,
        two_rows_before: List[Hashable],
        last_row: List[Hashable],
        current_height: float,
    ):
        new_row = []
        for v in last_row:
            for x in G.neighbors(v):
                if x not in two_rows_before:
                    new_row.append(x)

        new_row_length = len(new_row)

        if new_row_length == 0:
            return

        if new_row_length == 1:
            result[new_row[0]] = np.array([0, current_height, 0])
        else:
            for i in range(new_row_length):
                result[new_row[i]] = np.array(
                    [-1 + 2 * i / (new_row_length - 1), current_height, 0]
                )

        _recursive_position_for_row(
            G,
            result,
            two_rows_before=last_row,
            last_row=new_row,
            current_height=current_height + 1,
        )
    def fit(self, G: nx.classes.graph.Graph) -> Word2Vec:
        """Fit and get the embedding algorithm model.

        Args:
            G (networkx.classes.graph.Graph): A NetworkX graph object.

        Returns:
            (gensim.models.word2vec.Word2Vec): The Word2Vec model.
        """

        self.G = G
        walks = []
        for node in tqdm(G.nodes()):
            for _ in range(self.num_walks):
                walk = []
                walk.append(str(node))
                current_node = node
                previous_node = None
                former_neighbors = []

                for _ in range(self.walk_length):
                    current_neighbors = np.array(
                        list(G.neighbors(current_node)))
                    if np.size(current_neighbors) == 0:
                        break
                    probability = np.array([1 / self.q] *
                                           len(current_neighbors))
                    probability[current_neighbors ==
                                previous_node] = 1 / self.p
                    probability[(np.isin(current_neighbors,
                                         former_neighbors))] = 1

                    next_node = np.random.choice(current_neighbors,
                                                 1,
                                                 p=probability /
                                                 sum(probability))[0]
                    walk.append(str(next_node))

                    former_neighbors = current_neighbors
                    previous_node = current_node
                    current_node = next_node
                walks.append(walk)

        self.model = Word2Vec(walks,
                              size=self.size,
                              window=self.window,
                              seed=self.seed,
                              workers=self.workers,
                              iter=self.iter)

        return self.model
Exemple #3
0
    def fit(self, graph: nx.classes.graph.Graph):
        """
        Fitting a BigClam clustering model.

        Arg types:
            * **graph** *(NetworkX graph)* - The graph to be clustered.
        """
        self._set_seed()
        self._check_graph(graph)
        number_of_nodes = graph.number_of_nodes()
        self._initialize_features(number_of_nodes)
        nodes = [node for node in graph.nodes()]
        for i in range(self.iterations):
            random.shuffle(nodes)
            for node in nodes:
                nebs = [neb for neb in graph.neighbors(node)]
                neb_features = self._embedding[nebs, :]
                node_feature = self._embedding[node, :]
                gradient = self._calculate_gradient(node_feature, neb_features)
                self._do_updates(node, gradient, node_feature)
Exemple #4
0
def merge_nodes(G: nx.classes.graph.Graph, new_inst_type: str,
                list_of_nodes: list, matched_ports: dict):
    """
    Merges the  given nodes in list_of_nodes and returns a
     reduced graph.
     
    Parameters
    ----------
    G : netowrkx graph
        DESCRIPTION. Bipartite graph of circuit
    new_inst_type : str
        DESCRIPTION. name of new subckt to be created, 
        A super node is created in graph havinge a subgraph in its values
    list_of_nodes : list
        DESCRIPTION.
    matched_ports : dict
        DESCRIPTION. dictionary of {subkt port: connected net} be added in dubckt

    Returns
    -------
    G : nx.classes.graph.Graph
        returns updated graph.

    """
    for node in list_of_nodes:
        if not G.nodes[node]:
            logger.debug("node not in graph anymore")
            return G, nx.Graph
    logger.debug(f"Is input bipartite: {nx.is_bipartite(G)}")
    assert len(list_of_nodes) > 1
    #  print("Merging nodes",list_of_nodes)
    new_node = ""
    ports = {}
    subgraph = nx.Graph()
    max_value = {}
    for node in list_of_nodes:
        new_node += '_' + node
        subgraph.add_node(node,
                          inst_type=G.nodes[node]["inst_type"],
                          real_inst_type=G.nodes[node]["real_inst_type"],
                          ports=G.nodes[node]['ports'],
                          edge_weight=G.nodes[node]['edge_weight'],
                          values=merged_value({}, G.nodes[node]['values']))
        if 'ports_match' in G.nodes[node].keys():
            subgraph.nodes[node]["ports_match"] = G.nodes[node]['ports_match']

        logger.debug(f"removing node {G.nodes[node]}")
        max_value = merged_value(max_value, G.nodes[node]['values'])

        nbr = G.neighbors(node)
        for ele in nbr:
            if ele not in subgraph.nodes():
                if ele in matched_ports.keys():
                    subgraph.add_node(ele,
                                      inst_type=G.nodes[ele]["inst_type"],
                                      net_type="external")
                else:
                    subgraph.add_node(ele,
                                      inst_type=G.nodes[ele]["inst_type"],
                                      net_type=G.nodes[ele]["net_type"])

            #print("adding edge b/w:",node,ele,G[node][ele]["weight"])
            subgraph.add_edge(node, ele, weight=G[node][ele]["weight"])

            if ele in ports:
                # had to remove addition as combination of weight for cmc caused gate to be considered source
                # changed to bitwise and as all connections of CMB were considered as gate
                ports[ele] = ports[ele] | G[node][ele]["weight"]

            else:
                ports[ele] = G[node][ele]["weight"]

    new_node = new_node[1:]
    G.add_node(new_node,
               inst_type=new_inst_type,
               real_inst_type=new_inst_type,
               ports=list(matched_ports.keys()),
               edge_weight=list(ports.values()),
               ports_match=matched_ports,
               values=max_value)
    #logger.debug(f"creating a super node of combination of nodes: {new_inst_type}")
    for pins in list(ports):
        if set(G.neighbors(pins)) <= set(
                list_of_nodes) and G.nodes[pins]["net_type"] == 'internal':
            del ports[pins]
            G.remove_node(pins)
    for node in list_of_nodes:
        G.remove_node(node)
    for pins in ports:
        G.add_edge(new_node, pins, weight=ports[pins])
        #logger.debug(f"new ports: {pins},{ports[pins]}")

    check_nodes(subgraph)

    return G, subgraph, new_node
Exemple #5
0
def tree_positions(T: nx.classes.graph.Graph,
                   root: Union[str, int]) -> Dict[int, List[float]]:
    """Get positions for every node in the tree T with the given root.

    Args:
        T (nx.classes.graph.Graph): Tree graph.
        root (Union[str,int]): Root of the tree graph

    Returns:
        Dict[int, List[float]]: Dictionary from nodes in T to positions.
    """
    PAD = 0.1
    HORIZONTAL_SPACE = 0.2

    position = {}
    position[root] = (0.5, 1 - PAD)  # root position

    node_to_level = nx.single_source_shortest_path_length(T, root)
    level_count = max(node_to_level.values()) + 1
    levels = {}
    for l in range(level_count):
        levels[l] = [i for i in node_to_level if node_to_level[i] == l]

    level_heights = np.linspace(1.1, -0.1, level_count + 2)[1:-1]
    for l in range(1, level_count):
        # If there are more than 5 nodes in level, spread evenly across width;
        # otherwise, try to put nodes under their parent.
        if len(levels[l]) <= 4:
            # get parents of every pair of children in the level
            children = {}
            for node in levels[l]:
                parent = [i for i in list(T.neighbors(node)) if i < node][0]
                if parent in children:
                    children[parent].append(node)
                else:
                    children[parent] = [node]

            # initial attempt at positioning
            pos = {}
            for parent in children:
                x = position[parent][0]
                d = max((1 / 2)**(l + 1), HORIZONTAL_SPACE / 2)
                pos[children[parent][0]] = [x - d, level_heights[l]]
                pos[children[parent][1]] = [x + d, level_heights[l]]

            # perturb if needed
            keys = list(pos.keys())
            x = [p[0] for p in pos.values()]
            n = len(x) - 1
            while any(
                [x[i + 1] - x[i] + 0.05 < HORIZONTAL_SPACE for i in range(n)]):
                for i in range(len(x) - 1):
                    if abs(x[i + 1] - x[i]) < HORIZONTAL_SPACE:
                        shift = (HORIZONTAL_SPACE - abs(x[i + 1] - x[i])) / 2
                        x[i] -= shift
                        x[i + 1] += shift

            # shift to be within width
            x[0] = x[0] + (max(PAD - x[0], 0))
            for i in range(1, len(x)):
                x[i] = x[i] + max(HORIZONTAL_SPACE - (x[i] - x[i - 1]), 0)

            x[-1] = x[-1] - (max(x[-1] - (1 - PAD), 0))
            for i in reversed(range(len(x) - 1)):
                x[i] = x[i] - max(HORIZONTAL_SPACE - (x[i + 1] - x[i]), 0)

            # update the position dictionary with new x values
            for i in range(len(x)):
                pos[keys[i]][0] = x[i]

            # set position
            for node in pos:
                position[node] = pos[node]
        else:
            level_widths = np.linspace(-0.1, 1.1, len(levels[l]) + 2)[1:-1]
            for j in range(len(levels[l])):
                position[(levels[l][j])] = (level_widths[j], level_heights[i])

    return position
Exemple #6
0
def _tree_layout(
    T: nx.classes.graph.Graph,
    root_vertex: Union[Hashable, None],
    scale: Union[float, tuple] = 2,
    orientation: str = "down",
):
    children = {root_vertex: list(T.neighbors(root_vertex))}

    if not nx.is_tree(T):
        raise ValueError("The tree layout must be used with trees")
    if root_vertex is None:
        raise ValueError("The tree layout requires the root_vertex parameter")

    # The following code is SageMath's tree layout implementation, taken from
    # https://github.com/sagemath/sage/blob/cc60cfebc4576fed8b01f0fc487271bdee3cefed/src/sage/graphs/graph_plot.py#L1447

    # Always make a copy of the children because they get eaten
    stack = [list(children[root_vertex]).copy()]
    stick = [root_vertex]
    parent = {u: root_vertex for u in children[root_vertex]}
    pos = {}
    obstruction = [0.0] * len(T)
    if orientation == "down":
        o = -1
    else:
        o = 1

    def slide(v, dx):
        """
        Shift the vertex v and its descendants to the right by dx.
        Precondition: v and its descendents have already had their
        positions computed.
        """
        level = [v]
        while level:
            nextlevel = []
            for u in level:
                x, y = pos[u]
                x += dx
                obstruction[y] = max(x + 1, obstruction[y])
                pos[u] = x, y
                nextlevel += children[u]
            level = nextlevel

    while stack:
        C = stack[-1]
        if not C:
            p = stick.pop()
            stack.pop()
            cp = children[p]
            y = o * len(stack)
            if not cp:
                x = obstruction[y]
                pos[p] = x, y
            else:
                x = sum(pos[c][0] for c in cp) / float(len(cp))
                pos[p] = x, y
                ox = obstruction[y]
                if x < ox:
                    slide(p, ox - x)
                    x = ox
            obstruction[y] = x + 1
            continue

        t = C.pop()
        pt = parent[t]

        ct = [u for u in list(T.neighbors(t)) if u != pt]
        for c in ct:
            parent[c] = t
        children[t] = copy(ct)

        stack.append(ct)
        stick.append(t)

    # the resulting layout is then rescaled again to fit on Manim's canvas

    x_min = min(pos.values(), key=lambda t: t[0])[0]
    x_max = max(pos.values(), key=lambda t: t[0])[0]
    y_min = min(pos.values(), key=lambda t: t[1])[1]
    y_max = max(pos.values(), key=lambda t: t[1])[1]
    center = np.array([x_min + x_max, y_min + y_max, 0]) / 2
    height = y_max - y_min
    width = x_max - x_min
    if isinstance(scale, (float, int)):
        sf = 2 * scale / max(width, height)
    else:
        sf = np.array([2 * scale[0] / width, 2 * scale[1] / height, 0])
    return {
        v: (np.array([x, y, 0]) - center) * sf
        for v, (x, y) in pos.items()
    }