package shef.instantiator; import java.util.ArrayList; import java.util.HashSet; import java.util.Hashtable; import java.util.LinkedList; import java.util.List; import java.util.PriorityQueue; import java.util.Properties; import java.util.Queue; import java.util.Set; import shef.instantiator.andortree.Node; import shef.instantiator.andortree.NodeDepthComparator; import shef.instantiator.andortree.NodeType; import cs227b.teamIago.resolver.Atom; import cs227b.teamIago.resolver.ExpList; import cs227b.teamIago.resolver.Expression; import cs227b.teamIago.resolver.Implication; import cs227b.teamIago.resolver.Predicate; import cs227b.teamIago.resolver.Substitution; import cs227b.teamIago.resolver.Theory; import cs227b.teamIago.resolver.Variable; /* * * ~ ~ __|_\_ * ~ ~ =]_.-.__D> * ~ ~ /_/ * */ /** * Manages building an AND/OR tree which represents a GDL file * * @author jonathan * */ public class Instantiator { // debug constants /** Will print refinement steps */ private static final boolean VIEW_TREE_STEPS = false; // atom constants private static final Atom TRUTH = new Atom("true"); private static final Atom goal = new Atom("goal"); private static final Atom next = new Atom("next"); private static final Atom init = new Atom("init"); private static final Substitution s = new Substitution(); /** For hashes for {@link Node} memoization */ protected Hashtable<Expression, Node> orMemory = new Hashtable<Expression, Node>(); /** For hashes for {@link Node} memoization */ protected Hashtable<Expression, Node> andMemory = new Hashtable<Expression, Node>(); protected Theory theory; private Queue<Node> varCausingNodes = new PriorityQueue<Node>(1, new NodeDepthComparator()); private Hashtable<Expression, Node> goalHash = new Hashtable<Expression, Node>(); @SuppressWarnings("unchecked") public Instantiator(Theory t, Properties p) { this.theory = t; // init facts List<Expression> initFacts = theory.getCandidates(init).toArrayList(); for (Expression fact : initFacts) { if (fact instanceof Implication) { Implication initFact = (Implication) fact; Predicate conseqFact = (Predicate) initFact.getConsequence(); Implication iFact = new Implication(conseqFact.getOperands().get(0), initFact.getPremises()); theory.add(iFact); } else if (fact instanceof Predicate) { Predicate pFact = (Predicate) fact; theory.add(pFact.getOperands()); } } theory.buildVolatile(); } public Instantiator(Theory theory2) { this(theory2, new Properties()); } public List<Node> getProofTrees(int depth) { // fill state space System.out.println("adding extra info"); addExtraInfo(); // create the initial goal trees // this creates the correct structure System.out.println("creating goal trees"); createGoalTrees(depth); // instantiate variables System.out.println("filling in variables"); fillVariables(); System.out.println("clean up the tree"); cleanTrees(); return new ArrayList<Node>(goalHash.values()); } /** * remove any unnecessary clauses - can prune anything which isn't part */ private void cleanTrees() { for (Node goalNode : goalHash.values()) { Node.prune(goalNode); } } @SuppressWarnings("unchecked") private void addExtraInfo() { List<NextClause> toConsiderClauses = getNextClauses(theory); Set<Expression> expsToAdd = new HashSet<Expression>(); int last_c = 0; int newC = 0; do { last_c = newC; for (NextClause cl : toConsiderClauses) { List<Predicate> insts = new ArrayList<Predicate>(); Predicate next = cl.getNext(); insts.add(next); for (Expression premise : cl.getPremises()) { if (premise.firstOp().equals(TRUTH)) premise = ((Predicate) premise).getOperands().get(0); List<Expression> results = (List<Expression>) theory.getCandidates(premise).toArrayList(); List<Predicate> newPs = new ArrayList<Predicate>(); boolean replaceList = false; for (Expression e : results) { Substitution nS = premise.mapTo(s, e); if (nS != null) { boolean varInstantiate = false; for (Variable v : (ArrayList<Variable>) insts.get(0).getVars().toArrayList()) { if (nS.assigns(v)) { varInstantiate = true; replaceList = true; break; } } if (varInstantiate) { for (Predicate pr : insts) { newPs.add((Predicate) pr.apply(nS)); } } } } if (replaceList) insts = newPs; // add non-duplicate completed predicates to the theory for (Predicate p : insts) { if (p.getVars().size() == 0) { boolean already = expsToAdd.add(p); if (!already) theory.add(p); } } } } // check at least something has been added newC = expsToAdd.size(); } while (last_c != newC); } @SuppressWarnings("unchecked") /** * Returns a list clauses representing (NEXT (X)) statements */ private List<NextClause> getNextClauses(Theory theory) { List<Expression> facts = (ArrayList<Expression>) theory.getCandidates(theory.generateVar()).toArrayList(); List<NextClause> nextClauses = new ArrayList<NextClause>(); // find the (NEXT (X) ) statements for (Expression fact : facts) { if (fact instanceof Implication) { Implication impFact = (Implication) fact; Expression con = impFact.getConsequence(); if (con instanceof Predicate && con.firstOp().equals(next)) { List<Expression> prems = impFact.getPremises().toArrayList(); NextClause cl = new NextClause((Predicate) ((Predicate) con).getOperands().get(0), prems); nextClauses.add(cl); } } } return nextClauses; } /** * Create the AND/OR trees which represent the game these will be and or * structures created by fulfilling goal states * * @param depth * how deep the tree will go */ @SuppressWarnings("unchecked") private Hashtable<Expression, Node> createGoalTrees(int depth) { goalHash = new Hashtable<Expression, Node>(); // goal predicate Variable vRole = theory.generateVar(); Variable vScore = theory.generateVar(); Predicate goalPred = new Predicate(goal, new ExpList(new Expression[] { vRole, vScore })); ExpList goalImps = theory.getCandidates(goalPred); ExpList roles = theory.getCandidates(new Predicate("role", new Expression[] { theory.generateVar() })); for (Implication goalImp : (ArrayList<Implication>) goalImps.toArrayList()) { List<Node> toProcess = new LinkedList<Node>(); ExpList goalOps = ((Predicate) (goalImp.getConsequence())).getOperands(); if (goalOps.get(0) instanceof Variable) { // hack to give goals all the same variable values for (Expression role : (ArrayList<Expression>) roles.toArrayList()) { Implication goalInstImp = new Implication(new Predicate("goal", new ExpList(new Expression[] { goalPred.secondOp(), goalOps.get(1) })), goalImp.getPremises()); Substitution s = new Substitution(); s.addAssoc((Variable) goalOps.get(0), goalPred.secondOp()); s.addAssoc((Variable) goalPred.secondOp(), role.secondOp()); // apply twice goalInstImp = (Implication) goalInstImp.apply(s); goalInstImp = (Implication) goalInstImp.apply(s); addGoalTree(goalInstImp, toProcess); } } else { addGoalTree(goalImp, toProcess); } ProcessTree p = new ProcessTree(toProcess, this); p.run(); varCausingNodes.addAll(p.varCausingNodes); } return goalHash; } private void addGoalTree(Implication goalInstImp, List<Node> toProcess) { Node goalNode = goalHash.get(goalInstImp.getConsequence()); if (goalNode == null) { goalNode = new Node(goalInstImp, NodeType.ROOT); goalHash.put(goalInstImp.getConsequence(), goalNode); toProcess.add(goalNode); } } /** * Should be a list of OR or VAR_OR nodes * * @param varCausingNodes */ private void fillVariables() { while (!varCausingNodes.isEmpty()) { Node node; if(VIEW_TREE_STEPS){ node = varCausingNodes.peek(); System.out.println("ch: "+ node); System.out.println("fr: "+ varCausingNodes); System.out.println(new ArrayList<Node>(goalHash.values()).get(0).printTree()); varCausingNodes.poll(); } else { node = varCausingNodes.poll(); } assert node.nodetype == NodeType.OR || node.nodetype == NodeType.VAR_OR; List<Node> children = node.getChildren(); // select a node which has all of its children completed // pass these instantiations up Node completed = null; for (Node n : children) { // instantiate if it can be else it may need folding up if ((n.getNodeType() == NodeType.TRUTH || n.getNodeType() == NodeType.AND) && n.getHead().getVars().size() > 0 && n.isCompleted() && n.getChildCount() > 0) { node.resetChildren(); completed = n; break; } } /* * Replace a node which has no free variables in its children by an * instantiation for each of those possibilities as described in */ if (completed != null) { Implication varImp = node.getImplication(); Node varAnd = new Node(varImp, NodeType.VAR_AND); if (completed.negated) { System.err.println("neg node somewhere"); } node.addChild(varAnd); List<Node> completedChildren = completed.getChildren(); // TODO check there isn't anything in the facts which fulfils for (Node compChild : completedChildren) { Node varOr = new Node(varImp, NodeType.VAR_OR); varAnd.addChild(varOr); Substitution s = new Substitution(); s = completed.getImplication().getConsequence().mgu(compChild.getHead(), s, theory); if (s != null) { for (Node child : children) { Node newAnd = child.clone(s); varOr.addChild(newAnd); } } // else { // throw new RuntimeErrorException(null, "Fail mapping"); // } // if (varOr.getChildCount() == 0) { // varAnd.removeChild(varOr); // } // replace these new VAR_OR nodes with fully instantiated // nodes by mapping to the consequent // shouldn't remove any children here as there may be truths if (varOr.isCompleted()) { ExpList varOrPremises = varOr.getImplication().getPremises(); List<Node> varOrChildren = varOr.getChildren(); ExpList varOrExpList = new ExpList(); for (Node varOrChild : varOrChildren) { // if its a truth have to build the truth back in if (varOrChild.getNodeType() == NodeType.TRUTH) { varOrExpList.add(new Predicate("true", new ExpList(new Expression[] { varOrChild.getHead() }))); } else { varOrExpList.add(varOrChild.getHead()); } } Substitution sub = new Substitution(); sub = varOrPremises.mgu(varOrExpList, sub, theory); // now have a definite instantiation for the VAR_OR varOr.setImplication((Implication) varOr.getImplication().apply(sub)); } } varCausingNodes.add(node); } else { // if there is nothing which has free variables then everything // below here must be instantiated so flatten it Node parent = node.getParent(); if (node.getChildren().size() > 0) { Node firstChild = node.getChildren().get(0); // if the first child is a VAR_AND then can collapse all // VAR_ORs if (firstChild.getNodeType() == NodeType.VAR_AND) { List<Node> subs = firstChild.getChildren(); parent.removeChild(node); for (Node n : subs) { n.nodetype = NodeType.OR; parent.addChild(n); boolean add = !n.isCompleted() || n.getHead().getVars().size() > 0; if (add) { varCausingNodes.add(n); } } } } } // System.out.println("nfr:" + varCausingNodes); // System.out.println("-------"); } } }