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 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 tsp_dp(start, g): vts = frozenset(g.vertices()) table = {frozenset(sub): {v: inf for v in vts} for sub in subsets(vts)} table[frozenset([start])][start] = 0 for k in range(1, g.vertex_count() + 1): for subset in map(frozenset, combinations(vts, k)): for v in subset: reduced = subset - frozenset([v]) for u in filter(lambda u: g.edge_exists(u, v), vts): table[subset][v] = min( table[subset][v], table[reduced][u] + g.edge_weight(u, v)) cycle = [start] while len(vts) > 0: u = cycle[-1] v = min(g.adjacent(u), key=lambda v: table[vts][v] + g.edge_weight(v, u)) cycle.append(v) vts -= {v} return cycle
def at_most_one(cnf, vars): for x, y in combinations(vars, 2): cnf.add_clause([-x, -y])