def toCNF(gndFormulas, formulas, allPositive=False): ''' convert the given ground formulas to CNF if allPositive=True, then formulas with negative weights are negated to make all weights positive @return a new pair (gndFormulas, formulas) ''' # get list of formula indices where we must negate newFormulas = [] negate = [] if allPositive: for idxFormula, formula in enumerate(formulas): f = formula if formula.weight < 0: negate.append(idxFormula) if isinstance(formula, FOL.Negation): f = formula.children[0] else: f = FOL.Negation([formula]) f.weight = -formula.weight f.idxFormula = idxFormula newFormulas.append(f) # get CNF version of each ground formula newGndFormulas = [] for gf in gndFormulas: # non-logical constraint if not gf.isLogical( ): # don't apply any transformations to non-logical constraints if gf.idxFormula in negate: gf.negate() newGndFormulas.append(gf) continue # logical constraint if gf.idxFormula in negate: cnf = FOL.Negation([gf]).toCNF() else: cnf = gf.toCNF() if type( cnf ) == FOL.TrueFalse: # formulas that are always true or false can be ignored continue cnf.idxFormula = gf.idxFormula newGndFormulas.append(cnf) # return modified formulas return (newGndFormulas, newFormulas)
def _expandQueries(self, queries): ''' expands the list of queries where necessary, e.g. queries that are just predicate names are expanded to the corresponding list of atoms ''' equeries = [] for query in queries: #print "got query '%s' of type '%s'" % (str(query), str(type(query))) if type(query) == str: prevLen = len(equeries) if "(" in query: # a fully or partially grounded formula f = FOL.parseFormula(query) for gndFormula in f.iterGroundings(self.mln): equeries.append(gndFormula[0]) else: # just a predicate name try: for gndPred in self.mln._getPredGroundings(query): equeries.append(FOL.parseFormula(gndPred).ground(self.mln, {})) except: raise #Exception("Could not expand query '%s'" % query) if len(equeries) - prevLen == 0: raise Exception("String query '%s' could not be expanded." % query) elif isinstance(query, FOL.Formula): equeries.append(query) else: raise Exception("Received query of unsupported type '%s'" % str(type(query))) return equeries
def _groundAtoms(self, cur, predName, domNames, verbose=False): # if there are no more parameters to ground, we're done # and we cann add the ground atom to the MRF mrf = self.mrf assert len(mrf.gndFormulas) == 0 if domNames == []: atom = FOL.GroundAtom(predName, cur) mrf.addGroundAtom(atom) return # create ground atoms for each way of grounding the first of the # remaining variables whose domains are given in domNames dom = mrf.domains.get(domNames[0]) if dom is None or len(dom) == 0: raise Exception("Domain '%s' is empty!" % domNames[0]) for value in dom: self._groundAtoms(cur + [value], predName, domNames[1:])
def _infer(self, verbose=True, details=False, fittingMethod=InferenceMethods.Exact, fittingThreshold=1e-3, fittingSteps=100, fittingParams=None, maxThreshold=None, greedy=False, **args): # add formulas to the model whose weights we can then fit if verbose: print "extending model with %d formulas whose weights will be fit..." % len(self.mrf.softEvidence) for req in self.mrf.softEvidence: formula = FOL.parseFormula(req["expr"]) idxFormula = self.mrf._addFormula(formula, 0.0) gndFormula = formula.ground(self.mrf, {}) self.mrf._addGroundFormula(gndFormula, idxFormula) req["gndExpr"] = req["expr"] req["gndFormula"] = gndFormula req["idxFormula"] = idxFormula # do fitting if fittingParams is None: fittingParams = {} fittingParams.update(args) results, self.data = self.mrf._fitProbabilityConstraints(self.mrf.softEvidence, fittingMethod=fittingMethod, fittingThreshold=fittingThreshold, fittingSteps=fittingSteps, given=self.given, queries=self.queries, verbose=details, fittingParams=fittingParams, maxThreshold=maxThreshold, greedy=greedy) return results
def getValidVariableAssignments(self, conjunction, trueOrFalse, gndAtoms): variableAssignments = [] gndAtomIndices = [] for lit in conjunction.children: assignments = [] atomIndices = [] for gndAtom in gndAtoms: try: if gndAtom.predName != lit.predName: continue assignment = [] for (p1, p2) in zip(lit.params, gndAtom.params): if FOL.isVar(p1): assignment.append((p1, p2)) elif p1 != p2: raise assignments.append(tuple(assignment)) atomIndices.append(gndAtom.idx) except: pass variableAssignments.append(assignments) gndAtomIndices.append(atomIndices) return variableAssignments, gndAtomIndices
def getAdmissibleVarAssignments(self, f, trueGndAtoms): if not type(f) is Conjunction: return None cwPred = False assignments = [] for child in f.children: if not isinstance(child, Lit) and not isinstance(child, GroundLit) and not isinstance(child, GroundAtom): return None if child.predName in self.mrf.mln.closedWorldPreds and not cwPred: cwPred = True for gndAtom in trueGndAtoms: if gndAtom.predName != child.predName: continue assignment = [] try: for (p1, p2) in zip(child.params, gndAtom.params): if FOL.isVar(p1): assignment.append((p1, p2)) elif p1 != p2: raise assignments.append(tuple(assignment)) except: pass return assignments