def CountingPrinciple(M, p): """Generates the clauses for the counting matching principle. The principle claims that there is a way to partition M in sets of size p each. Arguments: - `M` : size of the domain - `p` : size of each class """ cnf = CNF() # Describe the formula name = "Counting Principle: {0} divided in parts of size {1}.".format(M, p) cnf.header = name + "\n" + cnf.header def var_name(tpl): return "Y_{{" + ",".join("{0}".format(v) for v in tpl) + "}}" # Incidence lists incidence = [[] for _ in range(M)] for tpl in combinations(list(range(M)), p): for i in tpl: incidence[i].append(tpl) # Each element of the domain is in exactly one part. for el in range(M): edge_vars = [var_name(tpl) for tpl in incidence[el]] cnf.add_equal_to(edge_vars, 1) return cnf
def PerfectMatchingPrinciple(G): """Generates the clauses for the graph perfect matching principle. The principle claims that there is a way to select edges to such that all vertices have exactly one incident edge set to 1. Parameters ---------- G : undirected graph """ cnf = CNF() # Describe the formula name = "Perfect Matching Principle" if hasattr(G, 'name'): cnf.header = name + " of graph:\n" + G.name + "\n" + cnf.header else: cnf.header = name + ".\n" + cnf.header def var_name(u, v): if u <= v: return 'x_{{{0},{1}}}'.format(u, v) else: return 'x_{{{0},{1}}}'.format(v, u) # Each vertex has exactly one edge set to one. for v in enumerate_vertices(G): edge_vars = [var_name(u, v) for u in neighbors(G, v)] cnf.add_equal_to(edge_vars, 1) return cnf
def CountingPrinciple(M,p): """Generates the clauses for the counting matching principle. The principle claims that there is a way to partition M in sets of size p each. Arguments: - `M` : size of the domain - `p` : size of each class """ cnf=CNF() # Describe the formula name="Counting Principle: {0} divided in parts of size {1}.".format(M,p) cnf.header=name+"\n"+cnf.header def var_name(tpl): return "Y_{{"+",".join("{0}".format(v) for v in tpl)+"}}" # Incidence lists incidence=[[] for _ in range(M)] for tpl in combinations(range(M),p): for i in tpl: incidence[i].append(tpl) # Each element of the domain is in exactly one part. for el in range(M): edge_vars = [var_name(tpl) for tpl in incidence[el]] cnf.add_equal_to(edge_vars,1) return cnf
def PerfectMatchingPrinciple(G): """Generates the clauses for the graph perfect matching principle. The principle claims that there is a way to select edges to such that all vertices have exactly one incident edge set to 1. Parameters ---------- G : undirected graph """ cnf=CNF() # Describe the formula name="Perfect Matching Principle" if hasattr(G,'name'): cnf.header=name+" of graph:\n"+G.name+"\n"+cnf.header else: cnf.header=name+".\n"+cnf.header def var_name(u,v): if u<=v: return 'x_{{{0},{1}}}'.format(u,v) else: return 'x_{{{0},{1}}}'.format(v,u) # Each vertex has exactly one edge set to one. for v in enumerate_vertices(G): edge_vars = [var_name(u,v) for u in neighbors(G,v)] cnf.add_equal_to(edge_vars,1) return cnf
def test_one_eq(self) : opb="""\ * #variable= 5 #constraint= 1 * +1 x1 +1 x2 +1 x3 +1 x4 +1 x5 = 2; """ F=CNF() F.add_equal_to(["a","b","c","d","e"],2) self.assertCnfEqualsOPB(F,opb)
def test_one_eq(self): opb = """\ * #variable= 5 #constraint= 1 * +1 x1 +1 x2 +1 x3 +1 x4 +1 x5 = 2; """ F = CNF() F.add_equal_to(["a", "b", "c", "d", "e"], 2) self.assertCnfEqualsOPB(F, opb)
def DominatingSetOPB(G,d,tiling,seed): F=CNF() def D(v): return "x_{{{0}}}".format(v) def N(v): return tuple(sorted([ v ] + [ u for u in G.neighbors(v) ])) # Fix the vertex order V=enumerate_vertices(G) #avgdegree=sum(len(set(N(v))) for v in V)/len(V) #d=len(V)/(avgdegree+1) # Create variables for v in V: F.add_variable(D(v)) # Not too many true variables if not tiling: F.add_less_or_equal([D(v) for v in V],d) # Every neighborhood must have a true D variable neighborhoods = sorted( set(N(v) for v in V) ) for N in neighborhoods: if tiling: F.add_equal_to([D(v) for v in N], 1) else: F.add_clause([(True,D(v)) for v in N]) # Set some vertex to true if seed: F.add_clause([(True,D(V[0]))]) return F
def CliqueColoring(n,k,c): r"""Clique-coloring CNF formula The formula claims that a graph :math:`G` with :math:`n` vertices simultaneously contains a clique of size :math:`k` and a coloring of size :math:`c`. If :math:`k = c + 1` then the formula is clearly unsatisfiable, and it is the only known example of a formula hard for cutting planes proof system. [1]_ Variables :math:`e_{u,v}` to encode the edges of the graph. Variables :math:`q_{i,v}` encode a function from :math:`[k]` to :math:`[n]` that represents a clique. Variables :math:`r_{v,\ell}` encode a function from :math:`[n]` to :math:`[c]` that represents a coloring. Parameters ---------- n : number of vertices in the graph k : size of the clique c : size of the coloring Returns ------- A CNF object References ---------- .. [1] Pavel Pudlak. Lower bounds for resolution and cutting plane proofs and monotone computations. Journal of Symbolic Logic (1997) """ def E(u,v): "Name of an edge variable" return 'e_{{{0},{1}}}'.format(min(u,v),max(u,v)) def Q(i,v): "Name of an edge variable" return 'q_{{{0},{1}}}'.format(i,v) def R(v,ell): "Name of an coloring variable" return 'r_{{{0},{1}}}'.format(v,ell) formula=CNF() formula.mode_strict() formula.header="There is a graph of {0} vertices with a {1}-clique".format(n,k)+\ " and a {0}-coloring\n\n".format(c)\ + formula.header # Edge variables for u in range(1,n+1): for v in range(u+1,n+1): formula.add_variable(E(u,v)) # Clique encoding variables for i in range(1,k+1): for v in range(1,n+1): formula.add_variable(Q(i,v)) # Coloring encoding variables for v in range(1,n+1): for ell in range(1,c+1): formula.add_variable(R(v,ell)) # some vertex is i'th member of clique formula.mode_strict() for k in range(1,k+1): formula.add_equal_to([Q(k,v) for v in range(1,n+1)], 1) # clique members are connected by edges for v in range(1,n+1): for i,j in combinations(range(1,k+1),2): formula.add_clause([(False, Q(i,v)), (False, Q(j,v))]) for u,v in combinations(range(1,n+1),2): for i,j in permutations(range(1,k+1),2): formula.add_clause([(True, E(u,v)), (False, Q(i,u)), (False, Q(j,v))]) # every vertex v has exactly one colour for v in range(1,n+1): formula.add_equal_to([R(v,ell) for ell in range(1,c+1)], 1) # neighbours have distinct colours for u,v in combinations(range(1,n+1),2): for ell in range(1,c+1): formula.add_clause([(False, E(u,v)), (False, R(u,ell)), (False, R(v,ell))]) return formula
def CliqueColoring(n, k, c): r"""Clique-coloring CNF formula The formula claims that a graph :math:`G` with :math:`n` vertices simultaneously contains a clique of size :math:`k` and a coloring of size :math:`c`. If :math:`k = c + 1` then the formula is clearly unsatisfiable, and it is the only known example of a formula hard for cutting planes proof system. [1]_ Variables :math:`e_{u,v}` to encode the edges of the graph. Variables :math:`q_{i,v}` encode a function from :math:`[k]` to :math:`[n]` that represents a clique. Variables :math:`r_{v,\ell}` encode a function from :math:`[n]` to :math:`[c]` that represents a coloring. Parameters ---------- n : number of vertices in the graph k : size of the clique c : size of the coloring Returns ------- A CNF object References ---------- .. [1] Pavel Pudlak. Lower bounds for resolution and cutting plane proofs and monotone computations. Journal of Symbolic Logic (1997) """ def E(u, v): "Name of an edge variable" return 'e_{{{0},{1}}}'.format(min(u, v), max(u, v)) def Q(i, v): "Name of an edge variable" return 'q_{{{0},{1}}}'.format(i, v) def R(v, ell): "Name of an coloring variable" return 'r_{{{0},{1}}}'.format(v, ell) formula = CNF() formula.mode_strict() formula.header = "There is a graph of {0} vertices with a {1}-clique".format(n, k) +\ " and a {0}-coloring\n\n".format(c)\ + formula.header # Edge variables for u in range(1, n + 1): for v in range(u + 1, n + 1): formula.add_variable(E(u, v)) # Clique encoding variables for i in range(1, k + 1): for v in range(1, n + 1): formula.add_variable(Q(i, v)) # Coloring encoding variables for v in range(1, n + 1): for ell in range(1, c + 1): formula.add_variable(R(v, ell)) # some vertex is i'th member of clique formula.mode_strict() for k in range(1, k + 1): formula.add_equal_to([Q(k, v) for v in range(1, n + 1)], 1) # clique members are connected by edges for v in range(1, n + 1): for i, j in combinations(list(range(1, k + 1)), 2): formula.add_clause([(False, Q(i, v)), (False, Q(j, v))]) for u, v in combinations(list(range(1, n + 1)), 2): for i, j in permutations(list(range(1, k + 1)), 2): formula.add_clause([(True, E(u, v)), (False, Q(i, u)), (False, Q(j, v))]) # every vertex v has exactly one colour for v in range(1, n + 1): formula.add_equal_to([R(v, ell) for ell in range(1, c + 1)], 1) # neighbours have distinct colours for u, v in combinations(list(range(1, n + 1)), 2): for ell in range(1, c + 1): formula.add_clause([(False, E(u, v)), (False, R(u, ell)), (False, R(v, ell))]) return formula