/** * Author: Georg Hofferek <georg.hofferek@iaik.tugraz.at> */ package at.iaik.suraq.util; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import at.iaik.suraq.proof.AnnotatedProofNode; import at.iaik.suraq.proof.AnnotatedProofNodes; import at.iaik.suraq.sexp.SExpressionConstants; import at.iaik.suraq.smtlib.TransformedZ3Proof; import at.iaik.suraq.smtlib.Z3Proof; import at.iaik.suraq.smtlib.formula.DomainEq; import at.iaik.suraq.smtlib.formula.EqualityFormula; import at.iaik.suraq.smtlib.formula.Formula; import at.iaik.suraq.smtlib.formula.FormulaTerm; import at.iaik.suraq.smtlib.formula.NotFormula; import at.iaik.suraq.smtlib.formula.OrFormula; import at.iaik.suraq.smtlib.formula.PropositionalEq; import at.iaik.suraq.smtlib.formula.PropositionalTerm; import at.iaik.suraq.smtlib.formula.Term; import at.iaik.suraq.util.graph.Graph; /** * * Helper class to build a chain of transitivity to proof a particular target * equality. * * @author Georg Hofferek <georg.hofferek@iaik.tugraz.at> * */ public class TransitivityChainBuilder { /** * The first term of the target equality. */ private final Term targetStartTerm; /** * The last term of the target equality. */ private final Term targetEndTerm; /** * Graph of equalities. */ private final Graph<Term, Z3Proof> graph = new Graph<Term, Z3Proof>(true); /** * * Constructs a new <code>TransitivityChainBuilder</code>. * * @param target * the target to prove. */ public TransitivityChainBuilder(Z3Proof target) { assert (Util.isLiteral(target.getConsequent())); Formula targetLiteral = Util.getSingleLiteral(target.getConsequent()); targetLiteral = Util.makeLiteralPositive(targetLiteral); if (!(targetLiteral instanceof EqualityFormula)) assert (false); EqualityFormula eq = (EqualityFormula) targetLiteral; assert (eq.getTerms().size() == 2); targetStartTerm = eq.getTerms().get(0); targetEndTerm = eq.getTerms().get(1); } public TransitivityChainBuilder(Term startTerm, Term endTerm) { this.targetStartTerm = startTerm; this.targetEndTerm = endTerm; } /** * Adds a new node that may be used to build the transitivity chain. If the * consequent of the node is not of type <code>EqualityFormula</code> (with * 2 terms), the node will be ignored. * * @param node */ public void addProofNode(TransformedZ3Proof node) { assert (Util.isLiteral(node.getConsequent())); Formula literal = Util.getSingleLiteral(node.getConsequent()); literal = Util.makeLiteralPositive(literal); if (!(literal instanceof EqualityFormula)) { System.out .println("INFO: Ignoring a node added to a chain builder."); return; } EqualityFormula newEq = (EqualityFormula) literal; if (newEq.getTerms().size() != 2) { System.out .println("INFO: Ignoring a node added to a chain builder."); return; } Term term1 = newEq.getTerms().get(0); Term term2 = newEq.getTerms().get(1); graph.addEdge(term1, term2, node); Z3Proof symmetry = Z3Proof.createSymmetryProof(node); graph.addEdge(term2, term1, symmetry); } /** * * @return a list of proofs that forms the desired transitivity chain, or * <code>null</code> if no path has been found in the graph. * */ public List<TransformedZ3Proof> getChain() { List<Z3Proof> chain = graph.findPath(targetStartTerm, targetEndTerm); if (chain == null) return null; assert (chain != null); List<TransformedZ3Proof> transformedChain = new ArrayList<TransformedZ3Proof>( chain.size()); for (Z3Proof proof : chain) { TransformedZ3Proof transformedProof = TransformedZ3Proof .convertToTransformedZ3Proof(proof); assert (proof.getConsequent().transformToConsequentsForm() .equals(transformedProof.getConsequent() .transformToConsequentsForm())); transformedChain.add(transformedProof); } return transformedChain; } /** * Converts the transitivity chain into a resolution chain. This is used for * modus ponens nodes with uninterpreted predicates. * * @param predicatePolarity * the polarity of the predicate in the first child of the modus * ponens node. * @return a proof with for a clause with two literals. The first is the * inverse of the first modus ponens child. The second is the * consequent of the modus ponens node. */ public TransformedZ3Proof convertToResolutionChain(boolean predicatePolarity) { assert (targetStartTerm instanceof PropositionalTerm); assert (targetEndTerm instanceof PropositionalTerm); boolean reversePolarity = false; List<Z3Proof> tmpChain = graph.findPath(targetStartTerm, targetEndTerm); if (tmpChain == null) { reversePolarity = true; PropositionalTerm reverseStartTerm = FormulaTerm .create(NotFormula.create((PropositionalTerm) targetStartTerm)); PropositionalTerm reverseEndTerm = FormulaTerm .create(NotFormula.create((PropositionalTerm) targetEndTerm)); tmpChain = graph.findPath(reverseStartTerm, reverseEndTerm); if (tmpChain == null) assert (false); } List<TransformedZ3Proof> chain = new ArrayList<TransformedZ3Proof>( tmpChain.size()); for (Z3Proof proof : tmpChain) { TransformedZ3Proof transformedProof = TransformedZ3Proof .convertToTransformedZ3Proof(proof); assert (Util.isLiteral(transformedProof.getConsequent())); if (Util.isBadLiteral(Util.getSingleLiteral(transformedProof .getConsequent()))) { AnnotatedProofNodes annotatedNodes = transformedProof .toLocalProof("<ResChainNode_" + DagOperationManager.myFormatter.format(proof .getID()) + ">.toLocalProof"); AnnotatedProofNode annotatedNode = annotatedNodes .getNodeWithConsequent( transformedProof.getConsequent(), transformedProof.getHypothesisFormulas(), new HashSet<Formula>()); assert (annotatedNode != null); assert (annotatedNode.numPremises() == 3); chain.add(annotatedNode.getPremise1()); chain.add(annotatedNode.getPremise2()); chain.add(annotatedNode.getPremise3()); } else chain.add(transformedProof); } TransformedZ3Proof intermediate = null; for (TransformedZ3Proof current : chain) { assert (Util.getSingleLiteral(current.getConsequent()) instanceof PropositionalEq); PropositionalEq propEq = (PropositionalEq) Util .getSingleLiteral(current.getConsequent()); PropositionalTerm term1 = (PropositionalTerm) propEq.getTerms() .get(0); PropositionalTerm term2 = (PropositionalTerm) propEq.getTerms() .get(1); List<Formula> disjuncts = new ArrayList<Formula>(3); disjuncts.add(predicatePolarity ^ reversePolarity ? NotFormula.create( term1) : term1); disjuncts.add(predicatePolarity ^ reversePolarity ? term2 : NotFormula.create(term2)); if (current.getProofType().equals(SExpressionConstants.SYMMETRY)) { assert (current.getSubProofs().size() == 1); assert (current.getSubProofs().get(0) instanceof TransformedZ3Proof); current = (TransformedZ3Proof) current.getSubProofs().get(0); } if (current.getProofType().equals(SExpressionConstants.ASSERTED)) { current = new TransformedZ3Proof(SExpressionConstants.ASSERTED, new ArrayList<TransformedZ3Proof>(0), (OrFormula.generate( disjuncts)).transformToConsequentsForm(), current.getAssertPartitionOfThisNode(), false); assert (current.checkZ3ProofNode()); // DEBUG } else { assert (current.getSubProofs().size() == 1 || current .getSubProofs().size() == 2); if (current.getSubProofs().size() == 1) { if (!(Util.getSingleLiteral(current.getSubProofs().get(0) .getConsequent()) instanceof DomainEq)) assert (false); disjuncts.add(NotFormula.create(current.getSubProofs().get(0) .getConsequent())); TransformedZ3Proof axiom = new TransformedZ3Proof( SExpressionConstants.ASSERTED, new ArrayList<TransformedZ3Proof>(0), (OrFormula.generate(disjuncts)) .transformToConsequentsForm(), current.getAssertPartitionOfThisNode(), true); List<TransformedZ3Proof> subProofs = new ArrayList<TransformedZ3Proof>( 2); assert (current.getSubProofs().get(0) instanceof TransformedZ3Proof); subProofs.add((TransformedZ3Proof) current.getSubProofs() .get(0)); subProofs.add(axiom); current = new TransformedZ3Proof( SExpressionConstants.UNIT_RESOLUTION, subProofs, (OrFormula.generate(disjuncts.subList(0, 2))) .transformToConsequentsForm()); assert (current.checkZ3ProofNode()); // DEBUG } else { assert (current.getSubProofs().size() == 2); assert (Util.getSingleLiteral(current.getSubProofs().get(0) .getConsequent()) instanceof DomainEq); assert (Util.getSingleLiteral(current.getSubProofs().get(1) .getConsequent()) instanceof DomainEq); disjuncts.add(NotFormula.create(current.getSubProofs().get(1) .getConsequent())); disjuncts.add(NotFormula.create(current.getSubProofs().get(0) .getConsequent())); TransformedZ3Proof axiom = new TransformedZ3Proof( SExpressionConstants.ASSERTED, new ArrayList<TransformedZ3Proof>(0), (OrFormula.generate(disjuncts)) .transformToConsequentsForm(), current.getAssertPartitionOfThisNode(), true); List<TransformedZ3Proof> currentSubProofs = new ArrayList<TransformedZ3Proof>(); for (Z3Proof proof : current.getSubProofs()) { assert (proof instanceof TransformedZ3Proof); currentSubProofs.add((TransformedZ3Proof) proof); } List<TransformedZ3Proof> subProofs = new ArrayList<TransformedZ3Proof>( 2); subProofs.add(currentSubProofs.get(0)); subProofs.add(axiom); current = new TransformedZ3Proof( SExpressionConstants.UNIT_RESOLUTION, subProofs, (OrFormula.generate(disjuncts.subList(0, 3))) .transformToConsequentsForm()); assert (current.checkZ3ProofNode()); // DEBUG subProofs = new ArrayList<TransformedZ3Proof>(2); subProofs.add(currentSubProofs.get(1)); subProofs.add(current); current = new TransformedZ3Proof( SExpressionConstants.UNIT_RESOLUTION, subProofs, (OrFormula.generate(disjuncts.subList(0, 2))) .transformToConsequentsForm()); assert (current.checkZ3ProofNode()); // DEBUG } } if (intermediate == null) intermediate = current; else { List<TransformedZ3Proof> subProofs = new ArrayList<TransformedZ3Proof>( 2); subProofs.add(intermediate); subProofs.add(current); List<Formula> intermediateDisjuncts = new ArrayList<Formula>(2); intermediateDisjuncts.add(((OrFormula) intermediate .getConsequent()).getDisjuncts().get(0)); intermediateDisjuncts.add(((OrFormula) current.getConsequent()) .getDisjuncts().get(1)); intermediate = new TransformedZ3Proof( SExpressionConstants.UNIT_RESOLUTION, subProofs, (OrFormula.generate(intermediateDisjuncts)) .transformToConsequentsForm()); assert (intermediate.checkZ3ProofNode()); // DEBUG } } return intermediate; } }