/**
* Author: Ashutosh Gupta <agupta@ist.ac.at>
*/
package at.iaik.suraq.resProof;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import at.iaik.suraq.exceptions.ParseError;
import at.iaik.suraq.main.SuraqOptions;
import at.iaik.suraq.parser.LogicParser;
import at.iaik.suraq.parser.VeriTParser;
import at.iaik.suraq.proof.VeriTToken;
import at.iaik.suraq.proof.VeritProofNode;
import at.iaik.suraq.sexp.Token;
import at.iaik.suraq.smtlib.formula.Formula;
import at.iaik.suraq.smtlib.formula.OrFormula;
import at.iaik.suraq.smtlib.formula.PropositionalConstant;
import at.iaik.suraq.smtlib.formula.PropositionalVariable;
import at.iaik.suraq.smtsolver.SMTSolver;
import at.iaik.suraq.smtsolver.VeriTSolver;
import at.iaik.suraq.util.ImmutableSet;
import at.iaik.suraq.util.Timer;
import at.iaik.suraq.util.Util;
public class ResProof {
// public static final int MAX_PROOF_SIZE = 100000;
// public static final int MAX_LIT_NUM = 10000;
/* Essential fields */// GHnote: Whatever that is supposed to mean.
/**
* The root node
*/
private final ResNode root;
/**
* the next fresh id.
*/
private int freshId = 1;
// public int[] varPart = new int[ResProof.MAX_LIT_NUM];
/**
* Map from literal IDs to partitions.
*/
private final Map<Integer, Integer> varPart = new HashMap<Integer, Integer>();
// public boolean[] visited = new boolean[ResProof.MAX_PROOF_SIZE];
/**
* Helper set to check which nodes were already visited during recursive
* operations.
*/
private final Set<Integer> visited = new HashSet<Integer>();
/* Proof vital */// GHnote: Whatever that is supposed to mean.
/**
* Stores whether the vital information on this proof is fresh.
*/
private boolean vitalInfoFresh = false;
// public ResNode[] nodeRef = new ResNode[ResProof.MAX_PROOF_SIZE];
/**
* Map from IDs to all nodes.
*/
private final Map<Integer, ResNode> nodeRef = new HashMap<Integer, ResNode>();
/**
* Probably the number of nodes. Not sure yet.
*/
private int numberOfNodes;
/**
* Counting nodes being dumped or loaded
*/
private int dumpLoadCounter = 0;
/**
* Probably the set of all leaves. Not sure yet.
*/
private final HashSet<ResNode> leaves = new HashSet<ResNode>();
/**
* Maps clause identifiers from veriT to already created ResNodes. Will be
* destroyed after parsing is complete!
*/
private Map<String, ResNode> namesOfResNodes = new HashMap<String, ResNode>();
/**
*
* Constructs a new <code>ResProof</code>.
*/
public ResProof() {
root = new ResNode(0);
}
/**
* Constructs a new <code>ResProof</code>.
*
* @param proof
* @param replacements
* @param literalIds
* map from (canonic) strings to literal IDs
* @param literalMap
* map from literal IDs (Integers) to <code>Formula</code>
* objects
*
* @param leafPartitions
* "output parameter" for partitions of leaf nodes
* @throws IOException
*/
public static ResProof create(Set<VeritProofNode> leaves,
Map<VeritProofNode, VeritProofNode> replacements,
Map<Integer, Formula> literalMap, LogicParser logicParser)
throws IOException {
Map<String, Integer> literalIds = new HashMap<String, Integer>();
Map<ImmutableSet<Integer>, Integer> leafPartitions = new HashMap<ImmutableSet<Integer>, Integer>();
Map<Integer, Integer> partitions = new HashMap<Integer, Integer>();
ResProof resProof = new ResProof();
String fileNamePrefix = SuraqOptions.getInstance()
.getInputWithoutExtension();
BufferedReader stream = null;
int maxLit = 0;
if (SuraqOptions.getInstance().getUseThisPropProofFile() == null) {
assert (leaves != null);
assert (replacements != null);
File tmpDimacsFile = File.createTempFile("tmp", ".dimacs",
new File("./"));
if (!SuraqOptions.getInstance().getKeepTemFiles())
tmpDimacsFile.deleteOnExit();
BufferedWriter writer = new BufferedWriter(new FileWriter(
tmpDimacsFile));
Set<VeritProofNode> allLeaves = new HashSet<VeritProofNode>(leaves);
for (VeritProofNode node : replacements.keySet()) {
allLeaves.remove(node);
VeritProofNode replacement = replacements.get(node);
assert (replacement != null);
Set<VeritProofNode> replacementLeaves = replacement.getLeaves();
allLeaves.addAll(replacementLeaves);
}
for (VeritProofNode leaf : allLeaves) {
Set<Integer> clause = new HashSet<Integer>(leaf
.getLiteralConclusions().size());
for (Formula literal : leaf.getLiteralConclusions()) {
int literalId = Util.getLiteralId(literal, literalIds,
partitions, literalMap);
if (Util.isNegativeLiteral(literal))
literalId *= -1;
writer.write(Integer.toString(literalId));
writer.write(' ');
clause.add(literalId);
}
writer.write("0\n");
int leafPartition;
if (!leaves.contains(leaf) || leaf.isAxiom()) {
// This is a leaf in the subproof of a replacement node
Set<Integer> tmpPartitions = leaf
.getPartitionsFromSymbols();
tmpPartitions.remove(-1);
assert (tmpPartitions.size() <= 1);
leafPartition = tmpPartitions.isEmpty() ? 0 : tmpPartitions
.iterator().next();
} else {
leafPartition = leaf.getLeafPartition();
}
leafPartitions.put(ImmutableSet.create(clause), leafPartition);
}
writer.close();
Util.dumpMetaData(fileNamePrefix, literalIds, literalMap,
partitions, leafPartitions);
VeriTSolver solver = new VeriTSolver();
solver.solveDimacs(tmpDimacsFile);
assert (solver.getState() == SMTSolver.UNSAT);
stream = solver.getStream();
maxLit = literalIds.size();
} else {
Util.printToSystemOutWithWallClockTimePrefix("Loading metadata of propositional proof from files "
+ fileNamePrefix + ".* ...");
assert (logicParser != null);
stream = new BufferedReader(new FileReader(SuraqOptions
.getInstance().getUseThisPropProofFile()));
try {
literalMap.clear();
literalMap.putAll(Util.loadLiteralMap(fileNamePrefix
+ ".literalMap", logicParser));
} catch (ParseError exc) {
Util.printToSystemOutWithWallClockTimePrefix("Parse Error: "
+ exc.getMessage() == null ? exc.getMessage() : "");
stream.close();
throw new RuntimeException(exc);
}
partitions = Util.loadPartitions(fileNamePrefix + ".partitions");
leafPartitions = Util.loadLeafPartitions(fileNamePrefix
+ ".leafPartitions");
for (Integer lit : literalMap.keySet()) {
if (lit > maxLit)
maxLit = lit;
}
Util.printToSystemOutWithWallClockTimePrefix("Done loading metadata.");
}
assert (maxLit != 0);
assert (stream != null);
Timer timer = new Timer();
timer.start();
Util.printToSystemOutWithWallClockTimePrefix("Parsing propositional proof...");
VeriTParser parser = new VeriTParser(stream, maxLit, resProof,
partitions, leafPartitions);
parser.parse();
stream.close();
timer.stop();
Util.printToSystemOutWithWallClockTimePrefix("Done. (Took "
+ timer.toString() + ".)");
resProof.killNamesOfResNodes();
return resProof;
}
private void killNamesOfResNodes() {
this.namesOfResNodes = null;
}
/**
* part for axioms should be 0
*
* @param clause
* @param part
* @return
*/
public ResNode addLeaf(Clause cl, int part) {
assert (!vitalInfoFresh);
ResNode n = new ResNode(freshId++, cl, null, null, 0, part);
nodeRef.put(n.id, n);
return n;
}
/**
* Adds a leaf with the given id.
*
* @param cl
* @param part
* @param id
* @return
*/
public ResNode addLeaf(Clause cl, int part, int id) {
freshId = freshId > id ? freshId : id + 1;
ResNode n = new ResNode(id, cl, null, null, 0, part);
nodeRef.put(n.id, n);
return n;
}
/**
* if clause==null then the clause is computed by applying resolution on
* left and right. If pivot == 0 then pivot variable is also discovered
* automatically. Node: part for internal node is set to be -1.
*/
public ResNode addIntNode(Clause cl, ResNode left, ResNode right, int pivot) {
assert (!vitalInfoFresh);
ResNode n = new ResNode(freshId++, cl, left, right, pivot, -1);
nodeRef.put(n.id, n);
return n;
}
/**
* Adds an internal node with the given id.
*
* @param cl
* @param left
* @param right
* @param pivot
* @return
*/
public ResNode addIntNode(Clause cl, ResNode left, ResNode right,
int pivot, int id) {
assert (!vitalInfoFresh);
freshId = freshId > id ? freshId : id + 1;
ResNode n = new ResNode(id, cl, left, right, pivot, -1);
nodeRef.put(n.id, n);
return n;
}
public void setRoot(ResNode n) {
assert (!vitalInfoFresh);
assert (n.getClause().isEmpty());
// GHnote: Not sure what this is supposed to do
root.setLeft(n);
n.addParent(root);
}
/**
* @return the root of the proof.
*/
public ResNode getRoot() {
// GHnote: Not sure why this is done this way.
// see also: setRoot(ResNode n)
return root.getLeft();
}
/**
* Destroys the vital information
*/
private void disruptVitals() {
vitalInfoFresh = false;
nodeRef.clear();
numberOfNodes = 0;
leaves.clear();
}
/**
* Internal recursion for computation of vital information.
*
* @param n
*/
private void recComputeVitals(ResNode n) {
if (visited.contains(n.id))
return;
numberOfNodes++;
nodeRef.put(n.id, n);
if (n.isLeaf()) {
leaves.add(n);
} else {
recComputeVitals(n.getLeft());
recComputeVitals(n.getRight());
}
visited.add(n.id);
}
/**
* Computes the vital information.
*/
protected void computeVitals() {
disruptVitals();
visited.clear();
ResNode root = getRoot();
if (root != null)
recComputeVitals(root);
vitalInfoFresh = true;
}
/**
* Internal recursion for dumping the proof.
*
* @param wr
* @param n
* @throws IOException
*/
private void recDumpProof(BufferedWriter wr, ResNode n) throws IOException {
if (visited.contains(n.id))
return;
dumpLoadCounter++;
if (n.isLeaf()) {
wr.write(String.valueOf(n.id));
wr.write(" ");
wr.write(String.valueOf(n.getPivot()));
wr.write(" ");
wr.write(String.valueOf(n.getPart()));
wr.write(" ");
Iterator<Literal> iter = n.getClause().iterator();
while (iter.hasNext()) {
Literal l = iter.next();
wr.write(String.valueOf(l.getLit()));
wr.write(" ");
}
} else {
recDumpProof(wr, n.getLeft());
recDumpProof(wr, n.getRight());
wr.write(String.valueOf(n.id));
wr.write(" ");
wr.write(String.valueOf(n.getPivot()));
wr.write(" ");
wr.write(String.valueOf(n.getLeft().id));
wr.write(" ");
wr.write(String.valueOf(n.getRight().id));
wr.write(" ");
}
wr.write("\n");
visited.add(n.id);
}
/**
* Dumps the proof to the file with the given name.
*
* @param file
*/
public void dumpProof(String file) {
// String file = "tmp/test.res";
visited.clear();
dumpLoadCounter = 0;
try {
// create FileOutputStream object
File fl = new File(file);
FileWriter fs = new FileWriter(fl);
BufferedWriter wr = new BufferedWriter(fs);
for (int v : varPart.keySet()) {
wr.write(String.valueOf(v));
wr.write(" ");
wr.write(String.valueOf(varPart.get(v)));
wr.write("\n");
}
wr.write(String.valueOf(0));
wr.write("\n");
recDumpProof(wr, getRoot());
wr.write(String.valueOf(0));
wr.write("\n");
// int v = 123;
// wr.write(String.valueOf(v));
wr.close();
} catch (IOException e) {
System.out.println("IOException : " + e);
}
Util.printToSystemOutWithWallClockTimePrefix("Dump counter: "
+ Util.largeNumberFormatter.format(dumpLoadCounter));
}
/**
* Loads the proof from the file with the given name.
*
* @param file
* @return the proof parsed from <code>file</code>
*/
public static ResProof loadProof(String file) {
ResProof resProof = new ResProof();
resProof.dumpLoadCounter = 0;
try {
// create FileOutputStream object
File fl = new File(file);
FileReader fs = new FileReader(fl);
BufferedReader rd = new BufferedReader(fs);
String rdLine;
while ((rdLine = rd.readLine()) != null) {
String[] is = rdLine.split(" ");
int v = Integer.parseInt(is[0]);
if (v == 0)
break;
// "var and only parts should be there"
assert (is.length == 2);
resProof.varPart.put(v, Integer.parseInt(is[1]));
}
ResNode n = null;
while ((rdLine = rd.readLine()) != null) {
String[] is = rdLine.split(" ");
int id = Integer.parseInt(is[0]);
if (id == 0)
break;
int piv = Integer.parseInt(is[1]);
if (piv == 0) {
int part = Integer.parseInt(is[2]);
List<Literal> clLits = new ArrayList<Literal>();
for (int i = 3; i < is.length; i++) {
Literal l = Literal.create(Integer.parseInt(is[i]));
clLits.add(l);
}
Clause cl = new Clause(clLits);
n = resProof.addLeaf(cl, part, id);
resProof.dumpLoadCounter++;
} else {
int lid = Integer.parseInt(is[2]);
int rid = Integer.parseInt(is[3]);
n = resProof.addIntNode(null, resProof.nodeRef.get(lid),
resProof.nodeRef.get(rid), piv, id);
resProof.dumpLoadCounter++;
}
}
resProof.setRoot(n);
rd.close();
} catch (IOException e) {
System.out.println("IOException : " + e);
}
Util.printToSystemOutWithWallClockTimePrefix("Load counter: "
+ Util.largeNumberFormatter.format(resProof.dumpLoadCounter));
return resProof;
}
/**
* Internal recursion for checking the proof.
*
* @param node
* @param doPrint
* print info while checking (not recommended for large proofs)
*/
private boolean recCheckProof(ResNode node, boolean doPrint) {
if (visited.contains(node.id))
return true;
visited.add(node.id);
if (doPrint)
System.out.println(node);
if (node.isLeaf()) {
if (node.getPivot() != 0)
// "Pivot at leaf!",
return false;
if (node.getLeft() != null || node.getRight() != null)
// "Parent of a leaf!",
return false;
Iterator<Literal> iter = node.getClause().iterator();
while (iter.hasNext()) {
Literal lit = iter.next();
if (!varPart.containsKey(lit.id()))
// "a local with uninitialized partition",
return false;
if (varPart.get(lit.id()) != 0)
if (varPart.get(lit.id()) != node.getPart())
// "a local is in wrong partition!",
return false;
}
} else {
if (node.getLeft() == null || node.getRight() == null)
// "A parent missing!",
return false;
if (!node.getLeft().getClause().contains(node.getPivot(), true)
|| !node.getRight().getClause()
.contains(node.getPivot(), false))
// "pivot literals are not present in parents!",
return false;
Clause clause = new Clause(node.getLeft().getClause(), node
.getRight().getClause(), node.getPivot());
if (!node.getClause().equals(clause))
// "node is not the result of resolution of parents",
return false;
boolean checkLeft = recCheckProof(node.getLeft(), doPrint);
if (!checkLeft)
return false;
boolean checkRight = recCheckProof(node.getRight(), doPrint);
if (!checkRight)
return false;
}
return true;
}
/**
* Checks the proof.
*
* @param doPrint
* @return
*/
public boolean checkProof(boolean doPrint) {
if (doPrint) {
System.out.println("============== Checking Proof ============");
if (vitalInfoFresh) {
System.out.println("Number of nodes = " + numberOfNodes);
System.out.println("Number of leaves = " + leaves.size());
} else {
System.out.println("Number of active nodes unknown.");
}
System.out.print("var partitions:");
for (Integer v : varPart.keySet())
System.out.print(" " + v + ":p" + varPart.get(v));
System.out.println("\n==========================================");
}
visited.clear();
boolean result = true;
ResNode root = getRoot();
if (root != null) {
// Assert.assertTrue("Root is not empty clause", root.cl.isEmpty());
if (!root.getClause().isEmpty())
return false;
result = recCheckProof(root, doPrint);
System.out.println("Checked "
+ Util.largeNumberFormatter.format(visited.size())
+ " nodes.");
}
if (doPrint)
System.out.println("==========================================");
return result;
}
/**
* Internal recursion of rmDoubleLits.
*
* @param node
*/
private void recRmDoubleLits(ResNode node) {
if (visited.contains(node.id))
return;
if (node.isLeaf()) {
visited.add(node.id);
return;
}
recRmDoubleLits(node.getLeft());
recRmDoubleLits(node.getRight());
visited.add(node.id);
// Node may get removed in refresh
if (!node.refresh())
return;
if (node.getClause().contains(node.getPivot(), true)) {
node.moveParents(true);
} else if (node.getClause().contains(node.getPivot(), false)) {
node.moveParents(false);
}
}
/**
* Probably removes double literals from clauses. (And thus obsolete nodes
* from the proof.)
*/
public void rmDoubleLits() {
disruptVitals();
visited.clear();
recRmDoubleLits(getRoot());
}
private void reOrderStep(ResNode node) {
boolean move = false;
do {
// If a node is derived form both parents
// that are "local" or "global axiom"
// then convert the node into a local node by
// setting n.part
//
// n.part == 0 -> axiom or only derived from axioms
// n.part == -1 -> derived from clauses of different parts
// n.part > 0 -> derived from a single part or global axioms
int leftPart = node.getLeft().getPart();
int rightPart = node.getRight().getPart();
if (leftPart != -1
&& rightPart != -1
&& (leftPart == rightPart || leftPart == 0 || rightPart == 0)) {
int nodePart = 0;
if (leftPart == 0)
nodePart = rightPart;
else
nodePart = leftPart;
node.setPart(nodePart);
return;
}
// if pivot is global then return
assert (varPart.containsKey(node.getPivot()));
if (varPart.get(node.getPivot()) == 0)
return;
// Check and fix if child pivot is in n
move = false;
boolean leftChild = false;
boolean leftGrandChild = false;
// Note: the following condition only checks the partition.
// If the child is derived from a single partition then
// we will not move in the direction and don't worry about it.
if (node.getLeft().getPart() == -1) {
if (node.getClause().contains(node.getLeft().getPivot(), true)) {
move = true;
leftChild = true;
leftGrandChild = true;
} else if (node.getClause().contains(node.getLeft().getPivot(),
false)) {
move = true;
leftChild = true;
leftGrandChild = false;
}
}
if (!move && node.getRight().getPart() == -1) {
if (node.getClause().contains(node.getRight().getPivot(), true)) {
move = true;
leftChild = false;
leftGrandChild = true;
} else if (node.getClause().contains(
node.getRight().getPivot(), false)) {
move = true;
leftChild = false;
leftGrandChild = false;
}
}
if (move) {
node.moveChild(leftChild, leftGrandChild);
if (!node.refresh())
return;
}
} while (move);
// move up the local resolution
Literal posPivot = Literal.create(node.getPivot(), true);
Literal negPivot = Literal.create(node.getPivot(), false);
// Check Left
int goLeft = node.getLeft().checkMovable(posPivot);
// Check Right
int goRight = node.getRight().checkMovable(negPivot);
// System.out.println("Moving a node!"+n);
assert (goLeft != -1 || goRight != -1);// n +
// ":Both unmovable parents is not possible!",
// L = Res(LL, LR), R = Res(RL, RR), N = Res(L,R)
ResNode L = node.getLeft();
ResNode R = node.getRight();
ResNode n1 = null;
ResNode n2 = null;
ResNode LL = null;
ResNode LR = null;
ResNode RL = null;
ResNode RR = null;
int piv = node.getPivot();
int Lpiv = 0;
int Rpiv = 0;
if (L.getPart() == -1) {
LL = L.getLeft();
LR = L.getRight();
Lpiv = L.getPivot();
}
if (R.getPart() == -1) {
RL = R.getLeft();
RR = R.getRight();
Rpiv = R.getPivot();
}
if (goLeft == 2) { // -> N1 = Res(LL,R) N = Res(N1,LR)
assert (LL != null);
assert (R != null);
n1 = addIntNode(null, LL, R, piv);
node.setLeft(n1);
node.setRight(LR);
node.setPivot(Lpiv);
} else if (goLeft == 3) { // -> N1 = Res(LR,R) N = Res(LL,N1)
assert (LR != null);
assert (R != null);
n1 = addIntNode(null, LR, R, piv);
node.setLeft(LL);
node.setRight(n1);
node.setPivot(Lpiv);
} else if (goRight == 2) { // -> N1 = Res(L,RL) N = Res(N1,RR)
assert (L != null);
assert (RL != null);
n1 = addIntNode(null, L, RL, piv);
node.setLeft(n1);
node.setRight(RR);
node.setPivot(Rpiv);
} else if (goRight == 3) { // -> N1 = Res(L,RR) N = Res(RL,N1)
assert (L != null);
assert (RR != null);
n1 = addIntNode(null, L, RR, piv);
node.setLeft(RL);
node.setRight(n1);
node.setPivot(Rpiv);
} else if (goLeft == 1) {// -> N1=Res(LL,R) N2=Res(LR,R) N = Res(N1,N2)
assert (LL != null);
assert (R != null);
assert (LR != null);
n1 = addIntNode(null, LL, R, piv);
n2 = addIntNode(null, LR, R, piv);
node.setLeft(n1);
node.setRight(n2);
node.setPivot(Lpiv);
} else if (goRight == 1) {// -> N1=Res(L,RL) N2=Res(L,RR) N = Res(N1,N2)
assert (L != null);
assert (RL != null);
assert (RR != null);
n1 = addIntNode(null, L, RL, piv);
n2 = addIntNode(null, L, RR, piv);
node.setLeft(n1);
node.setRight(n2);
node.setPivot(Rpiv);
}
node.getLeft().addParent(node);
node.getRight().addParent(node);
L.rmParentWithCleanUp(node);
R.rmParentWithCleanUp(node);
reOrderStep(n1);
if (n2 != null)
reOrderStep(n2);
if (!node.refresh())
return;
}
/**
* Internal recursion of deLocalize.
*
* @param node
*/
private void recDeLocalizeProof(ResNode node) {
if (visited.contains(node.id))
return;
if (node.isLeaf() || node.getPart() != -1) {
visited.add(node.id);
if (visited.size() % 10000 == 0) {
Util.printToSystemOutWithWallClockTimePrefix("Visited "
+ Util.largeNumberFormatter.format(visited.size())
+ " nodes.");
}
return;
}
recDeLocalizeProof(node.getLeft());
recDeLocalizeProof(node.getRight());
visited.add(node.id);
if (visited.size() % 10000 == 0) {
Util.printToSystemOutWithWallClockTimePrefix("Visited "
+ Util.largeNumberFormatter.format(visited.size())
+ " nodes.");
}
// Node may get removed in refresh
if (!node.refresh())
return;
reOrderStep(node);
}
/**
* deLocalize the proof.
*/
public void deLocalizeProof() {
disruptVitals();
visited.clear();
recDeLocalizeProof(getRoot());
}
/**
* Does rmDoubleLits followed by deLocalizeProof. Optionally verifies,
* prints and dumps the proof.
*
* @param verify
* @param print
* @param dump
*
* @return <code>iff</code> verification was enabled and failed.
*/
public boolean makeLocalFirst(boolean verify, boolean print, boolean dump) {
HashSet<ResNode> oldLeaves = null;
if (verify) {
Util.printToSystemOutWithWallClockTimePrefix(" Computing vitals ...");
computeVitals();
Util.printToSystemOutWithWallClockTimePrefix(" Done.");
Util.printToSystemOutWithWallClockTimePrefix(" Checking ResProof ...");
if (!checkProof(print))
return false;
Util.printToSystemOutWithWallClockTimePrefix(" Done.");
oldLeaves = new HashSet<ResNode>(leaves);
}
if (dump)
dumpProof("tmp/test.res");
Util.printToSystemOutWithWallClockTimePrefix(" rmDoubleLits ...");
rmDoubleLits();
Util.printToSystemOutWithWallClockTimePrefix(" Done.");
if (verify) {
Util.printToSystemOutWithWallClockTimePrefix(" Checking ResProof...");
if (!checkProof(print))
return false;
Util.printToSystemOutWithWallClockTimePrefix(" Done.");
}
Util.printToSystemOutWithWallClockTimePrefix(" deLocalize ...");
deLocalizeProof();
Util.printToSystemOutWithWallClockTimePrefix(" Done.");
if (verify) {
Util.printToSystemOutWithWallClockTimePrefix(" Computing vitals ...");
computeVitals();
Util.printToSystemOutWithWallClockTimePrefix(" Done.");
Util.printToSystemOutWithWallClockTimePrefix(" Checking ResProof.");
if (!checkProof(print))
return false;
Util.printToSystemOutWithWallClockTimePrefix(" Done.");
if (!oldLeaves.containsAll(leaves))
return false;
}
return true;
}
/**
* Stores the given partition for the given variable. Fails if the
* variable's partition has been set already.
*
* @param var
* @param part
*/
public void putVarPart(int var, int part) {
assert (!varPart.containsKey(var));
varPart.put(var, part);
}
/**
*
* @return size of the proof.
*/
public int size() {
if (vitalInfoFresh)
return numberOfNodes;
computeVitals();
return numberOfNodes;
}
/**
*
* @return the size of the proof when unwinding the DAG.
*/
public long treeSize() {
Map<ResNode, Long> nodeSizes = new HashMap<ResNode, Long>();
return this.getRoot().treeSize(nodeSizes);
}
/**
* @param name
* @param type
* @param conclusions
* @param parsed_clauses
* @param partitionsMap
* a map from literal IDs to partitions (0 being global)
*/
public void add(String name, Token type, List<Formula> conclusions,
String[] parsed_clauses, Map<Integer, Integer> partitionsMap,
Map<ImmutableSet<Integer>, Integer> leafPartitions) {
if (type.equals(VeriTToken.INPUT)) {
// We ignore INPUT-nodes with OR-formulas as conclusions
if (conclusions.size() == 1) {
if (conclusions.get(0) instanceof OrFormula)
return;
}
}
if (type.equals(VeriTToken.OR) || type.equals(VeriTToken.INPUT)) {
// This is a leaf
List<Literal> resClauseLits = new ArrayList<Literal>();
Set<Integer> resClausePartitions = new HashSet<Integer>();
for (Formula literal : conclusions) {
// assign literal IDs
Formula posLiteral = Util.makeLiteralPositive(literal);
assert (Util.isLiteral(posLiteral));
assert (Util.isAtom(posLiteral));
if (posLiteral.equals(PropositionalConstant.create(false))) {
resClausePartitions.add(0); // resProof package uses "0" for
// globals
continue;
}
assert (posLiteral instanceof PropositionalVariable);
Integer resLiteralID = Integer
.valueOf(((PropositionalVariable) posLiteral)
.getVarName().substring(2));
int partition = partitionsMap.get(resLiteralID);
this.varPart.put(resLiteralID, partition);
resClauseLits.add(Literal.create(resLiteralID,
Util.getSignValue(literal)));
resClausePartitions.add(partition < 0 ? 0 : partition);
}
// build leaf ResNodes
if (resClausePartitions.size() == 2)
resClausePartitions.remove(0); // resProof package uses "0"
// for globals
assert (resClausePartitions.size() == 1);
int leafPartition = resClausePartitions.iterator().next();
if (leafPartition == 0) {
Set<Integer> tmpClause = new TreeSet<Integer>();
for (Literal lit : resClauseLits) {
tmpClause.add(lit.signed_var());
}
ImmutableSet<Integer> clause = ImmutableSet.create(tmpClause);
assert (leafPartitions.containsKey(clause));
assert (leafPartitions.get(clause) >= 0);
leafPartition = leafPartitions.get(clause);
}
Clause clause = new Clause(resClauseLits);
ResNode resLeafNode = this.addLeaf(clause, leafPartition);
assert (resLeafNode != null);
namesOfResNodes.put(name, resLeafNode);
return;
}
// ------------------------------------------------------------------------------------------
if (type.equals(VeriTToken.RESOLUTION)) {
// This is an internal node
List<ResNode> remainingNodes = new LinkedList<ResNode>();
if (parsed_clauses.length > 2) {
for (String clause : parsed_clauses) {
ResNode node = namesOfResNodes.get(clause);
assert (node != null);
remainingNodes.add(node);
}
while (true) {
assert (remainingNodes.size() > 2);
ResNode left = remainingNodes.remove(0);
ResNode right = remainingNodes.remove(0);
ResNode intermediateNode = this.addIntNode(null, left,
right, 0);
remainingNodes.add(0, intermediateNode);
if (remainingNodes.size() == 2)
break;
}
} else {
ResNode left = namesOfResNodes.get(parsed_clauses[0]);
ResNode right = namesOfResNodes.get(parsed_clauses[1]);
assert (left != null);
assert (right != null);
remainingNodes.add(left);
remainingNodes.add(right);
}
assert (remainingNodes.size() == 2);
// build literal of resolution
ResNode resIntNode = this.addIntNode(null, remainingNodes.get(0),
remainingNodes.get(1), 0);
namesOfResNodes.put(name, resIntNode);
assert (resIntNode != null);
if (resIntNode.getClause().isEmpty())
this.setRoot(resIntNode);
return;
}
// Unknown node type
assert (false);
}
}