def is_perf_matching(g: Graph, m: List[Edge]) -> bool:
    """Is m a perfect matching in the graph g?"""
    if g.vertex_count() % 2 != 0 or len(m) != g.vertex_count() // 2:
        return False

    vts = set(reduce(lambda vs, e: vs + [e.u, e.v], m, []))
    return len(vts) == g.vertex_count() and all([g.has_vertex(v) for v in vts])
def _cities_denmark():
    """
    Constructs a complete graph with vertices corresponding to Danish cities.
    An edge between two cities is weighted by the great-circle distance between them.
    Returns the graph and the city names as a pair.
    Vertex v corresponds to city at index v.
    """
    names = []
    positions = []

    with open(cities_path) as reader:
        for line in reader.readlines():
            name, pos = line.split(",")
            lat, lon = pos.split("/")
            names.append(name)
            positions.append((float(lat), float(lon)))

    g = Graph(len(names))

    for u in range(len(names)):
        (lat1, lon1) = positions[u]
        for v in range(u + 1, len(names)):
            (lat2, lon2) = positions[v]
            g.add_edge(u, v, haversine(lat1, lon1, lat2, lon2))

    return g, names
示例#3
0
def brute_perf_matchings(g: Graph) -> int:
    """Computes the number of perfect matchings in g using brute force."""
    n = g.vertex_count()
    if n % 2 != 0: return 0
    return len([
        c for c in combinations(g.edges(), n // 2)
        if gh.is_perf_matching(g, c)
    ])
def is_hamcycle(g: Graph, tour: List[int]) -> bool:
    """Is the given tour a hamiltonian cycle in g?"""
    unique = len(set(tour)) == len(tour) - 1
    all_visited = all([v in tour for v in g.vertices()])
    is_cycle = tour[0] == tour[-1]
    legal_edges = all(
        [g.edge_exists(tour[i], tour[i + 1]) for i in range(len(tour) - 1)])
    return unique and all_visited and is_cycle and legal_edges
def make_path(n: int) -> Graph:
    """Constructs a path with n vertices (n-1 edges)"""
    assert (n >= 0)

    g = Graph(n)
    for i in range(n - 1):
        g.add_edge(i, i + 1)

    return g
示例#6
0
def brute_cheapest_hamcycle(g: Graph) -> float:
    """
    Computes the weight of the cheapest hamiltonian cycle in g.
    Returns inf if no hamiltonian cycle exists.
    """
    tours = [
        p + (p[0], ) for p in permutations(g.vertices(), g.vertex_count())
    ]
    ham_cycles = [t for t in tours if gh.is_hamcycle(g, t)]
    if len(ham_cycles) == 0: return math.inf
    return min([gh.tour_cost(g, t) for t in ham_cycles])
def make_random(n: int, p: float) -> Graph:
    """Constructs a random graph where each edge is sampled with probability p"""
    assert (n >= 0 and 0 <= p <= 1)

    g = Graph(n)

    for (u, v) in combinations(range(n), 2):
        if random() < p:
            g.add_edge(u, v)

    return g
def make_clique(n: int) -> Graph:
    """Constructs a clique with n vertices"""
    assert (n >= 0)

    g = Graph(n)
    if n < 2: return g

    for (u, v) in combinations(range(n), 2):
        g.add_edge(u, v)

    return g
def test_vc_approx(vc_approx: Callable[[Graph], Iterable[int]]) -> None:
    """Tests the implementation of a 2-approximation for vertex cover"""
    print(f"Testing: {vc_approx.__name__}...")
    g = Graph.from_file(graph_path)
    vc_size = 70
    vc = set(vc_approx(g))
    if not is_vc(g, vc):
        print("VC-Approx test failed: Not a vertex cover")
    elif (len(vc) / vc_size) > 2:
        print("VC-Approx test failed: |vc| > 2 * |optimal vc|")
    else:
        print("VC-Approx test passed!")
def make_cycle(n: int) -> Graph:
    """
    Constructs of cycle with n vertices.
    A cycle with 0 vertices is the empty graph.
    A cycle with 1 vertex is a loop.
    A cycle with 2 vertices is not permitted because of parallel edges.
    """
    assert (n >= 0 and n != 2)

    if n == 0: return Graph()
    g = make_path(n)
    g.add_edge(n - 1, 0)
    return g
示例#11
0
def mst(graph: Graph) -> Graph:
    """
    Computes a minimum spanning tree of the given graph using Prim's algorithm.
    The MST is returned as a graph g.
    """
    start_vtx = next(graph.vertices())
    tree = Graph(graph.vertex_count())
    in_tree = {v:v==start_vtx for v in graph.vertices()}
    edges = graph.incident(start_vtx)
    heapq.heapify(edges)

    while len(edges) > 0:
        u,v,w = heapq.heappop(edges)
        if in_tree[u] and in_tree[v]:
            continue
        new_vtx = u if in_tree[v] else v
        tree.add_edge(u,v,w)
        in_tree[new_vtx] = True
        for e in graph.incident(new_vtx):
            heapq.heappush(edges, e)
        
    return tree
def make_grid(rows: int, cols: int) -> Graph:
    """Constructs a grid graph with the given rows and columns"""
    assert (rows >= 0 <= cols)
    g = Graph(rows * cols)

    for r in range(rows):
        for c in range(cols):
            v = r * cols + c
            if c > 0: g.add_edge(v, v - 1)
            if r > 0: g.add_edge(v, v - cols)

    return g
示例#13
0
def brute_isets(g: Graph) -> List[Tuple[int]]:
    """Uses brute force to construct all independent sets of g"""
    return [s for s in subsets(g.vertices()) if gh.is_iset(g, s)]
示例#14
0
def brute_vc(g: Graph) -> int:
    """Computes the size of the minimum vertex cover of g using brute force"""
    return min([len(sub) for sub in subsets(g.vertices()) if gh.is_vc(g, sub)])
示例#15
0
def brute_hamcycles(g: Graph):
    """Constructs all hamiltonian cycles of g using brute force"""
    tours = (p + (p[0], )
             for p in permutations(g.vertices(), g.vertex_count()))
    return (t for t in tours if gh.is_hamcycle(g, t))
def tour_cost(g: Graph, tour: List[int]) -> float:
    """ Returns the total cost of the given tour in g. """
    return sum(
        [g.edge_weight(tour[i], tour[i + 1]) for i in range(len(tour) - 1)])
def is_vc(g: Graph, vc: Iterable[int]) -> bool:
    """Is vc a vertex cover of the graph g?"""
    return all([e.u in vc or e.v in vc for e in g.edges()])
示例#18
0
import os
from advalg.graph import Graph
from typing import Callable

dirname = os.path.dirname(__file__)
graph_path = os.path.join(dirname, 'data/vc_graph_small.txt')

tests_fpt = [
    ("10-path", make_path(10), 5),
    ("15-path", make_path(15), 7),
    ("10-cycle", make_cycle(10), 5),
    ("15-cycle", make_cycle(15), 8),
    ("24-cycle", make_cycle(24), 12),
    ("10-clique", make_clique(10), 9),
    ("15-clique", make_clique(15), 14),
    ("vc_graph_small", Graph.from_file(graph_path), 12)
]

tests_sat = [
    ("10-path", make_path(10), 5),
    ("15-path", make_path(15), 7),
    ("10-cycle", make_cycle(10), 5),
    ("15-cycle", make_cycle(15), 8),
    ("10-clique", make_clique(10), 9),
]

def run_tests(vc, cases):
    for name, g, size in cases:
        n = g.vertex_count()
        res = next(k for k in range(n+1) if vc(g, k))
        if res != size:
def is_iset(g: Graph, s: Iterable[int]) -> bool:
    """Is s an independent set of graph g?"""
    return not any([e.u in s and e.v in s for e in g.edges()])