![JAR search and dependency download from the Maven repository](/logo.png)
com.articulate.sigma.FormulaPreprocessor Maven / Gradle / Ivy
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();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy