com.articulate.sigma.FormulaPreprocessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sigma-component Show documentation
Show all versions of sigma-component Show documentation
Sigma knowledge engineering system is an system for developing, viewing and debugging theories in first
order logic. It works with Knowledge Interchange Format (KIF) and is optimized for the Suggested Upper Merged
Ontology (SUMO) www.ontologyportal.org.
The newest version!
package com.articulate.sigma;
import com.google.common.collect.Sets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FormulaPreprocessor {
/** ***************************************************************
* For any given formula, stop generating new pred var instantiations
* and row var expansions if this threshold value has been exceeded.
* The default value is 2000.
*/
private static final int AXIOM_EXPANSION_LIMIT = 2000;
private static boolean debug = false;
/** ***************************************************************
* A + is appended to the type if the parameter must be a class
*
* @return the type for each argument to the given predicate, where
* ArrayList element 0 is the result, if a function, 1 is the first
* argument, 2 is the second etc.
*/
private ArrayList getTypeList(String pred, KB kb) {
return kb.kbCache.signatures.get(pred);
}
/** ***************************************************************
* Find the argument type restriction for a given predicate and
* argument number that is inherited from one of its super-relations.
* A "+" is appended to the type if the parameter must be a class,
* meaning that a domainSubclass is defined for this argument in one
* of the loaded .kif files. Argument number 0 is used for the return
* type of a Function. Asking for a non-existent arg will return null;
*/
public static String findType(int numarg, String pred, KB kb) {
ArrayList sig = kb.kbCache.signatures.get(pred);
if (sig == null) {
if (!kb.isInstanceOf(pred, "VariableArityRelation"))
System.out.println("Error in FormulaPreprocessor.findType(): " +
"no type information for predicate " + pred);
return null;
}
if (numarg >= sig.size())
return null;
return sig.get(numarg);
}
/** ***************************************************************
* This method tries to remove all but the most specific relevant
* classes from a List of sortal classes.
*
* @param types A List of classes (class name Strings) that
* constrain the value of a SUO-KIF variable.
*
* @param kb The KB used to determine if any of the classes in the
* List types are redundant.
*
* @return void
*/
public void winnowTypeList(HashSet types, KB kb) {
long t1 = 0L;
if (types.size() > 1) {
Object[] valArr = types.toArray();
String clX = null;
String clY = null;
for (int i = 0; i < valArr.length; i++) {
boolean stop = false;
for (int j = 0; j < valArr.length; j++) {
if (i != j) {
clX = (String) valArr[i];
clY = (String) valArr[j];
if (clX.equals(clY) || kb.isSubclass(clX, clY)) {
types.remove(clY);
if (types.size() < 2) {
stop = true;
break;
}
}
}
}
if (stop) break;
}
}
return;
}
/** ***************************************************************
* Add clauses for every variable in the antecedent to restrict its
* type to the type restrictions defined on every relation in which
* it appears. For example
* (=>
* (foo ?A B)
* (bar B ?A))
*
* (domain foo 1 Z)
*
* would result in
*
* (=>
* (instance ?A Z)
* (=>
* (foo ?A B)
* (bar B ?A)))
*/
public Formula addTypeRestrictions(Formula form, KB kb) {
// get variable types from domain definitions
HashMap> varDomainTypes = computeVariableTypes(form, kb);
// get variable types which are explicitly defined in formula
HashMap> varExplicitTypes = findExplicitTypesClassesInAntecedent(form);
// only keep variables which are not explicitly defined in formula
HashMap> varmap = new HashMap>();
for (String var : varDomainTypes.keySet()) {
if (!varExplicitTypes.containsKey(var)) {
// var is not explicitly defined
varmap.put(var, varDomainTypes.get(var));
}
else {
// var is explicitly defined
HashSet domainTypes = varDomainTypes.get(var);
HashSet explicitTypes = varExplicitTypes.get(var);
HashSet types = new HashSet();
for (String dt : domainTypes) {
if (dt.endsWith("+")) types.add(dt);
}
for (String et : explicitTypes) {
if (et.endsWith("+")) types.add(et);
}
varmap.put(var, types);
}
}
// compute quantifiedVariables and unquantifiedVariables
ArrayList> quantifiedUnquantifiedVariables =
form.collectQuantifiedUnquantifiedVariables();
ArrayList unquantifiedVariables = quantifiedUnquantifiedVariables.get(1);
// add sortals for unquantifiedVariables
StringBuffer sb = new StringBuffer();
boolean begin = true;
for (int i = 0; i < unquantifiedVariables.size(); i++) {
String unquantifiedV = unquantifiedVariables.get(i);
HashSet types = varmap.get(unquantifiedV);
if (types != null && !types.isEmpty()) {
for (String t : types) {
if (begin) {
sb.append("(=> \n (and \n");
begin = false;
}
if (!t.endsWith("+"))
sb.append(" (instance " + unquantifiedV + " " + t + ") ");
else
sb.append(" (subclass " + unquantifiedV + " " + t.substring(0,t.length()-1) + ") ");
}
}
}
if (!begin)
sb.append(")\n");
// recursively add sortals for existentially quantified variables
addTypeRestrictionsRecurse(kb, form, sb);
if (!begin)
sb.append(")\n");
Formula f = new Formula();
f.read(sb.toString());
return f;
}
/** ***************************************************************
* Recursively add sortals for existentially quantified variables
*
* @param kb The KB used to add type restrictions.
* @param f The formula in KIF syntax
* @param sb A StringBuilder used to store the new formula with sortals
*/
private void addTypeRestrictionsRecurse(KB kb, Formula f, StringBuffer sb) {
if (f == null || StringUtil.emptyString(f.theFormula) || f.empty())
return;
String carstr = f.car();
if (Formula.atom(carstr) && Formula.isLogicalOperator(carstr)) {
sb.append("(" + carstr + " ");
if (carstr.equals(f.EQUANT) || carstr.equals(f.UQUANT)) {
// If we see existentially quantified variables, like (exists (?X ?Y) ...),
// and if ?X, ?Y are not explicitly restricted in the following statements,
// we need to add type restrictions for ?X, ?Y
sb.append(f.getArgument(1) + " ");
ArrayList quantifiedVariables = collectVariables(f.getArgument(1));
// set addSortals = true, if at least one variable is existentially quantified variable,
// and it is not explicitly restricted
boolean addSortals = false;
HashMap> varDomainTypes = computeVariableTypes(f, kb);
HashMap> varExplicitTypes = findExplicitTypesClassesInAntecedent(f);
// only keep variables which are not explicitly defined in formula
HashMap> varmap = (HashMap>) varDomainTypes.clone();
if (varExplicitTypes != null) {
for (String v : varExplicitTypes.keySet()) {
varmap.remove(v);
}
}
for (String ev : quantifiedVariables) {
HashSet types = varmap.get(ev);
if (types != null && !types.isEmpty()) {
addSortals = true;
break;
}
}
if (addSortals) {
if (carstr.equals(f.EQUANT)) sb.append("(and ");
else if (carstr.equals(f.UQUANT)) sb.append("(=> (and ");
}
for (int i = 0; i < quantifiedVariables.size(); i++) {
String existentiallyQV = quantifiedVariables.get(i);
HashSet types = varmap.get(existentiallyQV);
if (types != null && !types.isEmpty()) {
for (String t : types) {
if (!t.endsWith("+"))
sb.append(" (instance " + existentiallyQV + " " + t + ") ");
else
sb.append(" (subclass " + existentiallyQV + " " + t.substring(0,t.length()-1) + ") ");
}
}
}
if (addSortals && carstr.equals(f.UQUANT))
sb.append(")");
for (int i = 2 ; i < f.listLength(); i++) {
addTypeRestrictionsRecurse(kb, new Formula(f.getArgument(i)), sb);
}
if (addSortals)
sb.append(")");
}
else {
// recurse from the first argument if the formula is not in (exists ...) / (forall ...) scope
for (int i = 1; i < f.listLength(); i++) {
addTypeRestrictionsRecurse(kb, new Formula(f.getArgument(i)), sb);
}
}
sb.append(")");
}
else if (f.isSimpleClause()) {
sb.append(f + " ");
}
else {
addTypeRestrictionsRecurse(kb, f.carAsFormula(), sb);
addTypeRestrictionsRecurse(kb, f.cdrAsFormula(), sb);
}
}
/** ***************************************************************
* Collect variables from strings.
*
* For example,
* Input = (?X ?Y ?Z)
* Output = a list of ?X, ?Y and ?Z
*
* Input = ?X
* Output = a list of ?X
*/
private ArrayList collectVariables(String argstr) {
ArrayList arglist = new ArrayList<>();
if (argstr.startsWith(Formula.V_PREF)) {
arglist.add(argstr);
return arglist;
}
else if (argstr.startsWith(Formula.LP)) {
arglist = new ArrayList<>(Arrays.asList(argstr.substring(1, argstr.length()-1).split(" ")));
return arglist;
}
else {
System.err.println("Errors in FormulaPreprocessor.collectVariables ...");
return null;
}
}
/** ************************************************************************
* Get the most specific type for variables.
*
* @param kb The KB to be used for processing
* @param types a list of sumo types for a sumo term/variable
* @return the most specific sumo type for the term/variable
*
* For example
* types of ?Writing = [Entity, Physical, Process, IntentionalProcess,
* ContentDevelopment, Writing]
* return the most specific type Writing
*/
protected String getMostRelevantType(KB kb, HashSet types) {
HashSet insts = new HashSet();
Iterator iter = types.iterator();
while (iter.hasNext()) {
String type = iter.next();
if (!type.endsWith("+"))
insts.add(type);
else
insts.add(type.substring(0, type.length()-1));
}
if (insts != null) {
winnowTypeList(insts, kb);
Iterator it1 = insts.iterator();
while (it1.hasNext()) {
return it1.next();
}
}
return null;
}
/*****************************************************************
* Collect the types of any variables that are specifically defined
* in the antecedent of a rule with an instance or subclass expression.
* TODO: This may ultimately require CNF conversion and then checking negative
* literals, but for now it's just a hack to grab preconditions.
*/
public HashMap> findExplicitTypesInAntecedent(Formula form) {
if (!form.isRule())
// TODO: Consider returning empty map instead of null. Check callers for special behavior on null.
return null;
Formula f = new Formula();
f.read(form.theFormula);
Formula antecedent = f.cdrAsFormula().carAsFormula();
return findExplicitTypes(antecedent);
}
/*****************************************************************
* Collect the types of any variables that are specifically defined
* in the antecedent of a rule with an instance expression;
* Collect the super classes of any variables that are specifically
* defined in the antecedent of a rule with an subclass expression;
*/
public HashMap> findExplicitTypesClassesInAntecedent(Formula form) {
Formula f = new Formula();
f.read(form.theFormula);
Formula antecedent = findAntecedent(f);
HashMap> varExplicitTypes = new HashMap<>();
HashMap> varExplicitClasses = new HashMap<>();
findExplicitTypesClasses(antecedent, varExplicitTypes, varExplicitClasses);
return varExplicitTypes;
}
/** ***************************************************************
* Return a formula's antecedents
*/
private static Formula findAntecedent(Formula f) {
if (f.isSimpleClause())
return f;
String carstr = f.car();
if (Formula.atom(carstr) && Formula.isLogicalOperator(carstr)) {
if (carstr.equals(f.IF) || carstr.equals(f.IFF)) {
return f.cdrAsFormula().carAsFormula();
} else {
return f;
}
}
return f;
}
/*****************************************************************
* Collect variable names and their types from instance or subclass
* expressions. subclass restrictions are marked with a '+'.
*
* @param form The formula in KIF syntax
*
* @return A map of variables paired with a set of sumo types collected
* from instance and subclass expressions.
*
* TODO: This may ultimately require CNF conversion and then checking
* negative literals, but for now it's just a hack to grab preconditions.
*/
public HashMap> findExplicitTypes(Formula form) {
HashMap> varExplicitTypes = new HashMap>();
HashMap> varExplicitClasses = new HashMap>();
findExplicitTypesRecurse(form, false, varExplicitTypes, varExplicitClasses);
varExplicitTypes.putAll(varExplicitClasses);
return varExplicitTypes;
}
/*****************************************************************
* Collect variable names and their types from instance or subclass
* expressions.
*
* @param form The formula in KIF syntax
* @param varExplicitTypes A map of variables paired with sumo types
* collected from instance expressions
* @param varExplicitClasses A map of variables paired with sumo types
* collected from subclass expression
*/
public void findExplicitTypesClasses(Formula form,
HashMap> varExplicitTypes,
HashMap> varExplicitClasses) {
findExplicitTypesRecurse(form, false, varExplicitTypes, varExplicitClasses);
}
/*****************************************************************
* Recursively collect a variable name and its types.
*/
public static void findExplicitTypesRecurse(Formula form, boolean isNegativeLiteral,
HashMap> varExplicitTypes,
HashMap> varExplicitClasses) {
if (form == null || StringUtil.emptyString(form.theFormula) || form.empty())
return;
String carstr = form.car();
if (Formula.atom(carstr) && Formula.isLogicalOperator(carstr)) {
if (carstr.equals(form.EQUANT) || carstr.equals(form.UQUANT)) {
for (int i = 2 ; i < form.listLength(); i++) // (exists (?X ?Y) (foo1 ?X ?Y)), recurse from the second argument
findExplicitTypesRecurse(new Formula(form.getArgument(i)), false, varExplicitTypes, varExplicitClasses);
}
else if (carstr.equals(form.NOT)) {
for (int i = 1; i < form.listLength(); i++) // (not (foo1 ?X ?Human)), set isNegativeLiteral = true, and recurse from the first argument
findExplicitTypesRecurse(new Formula(form.getArgument(i)), true, varExplicitTypes, varExplicitClasses);
}
else {
for (int i = 1; i < form.listLength(); i++) // eg. (and (foo1 ?X ?Y) (foo2 ?X ?Z)), recurse from the first argument
findExplicitTypesRecurse(new Formula(form.getArgument(i)), false, varExplicitTypes, varExplicitClasses);
}
}
else if (form.isSimpleClause()) {
if (isNegativeLiteral == true) // If form is negative literal, do not add explicit type for the variable
return;
Pattern p = Pattern.compile("\\(instance (\\?[a-zA-Z0-9\\-_]+) ([\\?a-zA-Z0-9\\-_]+)");
Matcher m = p.matcher(form.theFormula);
while (m.find()) {
String var = m.group(1);
String cl = m.group(2);
HashSet hs = new HashSet<>();
if (!cl.startsWith("?")) {
if (varExplicitTypes.containsKey(var))
hs = varExplicitTypes.get(var);
hs.add(cl);
}
else {
if (varExplicitTypes.containsKey(var))
hs = varExplicitTypes.get(var);
}
varExplicitTypes.put(var, hs);
}
p = Pattern.compile("\\(subclass (\\?[a-zA-Z0-9\\-_]+) ([\\?a-zA-Z0-9\\-]+)");
m = p.matcher(form.theFormula);
while (m.find()) {
String var = m.group(1);
String cl = m.group(2);
HashSet hs = new HashSet<>();
if (!cl.startsWith("?")) {
if (varExplicitClasses.containsKey(var))
hs = varExplicitClasses.get(var);
hs.add(cl + "+");
}
else {
if (varExplicitClasses.containsKey(var))
hs = varExplicitClasses.get(var);
}
varExplicitClasses.put(var, hs);
}
}
else {
findExplicitTypesRecurse(form.carAsFormula(), false, varExplicitTypes, varExplicitClasses);
findExplicitTypesRecurse(form.cdrAsFormula(), false, varExplicitTypes, varExplicitClasses);
}
}
/** ***************************************************************
* utility method to add a String element to a HashMap of String
* keys and a value of an HashSet of Strings
*/
private static void addToMap(HashMap> map, String key, String element) {
HashSet al = map.get(key);
if (al == null)
al = new HashSet();
al.add(element);
map.put(key, al);
}
/** ***************************************************************
* utility method to merge two HashMaps of String keys and a values
* of an HashSet of Strings
*/
static HashMap> mergeToMap(HashMap> map1,
HashMap> map2, KB kb) {
HashMap> result = new HashMap>(map1);
for(String key : map2.keySet()) {
Set value = new HashSet();
if (result.containsKey(key)) {
value = result.get(key);
}
value.addAll(map2.get(key));
value = kb.removeSuperClasses(value);
result.put(key, Sets.newHashSet(value));
}
return result;
}
/*****************************************************************
* This method returns a HashMap that maps each String variable in
* this the names of types (classes) of which the variable must be
* an instance or the names of types of which the variable must be
* a subclass. Note that this method does not capture explicit type
* from assertions such as (=> (instance ?Foo Bar) ...). This method
* just consider restrictions implicitly defined from the arg types
* of relations.
*
* @param kb The KB to be used to compute the sortal constraints
* for each variable.
* @return A HashMap of variable names and their types. Subclass
* restrictions are marked with a '+', meaning that a
* domainSubclass is defined for this argument in one of
* the loaded .kif files. Instance restrictions have no
* special mark.
*/
public HashMap> computeVariableTypes(Formula form, KB kb) {
if (debug) System.out.println("INFO in FormulaPreprocessor.computeVariableTypes(): \n" + form);
Formula f = new Formula();
f.read(form.theFormula);
HashMap> result = new HashMap>();
return computeVariableTypesRecurse(kb,form,result);
}
/** ***************************************************************
*/
public HashMap> computeVariableTypesRecurse(KB kb, Formula f,
HashMap> input) {
HashMap> result = new HashMap>();
if (f == null || StringUtil.emptyString(f.theFormula) || f.empty())
return result;
if (debug) System.out.println("INFO in FormulaPreprocessor.computeVariableTypesRecurse(): \n" + f);
String carstr = f.car();
if (Formula.atom(carstr) && Formula.isLogicalOperator(carstr)) {// equals may require special treatment
result.putAll(input);
for (int i = 1; i < f.listLength(); i++)
result = mergeToMap(result,computeVariableTypesRecurse(kb,new Formula(f.getArgument(i)),input), kb);
}
else if (f.isSimpleClause()) {
String pred = carstr;
if (f.theFormula.indexOf("?") > -1 && !Formula.isVariable(pred)) {
Formula newf = f.cdrAsFormula();
int argnum = 1;
while (!newf.empty()) {
String arg = newf.car();
if (Formula.isVariable(arg)) {
String cl = findType(argnum,pred,kb);
if (debug) System.out.println("arg,pred,argnum,type: " + arg + ", " + pred + ", " + argnum + ", " + cl);
if (StringUtil.emptyString(cl)) {
if (!kb.kbCache.transInstOf(pred, "VariableArityRelation"))
System.out.println("Error in FormulaPreprocessor.computeVariableTypesRecurse(): " +
"no type information for arg " + argnum + " of relation " + pred + " in formula: \n" + f);
}
else
addToMap(result,arg,cl);
}
// If formula is function then recurse.
else if(Formula.isFunctionalTerm(arg)) {
result = mergeToMap(result, computeVariableTypesRecurse(kb, new Formula(arg), input), kb);
}
newf = newf.cdrAsFormula();
argnum++; // note that this will try an argument that doesn't exist, and terminate when it does
}
}
}
else {
result = mergeToMap(input,computeVariableTypesRecurse(kb,f.carAsFormula(),input), kb);
result = mergeToMap(result,computeVariableTypesRecurse(kb,f.cdrAsFormula(),input), kb);
}
return result;
}
/** ***************************************************************
* Pre-process a formula before sending it to the theorem prover.
* This includes ignoring meta-knowledge like documentation strings,
* translating mathematical operators, quoting higher-order formulas,
* expanding row variables and prepending the 'holds__' predicate.
* @return an ArrayList of Formula(s)
*/
private String preProcessRecurse(Formula f, String previousPred, boolean ignoreStrings,
boolean translateIneq, boolean translateMath) {
StringBuilder result = new StringBuilder();
if (f.listP() && !f.empty()) {
String prefix = "";
String pred = f.car();
if (Formula.isQuantifier(pred)) {
// The list of quantified variables.
result.append(" ");
result.append(f.cadr());
// The formula following the list of variables.
String next = f.caddr();
Formula nextF = new Formula();
nextF.read(next);
result.append(" ");
result.append(preProcessRecurse(nextF,"",ignoreStrings,translateIneq,translateMath));
}
else {
Formula restF = f.cdrAsFormula();
int argCount = 1;
while (!restF.empty()) {
argCount++;
String arg = restF.car();
Formula argF = new Formula();
argF.read(arg);
if (argF.listP()) {
String res = preProcessRecurse(argF,pred,ignoreStrings,translateIneq,translateMath);
result.append(" ");
if (!Formula.isLogicalOperator(pred) &&
!Formula.isComparisonOperator(pred) &&
!Formula.isMathFunction(pred) &&
!argF.isFunctionalTerm()) {
result.append("`");
}
result.append(res);
}
else
result.append(" " + arg);
restF.theFormula = restF.cdr();
}
if (KBmanager.getMgr().getPref("holdsPrefix").equals("yes")) {
if (!Formula.isLogicalOperator(pred) && !Formula.isQuantifierList(pred,previousPred))
prefix = "holds_";
if (f.isFunctionalTerm())
prefix = "apply_";
if (pred.equals("holds")) {
pred = "";
argCount--;
prefix = prefix + argCount + "__ ";
}
else {
if (!Formula.isLogicalOperator(pred) &&
!Formula.isQuantifierList(pred,previousPred) &&
!Formula.isMathFunction(pred) &&
!Formula.isComparisonOperator(pred)) {
prefix = prefix + argCount + "__ ";
}
else
prefix = "";
}
}
}
result.insert(0, pred);
result.insert(0, prefix);
result.insert(0, "(");
result.append(")");
}
return result.toString();
}
/** ***************************************************************
* Tries to successively instantiate predicate variables and then
* expand row variables in this Formula, looping until no new
* Formulae are generated.
*
* @param kb The KB to be used for processing this Formula
*
* @param addHoldsPrefix If true, predicate variables are not
* instantiated
*
* @return an ArrayList of Formula(s), which could be empty.
*/
private ArrayList replacePredVarsAndRowVars(Formula form, KB kb, boolean addHoldsPrefix) {
ArrayList result = new ArrayList();
Formula startF = new Formula();
startF.read(form.theFormula);
LinkedHashSet accumulator = new LinkedHashSet();
accumulator.add(startF);
ArrayList working = new ArrayList();
int prevAccumulatorSize = 0;
Formula f = null;
while (accumulator.size() != prevAccumulatorSize) {
prevAccumulatorSize = accumulator.size();
// Initialize predicate variables if we are not adding holds prefixes.
if (!addHoldsPrefix) {
working.clear();
working.addAll(accumulator);
accumulator.clear();
Iterator it = working.iterator();
while (it.hasNext()) {
f = (Formula) it.next();
Set instantiations = PredVarInst.instantiatePredVars(f,kb);
form.errors.addAll(f.getErrors());
// If the accumulator is null -- the formula can't be instantiated at all and has been marked "reject",
// don't add anything
// If the accumulator is empty -- no pred var instantiations were possible,
// add the original formula to the accumulator for possible row var expansion below.
if (instantiations != null) {
if (instantiations.isEmpty()) {
accumulator.add(f);
}
else {
accumulator.addAll(instantiations);
}
}
}
}
// Row var expansion. Iterate over the instantiated predicate formulas,
// doing row var expansion on each. If no predicate instantiations can be generated, the accumulator
// will contain just the original input formula.
if (!accumulator.isEmpty() && (accumulator.size() < AXIOM_EXPANSION_LIMIT)) {
working.clear();
working.addAll(accumulator);
accumulator.clear();
Iterator it2 = working.iterator();
while (it2.hasNext()) {
f = (Formula) it2.next();
RowVars rv = new RowVars();
accumulator.addAll(RowVars.expandRowVars(kb,f));
if (accumulator.size() > AXIOM_EXPANSION_LIMIT) {
System.out.println(" AXIOM_EXPANSION_LIMIT EXCEEDED: " + AXIOM_EXPANSION_LIMIT);
break;
}
}
}
}
result.addAll(accumulator);
return result;
}
/** ***************************************************************
* Returns true if this Formula appears not to have any of the
* characteristics that would cause it to be rejected during
* translation to TPTP form, or cause problems during inference.
* Otherwise, returns false.
*
* @param query true if this Formula represents a query, else
* false.
*
* @param kb The KB object to be used for evaluating the
* suitability of this Formula.
*
* @return boolean
*/
private static boolean isOkForInference(Formula f, boolean query, KB kb) {
boolean pass = false;
// kb isn't used yet, because the checks below are purely
// syntactic. But it probably will be used in the future.
pass = !(
StringUtil.containsNonAsciiChars(f.theFormula)
// ( ?X ...) - no free variables in an
// atomic formula that doesn't contain a string
// unless the formula is a query.
|| (!query
&& !Formula.isLogicalOperator(f.car())
// The formula does not contain a string.
&& (f.theFormula.indexOf('"') == -1)
// The formula contains a free variable.
&& f.theFormula.matches(".*\\?\\w+.*"))
// ... add more patterns here, as needed.
|| false
);
return pass;
}
/** ***************************************************************
* Adds statements of the form (instance ) if
* they are not already in the KB.
*
* @param kb The KB to be used for processing the input Formulae
* in variableReplacements
*
* @param isQuery If true, this method just returns the initial
* input List, variableReplacements, with no additions
*
* @param variableReplacements A List of Formulae in which
* predicate variables and row variables have already been
* replaced, and to which (instance )
* Formulae might be added
*
* @return an ArrayList of Formula(s), which could be larger than
* the input List, variableReplacements, or could be empty.
*/
private ArrayList addInstancesOfSetOrClass(Formula form, KB kb,
boolean isQuery, ArrayList variableReplacements) {
ArrayList result = new ArrayList();
if ((variableReplacements != null) && !variableReplacements.isEmpty()) {
if (isQuery)
result.addAll(variableReplacements);
else {
HashSet formulae = new HashSet();
String arg0 = null;
Formula f = null;
for (Iterator it = variableReplacements.iterator(); it.hasNext();) {
f = it.next();
formulae.add(f);
if (f.listP() && !f.empty()) { // Make sure every SetOrClass is stated to be such
arg0 = f.car();
int start = -1;
if (arg0.equals("subclass")) start = 0;
else if (arg0.equals("instance")) start = 1;
if (start > -1) {
ArrayList args =
new ArrayList(Arrays.asList(f.getArgument(1),f.getArgument(2)));
int argslen = args.size();
String ioStr = null;
Formula ioF = null;
String arg = null;
for (int i = start; i < argslen; i++) {
arg = args.get(i);
if (!Formula.isVariable(arg) && !arg.equals("SetOrClass") && Formula.atom(arg)) {
StringBuilder sb = new StringBuilder();
sb.setLength(0);
sb.append("(instance ");
sb.append(arg);
sb.append(" SetOrClass)");
ioF = new Formula();
ioStr = sb.toString().intern();
ioF.read(ioStr);
ioF.sourceFile = form.sourceFile;
if (!kb.formulaMap.containsKey(ioStr)) {
formulae.add(ioF);
}
}
}
}
}
}
result.addAll(formulae);
}
}
return result;
}
/** ***************************************************************
* Pre-process a formula before sending it to the theorem prover.
* This includes ignoring meta-knowledge like documentation strings,
* translating mathematical operators, quoting higher-order formulas,
* expanding row variables and prepending the 'holds__' predicate.
*
* @param isQuery If true the Formula is a query and should be
* existentially quantified, else the Formula is a
* statement and should be universally quantified
*
* @param kb The KB to be used for processing this Formula
*
* @return an ArrayList of Formula(s), which could be empty.
*
*/
public ArrayList preProcess(Formula form, boolean isQuery, KB kb) {
ArrayList results = new ArrayList();
if (!StringUtil.emptyString(form.theFormula)) {
KBmanager mgr = KBmanager.getMgr();
if (!form.isBalancedList()) {
String errStr = "Unbalanced parentheses or quotes in: " + form.theFormula;
form.errors.add(errStr);
return results;
}
boolean ignoreStrings = false;
boolean translateIneq = true;
boolean translateMath = true;
Formula f = new Formula();
f.read(form.theFormula);
if (StringUtil.containsNonAsciiChars(f.theFormula))
f.theFormula = StringUtil.replaceNonAsciiChars(f.theFormula);
boolean addHoldsPrefix = mgr.getPref("holdsPrefix").equalsIgnoreCase("yes");
ArrayList variableReplacements = replacePredVarsAndRowVars(form,kb, addHoldsPrefix);
form.errors.addAll(f.getErrors());
ArrayList accumulator = addInstancesOfSetOrClass(form,kb, isQuery, variableReplacements);
// Iterate over the formulae resulting from predicate variable instantiation and row variable expansion,
// passing each to preProcessRecurse for further processing.
if (!accumulator.isEmpty()) {
//boolean addSortals = mgr.getPref("typePrefix").equalsIgnoreCase("yes");
Formula fnew = null;
String theNewFormula = null;
Iterator it = accumulator.iterator();
int counter = 0;
while (it.hasNext()) {
fnew = (Formula) it.next();
FormulaPreprocessor fp = new FormulaPreprocessor();
theNewFormula = fp.preProcessRecurse(fnew,"",ignoreStrings,translateIneq,translateMath);
fnew.read(theNewFormula);
form.errors.addAll(fnew.getErrors());
if (isOkForInference(fnew,isQuery, kb)) {
fnew.sourceFile = form.sourceFile;
if (!StringUtil.emptyString(theNewFormula))
results.add(fnew);
}
else
form.errors.add("Formula rejected for inference: " + f.theFormula);
}
}
}
if (debug) System.out.println("INFO in FormulaPreprocessor.preProcess(): result: " + results);
// If typePrefix==yes and isQuery==false, add a "sortal" antecedent to every axiom
KBmanager mgr = KBmanager.getMgr();
boolean typePrefix = mgr.getPref("typePrefix").equalsIgnoreCase("yes");
if (typePrefix && !isQuery) {
Iterator it = results.iterator();
while (it.hasNext()) {
Formula f = it.next();
FormulaPreprocessor fp = new FormulaPreprocessor();
f.read(fp.addTypeRestrictions(f,kb).theFormula);
}
}
if (debug) System.out.println("INFO in FormulaPreprocessor.preProcess(): result: " + results);
return results;
}
/** ***************************************************************
*/
public static void testFindTypes() {
KBmanager.getMgr().initializeOnce();
KB kb = KBmanager.getMgr().getKB("SUMO");
System.out.println();
String strf = "(=> (forall (?ELEMENT) (<=> (element ?ELEMENT ?SET1) " +
"(element ?ELEMENT ?SET2))) (equal ?SET1 ?SET2))";
Formula f = new Formula();
f.read(strf);
FormulaPreprocessor fp = new FormulaPreprocessor();
System.out.println("Formula: " + f);
System.out.println("Var types: " + fp.computeVariableTypes(f,kb));
System.out.println();
strf = "(=> (and (attribute ?AREA LowTerrain) (part ?ZONE ?AREA)" +
" (slopeGradient ?ZONE ?SLOPE)) (greaterThan 0.03 ?SLOPE))";
f.read(strf);
fp = new FormulaPreprocessor();
System.out.println("Formula: " + f);
System.out.println("Var types: " + fp.computeVariableTypes(f,kb));
System.out.println();
strf = "(=> (and (typicalPart ?PART ?WHOLE) (instance ?X ?PART) " +
"(equal ?PARTPROB (ProbabilityFn (exists (?Y) (and " +
"(instance ?Y ?WHOLE) (part ?X ?Y))))) (equal ?NOTPARTPROB " +
"(ProbabilityFn (not (exists (?Z) (and (instance ?Z ?WHOLE) " +
"(part ?X ?Z))))))) (greaterThan ?PARTPROB ?NOTPARTPROB))";
f.read(strf);
fp = new FormulaPreprocessor();
System.out.println("Formula: " + f);
System.out.println("Var types: " + fp.computeVariableTypes(f,kb));
System.out.println();
strf = "(<=> (instance ?REL TransitiveRelation) " +
"(forall (?INST1 ?INST2 ?INST3) " +
"(=> (and (?REL ?INST1 ?INST2) " +
"(?REL ?INST2 ?INST3)) (?REL ?INST1 ?INST3))))";
f.read(strf);
fp = new FormulaPreprocessor();
System.out.println("Formula: " + f);
System.out.println("Var types: " + fp.computeVariableTypes(f,kb));
System.out.println("Explicit types: " + fp.findExplicitTypesInAntecedent(f));
}
/** ***************************************************************
*/
public static void testFindExplicit() {
String formStr = "(<=> (instance ?REL TransitiveRelation) " +
"(forall (?INST1 ?INST2 ?INST3) " +
"(=> (and (?REL ?INST1 ?INST2) " +
"(?REL ?INST2 ?INST3)) (?REL ?INST1 ?INST3))))";
Formula f = new Formula(formStr);
FormulaPreprocessor fp = new FormulaPreprocessor();
System.out.println("Formula: " + f);
Pattern p = Pattern.compile("\\(instance (\\?[a-zA-Z0-9]+) ([a-zA-Z0-9\\-_]+)");
Matcher m = p.matcher(formStr);
m.find();
String var = m.group(1);
String cl = m.group(2);
System.out.println("FormulaPreprocessor.testExplicit(): " + var + " " + cl);
System.out.println("Explicit types: " + fp.findExplicitTypesInAntecedent(f));
}
/** ***************************************************************
*/
public static void testAddTypes() {
KBmanager.getMgr().initializeOnce();
KB kb = KBmanager.getMgr().getKB("SUMO");
System.out.println();
String strf = "(=> (forall (?ELEMENT) (<=> (element ?ELEMENT ?SET1) " +
"(element ?ELEMENT ?SET2))) (equal ?SET1 ?SET2))";
Formula f = new Formula();
f.read(strf);
FormulaPreprocessor fp = new FormulaPreprocessor();
FormulaPreprocessor.debug = true;
System.out.println(fp.addTypeRestrictions(f,kb));
System.out.println();
strf = "(=> (and (attribute ?AREA LowTerrain) (part ?ZONE ?AREA)" +
" (slopeGradient ?ZONE ?SLOPE)) (greaterThan 0.03 ?SLOPE))";
f.read(strf);
fp = new FormulaPreprocessor();
System.out.println(fp.addTypeRestrictions(f,kb));
System.out.println();
strf = "(=> (and (typicalPart ?PART ?WHOLE) (instance ?X ?PART) " +
"(equal ?PARTPROB (ProbabilityFn (exists (?Y) (and " +
"(instance ?Y ?WHOLE) (part ?X ?Y))))) (equal ?NOTPARTPROB " +
"(ProbabilityFn (not (exists (?Z) (and (instance ?Z ?WHOLE) " +
"(part ?X ?Z))))))) (greaterThan ?PARTPROB ?NOTPARTPROB))";
f.read(strf);
fp = new FormulaPreprocessor();
System.out.println(fp.addTypeRestrictions(f,kb));
}
/** ***************************************************************
*/
public static void main(String[] args) {
testFindTypes();
testAddTypes();
testFindExplicit();
}
}