Example #1
0
 def roleExists(self, roleName, valueSet):
     roleValues = ArrayList()
     print roleName
     length = valueSet.getLength()
     for i in range(0, length):
         roleValues.add(valueSet.item(i).getTextContent())
     print roleValues.contains(roleName)
     if roleValues.contains(roleName):
         return True
     return False
Example #2
0
 def getBestIterationOrderCandidate(cls, rule, varDomains, functionInfoMap, completedSentenceFormSizes, preassignment, analyticFunctionOrdering):
     """ generated source for method getBestIterationOrderCandidate """
     # SentenceModel model,
     # Here are the things we need to pass into the first IOC constructor
     sourceConjunctCandidates = ArrayList()
     # What is a source conjunct candidate?
     # - It is a positive conjunct in the rule (i.e. a GdlSentence in the body).
     # - It has already been fully defined; i.e. it is not recursively defined in terms of the current form.
     # Furthermore, we know the number of potentially true tuples in it.
     varsToAssign = GdlUtils.getVariables(rule)
     newVarsToAssign = ArrayList()
     for var in varsToAssign:
         if not newVarsToAssign.contains(var):
             newVarsToAssign.add(var)
     varsToAssign = newVarsToAssign
     if preassignment != None:
         varsToAssign.removeAll(preassignment.keySet())
     # Calculate var domain sizes
     varDomainSizes = getVarDomainSizes(varDomains)# rule, model
     sourceConjunctSizes = ArrayList()
     for conjunct in rule.getBody():
         if isinstance(conjunct, (GdlRelation, )):
             if completedSentenceFormSizes != None and completedSentenceFormSizes.containsKey(form):
                 # New: Don't add if it will be useless as a source
                 # For now, we take a strict definition of that
                 # Compare its size with the product of the domains
                 # of the variables it defines
                 # In the future, we could require a certain ratio
                 # to decide that this is worthwhile
                 for var in vars:
                     maxSize *= domainSize
                 if size >= maxSize:
                     continue 
                 sourceConjunctCandidates.add(relation)
                 sourceConjunctSizes.add(size)
     functionalSentences = ArrayList()
     functionalSentencesInfo = ArrayList()
     for conjunct in rule.getBody():
         if isinstance(conjunct, (GdlSentence, )):
             if functionInfoMap != None and functionInfoMap.containsKey(form):
                 functionalSentences.add(conjunct)
                 functionalSentencesInfo.add(functionInfoMap.get(form))
     # TODO: If we have a head assignment, treat everything as already replaced
     # Maybe just translate the rule? Or should we keep the pool clean?
     emptyCandidate = IterationOrderCandidate(varsToAssign, sourceConjunctCandidates, sourceConjunctSizes, functionalSentences, functionalSentencesInfo, varDomainSizes)
     searchQueue = PriorityQueue()
     searchQueue.add(emptyCandidate)
     while not searchQueue.isEmpty():
         # 			print "Node being checked out: " + curNode;
         if curNode.isComplete():
             # This is the complete ordering with the lowest heuristic value
             return curNode
         searchQueue.addAll(curNode.getChildren(analyticFunctionOrdering))
     raise RuntimeException("Found no complete iteration orderings")
Example #3
0
 def __init__(self, headAssignment, rule, varDomains, functionInfoMap, completedSentenceFormValues):
     """ generated source for method __init__ """
     super(AssignmentsImpl, self).__init__()
     self.empty = False
     self.headAssignment = headAssignment
     # We first have to find the remaining variables in the body
     self.varsToAssign = GdlUtils.getVariables(rule)
     # Remove all the duplicates; we do, however, want to keep the ordering
     newVarsToAssign = ArrayList()
     for v in varsToAssign:
         if not newVarsToAssign.contains(v):
             newVarsToAssign.add(v)
     self.varsToAssign = newVarsToAssign
     self.varsToAssign.removeAll(headAssignment.keySet())
     # varsToAssign is set at this point
     # We see if iterating over entire tuples will give us a
     # better result, and we look for the best way of doing that.
     # Let's get the domains of the variables
     # Map<GdlVariable, Set<GdlConstant>> varDomains = model.getVarDomains(rule);
     # Since we're looking at a particular rule, we can do this one step better
     # by looking at the domain of the head, which may be more restrictive
     # and taking the intersections of the two domains where applicable
     # Map<GdlVariable, Set<GdlConstant>> headVarDomains = model.getVarDomainsInSentence(rule.getHead());
     # We can run the A* search for a good set of source conjuncts
     # at this point, then use the result to build the rest.
     completedSentenceFormSizes = HashMap()
     if completedSentenceFormValues != None:
         for form in completedSentenceFormValues.keySet():
             completedSentenceFormSizes.put(form, completedSentenceFormValues.get(form).size())
     varDomainSizes = HashMap()
     for var in varDomains.keySet():
         varDomainSizes.put(var, varDomains.get(var).size())
     bestOrdering = IterationOrderCandidate()
     bestOrdering = getBestIterationOrderCandidate(rule, varDomains, functionInfoMap, completedSentenceFormSizes, headAssignment, False)# model,
     # TODO: True here?
     # Want to replace next few things with order
     # Need a few extra things to handle the use of iteration over existing tuples
     self.varsToAssign = bestOrdering.getVariableOrdering()
     # For each of these vars, we have to find one or the other.
     # Let's start by finding all the domains, a task already done.
     self.valuesToIterate = Lists.newArrayListWithCapacity(len(self.varsToAssign))
     for var in varsToAssign:
         if varDomains.containsKey(var):
             if not varDomains.get(var).isEmpty():
                 self.valuesToIterate.add(ImmutableList.copyOf(varDomains.get(var)))
             else:
                 self.valuesToIterate.add(ImmutableList.of(GdlPool.getConstant("0")))
         else:
             self.valuesToIterate.add(ImmutableList.of(GdlPool.getConstant("0")))
     # Okay, the iteration-over-domain is done.
     # Now let's look at sourced iteration.
     self.sourceDefiningSlot = ArrayList(len(self.varsToAssign))
     i = 0
     while i < len(self.varsToAssign):
         self.sourceDefiningSlot.add(-1)
         i += 1
     # We also need to convert values into tuples
     # We should do so while constraining to any constants in the conjunct
     # Let's convert the conjuncts
     sourceConjuncts = bestOrdering.getSourceConjuncts()
     self.tuplesBySource = Lists.newArrayListWithCapacity(len(sourceConjuncts))
     # new ArrayList<List<List<GdlConstant>>>(len(sourceConjuncts));
     self.varsChosenBySource = Lists.newArrayListWithCapacity(len(sourceConjuncts))
     # new ArrayList<List<Integer>>(len(sourceConjuncts));
     self.putDontCheckBySource = Lists.newArrayListWithCapacity(len(sourceConjuncts))
     # new ArrayList<List<Boolean>>(len(sourceConjuncts));
     j = 0
     while j < len(sourceConjuncts):
         # flatten into a tuple
         # Go through the vars/constants in the tuple
         while i < len(conjunctTuple):
             if isinstance(term, (GdlConstant, )):
                 constraintSlots.add(i)
                 constraintValues.add(term)
                 # TODO: What if tuple size ends up being 0?
                 # Need to keep that in mind
             elif isinstance(term, (GdlVariable, )):
                 varsChosen.add(varIndex)
                 if self.sourceDefiningSlot.get(varIndex) == -1:
                     # We define it
                     self.sourceDefiningSlot.set(varIndex, j)
                     putDontCheck.add(True)
                 else:
                     # It's an overlap; we just check for consistency
                     putDontCheck.add(False)
             else:
                 raise RuntimeException("Function returned in tuple")
             i += 1
         self.varsChosenBySource.add(ImmutableList.copyOf(varsChosen))
         self.putDontCheckBySource.add(ImmutableList.copyOf(putDontCheck))
         # Now we put the tuples together
         # We use constraintSlots and constraintValues to check that the
         # tuples have compatible values
         for sentence in sentences:
             # Check that it doesn't conflict with our headAssignment
             if not headAssignment.isEmpty():
                 for var in headAssignment.keySet():
                     if tupleAssignment.containsKey(var) and tupleAssignment.get(var) != headAssignment.get(var):
                         continue 
             while c < len(constraintSlots):
                 if not longTuple.get(slot) == value:
                     continue 
                 c += 1
             while s < len(longTuple):
                 # constraintSlots is sorted in ascending order
                 if c < len(constraintSlots) and constraintSlots.get(c) == s:
                     c += 1
                 else:
                     shortTuple.add(longTuple.get(s))
                 s += 1
             # The tuple fits the source conjunct
             tuples.add(ImmutableList.copyOf(shortTuple))
         # sortTuples(tuples); //Needed? Useful? Not sure. Probably not?
         self.tuplesBySource.add(ImmutableList.copyOf(tuples))
         j += 1
     # We now want to see which we can give assignment functions to
     self.valuesToCompute = ArrayList(len(self.varsToAssign))
     for var in varsToAssign:
         self.valuesToCompute.add(None)
     self.indicesToChangeWhenNull = ArrayList(len(self.varsToAssign))
     i = 0
     while i < len(self.varsToAssign):
         # Change itself, why not?
         # Actually, instead let's try -1, to catch bugs better
         self.indicesToChangeWhenNull.add(-1)
         i += 1
     # Now we have our functions already selected by the ordering
     # bestOrdering.functionalConjunctIndices;
     # Make AssignmentFunctions out of the ordering
     functionalConjuncts = bestOrdering.getFunctionalConjuncts()
     # 		print "functionalConjuncts: " + functionalConjuncts;
     i = 0
     while i < len(functionalConjuncts):
         if functionalConjunct != None:
             # These are the only ones that could be constant functions
             if functionInfoMap != None:
                 functionInfo = functionInfoMap.get(conjForm)
             if functionInfo != None:
                 # Now we need to figure out which variables are involved
                 # and which are suitable as functional outputs.
                 # 1) Which vars are in this conjunct?
                 # 2) Of these vars, which is "rightmost"?
                 # 3) Is it only used once in the relation?
                 if Collections.frequency(varsInSentence, rightmostVar) != 1:
                     continue 
                 # Can't use it
                 # 4) Which slot is it used in in the relation?
                 # 5) Build an AssignmentFunction if appropriate.
                 #    This should be able to translate from values of
                 #    the other variables to the value of the wanted
                 #    variable.
                 # We don't guarantee that this works until we check
                 if not function_.functional():
                     continue 
                 self.valuesToCompute.set(index, function_)
                 remainingVarsInSentence.remove(rightmostVar)
                 self.indicesToChangeWhenNull.set(index, self.varsToAssign.indexOf(nextRightmostVar))
         i += 1
     # We now have the remainingVars also assigned their domains
     # We also cover the distincts here
     # Assume these are just variables and constants
     self.distincts = ArrayList()
     for literal in rule.getBody():
         if isinstance(literal, (GdlDistinct, )):
             self.distincts.add(literal)
     computeVarsToChangePerDistinct()
     # Need to add "distinct" restrictions to head assignment, too...
     checkDistinctsAgainstHead()
Example #4
0
class IterationOrderCandidate(Comparable, IterationOrderCandidate):
    """ generated source for class IterationOrderCandidate """
    # Information specific to this ordering
    sourceConjunctIndices = List()

    # Which conjuncts are we using as sources, and in what order?
    varOrdering = List()

    # In what order do we assign variables?
    functionalConjunctIndices = List()

    # Same size as varOrdering
    # Index of conjunct if functional, -1 otherwise
    varSources = List()

    # Same size as varOrdering
    # For each variable: Which source conjunct
    # originally contributes it? -1 if none
    # Becomes sourceResponsibleForVar
    # Information shared by the orderings
    # Presumably, this will also be used to construct the iterator to be used...
    varsToAssign = List()
    sourceConjunctCandidates = List()
    sourceConjunctSizes = List()

    # same indexing as candidates
    functionalSentences = List()
    functionalSentencesInfo = List()

    # Indexing same as functionalSentences
    varDomainSizes = Map()

    # 
    # 		 * This constructor is for creating the start node of the
    # 		 * search. No part of the ordering is specified.
    # 		 *
    # 		 * @param sourceConjunctCandidates
    # 		 * @param sourceConjunctSizes
    # 		 * @param functionalSentences
    # 		 * @param functionalSentencesInfo
    # 		 * @param allVars
    # 		 * @param varDomainSizes
    # 		 
    @overloaded
    def __init__(self, varsToAssign, sourceConjunctCandidates, sourceConjunctSizes, functionalSentences, functionalSentencesInfo, varDomainSizes):
        """ generated source for method __init__ """
        super(IterationOrderCandidate, self).__init__()
        self.sourceConjunctIndices = ArrayList()
        self.varOrdering = ArrayList()
        self.functionalConjunctIndices = ArrayList()
        self.varSources = ArrayList()
        self.varsToAssign = varsToAssign
        self.sourceConjunctCandidates = sourceConjunctCandidates
        self.sourceConjunctSizes = sourceConjunctSizes
        self.functionalSentences = functionalSentences
        self.functionalSentencesInfo = functionalSentencesInfo
        self.varDomainSizes = varDomainSizes

    def getFunctionalConjuncts(self):
        """ generated source for method getFunctionalConjuncts """
        # Returns, for each var, the conjunct defining it (if any)
        functionalConjuncts = ArrayList(len(self.functionalConjunctIndices))
        for index in functionalConjunctIndices:
            if index == -1:
                functionalConjuncts.add(None)
            else:
                functionalConjuncts.add(self.functionalSentences.get(index))
        return functionalConjuncts

    def getSourceConjuncts(self):
        """ generated source for method getSourceConjuncts """
        # These are the selected source conjuncts, not just the candidates.
        sourceConjuncts = ArrayList(len(self.sourceConjunctIndices))
        for index in sourceConjunctIndices:
            sourceConjuncts.add(self.sourceConjunctCandidates.get(index))
        return sourceConjuncts

    def getVariableOrdering(self):
        """ generated source for method getVariableOrdering """
        return self.varOrdering

    # 
    # 		 * This constructor is for "completing" the ordering by
    # 		 * adding all remaining variables, in some arbitrary order.
    # 		 * No source conjuncts or functions are added.
    # 		 
    @__init__.register(object, IterationOrderCandidate)
    def __init___0(self, parent):
        """ generated source for method __init___0 """
        super(IterationOrderCandidate, self).__init__()
        # Shared rules
        self.varsToAssign = parent.varsToAssign
        self.sourceConjunctCandidates = parent.sourceConjunctCandidates
        self.sourceConjunctSizes = parent.sourceConjunctSizes
        self.functionalSentences = parent.functionalSentences
        self.functionalSentencesInfo = parent.functionalSentencesInfo
        self.varDomainSizes = parent.varDomainSizes
        # Individual rules:
        # We can share this because we won't be adding to it
        self.sourceConjunctIndices = parent.sourceConjunctIndices
        # These others we'll be adding to
        self.varOrdering = ArrayList(parent.varOrdering)
        self.functionalConjunctIndices = ArrayList(parent.functionalConjunctIndices)
        self.varSources = ArrayList(parent.varSources)
        # Fill out the ordering with all remaining variables: Easy enough
        for var in varsToAssign:
            if not self.varOrdering.contains(var):
                self.varOrdering.add(var)
                self.functionalConjunctIndices.add(-1)
                self.varSources.add(-1)

    # 
    # 		 * This constructor is for adding a source conjunct to an
    # 		 * ordering.
    # 		 * @param i The index of the source conjunct being added.
    # 		 
    @__init__.register(object, IterationOrderCandidate, int)
    def __init___1(self, parent, i):
        """ generated source for method __init___1 """
        super(IterationOrderCandidate, self).__init__()
        # Shared rules:
        self.varsToAssign = parent.varsToAssign
        self.sourceConjunctCandidates = parent.sourceConjunctCandidates
        self.sourceConjunctSizes = parent.sourceConjunctSizes
        self.functionalSentences = parent.functionalSentences
        self.functionalSentencesInfo = parent.functionalSentencesInfo
        self.varDomainSizes = parent.varDomainSizes
        # Individual rules:
        self.sourceConjunctIndices = ArrayList(parent.sourceConjunctIndices)
        self.varOrdering = ArrayList(parent.varOrdering)
        self.functionalConjunctIndices = ArrayList(parent.functionalConjunctIndices)
        self.varSources = ArrayList(parent.varSources)
        # Add the new source conjunct
        self.sourceConjunctIndices.add(i)
        sourceConjunctCandidate = self.sourceConjunctCandidates.get(i)
        varsFromConjunct = GdlUtils.getVariables(sourceConjunctCandidate)
        # Ignore both previously added vars and duplicates
        # Oh, but we need to be careful here, at some point.
        # i.e., what if there are multiple of the same variable
        # in a single statement?
        # That should probably be handled later.
        for var in varsFromConjunct:
            if not self.varOrdering.contains(var):
                self.varOrdering.add(var)
                self.varSources.add(i)
                self.functionalConjunctIndices.add(-1)

    # 
    # 		 * This constructor is for adding a function to the ordering.
    # 		 
    @__init__.register(object, IterationOrderCandidate, GdlSentence, int, GdlVariable)
    def __init___2(self, parent, functionalSentence, functionalSentenceIndex, functionOutput):
        """ generated source for method __init___2 """
        super(IterationOrderCandidate, self).__init__()
        # Shared rules:
        self.varsToAssign = parent.varsToAssign
        self.sourceConjunctCandidates = parent.sourceConjunctCandidates
        self.sourceConjunctSizes = parent.sourceConjunctSizes
        self.functionalSentences = parent.functionalSentences
        self.functionalSentencesInfo = parent.functionalSentencesInfo
        self.varDomainSizes = parent.varDomainSizes
        # Individual rules:
        self.sourceConjunctIndices = ArrayList(parent.sourceConjunctIndices)
        self.varOrdering = ArrayList(parent.varOrdering)
        self.functionalConjunctIndices = ArrayList(parent.functionalConjunctIndices)
        self.varSources = ArrayList(parent.varSources)
        # And we add the function
        varsInFunction = GdlUtils.getVariables(functionalSentence)
        # First, add the remaining arguments
        for var in varsInFunction:
            if not self.varOrdering.contains(var) and not var == functionOutput and self.varsToAssign.contains(var):
                self.varOrdering.add(var)
                self.functionalConjunctIndices.add(-1)
                self.varSources.add(-1)
        # Then the output
        self.varOrdering.add(functionOutput)
        self.functionalConjunctIndices.add(functionalSentenceIndex)
        self.varSources.add(-1)

    def getHeuristicValue(self):
        """ generated source for method getHeuristicValue """
        heuristic = 1
        for sourceIndex in sourceConjunctIndices:
            heuristic *= self.sourceConjunctSizes.get(sourceIndex)
        v = 0
        while v < len(self.varOrdering):
            if self.varSources.get(v) == -1 and self.functionalConjunctIndices.get(v) == -1:
                # It's not set by a source conjunct or a function
                heuristic *= self.varDomainSizes.get(self.varOrdering.get(v))
            v += 1
        # We want complete orderings to show up faster
        # so we add a little incentive to pick them
        # Add 1 to the value of non-complete orderings
        if len(self.varOrdering) < len(self.varsToAssign):
            heuristic += 1
        # 			print "Heuristic value is " + heuristic + " with functionalConjunctIndices " + functionalConjunctIndices;
        return heuristic

    def isComplete(self):
        """ generated source for method isComplete """
        return self.varOrdering.containsAll(self.varsToAssign)

    def getChildren(self, analyticFunctionOrdering):
        """ generated source for method getChildren """
        allChildren = ArrayList()
        allChildren.addAll(getSourceConjunctChildren())
        allChildren.addAll(getFunctionAddedChildren(analyticFunctionOrdering))
        # 			print "Number of children being added: " + len(allChildren);
        return allChildren

    def getSourceConjunctChildren(self):
        """ generated source for method getSourceConjunctChildren """
        children = ArrayList()
        # If we are already using functions, short-circuit to cut off
        # repetition of the search space
        for index in functionalConjunctIndices:
            if index != -1:
                return Collections.emptyList()
        # This means we want a reference to the original list of conjuncts.
        lastSourceConjunctIndex = -1
        if not self.sourceConjunctIndices.isEmpty():
            lastSourceConjunctIndex = self.sourceConjunctIndices.get(len(self.sourceConjunctIndices) - 1)
        i = lastSourceConjunctIndex + 1
        while i < len(self.sourceConjunctCandidates):
            children.add(IterationOrderCandidate(self, i))
            i += 1
        return children

    def getFunctionAddedChildren(self, analyticFunctionOrdering):
        """ generated source for method getFunctionAddedChildren """
        # We can't just add those functions that
        # are "ready" to be added. We should be adding all those variables
        # "leading up to" the functions and then applying the functions.
        # We can even take this one step further by only adding one child
        # per remaining constant function; we choose as our function output the
        # variable that is a candidate for functionhood that has the
        # largest domain, or one that is tied for largest.
        # New criterion: Must also NOT be in preassignment.
        children = ArrayList()
        # It would be really nice here to just analytically choose
        # the set of functions we're going to use.
        # Here's one approach for doing that:
        # For each variable, get a list of the functions that could
        # potentially produce it.
        # For all the variables with no functions, add them.
        # Then repeatedly find the function with the fewest
        # number of additional variables (hopefully 0!) needed to
        # specify it and add it as a function.
        # The goal here is not to be optimal, but to be efficient!
        # Certain games (e.g. Pentago) break the old complete search method!
        # TODO: Eventual possible optimization here:
        # If something is dependent on a connected component that it is
        # not part of, wait until the connected component is resolved
        # (or something like that...)
        if analyticFunctionOrdering and len(self.functionalSentencesInfo) > 8:
            # For each variable, a list of functions
            # (refer to functions by their indices)
            # and the set of outstanding vars they depend on...
            # We start by adding to the varOrdering the vars not produced by functions
            # First, we have to find them
            while i < len(self.functionalSentencesInfo):
                for producibleVar in producibleVars:
                    if not functionsProducingVars.containsKey(producibleVar):
                        functionsProducingVars.put(producibleVar, HashSet())
                    functionsProducingVars.get(producibleVar).add(i)
                i += 1
            # Non-producible vars get iterated over before we start
            # deciding which functions to add
            for var in varsToAssign:
                if not self.varOrdering.contains(var):
                    if not functionsProducingVars.containsKey(var):
                        # Add var to the ordering
                        self.varOrdering.add(var)
                        self.functionalConjunctIndices.add(-1)
                        self.varSources.add(-1)
            # Map is from potential set of dependencies to function indices
            # Create this map...
            while i < len(self.functionalSentencesInfo):
                # Variables already in varOrdering don't go in dependents list
                producibleVars.removeAll(self.varOrdering)
                allVars.removeAll(self.varOrdering)
                for producibleVar in producibleVars:
                    dependencies.addAll(allVars)
                    dependencies.remove(producibleVar)
                    if not functionsHavingDependencies.containsKey(dependencies):
                        functionsHavingDependencies.put(dependencies, HashSet())
                    functionsHavingDependencies.get(dependencies).add(i)
                i += 1
            # Now, we can keep creating functions to generate the remaining variables
            while len(self.varOrdering) < len(self.varsToAssign):
                if functionsHavingDependencies.isEmpty():
                    raise RuntimeException("We should not run out of functions we could use")
                # Find the smallest set of dependencies
                if functionsHavingDependencies.containsKey(Collections.emptySet()):
                    dependencySetToUse = Collections.emptySet()
                else:
                    for dependencySet in functionsHavingDependencies.keySet():
                        if len(dependencySet) < smallestSize:
                            smallestSize = len(dependencySet)
                            dependencySetToUse = dependencySet
                # See if any of the functions are applicable
                for function_ in functions:
                    producibleVars.removeAll(dependencySetToUse)
                    producibleVars.removeAll(self.varOrdering)
                    if not 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 var in dependencySetToUse:
                        self.varOrdering.add(var)
                        self.functionalConjunctIndices.add(-1)
                        self.varSources.add(-1)
                    # 2) Add the function's produced variable (varProduced)
                    self.varOrdering.add(varProduced)
                    self.functionalConjunctIndices.add(functionToUse)
                    self.varSources.add(-1)
                    # 3) Remove all vars added this way from all dependency sets
                    addedVars.addAll(dependencySetToUse)
                    addedVars.add(varProduced)
                    # Tricky, because we have to merge sets
                    # Easier to use a new map
                    for entry in functionsHavingDependencies.entrySet():
                        newKey.removeAll(addedVars)
                        if not newFunctionsHavingDependencies.containsKey(newKey):
                            newFunctionsHavingDependencies.put(newKey, HashSet())
                        newFunctionsHavingDependencies.get(newKey).addAll(entry.getValue())
                    functionsHavingDependencies = newFunctionsHavingDependencies
                    # 4) Remove this function from the lists?
                    for functionSet in 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(IterationOrderCandidate(self))
        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.
            if not self.functionalConjunctIndices.isEmpty():
                lastFunctionUsedIndex = Collections.max(self.functionalConjunctIndices)
            while i < len(self.functionalConjunctIndices):
                if self.functionalConjunctIndices.get(i) != -1:
                    varsProducedByFunctions.add(self.varOrdering.get(i))
                i += 1
            while i < len(self.functionalSentencesInfo):
                if i < lastFunctionUsedIndex:
                    # We need to figure out whether i could use any of the
                    # vars we're producing with functions
                    # TODO: Try this with a finer grain
                    # i.e., see if i needs a var from a function that is after
                    # it, not one that might be before it
                    if Collections.disjoint(varsInSentence, varsProducedByFunctions):
                        continue 
                # What is the best variable to grab from this form, if there are any?
                if bestVariable == None:
                    continue 
                children.add(newCandidate)
                i += 1
            # If there are no more functions to add, add the completed version
            if children.isEmpty():
                children.add(IterationOrderCandidate(self))
            return children

    def getBestVariable(self, functionalSentence, functionInfo):
        """ generated source for method getBestVariable """
        # If all the variables that can be set by the functional sentence are in
        # the varOrdering, we return null. Otherwise, we return one of
        # those with the largest domain.
        # The FunctionInfo is sentence-independent, so we need the context
        # of the sentence (which has variables in it).
        tuple_ = GdlUtils.getTupleFromSentence(functionalSentence)
        dependentSlots = functionInfo.getDependentSlots()
        if len(tuple_) != len(dependentSlots):
            raise RuntimeException("Mismatched sentence " + functionalSentence + " and constant form " + functionInfo)
        candidateVars = HashSet()
        i = 0
        while i < len(tuple_):
            if isinstance(term, (GdlVariable, )) and dependentSlots.get(i) and not self.varOrdering.contains(term) and self.varsToAssign.contains(term):
                candidateVars.add(term)
            i += 1
        # Now we look at the domains, trying to find the largest
        bestVar = None
        bestDomainSize = 0
        for var in candidateVars:
            if domainSize > bestDomainSize:
                bestVar = var
                bestDomainSize = domainSize
        return bestVar
        # null if none are usable

    # This class has a natural ordering that is inconsistent with equals.
    def compareTo(self, o):
        """ generated source for method compareTo """
        diff = self.getHeuristicValue() - o.getHeuristicValue()
        if diff < 0:
            return -1
        elif diff == 0:
            return 0
        else:
            return 1

    def __str__(self):
        """ generated source for method toString """
        return self.varOrdering.__str__() + " with sources " + self.getSourceConjuncts().__str__() + "; functional?: " + self.functionalConjunctIndices + "; domain sizes are " + self.varDomainSizes