package net.certware.argument.sfp.util; import net.certware.argument.sfp.semiFormalProof.Conjunction; import net.certware.argument.sfp.semiFormalProof.Entailment; import net.certware.argument.sfp.semiFormalProof.Justification; import net.certware.argument.sfp.semiFormalProof.Justifications; import net.certware.argument.sfp.semiFormalProof.Proof; import net.certware.argument.sfp.semiFormalProof.Statement; import net.certware.argument.sfp.semiFormalProof.ValidationKind; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; /** * Proof utilities. * Static methods normally buried in generated classes. * We put them here instead owing to Xtext overwrites of the generated model classes. * @author mrb * @since 1.0.3 */ public class ProofUtil { /** * Whether the given ID is the tail of the entailment statement. * @param e entailment to check * @param id identifier to match entailment tail, ignoring case * @return true if string matches ignoring case, false otherwise; false if entailment null */ public static boolean isTail(Entailment e, String id) { if ( e == null ) { return false; } return e.getTail().equalsIgnoreCase(id); } /** * Whether the given ID is in the of the entailment statement. * @param e entailment to check * @param id identifier to match entailment head element, ignoring case * @return true if string matches ignoring case, false otherwise; false if entailment null */ public static boolean isInHead(Entailment e, String id) { if ( e != null ) { EList<String> heads = getHeadList(e); for ( String s : heads ) { if ( s.equalsIgnoreCase(id)) return true; } } return false; } /** * Generate and return a list of the identifiers appearing in the entailment head. * @param e entailment to iterate * @return list of identifiers appearing on the left-hand side of conjunctions */ public static EList<String> getHeadList(Entailment e) { EList<String> headList = new BasicEList<String>(); if ( e != null ) { Conjunction c = e.getHead(); while ( c != null ) { headList.add( c.getLhs() ); c = c.getRhs(); } } return headList; } /** * Returns true if statement justification includes a hypothesis. * @param s statement * @return true if any justification element includes hypothesis */ public static boolean statementIsHypothesis(Statement s) { if ( s != null && s.getJustification() != null ) { EList<Justification> justifications = s.getJustification().getJustifications(); if ( justifications != null ) { for ( Justification j : justifications ) { if ( j.isHypothesis() ) { return true; } } } } return false; } /** * Returns a comment associated with a statement, if any. * Includes hypothesis and epsilon enumeration types. * @param s statement * @return string of quoted assertion field, hypothesis, epsilon, or empty string (not null) */ public static String getStatementComment(Statement s) { if ( s != null ) { Justifications justifications = s.getJustification(); for ( Justification j : justifications.getJustifications() ) { if ( j.isEpsilon() ) return "epsilon"; if ( j.isHypothesis() ) return "hypothesis"; if ( j.getAssertion() != null && j.getAssertion().getText().isEmpty() == false ) return j.getAssertion().getText(); } } return ""; } /** * Returns true if statement justification includes epsilon. * @param s statement * @return true if any justification element includes epsilon */ public static boolean statementIsEpsilon(Statement s) { if ( s != null && s.getJustification() != null ) { EList<Justification> justifications = s.getJustification().getJustifications(); if ( justifications != null ) { for ( Justification j : justifications ) { if ( j.isHypothesis() ) { return true; } } } } return false; } /** * Whether the proof's statements are all valid. * @param p proof * @return true if all statements valid, false if null or any statement invalid or unknown */ public static boolean proofValidated(Proof p) { if ( p == null || p.getProofSteps() == null ) return false; for ( Statement s : p.getProofSteps().getStatements() ) { if ( s.getValidation() == null || s.getValidation().getState() == ValidationKind.INVALID || s.getValidation().getState() == ValidationKind.UNKNOWN ) return false; } return true; } /** * Compute and return the validation state for a proof. * If any statement has no validation, return unknown. * If any statement is unknown, return unknown. * If any statement is invalid, return invalid. * Otherwise, return valid. * @param p proof to scan * @return validation kind enumeration */ public static ValidationKind getProofValidationKind(Proof p) { if ( p == null || p.getProofSteps() == null ) return ValidationKind.UNKNOWN; // any statement not validated, return unknown for ( Statement s : p.getProofSteps().getStatements() ) { if ( s.getValidation() == null ) { return ValidationKind.UNKNOWN; } } // any statement invalid, return invalid for ( Statement s : p.getProofSteps().getStatements() ) { if ( s.getValidation().getState() == ValidationKind.INVALID ) { return ValidationKind.INVALID; } } // any statement unknown, return unknown for ( Statement s : p.getProofSteps().getStatements() ) { if ( s.getValidation().getState() == ValidationKind.UNKNOWN ) { return ValidationKind.UNKNOWN; } } // otherwise, all statements are valid return ValidationKind.VALID; } /** * Find a statement in a proof given its identifier. * @param p proof containing statement list * @param id statement identifier to find * @return first statement matching ignore case or null */ public static Statement findStatement( Proof p, String id ) { if ( p != null && p.getProofSteps() != null && id.isEmpty() == false ) { for ( Statement s : p.getProofSteps().getStatements() ) { if ( s.getId().equalsIgnoreCase(id)) return s; } } return null; } /** * Get a list of statements given as premises for a given statement. * @param p proof to search for statement references * @param s statement containing justifications * @return statement list, numeral references only (for now) */ public static EList<Statement> getStatementPremises(Proof p, Statement s) { EList<Statement> premises = new BasicEList<Statement>(); if ( statementIsHypothesis(s) ) return premises; if ( statementIsEpsilon(s) ) return premises; if ( s != null && s.getJustification() != null && s.getJustification().getJustifications().isEmpty() == false ) { // returns only the list of numeral statement references as inference premises, not entailment for deduction for ( Justification j : s.getJustification().getJustifications() ) { if ( j.getNumeral() != null ) { Statement rs = findStatement( p, j.getNumeral() ); if ( rs != null ) premises.add(rs); } } } return premises; } /** * Get the entailments element for a deduction statement. * @param s statement to search for entailment justifications. * @return entailment list */ public static EList<Entailment> getStatementEntailments(Statement s) { EList<Entailment> entailments = new BasicEList<Entailment>(); if ( s != null && s.getJustification() != null ) { for ( Justification j : s.getJustification().getJustifications() ) { if ( j.getEntailment() != null ) { entailments.add( j.getEntailment() ); } } } return entailments; } /** * Get the entailment elements for a theorem statement. * @param s statement to search for entailment justifications. * @return entailment list */ public static EList<Entailment> getTheoremEntailments(Proof p) { EList<Entailment> entailments = new BasicEList<Entailment>(); if ( p != null && p.getJustifications() != null ) { for ( Justification j : p.getJustifications().getJustifications() ) { if ( j.getEntailment() != null ) { entailments.add( j.getEntailment() ); } } } return entailments; } /** * Get a list of statements given as justifications for the theorem. * Includes each justification given as an inference (numeral). * @param p proof to search for statement references * @return statement list from proof, not showing any missing statements from invalid references */ public static EList<Statement> getTheoremPremises(Proof p) { EList<Statement> justifications = new BasicEList<Statement>(); if ( p != null && p.getJustifications() != null ) { for ( Justification j : p.getJustifications().getJustifications() ) { // inference statements if ( j.getNumeral() != null ) { Statement rs = findStatement( p, j.getNumeral() ); if ( rs != null ) justifications.add(rs); } /* else // entailment statements if ( j.getEntailment() != null ) { EList<String> heads = getHeadList(j.getEntailment()); // add head elements for ( String head : heads ) { Statement hs = findStatement(p, head); if ( hs != null ) justifications.add(hs); } // add tail Statement ts = findStatement( p, j.getEntailment().getTail() ); if ( ts != null ) justifications.add(ts); } */ } // for justifications } return justifications; } /** * Checks whether a statement's justifications are valid. * @param p proof * @param s statement * @return false if any justification statement is invalid */ public static boolean justificationsValid(Proof p, Statement s) { EList<Statement> dependencies = getStatementPremises(p,s); for ( Statement j : dependencies ) { if ( j.getValidation() != null && j.getValidation().getState() == ValidationKind.INVALID ) return false; } return true; } }