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
def first_iteration(self, parameters): """ Initialises the compiler with a set of parameters Ensures that for each SDD in the image of lit2sdd, the reference count is one. :param parameters: the set of "open" atoms, aka parameters of the logic program :return: nothing """ self.manager = sddm.sdd_manager_create(len(parameters), 1) largest_atom_num_used = 0 #print("=========================== In the first iteration: =============================") for param in parameters: largest_atom_num_used += 1 self.param2sddNum[param] = largest_atom_num_used sdd4lit = sddm.sdd_manager_literal(largest_atom_num_used, self.manager) self.lit2sdd[param] = sdd4lit sdd4neglit = sdd_negate(sdd4lit, self.manager) self.lit2sdd[param.negate()] = sdd4neglit sddm.sdd_ref(sdd4lit, self.manager) sddm.sdd_ref(sdd4neglit, self.manager) #sddm.sdd_save_as_dot(str(largest_atom_num_used),sdd4lit) #sddm.sdd_save_as_dot("not_"+str(largest_atom_num_used),sdd4neglit) #print(self.lit2sdd,len(self.lit2sdd)) #print(sddm.sdd_manager_size(self.manager)) #print("===========================END In the first iteration: =============================") return
def sdd_negate(sdd, manager): """ Negates the input sdd :param sdd: The sdd to negate :param manager: the manager managing the input sdd :return: An SDD: the negation of the input sdd. This SDD has +1 reference count. """ result = sddm.sdd_negate(sdd, manager) sddm.sdd_ref(result, manager) return result
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 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 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 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
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
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
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
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