def ExtendedEvenColoringFormula(G,T): F = EvenColoringFormula(G) F.mode_strict() def var_name(u,v,c): if u<=v: return '{2}_{{{0},{1}}}'.format(u,v,c) else: return '{2}_{{{0},{1}}}'.format(v,u,c) true_vars = [var_name(u,v,'t') for (u,v) in enumerate_edges(G)] false_vars = [var_name(u,v,'f') for (u,v) in enumerate_edges(G)] for var in true_vars: F.add_variable(var) for var in false_vars: F.add_variable(var) for (u, v) in enumerate_edges(G): F.add_clause([(True,var_name(u,v,'t')), (False,var_name(u,v,'x'))]) F.add_clause([(True,var_name(u,v,'f')), (True,var_name(u,v,'x'))]) F.add_linear(*chain(*[(3,var) for var in true_vars] + [(1,var) for var in false_vars] + [("<=", T)])) return F
def ExtendedEvenColoringFormula(G, T): F = EvenColoringFormula(G) F.mode_strict() def var_name(u, v, c): if u <= v: return '{2}_{{{0},{1}}}'.format(u, v, c) else: return '{2}_{{{0},{1}}}'.format(v, u, c) true_vars = [var_name(u, v, 't') for (u, v) in enumerate_edges(G)] false_vars = [var_name(u, v, 'f') for (u, v) in enumerate_edges(G)] for var in true_vars: F.add_variable(var) for var in false_vars: F.add_variable(var) for (u, v) in enumerate_edges(G): F.add_clause([(True, var_name(u, v, 't')), (False, var_name(u, v, 'x'))]) F.add_clause([(True, var_name(u, v, 'f')), (True, var_name(u, v, 'x'))]) F.add_linear(*chain(*[(3, var) for var in true_vars] + [(1, var) for var in false_vars] + [("<=", T)])) return F
def EvenColoringFormula(G): """Even coloring formula The formula is defined on a graph :math:`G` and claims that it is possible to split the edges of the graph in two parts, so that each vertex has an equal number of incident edges in each part. The formula is defined on graphs where all vertices have even degree. The formula is satisfiable only on those graphs with an even number of vertices in each connected component [1]_. Arguments --------- G : networkx.Graph a simple undirected graph where all vertices have even degree Raises ------ ValueError if the graph in input has a vertex with odd degree Returns ------- CNF object References ---------- .. [1] Locality and Hard SAT-instances, Klas Markstrom Journal on Satisfiability, Boolean Modeling and Computation 2 (2006) 221-228 """ F = CNF() F.mode_strict() F.header = "Even coloring formula on graph " + G.name + "\n" + F.header def var_name(u, v): if u <= v: return 'x_{{{0},{1}}}'.format(u, v) else: return 'x_{{{0},{1}}}'.format(v, u) for (u, v) in enumerate_edges(G): F.add_variable(var_name(u, v)) # Defined on both side for v in enumerate_vertices(G): if G.degree(v) % 2 == 1: raise ValueError( "Markstrom formulas requires all vertices to have even degree." ) edge_vars = [var_name(u, v) for u in neighbors(G, v)] # F.add_exactly_half_floor would work the same F.add_exactly_half_ceil(edge_vars) return F
def EvenColoringFormula(G): """Even coloring formula The formula is defined on a graph :math:`G` and claims that it is possible to split the edges of the graph in two parts, so that each vertex has an equal number of incident edges in each part. The formula is defined on graphs where all vertices have even degree. The formula is satisfiable only on those graphs with an even number of vertices in each connected component [1]_. Arguments --------- G : networkx.Graph a simple undirected graph where all vertices have even degree Raises ------ ValueError if the graph in input has a vertex with odd degree Returns ------- CNF object References ---------- .. [1] Locality and Hard SAT-instances, Klas Markstrom Journal on Satisfiability, Boolean Modeling and Computation 2 (2006) 221-228 """ F = CNF() F.header = "Even coloring formula on graph " + G.name + "\n" + F.header def var_name(u,v): if u<=v: return 'x_{{{0},{1}}}'.format(u,v) else: return 'x_{{{0},{1}}}'.format(v,u) for (u, v) in enumerate_edges(G): F.add_variable(var_name(u, v)) # Defined on both side for v in enumerate_vertices(G): if G.degree(v) % 2 == 1: raise ValueError("Markstrom formulas requires all vertices to have even degree.") edge_vars = [ var_name(u,v) for u in neighbors(G,v) ] for cls in CNF.equal_to_constraint(edge_vars, len(edge_vars)/2): F.add_clause(cls,strict=True) return F
def GraphColoringFormula(G,colors,functional=True): """Generates the clauses for colorability formula The formula encodes the fact that the graph :math:`G` has a coloring with color set ``colors``. This means that it is possible to assign one among the elements in ``colors``to that each vertex of the graph such that no two adjacent vertices get the same color. Parameters ---------- G : networkx.Graph a simple undirected graph colors : list or positive int a list of colors or a number of colors Returns ------- CNF the CNF encoding of the coloring problem on graph ``G`` """ col=CNF() col.mode_strict() if isinstance(colors,int) and colors>=0: colors = range(1,colors+1) if not isinstance(list, collections.Iterable): ValueError("Parameter \"colors\" is expected to be a iterable") # Describe the formula name="graph colorability" if hasattr(G,'name'): col.header=name+" of graph:\n"+G.name+".\n\n"+col.header else: col.header=name+".\n\n"+col.header # Fix the vertex order V=enumerate_vertices(G) # Create the variables for vertex in V: for color in colors: col.add_variable('x_{{{0},{1}}}'.format(vertex,color)) # Each vertex has a color for vertex in V: clause = [] for color in colors: clause += [(True,'x_{{{0},{1}}}'.format(vertex,color))] col.add_clause(clause) # unique color per vertex if functional: for (c1,c2) in combinations(colors,2): col.add_clause([ (False,'x_{{{0},{1}}}'.format(vertex,c1)), (False,'x_{{{0},{1}}}'.format(vertex,c2))]) # This is a legal coloring for (v1,v2) in enumerate_edges(G): for c in colors: col.add_clause([ (False,'x_{{{0},{1}}}'.format(v1,c)), (False,'x_{{{0},{1}}}'.format(v2,c))]) return col
def VertexCover(G,k, alternative = False): r"""Generates the clauses for a vertex cover for G of size <= k Parameters ---------- G : networkx.Graph a simple undirected graph k : a positive int the size limit for the vertex cover Returns ------- CNF the CNF encoding for vertex cover of size :math:`\leq k` for graph :math:`G` """ F=CNF() if not isinstance(k,int) or k<1: ValueError("Parameter \"k\" is expected to be a positive integer") # Describe the formula name="{}-vertex cover".format(k) 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) E=enumerate_edges(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,k+1),V): F.add_variable(M(v,i)) # No two (active) vertices map to the same index for i in range(1,k+1): for c in CNF.less_or_equal_constraint([M(v,i) for v in V],1): F.add_clause(c) # (Active) Vertices in the sequence are not repeated for i,j in combinations_with_replacement(range(1,k+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,k) for i,v in product(range(1,k+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,k+1)]) # Every neighborhood must have a true D variable for v1,v2 in E: F.add_clause([(True,D(v1)), (True,D(v2))]) return F
def GraphColoringFormula(G, colors, functional=True): """Generates the clauses for colorability formula The formula encodes the fact that the graph :math:`G` has a coloring with color set ``colors``. This means that it is possible to assign one among the elements in ``colors``to that each vertex of the graph such that no two adjacent vertices get the same color. Parameters ---------- G : networkx.Graph a simple undirected graph colors : list or positive int a list of colors or a number of colors Returns ------- CNF the CNF encoding of the coloring problem on graph ``G`` """ col = CNF() if isinstance(colors, int) and colors >= 0: colors = range(1, colors + 1) if not isinstance(list, collections.Iterable): ValueError("Parameter \"colors\" is expected to be a iterable") # Describe the formula name = "graph colorability" if hasattr(G, 'name'): col.header = name + " of graph:\n" + G.name + ".\n\n" + col.header else: col.header = name + ".\n\n" + col.header # Fix the vertex order V = enumerate_vertices(G) # Each vertex has a color for vertex in V: clause = [] for color in colors: clause += [(True, 'x_{{{0},{1}}}'.format(vertex, color))] col.add_clause(clause) # unique color per vertex if functional: for (c1, c2) in combinations(colors, 2): col.add_clause([(False, 'x_{{{0},{1}}}'.format(vertex, c1)), (False, 'x_{{{0},{1}}}'.format(vertex, c2))], strict=True) # This is a legal coloring for (v1, v2) in enumerate_edges(G): for c in colors: col.add_clause([(False, 'x_{{{0},{1}}}'.format(v1, c)), (False, 'x_{{{0},{1}}}'.format(v2, c))], strict=True) return col