package shef.instantiator;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import shef.instantiator.andortree.Node;
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.NotOp;
import cs227b.teamIago.resolver.OrOp;
import cs227b.teamIago.resolver.Predicate;
import cs227b.teamIago.resolver.Substitution;
import cs227b.teamIago.resolver.Term;
public class ProcessTree {
private static final Atom TRUTH = new Atom("true");
private static final Substitution blankSub = new Substitution();
protected List<Node> varCausingNodes = new ArrayList<Node>();
private List<Node> toProcess;
private Instantiator ins;
public ProcessTree(List<Node> toProcess, Instantiator ins) {
this.toProcess = toProcess;
this.ins = ins;
}
public void run() {
// Construct the basic tree
while (!toProcess.isEmpty()) {
// get the first in the tree and remove it from the to process list
Node n = toProcess.get(0);
toProcess.remove(0);
List<Node> re = instantiateOneLevel(n);
toProcess.addAll(re);
}
}
/**
* Build this node one level down
*
* @param processNode
* node to build from
* @return every new node which should be searched
*/
@SuppressWarnings("unchecked")
protected List<Node> instantiateOneLevel(Node processNode) {
LinkedList<Node> list = new LinkedList<Node>();
Expression originalExpression = processNode.getHead();
// return everything which would match this
ExpList candidates = ins.theory.getCandidates(originalExpression);
// should only appear for atoms
if (candidates.size() == 0) {
if (originalExpression.firstOp().equals(TRUTH)) {
processNode.becomeTruth();
}
} else {
if (candidates.size() > 0) {
// pre filter the list to predicates and implications
List<Expression> candidateList = candidates.toArrayList();
List<Implication> candidateListImps = new ArrayList<Implication>();
List<Predicate> candidateListPreds = new ArrayList<Predicate>();
for (Expression e : candidateList) {
if (e instanceof Implication) {
candidateListImps.add((Implication) e);
} else if (e instanceof Predicate) {
candidateListPreds.add((Predicate) e);
}
}
candidateListPreds = mapPredicates(originalExpression, candidateListPreds);
candidateListImps = mapExpressions(originalExpression, candidateListImps);
// add them to the parent node
list.addAll(processPredicates(processNode, candidateListPreds));
list.addAll(processImplications(processNode, candidateListImps));
}
}
return list;
}
/**
* Add a predicates which match the node
*
* @param parent
* @param candidatePredicates
* @return
*/
private List<Node> processPredicates(Node parent, List<Predicate> candidatePredicates) {
LinkedList<Node> newAnds = new LinkedList<Node>();
// process Predicates by adding the predicate OR and AND
NodeType baseType = parent.nodetype;
for (Predicate instPredicate : candidatePredicates) {
Implication impP = new Implication(instPredicate, new ExpList());
// Node newOrNode = new Node(impP, NodeType.OR);
Node newOrNode = ins.orMemory.get(impP);
if (newOrNode == null) {
newOrNode = new Node(impP, NodeType.OR);
ins.orMemory.put(impP, newOrNode);
parent.addChild(newOrNode);
Node newAndNode = ins.andMemory.get(impP);
if (newAndNode == null) {
newAndNode = new Node(impP, baseType);
}
newOrNode.addChild(newAndNode);
recordVarCausing(newOrNode);
} else {
parent.addChild(newOrNode);
}
}
return newAnds;
}
/**
* Add implications which match the node
*
* @param parent
* @param candidateListImps
* @return
*/
@SuppressWarnings("unchecked")
private List<Node> processImplications(Node parent, List<Implication> candidateListImps) {
LinkedList<Node> newAnds = new LinkedList<Node>();
for (Implication instImplication : candidateListImps) {
// Node newOrNode = new Node(instImplication, NodeType.OR);
Node newOrNode = ins.orMemory.get(instImplication);
if (newOrNode == null) {
newOrNode = new Node(instImplication, NodeType.OR);
ins.orMemory.put(instImplication, newOrNode);
// if the implication doesn't already exist make it and fill it
// out
parent.addChild(newOrNode);
for (Expression cons : (ArrayList<Expression>) instImplication.getPremises().toArrayList()) {
Implication newImpl = new Implication(cons, new ExpList());
Node newAndNode = ins.andMemory.get(newImpl);
if (newAndNode == null) {
newAndNode = new Node(newImpl, NodeType.AND);
if (cons instanceof Predicate) {
Predicate pred = (Predicate) cons;
Term firstOp = pred.firstOp();
if (firstOp.equals(TRUTH)) {
newAndNode.becomeTruth();
}
} else if (cons instanceof NotOp) {
// instantiate a not
newAndNode.negated = true;
newAndNode.setImplication(new Implication((((NotOp) cons).getOperands().get(0)), instImplication.getPremises()));
} else if (cons.getClass().equals(OrOp.class)) {
newAndNode.nodetype = NodeType.DISTINCT;
// XXX have to do the equals OrOp.class strange library
// incompatibility between expression and OrOp
OrOp or = (OrOp) cons;
List<Predicate> lP = (ArrayList<Predicate>)or.getOperands().toArrayList();
for (Predicate p : lP) {
Implication iP = new Implication(p, new ExpList());
Node orOr = new Node(iP, NodeType.OR);
Node orAnd = new Node(iP, NodeType.AND);
newAndNode.addChild(orOr);
orOr.addChild(orAnd);
newAnds.add(orAnd);
}
}
newAnds.add(newAndNode);
}
newOrNode.addChild(newAndNode);
}
recordVarCausing(newOrNode);
} else {
parent.addChild(newOrNode);
}
}
return newAnds;
}
private boolean recordVarCausing(Node goalNode) {
List<Node> children = goalNode.getChildren();
if (goalNode.getHead().getVars().size() > 0) {
varCausingNodes.add(goalNode);
return true;
}
for (Node child : children) {
if (child.getHead().getVars().size() > 0) {
varCausingNodes.add(goalNode);
return true;
}
}
return false;
}
/**
* Take the implications which possible instantiate this predicate and map
* the variables to the implication which generated them
*
* @param oldExp
* @param newUninstExps
* @return
*/
protected List<Implication> mapExpressions(Expression oldExp, List<Implication> newUninstExps) {
List<Implication> newInstImps = new ArrayList<Implication>();
final Substitution freshSub = new Substitution();
for (Implication newUninstExp : newUninstExps) {
Expression uninstantiatedExp = newUninstExp.getConsequence();
Substitution sMgu = uninstantiatedExp.mgu(oldExp, freshSub, ins.theory);
if (sMgu != null) {
// nothing which doesn't unify should be here
// worst is they match so can map and apply
Implication newinstExp = (Implication) newUninstExp.apply(sMgu);
/*
* should either be equal now OR newinstExp will be a refinement
* of oldExp (A ?x 1) (A 1 ?y) -> (A 1 1) (A ?x 1) (A ?y 1) ->
* (A ?y 1) there may be variables left over MAP THEM
*/
Substitution sMap = uninstantiatedExp.mapTo(freshSub, oldExp);
newinstExp = (Implication) newUninstExp.apply(sMap);
newInstImps.add(newinstExp);
}
}
return newInstImps;
}
protected List<Predicate> mapPredicates(Expression oldExpression, List<Predicate> newPreds) {
List<Predicate> newInstImps = new ArrayList<Predicate>();
for (Predicate newUninstExp : newPreds) {
Substitution sMgu = newUninstExp.mgu(oldExpression, blankSub, ins.theory);
if (sMgu != null) {
Predicate newinstExp = (Predicate) newUninstExp.apply(sMgu);
newInstImps.add(newinstExp);
}
}
return newInstImps;
}
}