//and the set of outstanding vars they depend on...
Map<GdlVariable, Set<Integer>> functionsProducingVars = new HashMap<GdlVariable, Set<Integer>>();
//We start by adding to the varOrdering the vars not produced by functions
//First, we have to find them
for(int i = 0; i < functionalSentencesInfo.size(); i++) {
GdlSentence functionalSentence = functionalSentences.get(i);
FunctionInfo functionInfo = functionalSentencesInfo.get(i);
Set<GdlVariable> producibleVars = functionInfo.getProducibleVars(functionalSentence);
for(GdlVariable producibleVar : producibleVars) {
if(!functionsProducingVars.containsKey(producibleVar))
functionsProducingVars.put(producibleVar, new HashSet<Integer>());
functionsProducingVars.get(producibleVar).add(i);
}
}
//Non-producible vars get iterated over before we start
//deciding which functions to add
for(GdlVariable var : varsToAssign) {
if(!varOrdering.contains(var)) {
if(!functionsProducingVars.containsKey(var)) {
//Add var to the ordering
varOrdering.add(var);
functionalConjunctIndices.add(-1);
varSources.add(-1);
}
}
}
//Map is from potential set of dependencies to function indices
Map<Set<GdlVariable>, Set<Integer>> functionsHavingDependencies = new HashMap<Set<GdlVariable>, Set<Integer>>();
//Create this map...
for(int i = 0; i < functionalSentencesInfo.size(); i++) {
GdlSentence functionalSentence = functionalSentences.get(i);
FunctionInfo functionInfo = functionalSentencesInfo.get(i);
Set<GdlVariable> producibleVars = functionInfo.getProducibleVars(functionalSentence);
Set<GdlVariable> allVars = new HashSet<GdlVariable>(GdlUtils.getVariables(functionalSentence));
//Variables already in varOrdering don't go in dependents list
producibleVars.removeAll(varOrdering);
allVars.removeAll(varOrdering);
for(GdlVariable producibleVar : producibleVars) {
Set<GdlVariable> dependencies = new HashSet<GdlVariable>();
dependencies.addAll(allVars);
dependencies.remove(producibleVar);
if(!functionsHavingDependencies.containsKey(dependencies))
functionsHavingDependencies.put(dependencies, new HashSet<Integer>());
functionsHavingDependencies.get(dependencies).add(i);
}
}
//Now, we can keep creating functions to generate the remaining variables
while(varOrdering.size() < varsToAssign.size()) {
if(functionsHavingDependencies.isEmpty())
throw new RuntimeException("We should not run out of functions we could use");
//Find the smallest set of dependencies
Set<GdlVariable> dependencySetToUse = null;
if(functionsHavingDependencies.containsKey(Collections.emptySet())) {
dependencySetToUse = Collections.emptySet();
} else {
int smallestSize = Integer.MAX_VALUE;
for(Set<GdlVariable> dependencySet : functionsHavingDependencies.keySet()) {
if(dependencySet.size() < smallestSize) {
smallestSize = dependencySet.size();
dependencySetToUse = dependencySet;
}
}
}
//See if any of the functions are applicable
Set<Integer> functions = functionsHavingDependencies.get(dependencySetToUse);
int functionToUse = -1;
GdlVariable varProduced = null;
for (int function : functions) {
GdlSentence functionalSentence = functionalSentences.get(function);
FunctionInfo functionInfo = functionalSentencesInfo.get(function);
Set<GdlVariable> producibleVars = functionInfo.getProducibleVars(functionalSentence);
producibleVars.removeAll(dependencySetToUse);
producibleVars.removeAll(varOrdering);
if(!producibleVars.isEmpty()) {
functionToUse = function;
varProduced = producibleVars.iterator().next();
break;
}
}
if(functionToUse == -1) {
//None of these functions were actually useful now?
//Dump the dependency set
functionsHavingDependencies.remove(dependencySetToUse);
} else {
//Apply the function
//1) Add the remaining dependencies as iterated variables
for(GdlVariable var : dependencySetToUse) {
varOrdering.add(var);
functionalConjunctIndices.add(-1);
varSources.add(-1);
}
//2) Add the function's produced variable (varProduced)
varOrdering.add(varProduced);
functionalConjunctIndices.add(functionToUse);
varSources.add(-1);
//3) Remove all vars added this way from all dependency sets
Set<GdlVariable> addedVars = new HashSet<GdlVariable>();
addedVars.addAll(dependencySetToUse);
addedVars.add(varProduced);
//Tricky, because we have to merge sets
//Easier to use a new map
Map<Set<GdlVariable>, Set<Integer>> newFunctionsHavingDependencies = new HashMap<Set<GdlVariable>, Set<Integer>>();
for(Entry<Set<GdlVariable>, Set<Integer>> entry : functionsHavingDependencies.entrySet()) {
Set<GdlVariable> newKey = new HashSet<GdlVariable>(entry.getKey());
newKey.removeAll(addedVars);
if(!newFunctionsHavingDependencies.containsKey(newKey))
newFunctionsHavingDependencies.put(newKey, new HashSet<Integer>());
newFunctionsHavingDependencies.get(newKey).addAll(entry.getValue());
}
functionsHavingDependencies = newFunctionsHavingDependencies;
//4) Remove this function from the lists?
for(Set<Integer> functionSet : functionsHavingDependencies.values())
functionSet.remove(functionToUse);
}
}
//Now we need to actually return the ordering in a list
//Here's the quick way to do that...
//(since we've added all the new stuff to ourself already)
return Collections.singletonList(new IterationOrderCandidate(this));
} else {
//Let's try a new technique for restricting the space of possibilities...
//We already have an ordering on the functions
//Let's try to constrain things to that order
//Namely, if i<j and constant form j is already used as a function,
//we cannot use constant form i UNLESS constant form j supplies
//as its variable something used by constant form i.
//We might also try requiring that c.f. i NOT provide a variable
//used by c.f. j, though there may be multiple possibilities as
//to what it could provide.
int lastFunctionUsedIndex = -1;
if (!functionalConjunctIndices.isEmpty()) {
lastFunctionUsedIndex = Collections.max(functionalConjunctIndices);
}
Set<GdlVariable> varsProducedByFunctions = new HashSet<GdlVariable>();
for (int i = 0; i < functionalConjunctIndices.size(); i++) {
if (functionalConjunctIndices.get(i) != -1) {
varsProducedByFunctions.add(varOrdering.get(i));
}
}
for (int i = 0; i < functionalSentencesInfo.size(); i++) {
GdlSentence functionalSentence = functionalSentences.get(i);
FunctionInfo functionInfo = functionalSentencesInfo.get(i);
if (i < lastFunctionUsedIndex) {
//We need to figure out whether i could use any of the
//vars we're producing with functions