예제 #1
0
def eval_queries(world):
    """
    Evaluates the queries given a possible world.
    """
    numerators = [0] * len(global_enumAsk.queries)
    denominator = 0
    expsum = 0
    for gf in global_enumAsk.grounder.itergroundings():
        if global_enumAsk.soft_evidence_formula(gf):
            expsum += gf.noisyor(world) * gf.weight
        else:
            truth = gf(world)
            if gf.weight == HARD:
                if truth in Interval(']0,1['):
                    raise Exception('No real-valued degrees of truth are allowed in hard constraints.')
                if truth == 1:
                    continue
                else:
                    return numerators, 0
            expsum += gf(world) * gf.weight
    expsum = exp(expsum)
    # update numerators
    for i, query in enumerate(global_enumAsk.queries):
        if query(world):
            numerators[i] += expsum
    denominator += expsum
    return numerators, denominator
예제 #2
0
 def consistent(self, world, strict=False):
     '''
     Checks for this variable if its assignment in the assignment `evidence` is consistent.
     
     :param evidence: the assignment to be checked.
     :param strict:   if True, no unknown assignments are allowed, i.e. there must not be any
                      ground atoms in the variable that do not have a truth value assigned.
     '''
     total = 0
     evstr = ','.join([ifNone(world[atom.idx], '?', str) for atom in self.gndatoms])
     for gnatom in self.gndatoms:
         val = world[gnatom.idx]
         if strict and val is None:
             raise MRFValueException('Not all values have truth assignments: %s: %s' % (repr(self), evstr))
         total += ifNone(val, 0)
     if not (total == 1 if strict else total in Interval('[0,1]')):
         raise MRFValueException('Invalid value of variable %s: %s' % (repr(self), evstr))
     return True
예제 #3
0
 def soft_evidence_formula(self, gf):
     return isinstance(self.mrf.mln.logic, FirstOrderLogic) and any(map(lambda a: a.truth(self.mrf.evidence) in Interval('(0,1)'), gf.gndatoms()))
예제 #4
0
    def set_evidence(self, atomvalues, erase=False, cw=False):
        '''
        Sets the evidence of variables in this MRF.
        
        If erase is `True`, for every ground atom appearing in atomvalues, the truth values of all ground
        ground atom in the respective MRF variable are erased before the evidences
        are set. All other ground atoms stay untouched.

        :param atomvalues:     a dict mapping ground atom strings/objects/indices to their truth
                               values.
        :param erase:          specifies whether or not variables shall be erased before asserting the evidences.
        :param cw:             applies the closed-world assumption for all non evidence atoms.
        '''
        # check validity of evidence values
        atomvalues_ = {}
        for key, value in dict(atomvalues).iteritems():
            # convert boolean to numeric values
            if value in (True, False):
                atomvalues[key] = {True: 1, False: 0}[value]
                value = atomvalues[key]
            gndatom = self.gndatom(key)
            if gndatom is None:
                self.print_gndatoms()
                raise MRFValueException('"%s" is not among the ground atoms.' % key)
            atomvalues_[str(gndatom)] = value
            var = self.variable(gndatom)
            if isinstance(self.mln.logic, FuzzyLogic):
                if (isinstance(var, MutexVariable) or isinstance(var, SoftMutexVariable) or isinstance(var, BinaryVariable)) and value is not None and value in Interval(']0,1['):
                    raise MRFValueException('Illegal value for the  (soft-) mutex or binary variable "%s": %s' % (str(var), value))
        atomvalues = atomvalues_
        if erase: # erase all variable assignments appearing in atomvalues
            for key, _ in atomvalues.iteritems():
                var = self.variable(self.gndatom(key))
                # unset all atoms in this variable
                for atom in var.gndatoms:
                    self._evidence[atom.idx] = None
        
        for key, value in atomvalues.iteritems():
            gndatom = self.gndatom(key)
            var = self.variable(gndatom)
            # create a template with admissible truth values for all
            # ground atoms in this variable 
            values = [-1] * len(var.gndatoms)
            if isinstance(var, FuzzyVariable):
                self._evidence[gndatom.idx] = value
                continue
            elif isinstance(var, BinaryVariable):
                self._evidence[gndatom.idx] = value
                continue
            for _, val in var.itervalues(evidence={gndatom.idx: value}):
                for i, (v, v_) in enumerate(zip(values, val)):
                    if v == -1: values[i] = v_
                    elif v is not None and v != v_:
                        values[i] = None
            for atom, val in zip(var.gndatoms, values):
                curval = self._evidence[atom.idx]
                if curval is not None and val is not None and curval != val:
                    raise MRFValueException('Contradictory evidence in variable %s: %s = %s vs. %s' % (var.name, str(gndatom), curval, val))
                elif curval is None and val is not None:
                    self._evidence[atom.idx] = val
        if cw: self.apply_cw()
예제 #5
0
 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