Beispiel #1
0
    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
Beispiel #2
0
    def get_entire_program_as_sdd(self):
        """
        Returns an SDD representing the entire logic program.
        :return: an SDD representing the entire logic program
        """
        if self._entire_program_as_sdd is not None:
            return self._entire_program_as_sdd

        equivalences = []

        for atom, sdd in self.atom2sdd.items():
            sdd_var_num = self.get_sdd_var_num(atom)
            sdd4atom = sddm.sdd_manager_literal(sdd_var_num, self.manager)
            sddm.sdd_ref(sdd4atom, self.manager)
            equiv = sdd_equiv(sdd4atom, sdd, self.manager)
            sddm.sdd_deref(sdd4atom, self.manager)
            equivalences.append(equiv)

        equivalences.append(self.constraint)
        sddm.sdd_ref(self.constraint, self.manager)

        equivalences = sort_sdds(equivalences)




        result = sdd_conjoin(equivalences, self.manager)



        for sdd in equivalences:
            sddm.sdd_ref(sdd, self.manager)

        self._entire_program_as_sdd = result
        return result
Beispiel #3
0
 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
Beispiel #4
0
 def addconstraint_without_evaluating(self, formula):
     """
     Adds a constraint to this data structure. Conjoins self.constraint with the compilation of the formula
     :param formula: the formula to compile. Literals in this constraint are replaced by the sdd var number stored
     for them in self.atom2sdd if existing, and to a new sdd variable otherwise.
     :return: nothing
     """
     new_constraint = compile_formula(formula, self.manager, self.get_literal_sdd_leaf)
     old_constraint = self.constraint
     self.constraint = sdd_conjoin([old_constraint, new_constraint], self.manager)
     sddm.sdd_deref(new_constraint, self.manager)
     sddm.sdd_deref(old_constraint, self.manager)
Beispiel #5
0
 def addconstraint(self, formula):
     """
     Adds a constraint to this data structure. Conjoins self.constraint with the compilation of the formula
     :param formula: the formula to compile. Literals in this constraint are replaced by their value according to
     self.get_literal_value
     :return: nothing
     """
     new_constraint = compile_formula(formula, self.manager, self.get_literal_value)
     old_constraint = self.constraint
     self.constraint = sdd_conjoin([old_constraint, new_constraint], self.manager)
     sddm.sdd_deref(new_constraint, self.manager)
     sddm.sdd_deref(old_constraint, self.manager)
Beispiel #6
0
 def collect_changed_lits_since_backup(self):
     """
     Collects all literals whose values have changed since last backup.
     Also cleans the set of backupSDDs
     :return: the set of literals whose value has changed.
     """
     changed = []
     for lit, backup_sdd in self.backup_sdd.items():
         new_sdd = self.lit2sdd[lit]
         if new_sdd != backup_sdd:
             changed.append(lit)
         sddm.sdd_deref(backup_sdd, self.manager)
     self.backup_sdd = OrderedDict()
     return changed
Beispiel #7
0
    def test_garbage_collection(self):
        all_sdds = list(self.lit2sdd.values())
        single_top = sdd_conjoin(all_sdds, self.manager)
        self.print_ref_counts()
        for sdd in all_sdds:
            sddm.sdd_deref(sdd, self.manager)

        sddsize = sddm.sdd_size(single_top)
        sdd_livesize = sddm.sdd_manager_live_size(self.manager)

        if sddsize == sdd_livesize:
            print('Your dereferencing was completely correct!')
        else:
            print('WARNING : Your dereferencing was NOT correct !!')
        return
Beispiel #8
0
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
Beispiel #9
0
def sdd_conjoin(sdd_list, manager):
    """
    Conjoins 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 conjunction of the input sdds. This SDD has +1 reference count.
    """

    #print("lenth of sdd_list = ",len(sdd_list))


    ####try divide and conquer, auto_SDD minimization
    '''if sdd_list is None:
        print("sdd_list is None")
        exit(0)
    elif len(sdd_list) == 1:
        alpha = sddm.sdd_manager_true(manager)
        beta = sddm.sdd_conjoin(alpha,sdd_list[0],manager)
        sddm.sdd_ref(beta, manager)
        sddm.sdd_deref(alpha, manager)
        alpha = beta
        sddm.sdd_ref(sdd_list[0], manager)

        return sdd_list[0]
    else:
        mid = len(sdd_list)//2
        left = sdd_conjoin(sdd_list[:mid], manager)
        right = sdd_conjoin(sdd_list[mid:], manager)


        bigger =  sddm.sdd_conjoin(left, right, manager)
        sddm.sdd_deref(left, manager)
        sddm.sdd_deref(right, manager)
        sddm.sdd_ref(bigger, manager)

        return bigger'''


    alpha = sddm.sdd_manager_true(manager)
    for sdd in sdd_list:
        beta = sddm.sdd_conjoin(alpha, sdd, manager)
        sddm.sdd_ref(beta, manager)
        sddm.sdd_deref(alpha, manager)
        alpha = beta

    return alpha
Beispiel #10
0
def sdd_forall(variables, sdd, manager):
    """
    Returns the formula
        \forall v_1, v_2, ..., v_n: sdd
    where v_i are the vars in vars
    :param variables: variables to quantify universally over
    :param sdd: the sdd to quantify
    :param manager: a manager managing both the sdd and vars
    :return: The resulting SDD. This SDD has +1 reference count
    """
    result = sdd
    sddm.sdd_ref(result, manager)
    for var in variables:
        newresult = sddm.sdd_forall(var, result, manager)
        sddm.sdd_ref(newresult, manager)
        sddm.sdd_deref(result, manager)
        result = newresult
    return result
Beispiel #11
0
 def get_literal_sdd_leaf(self, lit):
     """
     Returns an SDD representing the literal value.
     In case of a negated literal, returns the negation of the sdd representing the underlying atom
     :param lit: the literal to represent
     :return: An sdd representing this literal. Increases the reference count of this sdd by one
     """
     negated = lit.negated
     if negated:
         lit = lit.negate()
     num = self.get_sdd_var_num(lit)
     result = sddm.sdd_manager_literal(num, self.manager)
     sddm.sdd_ref(result, self.manager)
     if negated:
         newresult = sdd_negate(result, self.manager)
         sddm.sdd_deref(result, self.manager)
         result = newresult
     return result
Beispiel #12
0
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
Beispiel #13
0
 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
Beispiel #14
0
def sorted_apply(sdd_list, manager, apply_func):
    """
    Performs an apply operation on a list of sdds. Does this sorted in the sense that two smaller sdds will be
    applied before applying to larger sdds
    :param sdd_list: the sdds
    :param manager: the manager
    :param apply_func: an apply function (conjoin or disjoin); this function must increase reference count of its result
    :return: An SDD: the result of the apply. This SDD has +1 reference count.
    """
    for sdd in sdd_list:
        sddm.sdd_ref(sdd, manager)
    while len(sdd_list) > 2:
        sdd_list = sort_sdds(sdd_list)
        sdd1 = sdd_list[0]
        sdd2 = sdd_list[1]
        new = apply_func([sdd1, sdd2], manager)
        sdd_list.remove(sdd1)
        sddm.sdd_deref(sdd1, manager)
        sdd_list.remove(sdd2)
        sddm.sdd_deref(sdd2, manager)
        sdd_list.append(new)

    result = apply_func(sdd_list, manager)
    for sdd in sdd_list:
        sddm.sdd_deref(sdd, manager)
    return result
Beispiel #15
0
    def finish_two_valued(self, program):
        """ Finishes the compilation
        :return: a TwoValuedCompiledProgram containing the result of the compilation
        """
        atom2sdd = OrderedDict()
        for lit, sdd in self.lit2sdd.items():
            if lit.negated:
                atom = lit.negate()
                atom_sdd = self.lit2sdd.get(atom)
                if atom_sdd is None:
                    raise Exception("Compiled " + repr(lit) + " but never compiled value for " + repr(atom))
                neg_atom_sdd = sdd_negate(atom_sdd, self.manager)
                if neg_atom_sdd != sdd:
                    raise Exception("Trying to compile two-valued, but the result is three-valued for literal: " + str(
                        lit) + "\n This probably means that there are errors in the input program ("
                               "the well-founded model is not two-valued; check your program for loops over negation")
                sddm.sdd_deref(neg_atom_sdd, self.manager)
            else:
                atom2sdd[lit] = sdd


        return TwoValuedCompiledProgram(atom2sdd, self.param2sddNum, self.manager, program)
Beispiel #16
0
def sdd_equiv(sdd1, sdd2, manager):
    """
    Returns the sdd: sdd1 <=> sdd2
    :param sdd1: An input SDD
    :param sdd2: An input SDD
    :param manager: the manager managing the input sdds
    :return: An SDD: the sdd representing sdd1 <=> sdd2. This SDD has +1 reference count.
    """

    """
    sdd1n = sdd_negate(sdd1, manager)
    sddm.sdd_ref(sdd1n, manager)
    sdd2n = sdd_negate(sdd2, manager)
    sddm.sdd_ref(sdd2n, manager)
    sdde1 = sdd_conjoin([sdd1, sdd2], manager)
    sddm.sdd_ref(sdde1, manager)
    sdde2 = sdd_conjoin([sdd1n, sdd2n], manager)
    sddm.sdd_ref(sdde2, manager)
    sddequiv = sdd_disjoin([sdde1, sdde2], manager)
    sddm.sdd_ref(sddequiv, manager)
    """

    sdd1n = sdd_negate(sdd1, manager)
    sddm.sdd_ref(sdd1n, manager)
    sdd2n = sdd_negate(sdd2, manager)
    sddm.sdd_ref(sdd2n, manager)
    sdde1 = sdd_disjoin([sdd1, sdd2n], manager)
    sddm.sdd_ref(sdde1, manager)
    sdde2 = sdd_disjoin([sdd1n, sdd2], manager)
    sddm.sdd_ref(sdde2, manager)
    sddequiv = sdd_conjoin([sdde1, sdde2], manager)
    sddm.sdd_ref(sddequiv, manager)

    sddm.sdd_deref(sdd1n, manager)
    sddm.sdd_deref(sdd2n, manager)
    sddm.sdd_deref(sdde1, manager)
    sddm.sdd_deref(sdde2, manager)
    return sddequiv