All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.articulate.sigma.ProofProcessor Maven / Gradle / Ivy

Go to download

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;

/** This code is copyright Articulate Software (c) 2003.  Some portions
copyright Teknowledge (c) 2003 and reused under the terms of the GNU license.
This software is released under the GNU Public License .
Users of this code also consent, by use of this code, to credit Articulate Software
and Teknowledge in any writings, briefings, publications, presentations, or 
other representations of any software which incorporates, builds on, or uses this 
code.  Please cite the following article in any publication with references:

Pease, A., (2003). The Sigma Ontology Development Environment, 
in Working Notes of the IJCAI-2003 Workshop on Ontology and Distributed Systems,
August 9, Acapulco, Mexico.
*/

import edu.stanford.nlp.util.StringUtils;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** Process results from the inference engine.
 */
public class ProofProcessor {

     /** An ArrayList of BasicXMLelement (s). */
    private ArrayList xml = null;

    /** ***************************************************************
     * Take an ArrayList of BasicXMLelement (s) and process them as
     * needed
     */
    public ProofProcessor(ArrayList xmlInput) {

    	xml = new ArrayList(xmlInput);
    }
    
    /** ***************************************************************
     * Compare the answer with the expected answer.  Note that this method
     * is very unforgiving in that it requires the exact same format for the 
     * expected answer, including the order of variables.
     */
    public boolean equalsAnswer(int answerNum, String expectedAnswer) {

    	StringBuffer result = new StringBuffer();
    	ArrayList queryResponseElements = ((BasicXMLelement) xml.get(0)).subelements;
    	BasicXMLelement answer = queryResponseElements.get(answerNum);
    	if (((String) answer.attributes.get("result")).equalsIgnoreCase("no")) 
    		return false;
    	if (((String) answer.attributes.get("result")).equalsIgnoreCase("yes") &&
    			(expectedAnswer.equalsIgnoreCase("yes"))) 
    		return true;
    	BasicXMLelement bindingSet = (BasicXMLelement) answer.subelements.get(0);
    	if ( bindingSet != null ) {
    		String attr =  (String) bindingSet.attributes.get("type");
    		if ( (attr == null) || !(attr.equalsIgnoreCase("definite")) ) 
    			return false;    
    		BasicXMLelement binding = (BasicXMLelement) bindingSet.subelements.get(0); 
    		// The bindingSet element should just have one subelement, since non-definite answers are rejected.
    		for (int j = 0; j < binding.subelements.size(); j++) {
    			BasicXMLelement variableBinding = (BasicXMLelement) binding.subelements.get(j);
    			String variable = (String) variableBinding.attributes.get("name");
    			String value = (String) variableBinding.attributes.get("value");
    			result = result.append("(" + variable + " " + value + ")");
    			if (j < binding.subelements.size()-1) 
    				result = result.append(" ");
    		}
    	}
    	return result.toString().equalsIgnoreCase(expectedAnswer);
    }

    /** ***************************************************************
     
    public String returnAnswer(int answerNum) {
    	return returnAnswer(answerNum, "");
    }
    */
    /** ***************************************************************
     * Return the variable name and binding for the given answer.
     
    public String returnAnswer(int answerNum, String query) {

    	StringBuffer result = new StringBuffer();
    	ArrayList skolemTypes = new ArrayList();
    	//An ArrayList of BasicXMLelements 
    	ArrayList queryResponseElements = ((BasicXMLelement) xml.get(0)).subelements;
    	BasicXMLelement answer = queryResponseElements.get(answerNum);
    	if (((String) answer.attributes.get("result")).equalsIgnoreCase("no")) 
    		return "no";
    	BasicXMLelement bindingSet = (BasicXMLelement) answer.subelements.get(0);
    	if (bindingSet.tagname.equalsIgnoreCase("proof")) {
    		result = result.append("[" + (String) answer.attributes.get("result") + "] ");
    		return result.toString();
    	}
    	result = result.append("[" + (String) bindingSet.attributes.get("type") + "] ");
    	for (int i = 0; i < bindingSet.subelements.size(); i++) {
    		BasicXMLelement binding = (BasicXMLelement) bindingSet.subelements.get(i);
    		for (int j = 0; j < binding.subelements.size(); j++) {
    			BasicXMLelement variableBinding = (BasicXMLelement) binding.subelements.get(j);
    			String variable = (String) variableBinding.attributes.get("name");
    			String value = (String) variableBinding.attributes.get("value");
    			//see if a skolem function is present in the value (skolem functions are labeled sk[0-9]+
    			if (value.matches(".*?sk[0-9]+.*?")) {
    				String skolemType = findSkolemType(answerNum, value, query, variable);
    				if (skolemType != "")
    					skolemTypes.add("; " + value + " is of type " + skolemType);    				
    			}
    			result = result.append(variable + " = " + value);
    			if (j < binding.subelements.size()-1) 
    				result = result.append(",  ");
    		}
    		if (i < bindingSet.subelements.size()-1) 
    			result = result.append(" , ");
    		while (skolemTypes.size() > 0) {
    			result = result.append(skolemTypes.get(0));
    			skolemTypes.remove(0);
    		}
    		result.append(";");
    	}
    	return result.toString();
    }
*/
    /** ***************************************************************
     * Looks for skolem function from proofsteps if query is not given.
     * There are two types of skolem functions:
     * one with arguments, for instance: (sk0 Human123) or
     * one without, for example: sk2
     * We need to find either of these in the proofs to see what relationship it goes into
     */
    public static ArrayList returnSkolemStmt(String skolem, ArrayList proofSteps) {

    	if (skolem.startsWith("(") && skolem.endsWith(")")) 
    		skolem = skolem.substring(1, skolem.length()-1);
    	skolem = skolem.split(" ")[0];
    	Pattern pattern = Pattern.compile("(\\([^\\(|.]*?\\(" + skolem + " .+?\\).*?\\)|\\([^\\(|.]*?" + skolem + "[^\\)|.]*?\\))");
    	Matcher match;

    	ArrayList matches = new ArrayList();
    	for (int i = 0; i < proofSteps.size(); i++) {
    		ProofStep step = (ProofStep) proofSteps.get(i);
    		match = pattern.matcher(step.axiom);
    		while (match.find()) {
    			for (int j = 1; j <= match.groupCount(); j++) {
    				if (!matches.contains(match.group(j)))
    					matches.add(match.group(j));
    			}
    		}
    	}        
    	if (matches.size()>0)
    		return matches;
    	return null;
    }
    
    /** ***************************************************************
     * looks for skolem variable if a query string is given
     */
    private ArrayList returnSkolemStmt(String query, String variable) {

    	if (!StringUtil.emptyString(query)) {
    		query = query.replaceAll("\\" + variable, "_SKOLEM");
    		Pattern pattern = Pattern.compile("(\\([^\\(\\)]*?_SKOLEM[^\\)\\(]*?\\))");
    		Matcher match = pattern.matcher(query);

    		while (match.find()) {
    			ArrayList matches = new ArrayList();
    			for (int i = 1; i <= match.groupCount(); i++) {
    				if (!matches.contains(match.group(i)))
    					matches.add(match.group(i));
    			}
    			return matches;   
    		}
    	}    
    	return null;
    }

    /** *********************************************************************************
     * @param answerNum The nth answer in the result set
     * @param value The value in the bindingSet being analyzed
     
    private String findSkolemType(int answerNum, String value, String query, String variable) {   

    	ArrayList proofSteps = getProofSteps(answerNum); 
    	ArrayList skolemRelationArr;
    	// try and look for the skolem function in the proofSteps and determine the 
    	// relation statement it appears in
    	if (query == "")
    		skolemRelationArr = returnSkolemStmt(value, proofSteps);
    	else
    		skolemRelationArr = returnSkolemStmt(query, variable);

    	if (skolemRelationArr != null) {   
    		for (int j = 0; j < skolemRelationArr.size(); j++) {
    			String skolemRelation = skolemRelationArr.get(j);
    			skolemRelation = skolemRelation.substring(1, skolemRelation.length()-1);

    			// prepare skolem function to have the form sk0 .+? or sk0 (for skolem functions that don't have an argument)
    			// because value from answer contains an instance and not necessarily a variable
    			String skolem = value;
    			if(skolem.startsWith("(") && skolem.endsWith(")"))
    				skolem = value.substring(1, value.length()-1);
    			skolem = skolem.split(" ")[0];

    			// remove skolem and replace with temp variable
    			skolemRelation = skolemRelation.replaceAll("\\("+ skolem + " [^\\)]+?\\)", "_SKOLEM");
    			skolemRelation = skolemRelation.replaceAll(skolem, "_SKOLEM");
    			// remove all other skolem functions in the skolemRelation (if present) and replace with temp variable
    			skolemRelation = skolemRelation.replaceAll("\\(.+?\\)", "?TEMP");
    			//LOGGER.finest("skolemRelation: " + skolemRelation);

    			if (skolemRelation.matches("instance\\s_SKOLEM\\s[^\\s]+")) {
    				String[] arguments = skolemRelation.split(" ");
    				return arguments[arguments.length-1];
    			}

    			// assemble regex for skolemRelation
    			String[] skolemArguments = skolemRelation.split(" ");
    			StringBuffer regexStmt = new StringBuffer();

    			for (int i = 0; i < skolemArguments.length; i++) {
    				if (skolemArguments[i].equals("_SKOLEM")) 
    					regexStmt.append("([^\\s\\(\\)]+) ");    
    				else if (skolemArguments[i].startsWith("?") || i!=0) 
    					regexStmt.append("[^\\s\\(\\)]+ ");    
    				else 
    					regexStmt.append(skolemArguments[i] + " ");    
    			}

    			regexStmt.deleteCharAt(regexStmt.length()-1);
    			regexStmt.insert(0, "\\(");
    			regexStmt.insert(regexStmt.length(), "\\)");

    			// resulting regexStmt from something like (relationshipName ?X0 _SKOLEM)
    			// should be \\(relationshipName [^\\s\\(\\)]+ ([^\\s\\(\\)]+)\\)    
    			Pattern pattern = Pattern.compile(regexStmt.toString());
    			Matcher match;

    			// look for the presence of above pattern in each of the proof steps
    			for (int i = 0; i < proofSteps.size(); i++){
    				ProofStep proof = (ProofStep)proofSteps.get(i);
    				String varName = "";
    				match = pattern.matcher(proof.axiom);    
    				boolean varNameFound = false;

    				// if it is found, extract the variable name being used
    				// and then see if an (instance ?VARNAME ?CLASS) relationship can be found
    				// that defines the class membership of varName
    				while (match.find()) {
    					int k = 1;
    					while(k <= match.groupCount() && !varNameFound) {
    						varName = match.group(k);
    						if (varName.startsWith("?"))
    							varNameFound = true;
    						k++;    
    						if (varNameFound) {
    							String regexString = ".*?\\(instance \\" + varName + " ([^\\s\\)]+)\\).*?";
    							Pattern varPattern = Pattern.compile(regexString);
    							match = varPattern.matcher(proof.axiom);
    							if (match.find()) {
    								if (match.group(1) != null)
    									return match.group(1);    
    								else varNameFound = false;    
    							}
    							else varNameFound = false;
    						}
    					}
    				}
    			}
    		}
    	}
    	return "cannot be determined.";
    }
*/
    /** ***************************************************************
     * if the answer clause is found, return null
     */
    private static Formula removeNestedAnswerClauseRecurse(Formula f) {

    	if (StringUtil.emptyString(f.theFormula.trim()))
    		return null;
    	if (f.theFormula.indexOf("answer") == -1)
    		return f;
    	String relation = f.car(); 
    	if (relation.equals("answer")) 
    		return null;
    	if (relation.equals("not")) {
    		Formula fcdar = f.cdrAsFormula().carAsFormula();
    		if (fcdar == null) {
    			System.out.println("Error in ProofProcessor.removeNestedAnswerClauseRecurse(): bad arg to not: '" + f.theFormula + "'");
    			return null;
    		}
    		Formula fnew = removeNestedAnswerClauseRecurse(fcdar);
    		if (fnew == null)
    			return null;
    		else {
    			Formula result = new Formula();
    			result.read("(not " + fnew.theFormula + ")");    
    			return result;
    		}
    	}
    	boolean connective = false;
    	if (relation.equals("or") || relation.equals("and"))
    		connective = true;
    	ArrayList arglist = new ArrayList();
    	int arg = 1;
    	boolean foundAnswer = false;
    	String strArgs = "";
    	while (!StringUtil.emptyString(f.getArgument(arg))) {
    		Formula argForm = new Formula();
    		argForm.read(f.getArgument(arg));
    		Formula argRes = removeNestedAnswerClauseRecurse(argForm);
    		if (argRes == null) 
    			foundAnswer = true;    
    		else {
    			if (arg > 1)
    				strArgs = strArgs + " ";
    			strArgs = strArgs + argRes.theFormula;
    		}
    		arg = arg + 1;
    	}
    	Formula result = new Formula();
    	if (connective && foundAnswer && arg < 4)
    		result.read(strArgs);
    	else
    		result.read("(" + relation + " " + strArgs + ")");    
    	return result;
    }
    
    /** ***************************************************************
     * Remove the $answer clause that eProver returns, including any
     * surrounding connective.
     */
    public static String removeNestedAnswerClause(String st) {

    	if (st == null || st.indexOf("answer") == -1)
    		return st;
    	// clean the substring with "answer" in it
    	Formula f = new Formula();
    	f.read(st);

		// if there are no nested answers, return the original one
		Formula removeNestedAnswerFormula = removeNestedAnswerClauseRecurse(f);
		if (removeNestedAnswerFormula == null)
			return st;
    	return removeNestedAnswerFormula.theFormula;
    }

    /** ***************************************************************
     * Remove the $answer clause that Vampire returns, including any
     * surrounding "or".
     
    private static String removeAnswerClause(String st) {

    	if (st.indexOf("$answer") == -1)
    		return st;
    	// clean the substring with "answer" in it
    	st = st.replaceAll("\\(\\$answer\\s[\\(sk[0-9]+\\s[^\\)]+?\\)|[^\\(\\)]+?]+?\\)", "");

    	//count number of nested statements if statement starts with (or
    	//if nested statements is more than 2, keep or. If it is exactly 2 --
    	//which means it's just (or plus one other statement, remove or.
    	if (st.substring(0,3).equalsIgnoreCase("(or") || st.substring(0,3).equalsIgnoreCase("(and")){
    		boolean done = false;
    		String substr = st.substring(4, st.length()-1);
    		while (!done) {
    			String statement = " SUMO-AXIOM";
    			substr = substr.replaceAll("\\([^\\(|^\\)]+\\)", statement);
    			substr = substr.replaceAll("\\(not\\s[^\\(|^\\)]+\\)", statement);
    			if (substr.indexOf("(") == -1) 
    				done = true;        
    		}        
    		substr = substr.trim();        
    		if (substr.split(" ").length <= 2) {
    			st = st.substring(4, st.length()-1);
    		}
    	}         
    	return st;     
    }
*/
    /** ***************************************************************
     * Return an ArrayList of ProofSteps. It expects that the member variable
     * xml will contain a set of  tags.
     
    public ArrayList getProofSteps(int answerNum) {

    	BasicXMLelement proof;
    	ArrayList queryResponseElements = ((BasicXMLelement) xml.get(0)).subelements;
    	ArrayList proofSteps = new ArrayList();
    	BasicXMLelement answer = (BasicXMLelement) queryResponseElements.get(answerNum);

    	if (!((String) answer.attributes.get("result")).equalsIgnoreCase("no")) {
    		BasicXMLelement bindingOrProof = (BasicXMLelement) answer.subelements.get(0);
    		if (bindingOrProof.tagname.equalsIgnoreCase("proof")) 
    			proof = bindingOrProof;            // No binding set if query is for a true/false answer
    		else 
    			proof = (BasicXMLelement) answer.subelements.get(1);

    		ArrayList steps = proof.subelements;
    		for (int i = 0; i < steps.size(); i++) {
    			BasicXMLelement step = (BasicXMLelement) steps.get(i);
    			BasicXMLelement premises = (BasicXMLelement) step.subelements.get(0);
    			BasicXMLelement conclusion = (BasicXMLelement) step.subelements.get(1);
    			BasicXMLelement conclusionFormula = (BasicXMLelement) conclusion.subelements.get(0);
    			ProofStep processedStep = new ProofStep();
    			processedStep.formulaType = ((BasicXMLelement) conclusion.subelements.get(0)).tagname;
    			processedStep.axiom = Formula.postProcess(conclusionFormula.contents);

    			if (i == steps.size() - 1) 
    				processedStep.axiom = processedStep.axiom.replaceAll("\\$answer[\\s|\\n|\\r]+", "");                
    			else
    				processedStep.axiom = removeAnswerClause(processedStep.axiom);
    			//----If there is a conclusion role, record
    			if (conclusion.subelements.size() > 1) {
    				BasicXMLelement conclusionRole = (BasicXMLelement) conclusion.subelements.get(1);
    				if (conclusionRole.attributes.containsKey("type")) 
    					processedStep.formulaRole = (String) conclusionRole.attributes.get("type");                        
    			}
    			if (conclusionFormula.attributes.containsKey("number")) {
    				processedStep.number = new Integer(Integer.parseInt((String) conclusionFormula.attributes.get("number")));
    			}
    			for (int j = 0; j < premises.subelements.size(); j++) {
    				BasicXMLelement premise = (BasicXMLelement) premises.subelements.get(j);
    				BasicXMLelement formula = (BasicXMLelement) premise.subelements.get(0);
    				Integer premiseNum = new Integer(Integer.parseInt((String) formula.attributes.get("number"),10));
    				processedStep.premises.add(premiseNum);
    			}
    			proofSteps.add(processedStep);
    		}
    	}
    	return proofSteps;
    }
*/
    /** ***************************************************************
     * Return the number of answers contained in this proof.
     */
    public int numAnswers() {

    	if (xml == null || xml.size() == 0) 
    		return 0;
    	BasicXMLelement queryResponse = (BasicXMLelement) xml.get(0);
    	if (queryResponse.tagname.equalsIgnoreCase("queryResponse")) 
    		return queryResponse.subelements.size()-1;   
    	// Note that there is a  element under the queryResponse element that shouldn't be counted, hence the -1
    	else
    		System.out.println("Error in ProofProcessor.numAnswers(): Bad tag: " + queryResponse.tagname);
    	return 0;
    }

    /** ***************************************************************
     * Convert XML proof to TPTP format
     */
    public static String tptpProof(ArrayList proofSteps) {

    	StringBuffer result = new StringBuffer();
    	try {
    		for (int j = 0; j < proofSteps.size(); j++) {
    			ProofStep step = (ProofStep) proofSteps.get(j);
    			boolean isLeaf = step.premises.isEmpty() || 
    					(step.premises.size() == 1 && ((Integer)(step.premises.get(0))).intValue() == 0);
    			//----All are fof because the conversion from SUO-KIF quantifies the variables
    			result.append("fof(");
    			result.append(step.number);
    			result.append(",");
    			if (isLeaf) 
    				result.append("axiom");                
    			else 
    				result.append("plain");                
    			result.append(",");
    			result.append(SUMOformulaToTPTPformula.tptpParseSUOKIFString(step.axiom,false));                       

    			if (!isLeaf) {
    				result.append(",inference(rule,[],[" + step.premises.get(0));
    				for (int parent = 1; parent < step.premises.size(); parent++) 
    					result.append("," + step.premises.get(parent));                    
    				result.append("])");
    			}
    			result.append("  ).\n");
    		}
    	}
    	catch (Exception ex) {
    		ex.printStackTrace();
    	}
    	return(result.toString());
    }

    /** ***************************************************************
     *  A method used only for testing.  It should not be called
     *  during normal operation.
     
    public static void test (String[] args) {

    	try {
    		FileReader r = new FileReader(args[0]);
    		LineNumberReader lr = new LineNumberReader(r);
    		String line;
    		StringBuffer result = new StringBuffer();
    		while ((line = lr.readLine()) != null) 
    			result.append(line + "\n");            

    		BasicXMLparser res = new BasicXMLparser(result.toString());
    		result = new StringBuffer();
    		ProofProcessor pp = new ProofProcessor(res.elements);
    		for (int i = 0; i < pp.numAnswers(); i++) {
    			ArrayList proofSteps = pp.getProofSteps(i);
    			proofSteps = new ArrayList(ProofStep.normalizeProofStepNumbers(proofSteps));
    			if (i != 0) 
    				result.append("\n");               
    			result.append("%----Answer " + (i+1) + " " + pp.returnAnswer(i,"") + "\n");
    			if (!pp.returnAnswer(i).equalsIgnoreCase("no")) 
    				result.append(tptpProof(proofSteps));               
    		}
    		System.out.println(result.toString());
    	}
    	catch (IOException ioe) {
    		System.out.println("Error in ProofProcessor.main(): IOException: " + ioe.getMessage());
    	}     
    }   
     */
     /** ***************************************************************
      */
     public static void testRemoveAnswer() {

    	 String stmt = "(not (exists (?VAR1) (and (subclass ?VAR1 Object) " +
    			 "(not (answer (esk1_1 ?VAR1))))))";
    	 System.out.println(removeNestedAnswerClause(stmt));
    	 stmt = "(forall (?VAR1) (or (not (subclass ?VAR1 Object)) " +
    			 "(answer (esk1_1 ?VAR1))))";
    	 System.out.println(removeNestedAnswerClause(stmt));
     }

      /** ***************************************************************
       */
      public static void testFormatProof() {

    	  try {
    		  KBmanager.getMgr().initializeOnce();
    		  KB kb = KBmanager.getMgr().getKB("SUMO");
    		  String stmt = "(subclass ?X Entity)";
    		  String result = StringUtils.join(kb.ask(stmt, 30, 3), " ");
    		  result = HTMLformatter.formatProofResult(result,stmt,stmt,"
\n","SUMO","EnglishLanguage"); System.out.println(result); } catch (Exception ex) { System.out.println(ex.getMessage()); } } /** *************************************************************** * A main method, used only for testing. It should not be called * during normal operation. */ public static void main (String[] args) { testRemoveAnswer(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy