def test_one_leq(self) : opb="""\ * #variable= 5 #constraint= 1 * -1 x1 -1 x2 -1 x3 -1 x4 -1 x5 >= -2; """ F=CNF() F.add_less_or_equal(["a","b","c","d","e"],2) self.assertCnfEqualsOPB(F,opb)
def test_one_leq(self): opb = """\ * #variable= 5 #constraint= 1 * -1 x1 -1 x2 -1 x3 -1 x4 -1 x5 >= -2; """ F = CNF() F.add_less_or_equal(["a", "b", "c", "d", "e"], 2) self.assertCnfEqualsOPB(F, opb)
def VertexCover(G, d): F = CNF() def D(v): return "x_{{{0}}}".format(v) def N(v): return tuple(sorted([e for e in G.edges(v)])) # Fix the vertex order V = enumerate_vertices(G) # Create variables for v in V: F.add_variable(D(v)) # Not too many true variables F.add_less_or_equal([D(v) for v in V], d) # Every edge must have a true D variable for e in G.edges(): F.add_clause([(True, D(v)) for v in e]) return F
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 VertexCover(G,d): F=CNF() def D(v): return "x_{{{0}}}".format(v) def N(v): return tuple(sorted([ e for e in G.edges(v) ])) # Fix the vertex order V=enumerate_vertices(G) # Create variables for v in V: F.add_variable(D(v)) # Not too many true variables F.add_less_or_equal([D(v) for v in V],d) # Every edge must have a true D variable for e in G.edges(): F.add_clause([ (True,D(v)) for v in e]) return F
def DominatingSet(G,d, alternative = False): r"""Generates the clauses for a dominating set for G of size <= d The formula encodes the fact that the graph :math:`G` has a dominating set of size :math:`d`. This means that it is possible to pick at most :math:`d` vertices in :math:`V(G)` so that all remaining vertices have distance at most one from the selected ones. Parameters ---------- G : networkx.Graph a simple undirected graph d : a positive int the size limit for the dominating set alternative : bool use an alternative construction that is provably hard from resolution proofs. Returns ------- CNF the CNF encoding for dominating of size :math:`\leq d` for graph :math:`G` """ F=CNF() if not isinstance(d,int) or d<1: ValueError("Parameter \"d\" is expected to be a positive integer") # Describe the formula name="{}-dominating set".format(d) if hasattr(G,'name'): F.header=name+" of graph:\n"+G.name+".\n\n"+F.header else: F.header=name+".\n\n"+F.header # Fix the vertex order V=enumerate_vertices(G) def D(v): return "x_{{{0}}}".format(v) def M(v,i): return "g_{{{0},{1}}}".format(v,i) def N(v): return tuple(sorted([ v ] + [ u for u in G.neighbors(v) ])) # Create variables for v in V: F.add_variable(D(v)) for i,v in product(range(1,d+1),V): F.add_variable(M(v,i)) # No two (active) vertices map to the same index if alternative: for u,v in combinations(V,2): for i in range(1,d+1): F.add_clause( [ (False,D(u)),(False,D(v)), (False,M(u,i)), (False,M(v,i)) ]) else: for i in range(1,d+1): F.add_less_or_equal([M(v,i) for v in V],1) # (Active) Vertices in the sequence are not repeated if alternative: for v in V: for i,j in combinations(range(1,d+1),2): F.add_clause([(False,D(v)),(False,M(v,i)),(False,M(v,j))]) else: for i,j in combinations_with_replacement(range(1,d+1),2): i,j = min(i,j),max(i,j) for u,v in combinations(V,2): u,v = max(u,v),min(u,v) F.add_clause([(False,M(u,i)),(False,M(v,j))]) # D(v) = M(v,1) or M(v,2) or ... or M(v,d) if not alternative: for i,v in product(range(1,d+1),V): F.add_clause([(False,M(v,i)),(True,D(v))]) for v in V: F.add_clause([(False,D(v))] + [(True,M(v,i)) for i in range(1,d+1)]) # Every neighborhood must have a true D variable neighborhoods = sorted( set(N(v) for v in V) ) for N in neighborhoods: F.add_clause([ (True,D(v)) for v in N]) return F
def DominatingSet(G, d, alternative=False): r"""Generates the clauses for a dominating set for G of size <= d The formula encodes the fact that the graph :math:`G` has a dominating set of size :math:`d`. This means that it is possible to pick at most :math:`d` vertices in :math:`V(G)` so that all remaining vertices have distance at most one from the selected ones. Parameters ---------- G : networkx.Graph a simple undirected graph d : a positive int the size limit for the dominating set alternative : bool use an alternative construction that is provably hard from resolution proofs. Returns ------- CNF the CNF encoding for dominating of size :math:`\leq d` for graph :math:`G` """ F = CNF() if not isinstance(d, int) or d < 1: ValueError("Parameter \"d\" is expected to be a positive integer") # Describe the formula name = "{}-dominating set".format(d) if hasattr(G, 'name'): F.header = name + " of graph:\n" + G.name + ".\n\n" + F.header else: F.header = name + ".\n\n" + F.header # Fix the vertex order V = enumerate_vertices(G) def D(v): return "x_{{{0}}}".format(v) def M(v, i): return "g_{{{0},{1}}}".format(v, i) def N(v): return tuple(sorted([v] + [u for u in G.neighbors(v)])) # Create variables for v in V: F.add_variable(D(v)) for i, v in product(list(range(1, d + 1)), V): F.add_variable(M(v, i)) # No two (active) vertices map to the same index if alternative: for u, v in combinations(V, 2): for i in range(1, d + 1): F.add_clause([(False, D(u)), (False, D(v)), (False, M(u, i)), (False, M(v, i))]) else: for i in range(1, d + 1): F.add_less_or_equal([M(v, i) for v in V], 1) # (Active) Vertices in the sequence are not repeated if alternative: for v in V: for i, j in combinations(list(range(1, d + 1)), 2): F.add_clause([(False, D(v)), (False, M(v, i)), (False, M(v, j))]) else: for i, j in combinations_with_replacement(list(range(1, d + 1)), 2): i, j = min(i, j), max(i, j) for u, v in combinations(V, 2): u, v = max(u, v), min(u, v) F.add_clause([(False, M(u, i)), (False, M(v, j))]) # D(v) = M(v,1) or M(v,2) or ... or M(v,d) if not alternative: for i, v in product(list(range(1, d + 1)), V): F.add_clause([(False, M(v, i)), (True, D(v))]) for v in V: F.add_clause([(False, D(v))] + [(True, M(v, i)) for i in range(1, d + 1)]) # Every neighborhood must have a true D variable neighborhoods = sorted(set(N(v) for v in V)) for N in neighborhoods: F.add_clause([(True, D(v)) for v in N]) return F