def _init(self, formula): """ SAT oracle initialization. The method creates a new SAT oracle and feeds it with the formula's hard clauses. Afterwards, all soft clauses of the formula are augmented with selector literals and also added to the solver. The list of all introduced selectors is stored in variable ``self.sels``. :param formula: input MaxSAT formula :type formula: :class:`WCNF` """ self.oracle = Solver(name=self.solver, bootstrap_with=formula.hard, incr=True, use_timer=True) for i, cl in enumerate(formula.soft): # TODO: if clause is unit, use its literal as selector # (ITotalizer must be extended to support PB constraints first) selv = self.vpool._next() cl.append(selv) self.oracle.add_clause(cl) self.sels.append(selv) self.is_weighted = any(w > 1 for w in formula.wght) if self.verbose > 1: print('c formula: {0} vars, {1} hard, {2} soft'.format( formula.nv, len(formula.hard), len(formula.soft)))
def __init__(self, formula, use_cld=False, solver_name='m22', use_timer=False): """ Constructor. """ # bootstrapping the solver with hard clauses self.oracle = Solver(name=solver_name, bootstrap_with=formula.hard, use_timer=use_timer) self.topv = formula.nv # top variable id self.soft = formula.soft self.sels = [] self.ucld = use_cld # mappings between internal and external variables VariableMap = collections.namedtuple('VariableMap', ['e2i', 'i2e']) self.vmap = VariableMap(e2i={}, i2e={}) # at this point internal and external variables are the same for v in range(1, formula.nv + 1): self.vmap.e2i[v] = v self.vmap.i2e[v] = v for cl in self.soft: sel = cl[0] if len(cl) > 1 or cl[0] < 0: self.topv += 1 sel = self.topv self.oracle.add_clause(cl + [-sel]) self.sels.append(sel)
def test_cnfplus(): # testing cnf1: for name in solvers: if name != 'minicard': try: with Solver(name=name, bootstrap_with=cnf1) as s: s.solve() assert False, 'we should not get here' except NotImplementedError: pass else: with Solver(name=name, bootstrap_with=cnf1) as s: for i, model in enumerate(s.enum_models(), 1): pass assert i == 5, 'there should be 5 models' for name in solvers: if name != 'minicard': try: with Solver(name=name) as s: s.append_formula(cnf1) s.solve() assert False, 'we should not get here' except NotImplementedError: pass else: with Solver(name=name) as s: s.append_formula(cnf1) for i, model in enumerate(s.enum_models(), 1): pass assert i == 5, 'there should be 5 models'
def __init__(self, formula, use_cld=False, solver_name='m22', use_timer=False): """ Constructor. """ # bootstrapping the solver with hard clauses self.oracle = Solver(name=solver_name, bootstrap_with=formula.hard, use_timer=use_timer) self.topv = formula.nv # top variable id self.soft = formula.soft self.sels = [] self.ucld = use_cld self.vmap_dir = {} self.vmap_opp = {} for cl in self.soft: sel = cl[0] if len(cl) > 1 or cl[0] < 0: self.topv += 1 sel = self.topv self.oracle.add_clause(cl + [-sel]) self.sels.append(sel) self.vmap_dir[sel] = len(self.sels) self.vmap_opp[len(self.sels)] = sel
def __init__(self, formula, solver='m22', verbosity=1): """ Constructor. """ topv, self.verbose = formula.nv, verbosity # clause selectors and a mapping from selectors to clause ids self.sels, self.vmap = [], {} # constructing the oracle self.oracle = Solver(name=solver, bootstrap_with=formula.hard, use_timer=True) if isinstance(formula, WCNFPlus) and formula.atms: assert solver in SolverNames.minicard, \ 'Only Minicard supports native cardinality constraints. Make sure you use the right type of formula.' for atm in formula.atms: self.oracle.add_atmost(*atm) # relaxing soft clauses and adding them to the oracle for i, cl in enumerate(formula.soft): topv += 1 self.sels.append(topv) self.vmap[topv] = i self.oracle.add_clause(cl + [-topv])
def solve_problem(input): sat_solver = Solver(name='g4') db = constructor_of_db(input["observations"]) db_ops = constructor_of_ops(input["observations"]) initial_clause(db, db_ops, input, sat_solver) if input["police"] + input["medics"] == 0: operations(db, db_ops, input, sat_solver) else: teams_operations(db, db_ops, input, sat_solver) quarantine(db_ops, input, sat_solver) immune(db_ops, input, sat_solver) queries = input["queries"] ans_dic = {} for query in queries: literal = extract_literal(query,db) ans = sat_solver.solve(assumptions = [literal]) if ans: other_literal_list = extract_other_literals(query,db) ans_list = [] for other_literal in other_literal_list: ans_list.append(sat_solver.solve(assumptions = [other_literal])) if sum(ans_list) >= 1: ans = '?' else: ans = 'T' else: ans = 'F' ans_dic["{}".format(query)] = "{}".format(ans) for key, value in ans_dic.items(): print("{}".format(key),":","'{}'".format(value))
def _one_node_maps_to_alo_state_classic(self, solver: Solver, size: int, new_node_from: int = 0) -> None: for i in range(new_node_from, self._apta.size): solver.add_clause( tuple(self._vars.var('x', i, j) for j in range(size)))
def init(self, with_soft=True): """ The method for the SAT oracle initialization. Since the oracle is is used non-incrementally, it is reinitialized at every iteration of the MaxSAT algorithm (see :func:`reinit`). An input parameter ``with_soft`` (``False`` by default) regulates whether or not the formula's soft clauses are copied to the oracle. :param with_soft: copy formula's soft clauses to the oracle or not :type with_soft: bool """ self.oracle = Solver(name=self.solver, bootstrap_with=self.hard, use_timer=True) if self.atm1: # this check is needed at the beggining (before iteration 1) assert self.oracle.supports_atmost(), \ '{0} does not support native cardinality constraints. Make sure you use the right type of formula.'.format(solver_name) # self.atm1 is not empty only in case of minicard for am in self.atm1: self.oracle.add_atmost(*am) if with_soft: for cl, cpy in zip(self.soft, self.scpy): if cpy: self.oracle.add_clause(cl)
def __init__(self, formula, use_cld=False, solver_name='m22', use_timer=False): """ Constructor. """ # bootstrapping the solver with hard clauses self.oracle = Solver(name=solver_name, bootstrap_with=formula.hard, use_timer=use_timer) self.topv = formula.nv # top variable id self.soft = [] self.ucld = use_cld self.vmap_dir = {} self.vmap_opp = {} for cl in formula.soft: new_cl = cl[:] if len(cl) > 1 or cl[0] < 0: self.topv += 1 sel = self.topv new_cl.append(-sel) # creating a new selector self.oracle.add_clause(new_cl) else: sel = cl[0] self.soft.append([sel]) self.vmap_dir[sel] = len(self.soft) self.vmap_opp[len(self.soft)] = sel
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 _state_has_at_least_one_parent(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(max(1, old_size), size): solver.add_clause( tuple( self._vars.var('p', child, parent) for parent in range(child)))
def __init__(self, formula, solver='g3', adapt=False, exhaust=False, minz=False, trim=False, verbose=0): """ Constructor. """ # verbosity level self.verbose = verbose # constructing a local copy of the formula self.formula = WCNFPlus() self.formula.hard = formula.hard[:] self.formula.wght = formula.wght[:] self.formula.topw = formula.topw self.formula.nv = formula.nv # top variable identifier self.topv = formula.nv # processing soft clauses self._process_soft(formula) self.formula.nv = self.topv # creating an unweighted copy unweighted = self.formula.copy() unweighted.wght = [1 for w in unweighted.wght] # enumerating disjoint MCSes (including unit-size MCSes) to_hit, self.units = self._disjoint(unweighted, solver, adapt, exhaust, minz, trim) if self.verbose > 2: print('c mcses: {0} unit, {1} disj'.format( len(self.units), len(to_hit) + len(self.units))) # hitting set enumerator self.hitman = Hitman(bootstrap_with=to_hit, weights=self.weights, solver=solver, htype='sorted', mxs_adapt=adapt, mxs_exhaust=exhaust, mxs_minz=minz, mxs_trim=trim) # SAT oracle bootstrapped with the hard clauses; note that # clauses of the unit-size MCSes are enforced to be enabled self.oracle = Solver(name=solver, bootstrap_with=unweighted.hard + [[mcs] for mcs in self.units])
def _one_node_maps_to_at_most_one_state(self, solver: Solver, size: int, new_node_from: int = 0, old_size: int = 0) -> None: for v in range(new_node_from, self._apta.size): for i in range(old_size, size): for j in range(0, i): solver.add_clause((-self._vars.var('x', v, i), -self._vars.var('x', v, j)))
def _state_has_at_most_one_parent(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(old_size, size): for parent in range(child): for other_parent in range(parent): solver.add_clause( (-self._vars.var('p', child, parent), -self._vars.var('p', child, other_parent)))
def _order_parents_using_np_variables(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(max(1, old_size - 1), size - 1): for parent in range(child): solver.append_formula( _implication_to_clauses( self._vars.var('p', child, parent), self._vars.var('np', child + 1, parent - 1)))
def _preserve_parent_order_on_children(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(max(2, old_size - 1), size - 1): for parent in range(1, child): for pre_parent in range(parent): solver.append_formula( _implication_to_clauses( self._vars.var('p', child, parent), -self._vars.var('p', child + 1, pre_parent)))
def _inconsistency_graph_constraints(self, solver: Solver, size: int, new_node_from: int = 0, old_size: int = 0) -> None: for node1 in range(self._ig.size): for node2 in self._ig.edges[node1]: if node1 >= new_node_from or node2 >= new_node_from: for s in range(old_size, size): solver.add_clause((-self._vars.var('x', node1, s), -self._vars.var('x', node2, s)))
def _one_node_maps_to_alo_state_switch(self, solver: Solver, size: int, new_node_from: int = 0, old_size: int = 0) -> None: for i in range(new_node_from, self._apta.size): solver.add_clause( tuple(self._vars.var('x', i, j) for j in range(size)) + (self._vars.var('sw_x', size, i), )) if old_size > 0: for v in range(self._apta.size): solver.add_clause((self._vars.var('sw_x', old_size, v), ))
def _define_t_variables(self, solver: Solver, size: int, old_size: int = 0) -> None: for to in range(old_size, size): for from_ in range(to): solver.append_formula( _iff_disjunction_to_clauses( self._vars.var('t', from_, to), tuple( self._vars.var('y', from_, l_id, to) for l_id in range(self._alphabet_size))))
def _define_p_variables(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(old_size, size): for parent in range(child): solver.append_formula( _iff_conjunction_to_clauses( self._vars.var('p', child, parent), tuple(-self._vars.var('t', prev, child) for prev in range(parent)) + (self._vars.var('t', parent, child), )))
def search(self, lower_bound: int, upper_bound: int) -> Optional[DFA]: self._solver = Solver(self._solver_name) log_info('Solver has been started.') for size in range(lower_bound, upper_bound + 1): if self._assumptions_mode == 'none' and size > lower_bound: self._solver = Solver(self._solver_name) log_info('Solver has been restarted.') log_br() log_info('Trying to build a DFA with {0} states.'.format(size)) STATISTICS.start_formula_timer() if self._assumptions_mode != 'none' and size > lower_bound: self._clause_generator.generate_with_new_size( self._solver, size - 1, size) else: self._clause_generator.generate(self._solver, size) STATISTICS.stop_formula_timer() assumptions = self._clause_generator.build_assumptions( size, self._solver) while True: dfa = self._try_to_synthesize_dfa(size, assumptions) if dfa: counter_examples = self._examples_provider.get_counter_examples( dfa) if counter_examples: log_info( 'An inconsistent DFA with {0} states is found.'. format(size)) log_info('Added {0} counterexamples.'.format( len(counter_examples))) STATISTICS.start_apta_building_timer() (new_nodes_from, changed_statuses ) = self._apta.add_examples(counter_examples) STATISTICS.stop_apta_building_timer() STATISTICS.start_ig_building_timer() self._ig.update(new_nodes_from) STATISTICS.stop_ig_building_timer() STATISTICS.start_formula_timer() self._clause_generator.generate_with_new_counterexamples( self._solver, size, new_nodes_from, changed_statuses) STATISTICS.stop_formula_timer() continue break if not dfa: log_info('Not found a DFA with {0} states.'.format(size)) else: log_success('The DFA with {0} states is found!'.format(size)) return dfa return None
def __init__(self, formula, use_cld=False, solver_name='m22', use_timer=False): """ Constructor. """ # bootstrapping the solver with hard clauses self.oracle = Solver(name=solver_name, bootstrap_with=formula.hard, use_timer=use_timer) self.solver = solver_name # adding native cardinality constraints (if any) as hard clauses # this can be done only if the Minicard solver is in use if isinstance(formula, WCNFPlus) and formula.atms: assert solver_name in SolverNames.minicard or \ solver_name in SolverNames.gluecard3 or \ solver_name in SolverNames.gluecard4, \ '{0} does not support native cardinality constraints'.format(solver_name) for atm in formula.atms: self.oracle.add_atmost(*atm) self.topv = formula.nv # top variable id self.sels = [] self.ucld = use_cld self.smap = {} # mappings between internal and external variables VariableMap = collections.namedtuple('VariableMap', ['e2i', 'i2e']) self.vmap = VariableMap(e2i={}, i2e={}) # at this point internal and external variables are the same for v in range(1, formula.nv + 1): self.vmap.e2i[v] = v self.vmap.i2e[v] = v for cl in formula.soft: new_cl = cl[:] if len(cl) > 1 or cl[0] < 0: self.topv += 1 sel = self.topv new_cl.append(-sel) # creating a new selector self.oracle.add_clause(new_cl) else: sel = cl[0] self.sels.append(sel) self.smap[sel] = len(self.sels)
def _define_m_variables(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(old_size, size): for parent in range(child): for l_num in range(self._alphabet_size): solver.append_formula( _iff_conjunction_to_clauses( self._vars.var('m', parent, l_num, child), tuple(-self._vars.var('y', parent, l_less, child) for l_less in range(l_num)) + (self._vars.var('y', parent, l_num, child), )))
def _define_np_variables(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(max(old_size, 2), size): solver.append_formula( _iff_to_clauses(self._vars.var('np', child, 0), -self._vars.var('p', child, 0))) for parent in range(1, child): solver.append_formula( _iff_conjunction_to_clauses( self._vars.var('np', child, parent), (self._vars.var('np', child, parent - 1), -self._vars.var('p', child, parent))))
def test_cnf(): # testing cnf2 for name in solvers: with Solver(name=name, bootstrap_with=cnf2) as s: for i, model in enumerate(s.enum_models(), 1): pass assert i == 5, 'there should be 5 models' for name in solvers: with Solver(name=name) as s: s.append_formula(cnf2) for i, model in enumerate(s.enum_models(), 1): pass assert i == 5, 'there should be 5 models'
def _define_p_variables_using_nt(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(max(1, old_size), size): solver.append_formula( _iff_to_clauses(self._vars.var('p', child, 0), self._vars.var('t', 0, child))) for parent in range(1, child): solver.append_formula( _iff_conjunction_to_clauses( self._vars.var('p', child, parent), (self._vars.var('t', parent, child), self._vars.var('nt', parent - 1, child))))
def _order_children_using_zm(self, solver: Solver, size: int, old_size: int = 0) -> None: for child in range(max(0, old_size - 1), size - 1): for parent in range(child): for l_num in range(1, self._alphabet_size): solver.append_formula( _conjunction_implies_to_clauses( (self._vars.var('p', child, parent), self._vars.var('p', child + 1, parent), self._vars.var('m', parent, l_num, child)), self._vars.var('zm', parent, l_num - 1, child + 1)))
def _dfa_is_deterministic(self, solver: Solver, size: int, old_size: int = 0) -> None: for l_id in range(self._alphabet_size): for i in range(old_size): for j in range(old_size, size): for k in range(j): solver.add_clause((-self._vars.var('y', i, l_id, j), -self._vars.var('y', i, l_id, k))) for i in range(old_size, size): for j in range(size): for k in range(j): solver.add_clause((-self._vars.var('y', i, l_id, j), -self._vars.var('y', i, l_id, k)))
def vdWtest(): fmla = vdW(3, 3, 20) fmla.to_fp(sys.stdout) for N in range(1, 50): print(N) with Solver(name="cdl", bootstrap_with=vdW(3, 3, N)) as S: print(S.solve())
def GreedyCoreMetric(fmla, y_true, y_pred): """ Args: y_true: a bitmask y_pred: probability distribution """ UNSAT_FLAG = False sorted_indices = np.argsort(y_pred, kind="mergesort") print(sorted_indices) with Solver(name="cdl") as S: count = 0 indices = [] for i in range(len(sorted_indices)): next_index = sorted_indices[-(i + 1)] indices.append(next_index) next_clause = fmla.clauses[next_index] S.add_clause(next_clause) count += 1 if not S.solve(): UNSAT_FLAG = True break assert UNSAT_FLAG gen_core_length = len(indices) labelled_core_length = int( tf.reduce_sum(tf.cast(y_true, tf.int32), axis=-1)) return indices, gen_core_length, labelled_core_length, float( gen_core_length / labelled_core_length)