def get_literal_value(self, lit): """ Returns an SDD representing the literal value. For each literal this will be (the negation of) an sdd variable If an input atom has no sdd var representation yet, a new sdd variable is created :param lit: the literal to represent :return: An sdd representing this literal. """ if not lit.negated: result = self.atom2sdd.setdefault(lit, sddm.sdd_manager_false(self.manager)) sddm.sdd_ref(result, self.manager) return result else: result = self.atom2sdd.setdefault(lit.negate(), sddm.sdd_manager_false(self.manager)) result = sdd_negate(result, self.manager) # Note: sdd_negate increases the reference count by one. return result
def compile_new_proof(self, head, new_proof): """ Compiles a new proof for head :param head: the head whose sdd should be updated :param new_proof: a formula representing a new proof for head. I.e., a formula such that lit2sdd(head) should be updated to lit2sdd(head) | compile(new_proof) :return True if lit2sdd[head] has changed; False otherwise """ if head not in self.lit2sdd: self.lit2sdd[head] = sddm.sdd_manager_false(self.manager) sdd_head_changed = True sdd_head_old = self.lit2sdd[head] new_sdd = compile_formula(new_proof, self.manager, self.get_literal_value) # new_sdd is an SDD represeting the new proof final_sdd = sdd_disjoin([self.lit2sdd[head], new_sdd], self.manager) # final_sdd is an SDD represeting the new value of lit2sdd[head] sddm.sdd_deref(new_sdd, self.manager) self.lit2sdd[head] = final_sdd if sdd_head_old == self.lit2sdd[head]: sdd_head_changed = False sddm.sdd_deref(sdd_head_old, self.manager) return sdd_head_changed
def compile_default(self, lits): """ Sets the literals in lits to their default value (false) if they are not compiled yet :param lits: The set of literals that should have a value after calling this method :return: """ for lit in lits: self.lit2sdd.setdefault(lit, sddm.sdd_manager_false(self.manager))
def get_literal_value(self, lit): """ Returns an SDD representing the literal value. This basically looks up lit in lit2sdd, returning a false SDD in case this literal is not yet present in the mapping :param lit: the literal to represent :return: An sdd representing this literal. Increases the reference count of this sdd by one """ result = self.lit2sdd.setdefault(lit, sddm.sdd_manager_false(self.manager)) sddm.sdd_ref(result, self.manager) return result
def set_value_to(self, lit, formula): """ Sets the value of lit in lit2sdd to the value obtained by compiling the formula :param lit: the literal whose value should change :param formula: the formula representing the new value of lit :return: """ orig_value = self.lit2sdd.get(lit, sddm.sdd_manager_false(self.manager)) new_value = compile_formula(formula, self.manager, self.get_literal_value) sddm.sdd_deref(orig_value, self.manager) self.lit2sdd[lit] = new_value
def sdd_disjoin(sdd_list, manager): """ Disjoins all the input sdds to one large sdd :param sdd_list: a list of input sdds :param manager: the manager managing all of the input sdds :return: An SDD: the disjunction of the input sdds. This SDD has +1 reference count. """ import time alpha = sddm.sdd_manager_false(manager) for sdd in sdd_list: beta = sddm.sdd_disjoin(alpha, sdd, manager) sddm.sdd_ref(beta, manager) sddm.sdd_deref(alpha, manager) alpha = beta return alpha
def compile_formula(formula, manager, get_literal_value): """ Compiles the input formula for the given manager. :param formula: the logical formula to compile to an sdd :param manager: the manager managing all sdds :param get_literal_value: a function that returns for each literal an sdd, used to compile leafs of the formula this function is supposed to increase the reference count of the SDD it outputs by one! :return: An SDD represeting the formula. This SDD has +1 reference count. """ # Flyweights doen iets raar met types. type(formula) is ground.LIterals werkt bijvoorbeeld niet. # Daarom de lelijke hacks if formula is logic.TrueForm(): return sddm.sdd_manager_true(manager) elif formula is logic.FalseForm(): return sddm.sdd_manager_false(manager) elif isinstance(formula, type(logic.Literal("", True))): result = get_literal_value(formula) # Note: get_literal_value does the increment of the reference count return result elif type(formula) is logic.Disjunction: compiled_subforms = [] for subform in formula.subforms: compiled_subform = compile_formula(subform, manager, get_literal_value) compiled_subforms.append(compiled_subform) result = sdd_disjoin(compiled_subforms, manager) # Note: sdd_disjoin does the increment of the reference count for compiled_form in compiled_subforms: sddm.sdd_deref(compiled_form, manager) return result elif type(formula) is logic.Conjunction: compiled_subforms = [] for subform in formula.subforms: compiled_subform = compile_formula(subform, manager, get_literal_value) compiled_subforms.append(compiled_subform) result = sdd_conjoin(compiled_subforms, manager) # Note: sdd_conjoin does the increment of the reference count for compiled_form in compiled_subforms: sddm.sdd_deref(compiled_form, manager) return result else: print(type(formula)) raise NotImplementedError
def backup_neg_literals(self): """ Backups all SDDs associated to negative literals and replaces those SDDs by "True". This is used to prepare a logic program for unfounded set computation. NOTE: if some atom is already interpreted two-valued, its negative literal will not be updated. :return: the set of literals whose value has changed. """ changed = [] self.backup_sdd = OrderedDict() for lit, sdd in self.lit2sdd.items(): to_backup = lit.negated to_backup &= (sdd != sddm.sdd_manager_true(self.manager)) true_sdd = self.lit2sdd.get(lit.negate(), sddm.sdd_manager_false(self.manager)) neg_true_sdd = sdd_negate(true_sdd, self.manager) to_backup &= (sdd != neg_true_sdd) sddm.sdd_deref(neg_true_sdd, self.manager) if to_backup: self.backup_sdd[lit] = sdd changed.append(lit) self.lit2sdd[lit] = sddm.sdd_manager_true(self.manager) return changed