예제 #1
0
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
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
 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)
예제 #6
0
 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)
예제 #7
0
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
예제 #8
0
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
예제 #9
0
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