def _distributive(self): if self.type in __distributions: star = __distributions[self.type] extracted = [] factorList = Counter() def _pushToExtracted(child, count): assert count == 1 extracted.append(child) factorList.update(keysExcept(child.children, Expression.isConstant)) (rest, hasStar) = performIf(self.children, Expression.isType(star), _pushToExtracted) if hasStar: # Algorithm for factorization: # # 1. find the most common factor # 2. check if that factor has appeared >1 times. If no, quit. # 3. otherwise, scan for all children which contain that factor. # 4. remove that factor from those children, and create a new # a*(b+c+d) style expression. factorizedOnce = False while factorList: (commonest, count) = factorList.most_common(1)[0] if count == 1: if factorizedOnce: rest.update(extracted) return self.replaceChildren(rest) else: return None else: factorizedOnce = True oldExtracted = extracted extracted = [] newChildrenList = [] for child in oldExtracted: if commonest in child.children: factorList.subtract( keysExcept(child.children, Expression.isConstant)) newChildChildren = Counter(child.children) newChildChildren[commonest] -= 1 newChild = child.replaceChildren(newChildChildren) newChildrenList.append(newChild) else: extracted.append(child) newExpression = Expression( star, commonest, Expression(self.type, *newChildrenList)) extracted.append(newExpression) factorList.update( keysExcept(child.children, Expression.isConstant))
def _distributive(self): if self.type in __distributions: star = __distributions[self.type] extracted = [] factorList = Counter() def _pushToExtracted(child, count): assert count == 1 extracted.append(child) factorList.update( keysExcept(child.children, Expression.isConstant)) (rest, hasStar) = performIf(self.children, Expression.isType(star), _pushToExtracted) if hasStar: # Algorithm for factorization: # # 1. find the most common factor # 2. check if that factor has appeared >1 times. If no, quit. # 3. otherwise, scan for all children which contain that factor. # 4. remove that factor from those children, and create a new # a*(b+c+d) style expression. factorizedOnce = False while factorList: (commonest, count) = factorList.most_common(1)[0] if count == 1: if factorizedOnce: rest.update(extracted) return self.replaceChildren(rest) else: return None else: factorizedOnce = True oldExtracted = extracted extracted = [] newChildrenList = [] for child in oldExtracted: if commonest in child.children: factorList.subtract( keysExcept(child.children, Expression.isConstant)) newChildChildren = Counter(child.children) newChildChildren[commonest] -= 1 newChild = child.replaceChildren(newChildChildren) newChildrenList.append(newChild) else: extracted.append(child) newExpression = Expression( star, commonest, Expression(self.type, *newChildrenList)) extracted.append(newExpression) factorList.update( keysExcept(child.children, Expression.isConstant))
def _flatten(self): # flatten an expression tree of the same type by applying associativity. # a + (b + c) == a + b + c. if self.type in ('+', '*', '&', '|', '^', '&&', '||'): flatPart = Counter() def _flattenAction(child, count): nonlocal flatPart flatPart += Counter({k: v*count for k, v in child.children.items()}) (rest, hasFlatten) = performIf(self.children, Expression.isType(self.type), _flattenAction) if hasFlatten: rest += flatPart return self.replaceChildren(rest)
def _subtractionAndCompareWithZero(self): # a-b < 0 <=> a < b if self.type in ('==', '<=', '!=', '<'): otherChildIndex = __findNonZeroSide(self) if otherChildIndex >= 0: otherChild = self.children[otherChildIndex] if otherChild.type == '+': negatedFactors = Counter() def addNegatedFactor(child, count): nonlocal negatedFactors negatedFactors[-child] += count (positiveFactors, anyNeg) = performIf(otherChild.children, __isNegativeFactor, addNegatedFactor) if anyNeg: lhs = otherChild.replaceChildren(positiveFactors) rhs = otherChild.replaceChildren(negatedFactors) return self.replaceChildren([lhs, rhs])
def _nary(self): if self.type in __naryDefaultValue: default = __naryDefaultValue[self.type] val = default rests = Counter() totalValCount = 0 def _updateVal(child, count): nonlocal val, totalValCount if child.value != default: val = _applyNtimes(self.type, child.value, count, val) totalValCount += count (rests, _) = performIf(self.children, Expression.isConstant, _updateVal) if val != default: rests[Constant(val)] += 1 if totalValCount > 1 or (totalValCount == 1 and val == default): return self.replaceChildren(rests)
def _flatten(self): # flatten an expression tree of the same type by applying associativity. # a + (b + c) == a + b + c. if self.type in ('+', '*', '&', '|', '^', '&&', '||'): flatPart = Counter() def _flattenAction(child, count): nonlocal flatPart flatPart += Counter( {k: v * count for k, v in list(child.children.items())}) (rest, hasFlatten) = performIf(self.children, Expression.isType(self.type), _flattenAction) if hasFlatten: rest += flatPart return self.replaceChildren(rest)
def _nary(self): if self.type in __naryDefaultValue: default = __naryDefaultValue[self.type] val = default rests = Counter() totalValCount = 0 def _updateVal(child, count): nonlocal val, totalValCount if child.value != default: val = _applyNtimes(self.type, child.value, count, val) totalValCount += count (rests, _) = performIf(self.children, Expression.isConstant, _updateVal) if val != default: rests[Constant(val)] += 1 if totalValCount > 1 or (totalValCount == 1 and val == default): return self.replaceChildren(rests)
def _subtractionAndCompareWithZero(self): # a-b < 0 <=> a < b if self.type in ('==', '<=', '!=', '<'): otherChildIndex = __findNonZeroSide(self) if otherChildIndex >= 0: otherChild = self.children[otherChildIndex] if otherChild.type == '+': negatedFactors = Counter() def addNegatedFactor(child, count): nonlocal negatedFactors negatedFactors[-child] += count (positiveFactors, anyNeg) = performIf(otherChild.children, __isNegativeFactor, addNegatedFactor) if anyNeg: lhs = otherChild.replaceChildren(positiveFactors) rhs = otherChild.replaceChildren(negatedFactors) return self.replaceChildren([lhs, rhs])