def _assert_lt(self, cost): """ The method enforces an upper bound on the cost of the MaxSAT solution. This is done by encoding the sum of all soft clause selectors with the use the iterative totalizer encoding, i.e. :class:`.ITotalizer`. Note that the sum is created once, at the beginning. Each of the following calls to this method only enforces the upper bound on the created sum by adding the corresponding unit size clause. Each such clause is added on the fly with no restart of the underlying SAT oracle. :param cost: the cost of the next MaxSAT solution is enforced to be *lower* than this current cost :type cost: int """ if self.tot == None: self.tot = ITotalizer(lits=self.sels, ubound=cost-1, top_id=self.topv) self.topv = self.tot.top_id for cl in self.tot.cnf.clauses: self.oracle.add_clause(cl) self.oracle.add_clause([-self.tot.rhs[cost-1]])
def itotalizer(self, lits, ubound=None): """ **Added in SugarRush**\n Uses :meth:`pysat.card.ITotalizer`. Adds automatic bookkeeping of literals. """ if ubound is None: ubound = len(lits) itot = ITotalizer(lits, ubound) clauses = itot.cnf.clauses bound_vars = itot.rhs self._add_lits_from(clauses) return clauses, bound_vars
def calc_sensitivity(model): n_eq = 0 it = ITotalizer(lits=[model['net_map'][n] for n in model['flip_outputs']], top_id=len(model['net_map']), ubound=len(model['inputs'])) solver = Cadical(bootstrap_with=model['clauses'] + it.cnf.clauses) while True: if solver.solve(assumptions=[-it.rhs[n_eq]]): break else: n_eq += 1 if n_eq == len(model['inputs']): print('0 sensitivity reached') exit() model['sensitivity'] = (len(model['inputs']) - n_eq) / len(model['inputs'])
def _assert_lt(self, cost): """ The method enforces an upper bound on the cost of the MaxSAT solution. For unweighted problems, this is done by encoding the sum of all soft clause selectors with the use the iterative totalizer encoding, i.e. :class:`.ITotalizer`. Note that the sum is created once, at the beginning. Each of the following calls to this method only enforces the upper bound on the created sum by adding the corresponding unit size clause. For weighted problems, the PB encoding given through the :meth:`__init__` method is used. Each such clause is added on the fly with no restart of the underlying SAT oracle. :param cost: the cost of the next MaxSAT solution is enforced to be *lower* than this current cost :type cost: int """ if self.is_weighted: # TODO: use incremental PB encoding self.oracle.append_formula( PBEnc.leq(self.sels, weights=self.formula.wght, bound=cost - 1, vpool=self.vpool)) else: if self.tot is None: self.tot = ITotalizer(lits=self.sels, ubound=cost - 1, top_id=self.vpool.top) self.vpool.top = self.tot.top_id for cl in self.tot.cnf.clauses: self.oracle.add_clause(cl) self.oracle.add_clause([-self.tot.rhs[cost - 1]])
def create_sum(self, bound=1): """ Create a totalizer object encoding a new cardinality constraint. For Minicard, native atmostb constraints is used instead. """ if self.solver != 'mc': # standard totalizer-based encoding # new totalizer sum t = ITotalizer(lits=self.rels, ubound=bound, top_id=self.topv) # updating top variable id self.topv = t.top_id # adding its clauses to oracle for cl in t.cnf.clauses: self.oracle.add_clause(cl) else: # for minicard, use native cardinality constraints instead of the # standard totalizer, i.e. create a new (empty) totalizer sum and # fill it with the necessary data supported by minicard t = ITotalizer() t.lits = self.rels self.topv += 1 # a new variable will represent the bound # proper initial bound t.rhs = [None] * (len(t.lits)) t.rhs[bound] = self.topv # new atmostb constraint instrumented with # an implication and represented natively rhs = len(t.lits) amb = [[-self.topv] * (rhs - bound) + t.lits, rhs] # add constraint to the solver self.oracle.add_atmost(*amb) return t
for inp_con in other_inputs: c.nodes[f'flip_{inp}_{inp_con}']['gate'] = 'buf' c.add_edge(inp_con, f'flip_{inp}_{inp_con}') # add output xnor c.add_node(f'flip_{inp}_output_xnor', gate='xnor') c.add_edge(f'flip_{inp}_out', f'flip_{inp}_output_xnor') c.add_edge('out', f'flip_{inp}_output_xnor') flip_outputs.append(f'flip_{inp}_output_xnor') # get dimacs clauses, net_map = gates2dimacs(c) # encode sensitivity value it = ITotalizer(lits=[net_map[n] for n in flip_outputs], top_id=len(net_map), ubound=len(protected_inputs)) solver = Cadical(bootstrap_with=clauses + it.cnf.clauses) # find max sensitivity input, check n_eq = 0 while n_eq < len(protected_inputs): if solver.solve(assumptions=[-it.rhs[n_eq]]): # get input output m = solver.get_model() inp = {i: m[net_map[i] - 1] > 0 for i in protected_inputs} s = (len(protected_inputs) - n_eq) / len(protected_inputs) print(f'found input w/ sensitivity {s}') # check input against key if all(inp[f'protected_in_{i}_'] == k for i, k in enumerate(key)):