/* * Created on Apr 20, 2005 * * TODO To change the template for this generated file go to * Window - Preferences - Java - Code Style - Code Templates */ package cs227b.teamIago.resolver; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import cs227b.teamIago.util.GameState; /** * @author Nick * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class Theory { protected HashMap univ; protected HashMap trans; protected HashMap rules; protected ExpList moves; protected ExpList premises; protected long topVar; protected boolean debug; protected boolean useOpt; protected int proofLevel; protected boolean abort = false; /* Memoization tools (dynamic programming optimization) */ protected HashMap provenStat; protected HashSet disprovenStat; protected static final boolean memoTrans = true; protected static final boolean storeTrans = false; protected HashMap provenTrans; protected HashSet disprovenTrans; static final Atom aTrue = new Atom("TRUE"); static final Atom aImp = new Atom("<="); static final Atom aVar = new Atom("*"); static final Atom aDoes = new Atom("DOES"); static final Atom aDummy = new Atom("found"); public Theory(boolean debug, boolean useOpt) { univ = new HashMap(); rules = new HashMap(); provenStat = new HashMap(); disprovenStat = new HashSet(); clearState(); topVar = Long.MIN_VALUE; this.debug = debug; this.useOpt = useOpt; proofLevel = 0; premises = null; } public void buildVolatile() { // Work out which predicates are static // and which depend on transients // Recursive, but doesn't require that much // maintenance--basically a startup cost ArrayList ruleLists = new ArrayList(rules.values()); ExpList ruleList = new ExpList(); for (int i = 0; i < ruleLists.size(); ++i) { ruleList.addAll((ExpList)ruleLists.get(i)); } boolean stillBuilding = true; while (stillBuilding) { ruleList.resetVolatile(); stillBuilding = ruleList.buildVolatile(false); if (!stillBuilding) break; for (int i = 0; i < ruleList.size();) { if (ruleList.get(i).isVolatile()) { ruleList.remove(i); } else ++i; } } ArrayList statLists = new ArrayList(univ.values()); ExpList statList = new ExpList(); for (int i = 0; i < statLists.size(); ++i) { statList.addAll((ExpList)statLists.get(i)); } statList.buildVolatile(false); } public void clearState() { if (trans == null || trans.size() != 0) trans = new HashMap(); clearMoves(); //if (useOpt && memoTrans) clearTransProofs(); } protected void clearProofs() { if (!useOpt) return; if (provenStat == null || provenStat.size() != 0) provenStat = new HashMap(); if (disprovenStat == null || disprovenStat.size() != 0) disprovenStat = new HashSet(); if (memoTrans) clearTransProofs(); } protected void clearTransProofs() { if (!useOpt || !memoTrans) return; if (provenTrans == null || provenTrans.size() != 0) provenTrans = new HashMap(); if (disprovenTrans == null || disprovenTrans.size() != 0) disprovenTrans = new HashSet(); } public void clearMoves() { if (memoTrans) clearTransProofs(); moves = new ExpList(); } public GameState getState() { if (memoTrans && storeTrans) return new GameState(trans,provenTrans,disprovenTrans); else return new GameState(trans); } public void setState(GameState state) { if (state == null) clearState(); else { clearMoves(); trans = state.getMap(); if (!useOpt || !memoTrans || !storeTrans) return; HashMap sp = state.getProven(); HashSet sdp = state.getDisproven(); if (sp != null) provenTrans = sp; else provenTrans = new HashMap(); if (sdp != null) disprovenTrans = sdp; else disprovenTrans = new HashSet(); } } public void setState(ExpList state) { clearState(); for (int i = 0; i < state.size(); i++) { addToTrans(state.get(i)); } } public Variable generateVar() { return new Variable(++topVar); } public Substitution uniquifier(Expression e) { long minVar = e.getMaxVarNum(); if (topVar < minVar) topVar = minVar; ExpList vars = e.getVars(); vars = vars.removeDuplicates(); Substitution uni = new Substitution(); if (vars == null) return uni; for (int i = 0; i < vars.size(); i++) uni.addAssoc((Variable)vars.get(i),generateVar()); return uni; } public boolean truep(Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); if (truex(aDummy, uniqueMatch) == null) return false; */ if (truex(aDummy, toMatch) == null) return false; return true; } public Expression truex(Expression fill, Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); Substitution sigma = uniqueMatch.evalOne(new Substitution(), this); */ Substitution xi; if (useOpt) xi = uniquifier(toMatch); else xi = new Substitution(); if (useOpt) toMatch.buildVolatile(false); Substitution sigma = toMatch.evalOne(xi, this); return retExp(fill,sigma); } public ExpList trues(Expression fill, Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); ArrayList sigmas = uniqueMatch.eval(new Substitution(), this); */ Substitution xi; if (useOpt) xi = uniquifier(toMatch); else xi = new Substitution(); if (useOpt) toMatch.buildVolatile(false); ArrayList sigmas = toMatch.eval(xi, this); return retExpList(fill,sigmas); } public boolean findp(Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); if (findx(aDummy, uniqueMatch) == null) return false; */ if (findx(aDummy, toMatch) == null) return false; return true; } public Expression findx(Expression fill, Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); Substitution sigma = uniqueMatch.chainOne(new Substitution(), this); */ Substitution xi; if (useOpt) xi = uniquifier(toMatch); else xi = new Substitution(); if (useOpt) toMatch.buildVolatile(false); Substitution sigma = toMatch.chainOne(xi, this, false); return retExp(fill,sigma); } public ExpList findx(ExpList fill, Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); Substitution sigma = uniqueMatch.chainOne(new Substitution(), this); */ Substitution xi; if (useOpt) xi = uniquifier(toMatch); else xi = new Substitution(); if (useOpt) toMatch.buildVolatile(false); Substitution sigma = toMatch.chainOne(xi, this, false); return retExpList(fill,sigma); } public ExpList finds(Expression fill, Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); ArrayList sigmas = uniqueMatch.chain(new Substitution(), this); */ Substitution xi; if (useOpt) xi = uniquifier(toMatch); else xi = new Substitution(); if (useOpt) toMatch.buildVolatile(false); ArrayList sigmas = toMatch.chain(xi, this, false); return retExpList(fill,sigmas); } public ArrayList finds(ExpList fill, Expression toMatch) throws InterruptedException { /* Substitution sub = uniquifier(toMatch); Expression uniqueMatch = toMatch.apply(sub); ArrayList sigmas = uniqueMatch.chain(new Substitution(), this); */ Substitution xi; if (useOpt) xi = uniquifier(toMatch); else xi = new Substitution(); if (useOpt) toMatch.buildVolatile(false); ArrayList sigmas = toMatch.chain(xi, this, false); return retExpLists(fill,sigmas); } public boolean findpConditional(Expression toProve,ExpList given) throws InterruptedException { boolean value; premises = given; Substitution sigma = toProve.chainOne(new Substitution(), this, true); value = (sigma != null); premises = null; return value; } public ExpList findxConditional(Expression toProve,ExpList given) throws InterruptedException { ExpList value; premises = given; Substitution sigma = toProve.chainOne(new Substitution(), this, true); value = retExpList(given,sigma); premises = null; return value; } public ArrayList findsConditional(Expression toProve, ExpList given) throws InterruptedException { ArrayList value; premises = given; ArrayList sigmas = toProve.chain(new Substitution(),this, true); value = retExpLists(given,sigmas); premises = null; return value; } public void add(ExpList exps) { for (int i = 0; i < exps.size(); i++) { add(exps.get(i)); } } public boolean add(Expression exp) { if (useOpt) exp.buildVolatile(false); long maxVar = exp.getMaxVarNum(); if (maxVar > topVar) topVar = maxVar + 1; Term first = exp.firstOp(); boolean toTrue = first.equals(aTrue); boolean toImp = first.equals(aImp); boolean toDoes = first.equals(aDoes); if (toTrue) return addToTrans(exp); else if (toImp) return addToRules(exp); else if (toDoes) return addToMoves(exp); else return addToUniv(exp); } public ExpList getCandidates(Expression exp) { ArrayList rets = new ArrayList(); Term temp; Atom first, second; temp = exp.firstOp(); if (!(temp instanceof Atom)) { // If the operator is not an atom, but a variable, // we can match anything in either // the unqualified universals or the rules. // (and the moves) first = aVar; temp = exp.secondOp(); if (!(temp instanceof Atom)) second = aVar; else second = (Atom)temp; Collection c = univ.values(); for (Iterator i = c.iterator(); i.hasNext();) { Object obj = i.next(); ExpList tempList = (ExpList) obj; rets.addAll(tempList.toArrayList()); } c = rules.values(); for (Iterator i = c.iterator(); i.hasNext();) { Object obj = i.next(); ExpList tempList = (ExpList) obj; rets.addAll(tempList.toArrayList()); } // moves are just a list rets.addAll(moves.toArrayList()); // Since the first op is a wildcard, it will also match "true." // This means we also have to check for things in the // transient state whose second op matches. // If the second op is a star, we are in big trouble. // Then it's just every danged thing in the theory. if (second.equals(aVar)) { c = trans.values(); for (Iterator i = c.iterator(); i.hasNext();) { Object obj = i.next(); ExpList tempList = (ExpList) obj; rets.addAll(tempList.toArrayList()); } } else { // The second op was a literal, so we only get the // "true"s that actually match, or that have a // variable op in the axioms ExpList matchTrans = (ExpList) trans.get(second); ExpList starTrans = (ExpList) trans.get(aVar); if (matchTrans != null) rets.addAll(matchTrans.toArrayList()); if (starTrans != null) rets.addAll(starTrans.toArrayList()); } } else { // First operator was not a variable, // but a literal (whew!) // so we can match it first = (Atom)temp; boolean isTrans = first.equals(aTrue); boolean isMove = first.equals(aDoes); temp = exp.secondOp(); if (temp instanceof Atom) second = (Atom)temp; else second = aVar; // Everything matches the (first op of the) "*" list ExpList starUniv = (ExpList)univ.get(aVar); if (starUniv != null) rets.addAll(starUniv.toArrayList()); ExpList starRules = (ExpList) rules.get(aVar); if (starRules != null) rets.addAll(starRules.toArrayList()); if (!isTrans && !isMove) { ExpList matchUniv = (ExpList)univ.get(first); if (matchUniv != null) rets.addAll(matchUniv.toArrayList()); ExpList matchRules = (ExpList) rules.get(first); if (matchRules != null) rets.addAll(matchRules.toArrayList()); } else if (isMove) { rets.addAll(moves.toArrayList()); } else { // either true(expression) or true(*) if (!second.equals(aVar)) { ExpList matchTrans = (ExpList) trans.get(second); ExpList starTrans = (ExpList) trans.get(aVar); if (matchTrans != null) rets.addAll(matchTrans.toArrayList()); if (starTrans != null) rets.addAll(starTrans.toArrayList()); } else { // Second operator is a variable--everything's a candidate // (true *), so add the whole transient set Collection c = trans.values(); for (Iterator i = c.iterator(); i.hasNext();) { Object obj = i.next(); ExpList tempList = (ExpList) obj; rets.addAll(tempList.toArrayList()); } } } } ExpList preRetExp = new ExpList(rets); ExpList retExp = new ExpList(); for (int j = 0; j < preRetExp.size(); j++) { Expression e = preRetExp.get(j); Substitution psi = uniquifier(e); Expression f = e.apply(psi); retExp.add(f); } if (premises != null){ // Add premises after uniquification, so that variables in them // don't get relabelled and are thus only bound once // Also, add them at the end, so that we'll bind with other // clauses if it's provable in another way for (int j = 0; j < premises.size(); j++) { retExp.add((Expression) premises.get(j)); } } return retExp; // replacement code --had to undo this, it didn't work right // return new ExpList(rets); } protected boolean addToMap(HashMap map, Atom key, Expression exp) { ExpList eL = (ExpList) map.get(key); if (eL == null) { eL = new ExpList(); eL.add(exp); map.put(key,eL); return true; } else if (!eL.contains(exp)) { eL.add(exp); return true; } else return false; } protected boolean addToUniv(Expression exp) { if (useOpt) clearProofs(); Term first = exp.firstOp(); if (!(first instanceof Atom)) return addToMap(univ,aVar,exp); else return addToMap(univ,(Atom) first, exp); } protected boolean addToTrans(Expression exp) { if (useOpt && memoTrans) clearTransProofs(); Term secondOp = exp.secondOp(); if (!(secondOp instanceof Atom)) return addToMap(trans,aVar,exp); else return addToMap(trans, (Atom) secondOp, exp); } protected boolean addToRules(Expression exp) { if (useOpt) clearProofs(); Implication imp = (Implication)exp; Term second = imp.secondOp(); if (!( second instanceof Atom)) return addToMap(rules,aVar,exp); else return addToMap(rules,(Atom)second,exp); } protected boolean addToMoves(Expression exp) { if (useOpt && memoTrans) clearTransProofs(); return moves.add(exp); } /** * @return Returns the debug. */ public boolean isDebug() { return debug; } /** * @param debug The debug to set. */ public void setDebug(boolean debug) { this.debug = debug; } /** * @return Returns the topVar. */ public long getTopVar() { return topVar; } /** * @param topVar The topVar to set. */ public void setTopVar(long topVar) { this.topVar = topVar; } /** * @return Returns the proofLevel. */ public int getProofLevel() { return proofLevel; } public void incProofLevel() { ++proofLevel; } public void decProofLevel() { --proofLevel; } protected void indent(int amount) { for (int i=0;i<amount;i++) System.err.print(" "); } public void enterChain(Object e) { incProofLevel(); if (debug) { indent(proofLevel); System.err.println("Prove: " + e); } } public void exitChain(Object e, boolean result, Object res) { if (debug) { indent(proofLevel); System.err.print("Exit: "); if (result) System.err.println("true: " + res); else System.err.println("false"); } decProofLevel(); } public ArrayList checkProven(Substitution sigma, Expression e) { if (!useOpt) return null; ResolveMemoEntry mem = new ResolveMemoEntry(e); ResolveMemoEntry rMem = (ResolveMemoEntry) provenStat.get(mem); if (memoTrans && rMem == null) rMem = (ResolveMemoEntry) provenTrans.get(mem); if (rMem == null) return null; ArrayList rSubs = rMem.getSubs(e); Substitution sigmaC = sigma.factor(); ArrayList retSubs = new ArrayList(); for (int i = 0; i < rSubs.size(); ++i) { Substitution oneSub = (Substitution) rSubs.get(i); Substitution psi = sigmaC.apply(oneSub); retSubs.add(psi); } // if (rSubs != null) System.out.println("Using pre-proven result."); return retSubs; } public boolean checkDisproven(Expression e) { if (!useOpt) return false; // TODO change this to work not just if e // in the list, but if e *unifies* with something // in the list // if it makes it in to disprovenStat, it's *always* stat // so it's disproven forever (no trans can make it true) ResolveMemoEntry mem = new ResolveMemoEntry(e); if (disprovenStat.contains(mem)) return true; if (memoTrans && disprovenTrans.contains(mem)) return true; return false; } public void setProven(Expression e, ArrayList subs) { if (!useOpt) return; // Cut this to only the portion // necessary to ground e and match it with its // proof ArrayList rSubs = new ArrayList(); for (int i = 0; i < subs.size(); ++i) { Substitution psi = (Substitution) subs.get(i); Substitution sigma = psi.restrict(e); if (!rSubs.contains(sigma)) rSubs.add(sigma); } ResolveMemoEntry mem = new ResolveMemoEntry(e); mem.subs = rSubs; // Then store it into the system if (e.isVolatile()) { if (memoTrans) provenTrans.put(mem,mem); } else provenStat.put(mem,mem); } public void setDisproven(Expression e) { if (!useOpt) return; ResolveMemoEntry mem = new ResolveMemoEntry(e); if (e.isVolatile()) { if (memoTrans) disprovenTrans.add(mem); } else disprovenStat.add(mem); } protected ExpList retExpList(Expression toFill, ArrayList sigmas) { if (sigmas == null) return null; ExpList results = new ExpList(); for (int i = 0; i < sigmas.size(); i++) { Substitution psi = (Substitution)sigmas.get(i); if ((psi == null) || psi.empty()) continue; Expression e = toFill; Expression retExp = e.apply(psi); while (!retExp.equals(e)) { e = retExp; retExp = e.apply(psi); } if (!results.contains(retExp)) results.add(retExp); } if (results.size() == 0) return null; else return results; } protected ArrayList retExpLists(ExpList toFill, ArrayList sigmas){ if (sigmas == null) return null; ArrayList retList = new ArrayList(); for (int i = 0; i < sigmas.size(); i++) { Substitution psi = (Substitution)sigmas.get(i); if ((psi == null) || psi.empty()) continue; ExpList e = toFill; ExpList retExp = e.apply(psi); while (!retExp.equals(e)) { e = retExp; retExp = e.apply(psi); } if (!retList.contains(retExp)) retList.add(retExp); } if (retList.size() == 0) return null; else return retList; } protected Expression retExp(Expression toFill, Substitution sigma) { if (sigma == null) return null; Expression retExp = toFill.apply(sigma); while (!retExp.equals(toFill)) { toFill = retExp; retExp = toFill.apply(sigma); } return retExp; } protected ExpList retExpList(ExpList toFill, Substitution sigma) { if (sigma == null) return null; ExpList retExp = toFill.apply(sigma); while (!retExp.equals(toFill)) { toFill = retExp; retExp = toFill.apply(sigma); } return retExp; } public void interrupt() { abort = true; } public boolean interrupted() { return abort; } }