Exemple #1
0
def create_sat_problem(sat_required, *args):
    """
    Creates a new instance of a SAT problem and returns the list of clauses.
    :param sat_required: is the problem instance required to be satisfiable?
    :param args: list of arguments as if cnfgen is being called from the command line
    :return:
    """
    # calls cnfgen to generate an instance
    # TODO use cnfgen programatically, if possible
    command_array = ['cnfgen', '-q', '-o', 'tmp.cnf'] + [str(a) for a in args]
    subprocess.call(command_array)
    f = CNF(from_file='tmp.cnf')
    if not sat_required:
        os.remove('tmp.cnf')
        return f.clauses

    else:  # the instance must be satisfiable, will check with Pysat's solver
        while True:
            with Solver(name='Glucose3', bootstrap_with=f.clauses) as solver:
                if solver.solve():  # instance is satisfiable, return it
                    os.remove('tmp.cnf')
                    return f.clauses
                else:
                    # generates a new instance
                    subprocess.call(command_array)
                    f = CNF(from_file='tmp.cnf')
Exemple #2
0
    def test_from_dataset(self):
        """
        Simple test with a 2-instance dataset
        :return:
        """
        dataset = [
            'instances/sat_00001_k3_v20_c91.cnf',
            'instances/sat_00002_k3_v20_c91.cnf'
        ]
        env = MultiSATEnv(LocalSearchSAT, from_dataset=dataset)
        self.assertEqual(dataset, env.dataset)
        self.assertEqual(0, env.dataset_index)

        # at reset, the environment will load the first instance
        env.reset()
        self.assertEqual(
            CNF(dataset[0]).clauses, env.current_instance.original_clauses)
        self.assertEqual(1, env.dataset_index)

        # now the second instance
        env.reset()
        self.assertEqual(
            CNF(dataset[1]).clauses, env.current_instance.original_clauses)
        self.assertEqual(0, env.dataset_index)  # index wrapped around

        # first instance again (wrapped)
        env.reset()
        self.assertEqual(
            CNF(dataset[0]).clauses, env.current_instance.original_clauses)
        self.assertEqual(1, env.dataset_index)
def solve_sudoku_SAT(sudoku, k):
    num_vertices = k ** 4
    vertices, edges = make_sudoku_graph(k)

    number_colors = k ** 2
    formula = CNF()

    # Assign a positive integer for each propositional variable.
    def var_number(i, c):
        return ((i - 1) * number_colors) + c

    flatten_sudoku = np.array(sudoku).reshape(num_vertices)

    # Clause that ensures that each vertex there is one value.
    for i in range(1, num_vertices + 1):
        clause = []

        sudoku_value = int(flatten_sudoku[i - 1])
        not_assigned = sudoku_value == 0

        if not_assigned:
            for c in range(1, number_colors + 1):
                clause.append(var_number(i, c))
        else:
            clause.append(var_number(i, sudoku_value))

        formula.append(clause)

    # Ensure that only one value is assigned.
    for i in range(1, num_vertices + 1):
        for c1 in range(1, number_colors + 1):
            for c2 in range(c1 + 1, number_colors + 1):
                clause = [-1 * var_number(i, c1), -1 * var_number(i, c2)]
                formula.append(clause)

    # Ensure that the rules of sudoku are kept, no adjacent vertices should have the same color/value.
    for (v1, v2) in edges:
        for c in range(1, number_colors + 1):
            clause = [-1 * var_number(v1, c), -1 * var_number(v2, c)]
            formula.append(clause)

    solver = MinisatGH()
    solver.append_formula(formula)
    answer = solver.solve()

    flatten_vertices = np.array(vertices).reshape(num_vertices)

    if answer:
        print("The sudoku is solved.")
        model = solver.get_model()
        print(model)
        for i in range(1, num_vertices + 1):
            for c in range(1, number_colors + 1):
                if var_number(i, c) in model:
                    flatten_vertices[i - 1] = c

        return flatten_vertices.reshape(k**2, k**2).tolist()
    else:
        print("The sudoku has no solution.")
        return None
Exemple #4
0
    def load_from(self, infile):
        """
            Loads the encoding from an input file.
        """

        self.enc = CNF(from_file=infile)

        # empty intervals for the standard encoding
        self.intvs, self.imaps, self.ivars = {}, {}, {}

        for line in self.enc.comments:
            if line.startswith('c i ') and 'none' not in line:
                f, arr = line[4:].strip().split(': ', 1)
                f = f.replace('-', '_')
                self.intvs[f], self.imaps[f], self.ivars[f] = [], {}, []

                for i, pair in enumerate(arr.split(', ')):
                    ub, symb = pair.split(' <-> ')
                    ub = ub.strip('"')
                    symb = symb.strip('"')

                    if ub[0] != '+':
                        ub = float(ub)

                    self.intvs[f].append(ub)
                    self.ivars[f].append(symb)
                    self.imaps[f][ub] = i

            elif line.startswith('c features:'):
                self.feats = line[11:].strip().split(', ')
            elif line.startswith('c classes:'):
                self.nofcl = int(line[10:].strip())
def RandKCNF(k, n, m):
    clauses = [
        randomly_flip(random.sample(range(1,
                                          int(n) + 1), k))
        for _ in range(int(m))
    ]
    return CNF(from_clauses=clauses)
 def gen_formula(self):
     try:
         cnf = CNF(from_file=self.files[self.file_index])
     except IndexError:
         raise StopIteration
     self.file_index += 1
     return cnf
Exemple #7
0
def is_satisfiable(e):
    formula = CNF()
    clauses, _, _ = _tseitin(e)
    for clause in clauses:
        formula.append(clause)
    with Lingeling(bootstrap_with=formula.clauses) as ling:
        return ling.solve()
Exemple #8
0
 def __init__(self):
     """
     Constructor of the class. Always create an empty solver
     """
     self.formula = CNF()
     self.quantifiers = []
     self.propagate = []
def sample_SRC_aux(n, u1, c_idx, l_idx, p_geo=0.4, p_binom=0.7):
    """
  Args:
  n: positive integer
  u1: an unsat core
  c_idx: a clause index
  l_idx: a literal index
  
  u1 must become sat if the literal at (c_idx, l_idx) is flipped.

  Note that if result, vs = sample_SR_aux(args...), then result + vs is a valid argument for u1

  Returns: a random formula drawn from n variables containing u1 as an unsat core, and the unsat core
  """
    result = CNF()
    u2 = u1.copy()
    u2.clauses[c_idx][l_idx] = -u2.clauses[c_idx][l_idx]
    with Solver(name="cdl") as S:
        while True:
            S.append_formula(u2)
            k = 1 + np.random.binomial(n=1,
                                       p=p_binom) + np.random.geometric(p_geo)
            vs = np.random.choice(n, size=min(n, k), replace=False)
            vs = [
                int(v + 1) if random.random() < 0.5 else int(-(v + 1))
                for v in vs
            ]
            S.add_clause(vs)
            if S.solve():
                result.append(vs)
            else:
                break
        for cls in u1.clauses:
            result.append(cls)
    return result, u1  # TODO(jesse): output a core clause mask
Exemple #10
0
    def sample(self, cnf_file, max_samples=1000):
        """
        Uses Unigen2 (https://bitbucket.org/kuldeepmeel/unigen) to generate a dataset
        :param cnf_file:
        :param max_samples:
        :return:
        """
        # makes sure that unigen working dir exists for positive and negative samples
        pos_dir = os.path.join(self.tmp_dir, 'positives')
        neg_dir = os.path.join(self.tmp_dir, 'negatives')
        os.makedirs(pos_dir, exist_ok=True)
        os.makedirs(neg_dir, exist_ok=True)

        # gets f from the cnf file
        f = CNF(cnf_file)
        self.formula = f

        print("Generating positive instances.")
        self.run_unigen(cnf_file, pos_dir, max_samples)
        # the file with the positive samples is pos_dir/cnf_file_0.txt
        cnf_name = os.path.splitext(os.path.basename(cnf_file))[0]
        positives = self.retrieve_samples(
            os.path.join(pos_dir, f'{cnf_name}_0.txt'))
        print(f'Sampled {len(positives)} unique positive instances')

        return positives  # prepare_dataset(positives, negatives, ds_path)
def sample_SR_aux(n, min_cls_len=1, p_binom=0.7, p_geo=0.4):
    """
  Args:
  n: positive integer

  Returns:
  A randomly-generated formula and a clause which makes the formula unsat

  This procedure has no guarantees on the number of clauses in the formula.

  Reference implementation in source code of NeuroSAT:
  https://github.com/dselsam/neurosat/blob/master/python/gen_sr_dimacs.py
  """
    result = CNF()
    with Solver(name="cdl") as S:
        while True:
            k = min_cls_len + np.random.binomial(
                n=1, p=p_binom) + np.random.geometric(p_geo)
            vs = np.random.choice(n, size=min(n, k), replace=False)
            vs = [
                int(v + 1) if random.random() < 0.5 else int(-(v + 1))
                for v in vs
            ]
            S.add_clause(vs)
            if S.solve():
                result.append(vs)
            else:
                break

    return result, vs
    def test_unigen_generate_dataset_small_formula(self):
        cnf_file = '/tmp/test_small.cnf'
        f = CNF(from_clauses=[[1, 2, 3], [4]])
        '''
        the formula above has 7 positive samples:
        positives = {  
            (1, 2, 3, 4),
            (1, 2, -3, 4),
            (1, -2, 3, 4),
            (1, -2, -3, 4),
            (-1, 2, 3, 4),
            (-1, 2, -3, 4),
            (-1, -2, 3, 4),
        }
        '''
        f.to_file(cnf_file)

        sampler = mlbf.positives.UnigenSampler()

        # a formula with very few solutions will return an empty dataset
        data = sampler.sample(cnf_file, 50)
        self.assertEqual(0, len(data))

        # deletes the temp file used to store the formula
        os.unlink(cnf_file)
Exemple #13
0
def solve_ins(instance):
    print(f"Solving using insertion: {instance}", flush=True)
    f = CNF(from_file=instance).clauses

    global calls
    calls = 0

    mus = list()

    while len(f) > 0:
        s = mus.copy()

        ci = 0
        clause = None
        while solve_CNF(s):
            clause = f[ci]
            s.append(clause)
            ci += 1

        if clause == None:
            break

        mus.append(clause)
        s.pop(-1)
        f = s

    return (calls, mus)
Exemple #14
0
def solve_ins_csr(instance):
    print(f"Solving using insertion and clause-set refinement: {instance}",
          flush=True)
    f = CNF(from_file=instance).clauses

    global calls
    calls = 0

    mus = list()

    while len(f) > 0:
        solve_with = mus.copy()
        solve_with.extend(f)

        if len(solve_with) == 0:
            break

        c = solve_with.pop(-1)
        res = solve_CNF_core(solve_with)
        print(res)
        if res[0]:
            mus.append(c)
            f.pop(-1)
        else:
            f = res[1]
            for m in mus:
                f.remove(m)

    return (calls, mus)
Exemple #15
0
def proccess_sat_file(filename, sat, solver):
  start_time = time.time()

  result = "{} || solver {} ".format(filename, solver)
  formula = CNF(from_file="./InstanciasSAT/" + filename)
  clauses = formula.clauses[:]
  nv = formula.nv

  original_time = time.time()
  original_solution = solve_clauses(clauses, solver)
  result += "|| original: {} || Tiempo: {:.10f} segundos ".format(original_solution, time.time() - original_time)

  clauses, nv = sat_to_3_sat(clauses, nv)
  if sat > 3:
    x_sat = 3
    while x_sat < sat:
      clauses, nv = reduce_to_x_sat(clauses, nv)
      x_sat += 1

  x_sat_time = time.time()
  x_sat_solution = solve_clauses(clauses, solver)
  result += "|| {}-SAT: {} || Tiempo: {:.10f} segundos ".format(sat, x_sat_solution, time.time() - x_sat_time)

  formula.clauses = clauses
  formula.nv = nv
  formula.to_file("./X-SAT/" + filename)

  result += "|| Tiempo total: {:.10f} segundos".format(time.time() - start_time)
  print(result)
Exemple #16
0
    def __init__(self, lits=[], ubound=1, top_id=None):
        """
            Constructor.
        """

        # internal totalizer object
        self.tobj = None

        # its characteristics
        self.lits = []
        self.ubound = 0
        self.top_id = 0

        # encoding result
        self.cnf = CNF()  # CNF formula encoding the totalizer object
        self.rhs = []  # upper bounds on the number of literals (rhs)

        # number of new clauses
        self.nof_new = 0

        # this newly created totalizer object is not yet merged in any other
        self._merged = False

        if lits:
            self.new(lits=lits, ubound=ubound, top_id=top_id)
Exemple #17
0
    def U_tile_dynamics(self):
        clauses = []
        for i in range(self.rows):
            for j in range(self.cols):
                for t in range(self.t_max + 1):
                    # first
                    if t == 0:
                        clauses.append([
                            -self.obj2id[f"U_{i}_{j}^{t}"],
                            self.obj2id[f"U_{i}_{j}^{t + 1}"]
                        ])

                    # middle
                    if t > 0 and t != self.t_max:
                        clauses.append([
                            -self.obj2id[f"U_{i}_{j}^{t}"],
                            self.obj2id[f"U_{i}_{j}^{t + 1}"]
                        ])
                        clauses.append([
                            -self.obj2id[f"U_{i}_{j}^{t}"],
                            self.obj2id[f"U_{i}_{j}^{t - 1}"]
                        ])

                    # last
                    if t == self.t_max:
                        clauses.append([
                            -self.obj2id[f"U_{i}_{j}^{t}"],
                            self.obj2id[f"U_{i}_{j}^{t - 1}"]
                        ])

        return CNF(from_clauses=clauses)
def reduce_board(size: int, rows: [[int]], cols: [[int]]):
    """Reduces the the description of a Nonogram puzzle to a CNF formula

    :param size: The number of cells in each row/column
    :param rows: The hints for each row
    :param cols: The hints for each column
    :return: A CNF object representing the board's possible solutions
    """
    clauses = []

    base = size * size
    for i, row in enumerate(rows):
        uvars = [j + (i * size) + 1 for j in range(size)]
        reduction = reduce_set(size, row, uvars, base)
        clauses += reduction.clauses
        base += len(reduction.auxvars)

    for i, col in enumerate(cols):
        uvars = [i + (j * size) + 1 for j in range(size)]
        reduction = reduce_set(size, col, uvars, base)
        clauses += reduction.clauses
        base += len(reduction.auxvars)

    cnf = CNF()
    for clause in clauses:
        cnf.append(clause)

    return cnf
Exemple #19
0
def resolver(passo: int,
             conjuntoVertices: bool = False,
             ordemVertices: bool = True):
    """Resolve o caminho eureliano do grafo.

	:param passo: Recebe um array contendo os primeiros passos de cada possível começo do problema
	:param conjuntoVertices: Exibir o uma lista fora de ordem com o conjunto dos vértices que resolvem o problema. (Default value = False)
	:param ordemVertices: Exibir o caminho pelos vértices a ser percorrido para resolver o problema. (Default value = True)

 	"""
    formula = CNF()
    g = Glucose4()
    getClausulas(matriz, formula)
    formula.append([passo])
    g.append_formula(formula)
    print(
        f'O passo inicial para prova é: \33[32m{passo}\33[m, o caminho com ele é \33[34m{g.solve()}\33[m'
    )
    model = g.get_model()
    if model:
        valoracaoValida = valoresValidos(model)
        print(f'Passos válidos: \33[35m{valoracaoValida}\33[m')
        if conjuntoVertices:
            print(
                f'Esse são os conjuntos de vértices usados (fora de ordem): \33[36m{caminhosUsados(model)}\33[m'
            )
        if ordemVertices:
            print(f"Ordem de passagem pelos vértices: ")
            printEmOrdem(valoracaoValida)
    print()
Exemple #20
0
    def read_observations(self):
        clauses = []
        for t in range(self.num_observations):
            for i in range(self.rows):
                for j in range(self.cols):
                    if self.observations[t][i][j] == "S":
                        clauses.append([
                            self.obj2id[f"S0_{i}_{j}^{t}"],
                            self.obj2id[f"S1_{i}_{j}^{t}"],
                            self.obj2id[f"S2_{i}_{j}^{t}"]
                        ])
                        continue
                    if self.observations[t][i][j] == "Q":
                        clauses.append([
                            self.obj2id[f"Q0_{i}_{j}^{t}"],
                            self.obj2id[f"Q1_{i}_{j}^{t}"]
                        ])
                        continue
                    if self.observations[t][i][j] == "U":
                        clauses.append([self.obj2id[f"U_{i}_{j}^{t}"]])
                        continue
                    if self.observations[t][i][j] == "H":
                        clauses.append([self.obj2id[f"H_{i}_{j}^{t}"]])
                        continue
                    if self.observations[t][i][j] == "I":
                        clauses.append([
                            self.obj2id[f"I0_{i}_{j}^{t}"],
                            self.obj2id[f"I_{i}_{j}^{t}"]
                        ])
                        continue

        return CNF(from_clauses=clauses)
Exemple #21
0
    def build_cnf(self):

        self.formula = CNF()
        colors = list(range(1, self.ncolors + 1))

        for n1, n2 in self.g.edges():
            for c in colors:
                self.formula.append(
                    [-self.cmap.enc(n1, c), -self.cmap.enc(n2, c)])

        #specials = [28, 194, 242, 355, 387, 397, 468]
        #ii = 1
        #for n in specials:
        #   self.formula.append([self.cmap.enc(n, ii)])
        #  ii += 1

        for n in self.g.nodes():
            #if not n in specials:
            self.formula.append([self.cmap.enc(n, c) for c in colors])
            for c1 in colors:
                for c2 in colors:
                    if c1 < c2:
                        self.formula.append(
                            [-self.cmap.enc(n, c1), -self.cmap.enc(n, c2)])

        return self.formula
Exemple #22
0
def get_formula(observations, decision_variables_p, p_to_atom,
                decision_variables_a, a_to_atom, no_police, no_medics,
                indices_list, state_codes, no_rounds):
    formula = CNF()

    initial_state_clauses = get_initial_state_clauses(observations,
                                                      decision_variables_p,
                                                      p_to_atom, state_codes,
                                                      indices_list)

    action_precondition_clauses = get_action_precondition_clauses(
        decision_variables_a, p_to_atom, a_to_atom, no_police, no_medics,
        indices_list)

    action_interference_clauses = get_action_interference_clauses(
        decision_variables_a, a_to_atom, state_codes, no_rounds)

    fact_achievement_clauses = get_fact_achievement_clauses(
        decision_variables_p, p_to_atom, decision_variables_a, a_to_atom)

    permanent_clauses = get_permanent_clauses(p_to_atom, decision_variables_a,
                                              a_to_atom, no_police, no_medics,
                                              indices_list, state_codes)

    clauses = initial_state_clauses + action_precondition_clauses + action_interference_clauses +\
              fact_achievement_clauses + permanent_clauses

    formula.extend(clauses)

    return formula
Exemple #23
0
    def build_cnf(self, ):
        
        self.formula = CNF()
        colors = list(range(1, self.ncolors + 1))    

        for clique in nx.find_cliques(self.g):
            col = 1
            for v in clique:
                self.formula.append([self.cmap.enc(v, col)])
                col += 1
            break

        for n1, n2 in self.g.edges():
            for c in colors:            
                self.formula.append([-self.cmap.enc(n1, c), -self.cmap.enc(n2, c)])


        for n in self.g.nodes():
            #if not n in specials:
            self.formula.append([self.cmap.enc(n, c) for c in colors])
            #for c1 in colors:
            #    for c2 in colors:
            #        if c1 < c2:
            #            self.formula.append([-self.cmap.enc(n, c1), -self.cmap.enc(n, c2)])
        
        return self.formula
Exemple #24
0
    def __init__(self, cnf_file=None, formula=None, choice_function=None):
        """
        Creates a DPLL search instance. Either the cnf_file or the formula must be supplied
        :param cnf_file: path to a .cnf file
        :param formula: pysat.formula.CNF instance
        :param choice_function: function that receives a formula (pysat.formula.CNF) and a model (dict(var->assignment in DIMACS notation)) and chooses the next literal to branch on
        """
        if cnf_file is None and formula is None:
            raise ValueError('Please provide either a cnf file or a formula')
        self.choose_literal = choice_function if choice_function is not None else dpll.choose_random_literal

        self.formula = formula if formula is not None else CNF(
            from_file=cnf_file)
        self.n_vars = self.formula.nv

        self.statistics = {
            'branches': 0,
            'unit_propagations': 0,
            'purifications': 0,
            'up_clauses_cleaned': 0,
            'up_literals_cleaned': 0,
        }

        self.solved = False
        self.model_count = 0
Exemple #25
0
def solve_sudoku_SAT(sudoku, k):
    #############
    # this solution is adjusted from https://github.com/taufanardi/sudoku-sat-solver/blob/master/Sudoku.py
    # what I have done differently:
    # 1. Adjusted so that it can generate to k-sized problem, not just hardcoded k=3 in the original post
    # 2. Refactored the code to make it more readable and splitted into smaller functions instead of chunk of code
    # 3. Rewrited the `add_distinct_clauses` code to make it more robust and easy to understand
    #############
    # make clauses
    clauses = create_clauses(sudoku, k)
    # append clauses to formula
    formula = CNF()
    for c in clauses:
        formula.append(c)
    # solve the SAT problem
    solver = MinisatGH()
    solver.append_formula(formula)
    answer = solver.solve()
    if not answer:
        return None
    # get the solution
    solution = solver.get_model()
    # reformat the solution into a suduko representation
    for i in range(1, k**2 + 1):
        for j in range(1, k**2 + 1):
            sudoku[i - 1][j - 1] = extract_digit_from_solution(
                i, j, solution, k)
    return sudoku
def _optimize(epeg, constraints, top_id, lower_bound, upper_bound, model):

    if lower_bound <= upper_bound:

        cost = int((2 * lower_bound + upper_bound) / 3)

        lits = []
        weights = []
        for key, value in epeg.nodes.items():
            lits.append(key)
            weights.append(value.cost)

        object_function = PBEnc.leq(lits=lits,
                                    weights=weights,
                                    bound=cost,
                                    top_id=top_id)

        cnf = CNF(from_clauses=constraints.clauses + object_function.clauses)
        solver = Minisat22()
        solver.append_formula(cnf.clauses)

        if solver.solve():
            model = solver.get_model()
            return _optimize(epeg, constraints, top_id, lower_bound, cost - 1,
                             model)
        else:
            return _optimize(epeg, constraints, top_id, cost + 1, upper_bound,
                             model)

    return model, lower_bound
 def __init__(self, dimacs_file, csv_file, verbose=False):
     self.__dimacs = DimacsFile(dimacs_file)
     self.__csv = CSVFile(csv_file)
     self.__cnf = CNF(from_file=dimacs_file)
     self.__formula = Solver(bootstrap_with=self.__cnf.clauses)
     assert self.__formula.solve() is True, "initial formula is UNSAT"
     self.__config_d = None
     self.__verbose = verbose
 def test_step_flips_correct_var(self):
     f = CNF(from_clauses=[[-1, -2], [2], [2, -3, -4]])
     env = LocalSearchSAT(f.clauses)
     exp_model = np.copy(env.values)
     # flips the first var in the expected model and compares if it is equal to the environment's
     obs, reward, done, info = env.step(0)
     exp_model[0] = -exp_model[0]
     self.assertTrue((exp_model == obs['values']).all(), f'exp=\n{exp_model}\nactual=\n{obs["values"]}')
def unsat_core_example():
    fmla = CNF()
    fmla.append([1, 2, 3])
    fmla.append([-1, 2, 3])
    fmla.append([2, -3])
    fmla.append([-2, -3])
    fmla.append([-2, 3])
    return fmla
def validate_get_unsat_core_pysat(fmla, result, bad_asms):
    core = CNF(from_clauses=[fmla.clauses[i] for i in result])
    for asm in bad_asms:
        core.append([asm])
    with Solver(name="cdl") as S:
        S.append_formula(core)
        assert S.solve() is False
        print("ok")