Пример #1
0
def path_graph(n: int, directed=False) -> Graph:
    vertices: List[Vertex] = [Vertex(label=f'{i}', index=i) for i in range(n)]
    edges = [Edge(vertices[i], vertices[i + 1]) for i in range(n - 1)]
    if not directed:
        edges += [Edge(vertices[i], vertices[i - 1]) for i in range(1, n)]

    return Graph(vertices, edges, directed=directed)
Пример #2
0
def complete_binary_tree(n: int = None,
                         h: int = None,
                         directed=False) -> Graph:
    """
    Construct a perfect binary tree with n nodes/height of h.
    :param n: number of nodes
    :param h: height
    :param directed: directed edges
    :return:
    """
    if n is None and h is None:
        raise ValueError('One of n and h must be not-null.')
    if n is None and h is not None:
        n = 2**(h + 1) - 1
    if n == 0:
        return Graph([], [])
    # check n+1 is a power of two - 1
    if not (n & (n + 1)) == 0:
        raise ValueError(
            'Number of nodes not enough for a complete binary tree.')
    vertices: List[Vertex] = [Vertex(label=f'{i}', index=i) for i in range(n)]

    edges = [Edge(vertices[i], vertices[2 * i + 1]) for i in range(n // 2)]
    edges += [
        Edge(vertices[i], vertices[2 * i + 2]) for i in range(n // 2 - 1)
    ]
    if directed:
        return Graph(vertices, edges, directed=True)
    edges += [Edge(vertices[2 * i + 1], vertices[i]) for i in range(n // 2)]
    edges += [
        Edge(vertices[2 * i + 2], vertices[i]) for i in range(n // 2 - 1)
    ]
    return Graph(vertices, edges)
Пример #3
0
def complete_graph(n: int, directed=False) -> Graph:
    vertices: List[Vertex] = [Vertex(label=f'{i}', index=i) for i in range(n)]
    if directed:
        edges = [Edge(v, i) for v, i in itertools.combinations(vertices, 2)]
    else:
        edges = [Edge(v, i) for v, i in itertools.permutations(vertices, 2)]
    return Graph(vertices, edges, directed=directed)
Пример #4
0
def euler_graph(n: int, cycle=True) -> Graph:
    # TODO
    """
    Create a random graph with an Euler path.
    :param n: number of vertices
    :param cycle: if True, there is also an Euler cycle in the graph.
    :return:
    """
    vertices: List[Vertex] = [Vertex(label=f'{i}', index=i) for i in range(n)]
    v2 = random.choices(vertices, k=n)
    edges = [Edge(v, i) for v, i in zip(vertices, v2)]
Пример #5
0
def _parse_edge(e: str,
                sep: str = None,
                default_weight: Union[int, float] = None,
                edge_type=None) -> Edge:
    """
    Parse a string into an edge.
    Parameters
    ----------
    e: str
        Input string
    sep: str
        Separator
    default_weight
        Default weight value for the missing weights.
    edge_type

    Returns
    -------

    """
    if type(edge_type) == str:
        edge_type = eval(edge_type)

    v1, v2, *weight = e.split(sep=sep)
    if default_weight is not None and (weight == [] or weight[0] == ''):
        if edge_type != type(default_weight):
            warn(
                message=
                f'The edge type provided is {edge_type} but the default weight is {type(default_weight)}.'
                f' The default weight will be converted to the edge type.')

        weight = default_weight
    if type(weight) == list:
        weight = weight[0]

    try:
        weight = edge_type(weight)
    except ValueError:
        raise ValueError(
            'You have specified int as an edge weight type but one of your edge weights if of type float.'
        )
    return Edge(v1, v2, weight)
Пример #6
0
def cycle_graph(n: int) -> Graph:
    p = path_graph(n)
    edge = [Edge(p.vertices[-1], p.vertices[0])]
    p.add_egdes(edge)
    return p
Пример #7
0
def parse_edges_from_list(l: list,
                          default_weight: Union[int, float] = None,
                          edge_type=None,
                          **meta):
    """
    Parse a list of edges into a graph.
    Parameters
    ----------
    l: list
        List of edges. Edges could be strings of the format 'node1 node2 (weight)' or tuples.
    sep: str
        Separator in case that edges are given by strings.
    default_weight: int or float
        If only some edges are weighted, use this value as default for the others.
    edge_type: str or type
        The type of the edges of the graph.
    meta: dict
        Meta data of the graph

    Returns
    -------
    g: Graph

    Examples
    -------
    With string input
    l1 = ['v1 v2 2', 'v1 v3 1']
    g = parse_edges_from_list(l1)

    With default weight:
    l1 = ['v1 v2 2', 'v1 v3 1']
    g = parse_edges_from_list(l1)

    With tuple input:
    l2 = [('v1','v2', 2), ('v1','v3', 1)]
    g = parse_edges_from_list(l2)

    """
    if l is None or len(l) == 0:
        return Graph()
    l_type = type(l[0])

    if l_type == str:
        edges = [
            _parse_edge(e, default_weight=default_weight, edge_type=edge_type)
            for e in l
        ]
    elif l_type == tuple or l_type == list:
        # weighted graph with default edges
        if default_weight is not None:
            edges = [
                Edge(e[0], e[1], e[2]) if len(e) == 3 else Edge(
                    e[0], e[1], default_weight) for e in l
            ]

        # weighted graph
        elif len(l[0]) == 3:
            try:
                edges = [Edge(e[0], e[1], e[2]) for e in l]
            except IndexError:
                raise IndexError(
                    "It seems that not every edge is weighted. If this is on purpose, "
                    "use the default_weight argument to specify default weight for the missing weights."
                )

        # unweighted graph
        else:
            edges = [Edge(e[0], e[1]) for e in l]
    else:
        raise ValueError(
            'An edge must be represented either by a string or by a tuple or list.'
        )
    g = Graph(edges=edges)
    g.meta = meta
    return g