コード例 #1
0
ファイル: bpll.py プロジェクト: Bovril/pracmln
 def _itergroundings_fast(self, formula, constituents, cidx, assignment, variables, falsevar=None, level=0):
     if cidx == len(constituents):
         # no remaining literals to ground. return the ground formula and statistics
         stat = [(varidx, validx, count) for (varidx, validx, count) in variables]
         yield formula.idx, stat
         return
     c = constituents[cidx]
     # go through all remaining groundings of the current constituent
     for varass in c.itervargroundings(self.mrf, partial=assignment):
         gnd = c.ground(self.mrf, dict_union(varass, assignment))
         # check if it violates a hard constraint
         if formula.weight == HARD and gnd(self.mrf.evidence) < 1:
             raise SatisfiabilityException('MLN is unsatisfiable by evidence due to hard constraint violation %s (see above)' % global_bpll_grounding.mrf.formulas[formula.idx])
         if isinstance(gnd, Logic.Equality):
             # if an equality grounding is false in a conjunction, we can stop since the 
             # conjunction cannot be rendered true in any grounding that follows
             if gnd.truth(None) == 0: continue
             for gf in self._itergroundings_fast(formula, constituents, cidx+1, dict_union(assignment, varass), variables, falsevar, level+1):
                 yield gf
         else:
             var = self.mrf.variable(gnd.gndatom)
             world_ = list(self.mrf.evidence)
             stat = []
             skip = False
             falsevar_ = falsevar
             vars_ = list(variables)
             for validx, value in var.itervalues():
                 var.setval(value, world_)
                 truth = gnd(world_)
                 if truth == 0 and value == var.evidence_value():
                     # if the evidence value renders the current consituent false
                     # and there was already a false literal in the grounding path,
                     # we can prune the tree since no grounding will be true 
                     if falsevar is not None and falsevar != var.idx:
                         skip = True
                         break
                     else:
                         # if there was no literal false so far, we collect statistics only for the current literal
                         # and only if all future literals will be true by evidence 
                         vars_ = []
                         falsevar_ = var.idx
                 if truth > 0 and falsevar is None:
                     stat.append((var.idx, validx, truth))
             if falsevar is not None and falsevar == var.idx:
                 # in case of non-mutual exclusive values take only the values that render all literals true
                 # example: soft-functional constraint with !foo(?x) ^ foo(?y), x={X,Y,Z} where the evidence foo(Z) is true
                 # here the grounding !foo(X) ^ foo(Y) is false:
                 #       !foo(X) is true for foo(Z) and foo(Y) and (!foo(Z) ^ !foox(X) ^ !foo(Y)) 
                 #       foo(Y) is true for foo(Y)
                 #   both are only true for foo(Y)
                 stat = set(variables).intersection(stat)
                 skip = not bool(stat) # skip if no values remain
             if skip: continue
             for gf in self._itergroundings_fast(formula, constituents, cidx+1, dict_union(assignment, varass), vars_ + stat, falsevar=falsevar_, level=level+1):
                 yield gf
コード例 #2
0
ファイル: fastconj.py プロジェクト: danielnyga/pracmln
 def _itergroundings_fast(self, formula, constituents, cidx, pivotfct, truthpivot, assignment, level=0):
     if truthpivot == 0 and (isinstance(formula, Logic.Conjunction) or self.mrf.mln.logic.islit(formula)):
         if formula.weight == HARD:
             raise SatisfiabilityException('MLN is unsatisfiable given evidence due to hard constraint violation: {}'.format(str(formula)))
         return
     if truthpivot == 1 and (isinstance(formula, Logic.Disjunction) or self.mrf.mln.logic.islit(formula)):
         return
     if cidx == len(constituents):
         # we have reached the end of the formula constituents
         gf = formula.ground(self.mrf, assignment, simplify=True)
         if isinstance(gf, Logic.TrueFalse):
             return
         yield gf
         return
     c = constituents[cidx]
     for varass in c.itervargroundings(self.mrf, partial=assignment):
         newass = dict_union(assignment, varass)
         ga = c.ground(self.mrf, newass)
         truth = ga.truth(self.mrf.evidence)
         if truth is None:
             truthpivot_ = truthpivot
         elif truthpivot is None:
             truthpivot_ = truth
         else:
             truthpivot_ = pivotfct(truthpivot, truth)
         for gf in self._itergroundings_fast(formula, constituents, cidx + 1, pivotfct, truthpivot_, newass, level + 1):
             yield gf
コード例 #3
0
 def _iter_valid_variable_assignments(self, variables, assignments,
                                      eq_groundings):
     if not variables:
         yield assignments
         return
     eq_groundings = [
         eq for eq in eq_groundings
         if not all([not self.mrf.mln.logic.isvar(a) for a in eq.args])
     ]
     variable = variables[0]
     for value in self.mrf.domains[self.vardomains[variable]]:
         new_eq_groundings = []
         goon = True
         for eq in eq_groundings:
             geq = eq.ground(None, {variable: value}, partial=True)
             t = geq(None)
             if t is not None and t != self.truth:
                 goon = False
                 break
             new_eq_groundings.append(geq)
         if not goon: continue
         for assignment in self._iter_valid_variable_assignments(
                 variables[1:], dict_union(assignments, {variable: value}),
                 new_eq_groundings):
             yield assignment
コード例 #4
0
ファイル: default.py プロジェクト: Bovril/pracmln
 def _iter_valid_variable_assignments(self, variables, assignments, eq_groundings):
     if not variables: 
         yield assignments
         return
     eq_groundings = [eq for eq in eq_groundings if not all([not self.mrf.mln.logic.isvar(a) for a in eq.args])]
     variable = variables[0]
     for value in self.mrf.domains[self.vardomains[variable]]:
         new_eq_groundings = []
         goon = True
         for eq in eq_groundings:
             geq = eq.ground(None, {variable: value}, partial=True)
             t = geq(None)
             if t is not None and t != self.truth:
                 goon = False
                 break
             new_eq_groundings.append(geq)
         if not goon: continue
         for assignment in self._iter_valid_variable_assignments(variables[1:], dict_union(assignments, {variable: value}), new_eq_groundings):
             yield assignment
コード例 #5
0
 def _itergroundings_fast(self,
                          formula,
                          constituents,
                          cidx,
                          pivotfct,
                          truthpivot,
                          assignment,
                          level=0):
     if truthpivot == 0 and (isinstance(formula, Logic.Conjunction)
                             or self.mrf.mln.logic.islit(formula)):
         if formula.weight == HARD:
             raise SatisfiabilityException(
                 'MLN is unsatisfiable given evidence due to hard constraint violation: %s'
                 % str(formula))
         return
     if truthpivot == 1 and (isinstance(formula, Logic.Disjunction)
                             or self.mrf.mln.logic.islit(formula)):
         return
     if cidx == len(
             constituents
     ):  # we have reached the end of the formula constituents
         gf = formula.ground(self.mrf, assignment, simplify=True)
         if isinstance(gf, Logic.TrueFalse):
             return
         yield gf
         return
     c = constituents[cidx]
     for varass in c.itervargroundings(self.mrf, partial=assignment):
         newass = dict_union(assignment, varass)
         ga = c.ground(self.mrf, newass)
         truth = ga.truth(self.mrf.evidence)
         if truth is None:
             truthpivot_ = truthpivot
         elif truthpivot is None:
             truthpivot_ = truth
         else:
             truthpivot_ = pivotfct(truthpivot, truth)
         for gf in self._itergroundings_fast(formula, constituents,
                                             cidx + 1, pivotfct,
                                             truthpivot_, newass,
                                             level + 1):
             yield gf
コード例 #6
0
ファイル: bpll.py プロジェクト: pombredanne/pracmln
 def _itergroundings_fast(self,
                          formula,
                          constituents,
                          cidx,
                          assignment,
                          variables,
                          falsevar=None,
                          level=0):
     if cidx == len(constituents):
         # no remaining literals to ground. return the ground formula
         # and statistics
         stat = [(varidx, validx, count)
                 for (varidx, validx, count) in variables]
         yield formula.idx, stat
         return
     c = constituents[cidx]
     # go through all remaining groundings of the current constituent
     for varass in c.itervargroundings(self.mrf, partial=assignment):
         gnd = c.ground(self.mrf, dict_union(varass, assignment))
         # check if it violates a hard constraint
         if formula.weight == HARD and gnd(self.mrf.evidence) < 1:
             raise SatisfiabilityException(
                 'MLN is unsatisfiable by evidence due to hard constraint violation {} (see above)'
                 .format(global_bpll_grounding.mrf.formulas[formula.idx]))
         if isinstance(gnd, Logic.Equality):
             # if an equality grounding is false in a conjunction, we can
             # stop since the  conjunction cannot be rendered true in any
             # grounding that follows
             if gnd.truth(None) == 0: continue
             for gf in self._itergroundings_fast(
                     formula, constituents, cidx + 1,
                     dict_union(assignment, varass), variables, falsevar,
                     level + 1):
                 yield gf
         else:
             var = self.mrf.variable(gnd.gndatom)
             world_ = list(self.mrf.evidence)
             stat = []
             skip = False
             falsevar_ = falsevar
             vars_ = list(variables)
             for validx, value in var.itervalues():
                 var.setval(value, world_)
                 truth = gnd(world_)
                 if truth == 0 and value == var.evidence_value():
                     # if the evidence value renders the current
                     # consituent false and there was already a false
                     # literal in the grounding path, we can prune the
                     # tree since no grounding will be true
                     if falsevar is not None and falsevar != var.idx:
                         skip = True
                         break
                     else:
                         # if there was no literal false so far, we
                         # collect statistics only for the current literal
                         # and only if all future literals will be true
                         # by evidence
                         vars_ = []
                         falsevar_ = var.idx
                 if truth > 0 and falsevar is None:
                     stat.append((var.idx, validx, truth))
             if falsevar is not None and falsevar == var.idx:
                 # in case of non-mutual exclusive values take only the
                 # values that render all literals true
                 # example: soft-functional constraint with
                 # !foo(?x) ^ foo(?y), x={X,Y,Z} where the evidence
                 # foo(Z) is true
                 # here the grounding !foo(X) ^ foo(Y) is false:
                 # !foo(X) is true for foo(Z) and foo(Y) and
                 # (!foo(Z) ^ !foox(X) ^ !foo(Y))
                 #       foo(Y) is true for foo(Y)
                 #   both are only true for foo(Y)
                 stat = set(variables).intersection(stat)
                 skip = not bool(stat)  # skip if no values remain
             if skip: continue
             for gf in self._itergroundings_fast(formula,
                                                 constituents,
                                                 cidx + 1,
                                                 dict_union(
                                                     assignment, varass),
                                                 vars_ + stat,
                                                 falsevar=falsevar_,
                                                 level=level + 1):
                 yield gf
コード例 #7
0
ファイル: wcspinfer.py プロジェクト: pombredanne/pracmln
 def _gather_constraint_tuples(self, varindices, formula):
     '''
     Collects and evaluates all tuples that belong to the constraint
     given by a formula. In case of disjunctions and conjunctions,
     this is fairly efficient since not all combinations
     need to be evaluated. Returns a dictionary mapping the constraint
     costs to the list of respective variable assignments.
     '''
     logic = self.mrf.mln.logic
     # we can treat conjunctions and disjunctions fairly efficiently
     defaultProcedure = False
     conj = logic.islitconj(formula)
     disj = False
     if not conj:
         disj = logic.isclause(formula)
     if not varindices:
         return None
     if not conj and not disj:
         defaultProcedure = True
     if not defaultProcedure:
         assignment = [None] * len(varindices)
         children = list(formula.literals())
         for gndlit in children:
             # constants are handled in the maxtruth/mintruth calls below
             if isinstance(gndlit, Logic.TrueFalse): continue
             # get the value of the gndlit that renders the formula true (conj) or false (disj):
             # for a conjunction, the literal must be true,
             # for a disjunction, it must be false.
             (gndatom, val) = (gndlit.gndatom, not gndlit.negated)
             if disj: val = not val
             val = 1 if val else 0
             variable = self.variables[self.atom2var[gndatom.idx]]
             # in case there are multiple values of a variable that may render the formula true
             # we cannot apply this efficient implementation and have to fall back to the naive impl. 
             tmp_evidence = variable.value2dict(variable.evidence_value())
             evval = tmp_evidence.get(gndatom.idx)
             if evval is not None and evval != val:
                 # the supposed value of the variable and the evidence value mismatch,
                 # so the conjunction (disjunction) can never be rendered true (false)
                 return  
             tmp_evidence = dict_union(tmp_evidence, {gndatom.idx: val})
             if variable.valuecount(tmp_evidence) > 1:
                 defaultProcedure = True
                 break
             # there is only one value remaining
             for _, value in variable.itervalues(tmp_evidence):
                 varidx = self.atom2var[gndatom.idx] 
                 validx = self.val2idx[varidx][value]
             # if there are two different values needed to render the formula true...
             if assignment[varindices.index(varidx)] is not None and assignment[varindices.index(varidx)] != value:
                 if formula.weight == HARD:
                     if conj: # ...if it's a hard conjunction, the MLN is unsatisfiable -- e.g. foo(x) ^ !foo(x) 
                         raise SatisfiabilityException('Knowledge base is unsatisfiable due to hard constraint violation: %s' % formula)
                     elif disj: # ...if it's a hard disjunction, it's a tautology -- e.g. foo(x) v !foo(x)
                         continue
                 else: # for soft constraints, unsatisfiable formulas and tautologies  can be ignored
                     return None
             assignment[varindices.index(varidx)] = validx
         if not defaultProcedure:
             maxtruth = formula.maxtruth(self.mrf.evidence)
             mintruth = formula.mintruth(self.mrf.evidence)
             if formula.weight == HARD and (maxtruth in Interval(']0,1[') or mintruth in Interval(']0,1[')):
                 raise MRFValueException('No fuzzy truth values are allowed in hard constraints.')
             if conj:
                 if formula.weight == HARD:
                     cost = 0
                     defcost = self.wcsp.top
                 else:
                     cost = formula.weight * (1 - maxtruth)
                     defcost = formula.weight
             else:
                 if formula.weight == HARD:
                     cost = self.wcsp.top
                     defcost = 0
                 else:
                     defcost = 0
                     cost = formula.weight * (1 - mintruth)
             if len(assignment) != len(varindices):
                 raise MRFValueException('Illegal variable assignments. Variables: %s, Assignment: %s' % (varindices, assignment))
             return {cost: [tuple(assignment)], defcost: 'else'}
     if defaultProcedure: 
         # fallback: go through all combinations of truth assignments
         domains = [self.domains[v] for v in varindices]
         cost2assignments = defaultdict(list)
         # compute number of worlds to be examined and print a warning
         worlds = 1
         for d in domains: worlds *= len(d)
         if worlds > 1000000:
             logger.warning('!!! WARNING: %d POSSIBLE WORLDS ARE GOING TO BE EVALUATED. KEEP IN SIGHT YOUR MEMORY CONSUMPTION !!!' % worlds)
         for c in combinations(domains):
             world = [0] * len(self.mrf.gndatoms)
             assignment = []
             for varidx, value in zip(varindices, c):
                 world = self.variables[varidx].setval(value, world)
                 assignment.append(self.val2idx[varidx][value])
             # the MRF feature imposed by this formula 
             truth = formula(world)
             if truth is None:
                 print 'POSSIBLE WORLD:'
                 print '==============='
                 self.mrf.print_world_vars(world)
                 print 'GROUND FORMULA:'
                 print '==============='
                 formula.print_structure(world)
                 raise Exception('Something went wrong: Truth of ground formula cannot be evaluated (see above)')
             
             if truth in Interval(']0,1[') and formula.weight == HARD:
                 raise MRFValueException('No fuzzy truth values are allowed in hard constraints.')
             if formula.weight == HARD:
                 if truth == 1:
                     cost = 0
                 else:
                     cost = self.wcsp.top
             else:
                 cost = ((1 - truth) * formula.weight)
             cost2assignments[cost].append(tuple(assignment))
         return cost2assignments
     assert False # unreachable
コード例 #8
0
ファイル: cll.py プロジェクト: Bovril/pracmln
    def _compute_stat_rec(self, literals, gndliterals, var_assign, formula, f_gndlit_parts=None, processed=None, isconj=False):
        '''
        TODO: make sure that there are no equality constraints in the conjunction!
        '''
        if len(literals) == 0:
            # at this point, we have a fully grounded conjunction in gndliterals
            # create a mapping from a partition to the ground literals in this formula
            # (criterion no. 1, applies to all kinds of formulas)
            part2gndlits = defaultdict(list)
            part_with_f_lit = None
            for gndlit in gndliterals:
                if isinstance(gndlit, Logic.Equality) or hasattr(self, 'qpreds') and gndlit.gndatom.predname not in self.qpreds: continue
                part = self.atomidx2partition[gndlit.gndatom.idx]
                part2gndlits[part].append(gndlit)
                if gndlit(self.mrf.evidence) == 0:
                    part_with_f_lit = part  
            # if there is a false ground literal we only need to take into account
            # the partition comprising this literal (criterion no. 2)
            # there is maximally one such partition with false literals in the conjunction
            # because of criterion no. 5
            if isconj and part_with_f_lit is not None:
                gndlits = part2gndlits[part_with_f_lit]
                part2gndlits = {part_with_f_lit: gndlits}
            if not isconj: # if we don't have a conjunction, ground the formula with the given variable assignment
                gndformula = formula.ground(self.mrf, var_assign)
            for partition, gndlits in part2gndlits.iteritems():
                # for each partition, select the ground atom truth assignments
                # in such a way that the conjunction is rendered true. There
                # is precisely one such assignment for each partition. (criterion 3/4)
                evidence = {}
                if isconj:
                    for gndlit in gndlits:
                        evidence[gndlit.gndatom.idx] = 0 if gndlit.negated else 1
                for world in partition.itervalues(evidence):
                    # update the sufficient statistics for the given formula, partition and world value
                    worldidx = partition.valueidx(world)
                    if isconj:
                        truth = 1
                    else:
                        # temporarily set the evidence in the MRF, compute the truth value of the 
                        # formula and remove the temp evidence
                        with temporary_evidence(self.mrf):
                            for atomidx, value in partition.value2dict(world).iteritems():
                                self.mrf[atomidx] = value
                            truth = gndformula(self.mrf.evidence)
                    if truth != 0:
                        self.partition2formulas[partition.idx].add(formula.idx)
                        self._addstat(formula.idx, partition.idx, worldidx, truth)
            return
            
        lit = literals[0]
        # ground the literal with the existing assignments
        gndlit = lit.ground(self.mrf, var_assign, partial=True)
        for assign in Logic.iter_eq_varassignments(gndlit, formula, self.mrf) if isinstance(gndlit, Logic.Equality) else gndlit.itervargroundings(self.mrf):
            # copy the arguments to avoid side effects
            # if f_gndlit_parts is None: f_gndlit_parts = set()
            # else: f_gndlit_parts = set(f_gndlit_parts)
            if processed is None: processed = []
            else: processed = list(processed)
            # ground with the remaining free variables
            gndlit_ = gndlit.ground(self.mrf, assign)
            truth = gndlit_(self.mrf.evidence)
            # treatment of equality constraints
            if isinstance(gndlit_, Logic.Equality):
                if isconj:
                    if truth == 1:
                        self._compute_stat_rec(literals[1:], gndliterals, dict_union(var_assign, assign), formula, f_gndlit_parts, processed, isconj)
                    else: continue
                else:
                    self._compute_stat_rec(literals[1:], gndliterals + [gndlit_], dict_union(var_assign, assign), formula, f_gndlit_parts, processed, isconj) 
                continue
            atom = gndlit_.gndatom

            if atom.idx in processed: continue
            
            # if we encounter a gnd literal that is false by the evidence
            # and there is already a false one in this grounding from a different
            # partition, we can stop the grounding process here. The gnd conjunction
            # will never ever be rendered true by any of this partitions values (criterion no. 5)
            isevidence = hasattr(self, 'qpreds') and gndlit_.gndatom.predname not in self.qpreds
            #assert isEvidence == False
            if isconj and truth == 0:
                if f_gndlit_parts is not None and atom not in f_gndlit_parts:
                    continue
                elif isevidence: continue
                else:
                    self._compute_stat_rec(literals[1:], gndliterals + [gndlit_], dict_union(var_assign, assign), formula, self.atomidx2partition[atom.idx], processed, isconj) 
                    continue
            elif isconj and isevidence:
                self._compute_stat_rec(literals[1:], gndliterals, dict_union(var_assign, assign), formula, f_gndlit_parts, processed, isconj) 
                continue
                 
            self._compute_stat_rec(literals[1:], gndliterals + [gndlit_], dict_union(var_assign, assign), formula, f_gndlit_parts, processed, isconj) 
コード例 #9
0
    def _compute_stat_rec(self,
                          literals,
                          gndliterals,
                          var_assign,
                          formula,
                          f_gndlit_parts=None,
                          processed=None,
                          isconj=False):
        '''
        TODO: make sure that there are no equality constraints in the conjunction!
        '''

        if len(literals) == 0:
            # at this point, we have a fully grounded conjunction in gndliterals
            # create a mapping from a partition to the ground literals in this formula
            # (criterion no. 1, applies to all kinds of formulas)
            part2gndlits = defaultdict(list)
            part_with_f_lit = None
            for gndlit in gndliterals:
                if isinstance(gndlit, Logic.Equality) or hasattr(
                        self, 'qpreds'
                ) and gndlit.gndatom.predname not in self.qpreds:
                    continue
                part = self.atomidx2partition[gndlit.gndatom.idx]
                part2gndlits[part].append(gndlit)
                if gndlit(self.mrf.evidence) == 0:
                    part_with_f_lit = part

            # if there is a false ground literal we only need to take into account
            # the partition comprising this literal (criterion no. 2)
            # there is maximally one such partition with false literals in the conjunction
            # because of criterion no. 5
            if isconj and part_with_f_lit is not None:
                gndlits = part2gndlits[part_with_f_lit]
                part2gndlits = {part_with_f_lit: gndlits}
            if not isconj:  # if we don't have a conjunction, ground the formula with the given variable assignment
                # print 'formula', formula
                gndformula = formula.ground(self.mrf, var_assign)
                # print 'gndformula', gndformula
                # stop()
            for partition, gndlits in part2gndlits.iteritems():
                # for each partition, select the ground atom truth assignments
                # in such a way that the conjunction is rendered true. There
                # is precisely one such assignment for each partition. (criterion 3/4)
                evidence = {}
                if isconj:
                    for gndlit in gndlits:
                        evidence[
                            gndlit.gndatom.idx] = 0 if gndlit.negated else 1
                for world in partition.itervalues(evidence):
                    # update the sufficient statistics for the given formula, partition and world value
                    worldidx = partition.valueidx(world)
                    if isconj:
                        truth = 1
                    else:
                        # temporarily set the evidence in the MRF, compute the truth value of the
                        # formula and remove the temp evidence
                        with temporary_evidence(self.mrf):
                            for atomidx, value in partition.value2dict(
                                    world).iteritems():
                                self.mrf.set_evidence({atomidx: value},
                                                      erase=True)
                            truth = gndformula(self.mrf.evidence)
                            if truth is None:
                                print gndformula
                                print gndformula.print_structure(
                                    self.mrf.evidence)

                    if truth != 0:
                        self.partition2formulas[partition.idx].add(formula.idx)
                        self._addstat(formula.idx, partition.idx, worldidx,
                                      truth)
            return

        lit = literals[0]
        # ground the literal with the existing assignments
        gndlit = lit.ground(self.mrf, var_assign, partial=True)
        for assign in Logic.iter_eq_varassignments(
                gndlit, formula, self.mrf) if isinstance(
                    gndlit, Logic.Equality) else gndlit.itervargroundings(
                        self.mrf):
            # copy the arguments to avoid side effects
            # if f_gndlit_parts is None: f_gndlit_parts = set()
            # else: f_gndlit_parts = set(f_gndlit_parts)
            if processed is None: processed = []
            else: processed = list(processed)
            # ground with the remaining free variables
            gndlit_ = gndlit.ground(self.mrf, assign)
            truth = gndlit_(self.mrf.evidence)
            # treatment of equality constraints
            if isinstance(gndlit_, Logic.Equality):
                if isconj:
                    if truth == 1:
                        self._compute_stat_rec(literals[1:], gndliterals,
                                               dict_union(var_assign, assign),
                                               formula, f_gndlit_parts,
                                               processed, isconj)
                    else:
                        continue
                else:
                    self._compute_stat_rec(literals[1:],
                                           gndliterals + [gndlit_],
                                           dict_union(var_assign,
                                                      assign), formula,
                                           f_gndlit_parts, processed, isconj)
                continue
            atom = gndlit_.gndatom

            if atom.idx in processed: continue

            # if we encounter a gnd literal that is false by the evidence
            # and there is already a false one in this grounding from a different
            # partition, we can stop the grounding process here. The gnd conjunction
            # will never ever be rendered true by any of this partitions values (criterion no. 5)
            isevidence = hasattr(
                self, 'qpreds') and gndlit_.gndatom.predname not in self.qpreds
            #assert isEvidence == False
            if isconj and truth == 0:
                if f_gndlit_parts is not None and atom not in f_gndlit_parts:
                    continue
                elif isevidence:
                    continue
                else:
                    self._compute_stat_rec(literals[1:],
                                           gndliterals + [gndlit_],
                                           dict_union(var_assign,
                                                      assign), formula,
                                           self.atomidx2partition[atom.idx],
                                           processed, isconj)
                    continue
            elif isconj and isevidence:
                self._compute_stat_rec(literals[1:], gndliterals,
                                       dict_union(var_assign, assign), formula,
                                       f_gndlit_parts, processed, isconj)
                continue

            self._compute_stat_rec(literals[1:], gndliterals + [gndlit_],
                                   dict_union(var_assign, assign), formula,
                                   f_gndlit_parts, processed, isconj)