def getCondensationSet(cls, rule, model, checker, sentenceNameSource): """ generated source for method getCondensationSet """ varsInRule = GdlUtils.getVariables(rule) varsInHead = GdlUtils.getVariables(rule.getHead()) varsNotInHead = ArrayList(varsInRule) varsNotInHead.removeAll(varsInHead) for var in varsNotInHead: ConcurrencyUtils.checkForInterruption() for literal in rule.getBody(): if GdlUtils.getVariables(literal).contains(var): minSet.add(literal) for literal in minSet: if isinstance(literal, (GdlRelation, )): varsSupplied.addAll(GdlUtils.getVariables(literal)) elif isinstance(literal, (GdlDistinct, )) or isinstance(literal, (GdlNot, )): varsNeeded.addAll(GdlUtils.getVariables(literal)) varsNeeded.removeAll(varsSupplied) if not varsNeeded.isEmpty(): continue for varNeeded in varsNeeded: for literal in rule.getBody(): if isinstance(literal, (GdlRelation, )): if GdlUtils.getVariables(literal).contains(varNeeded): suppliers.add(literal) candidateSuppliersList.add(suppliers) for suppliers in candidateSuppliersList: if Collections.disjoint(suppliers, literalsToAdd): literalsToAdd.add(suppliers.iterator().next()) minSet.addAll(literalsToAdd) if goodCondensationSetByHeuristic(minSet, rule, model, checker, sentenceNameSource): return minSet return None
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