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)
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)
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)
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)]
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)
def cycle_graph(n: int) -> Graph: p = path_graph(n) edge = [Edge(p.vertices[-1], p.vertices[0])] p.add_egdes(edge) return p
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