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 _involution(self): # (a ^ a) == 0 if self.type == '^': if any(count > 1 for count in list(self.children.values())): return Expression( self.type, *(k for k, c in list(self.children.items()) if c % 2 != 0))
def _negatedComparison(self): # !(a < b) <=> b <= a if self.type == '!': child = self.children[0] if child.type in __negatedComparisonMap: return Expression(__negatedComparisonMap[child.type], child.children[1], child.children[0])
def _evaluteRepetition(child, count): grouped.append(Expression(star, child, Constant(count)))
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)) Expression.addSimplificationRule(_repetition, 'repetition (a+a+a=3*a)') Expression.addSimplificationRule(_distributive, 'distributive (a*b+a*c=a*(b+c))') if __name__ == '__main__': import symbolic.simplify.recursive from symbolic.expression import Symbol Expression.setDebugSimplify(True) a = Expression('+', Symbol('a'), Symbol('a'), Symbol('b'), Symbol('a'), Symbol('b'), Symbol('b'), Symbol('a'), Symbol('c')) + \ Expression('+', Symbol('c'), Symbol('a'), Symbol('c'), Symbol('c'), Symbol('b'), Symbol('a'), Symbol('a'), Symbol('d')) assert a.simplify() == Expression( '+', Expression('*', Symbol('a'), Constant(7)), Expression('*', Symbol('b'), Constant(4)), Expression('*', Symbol('c'), Constant(4)), Symbol('d'))
Expression.addSimplificationRule(_unary, 'fold constant (unary)') Expression.addSimplificationRule(_binary, 'fold constant (binary)') Expression.addSimplificationRule(_shortCircuit, 'short circuit') Expression.addSimplificationRule(_nary, 'fold constant (N-ary)') Expression.addSimplificationRule(_naryBaseCondition, 'base condition (N-ary)') Expression.addSimplificationRule(_evaluateIfThenElse, 'constant condition (?:)') if __name__ == '__main__': from symbolic.simplify.recursive import * from symbolic.expression import Symbol Expression.setDebugSimplify(True) a = Constant(3) / Constant(2) assert Constant(1.5) == a.simplify() a = Expression('+', Constant(1), Constant(5), Constant(12), Constant(44)) assert Constant(62) == a.simplify() a = Expression.if_(Expression.ge(Constant(7), Constant(2)), Constant(11), Constant(55)) assert Constant(11) == a.simplify() a = (Constant(1) ^ Constant(5) - Constant(122) // Constant(4))**Constant(2) assert Constant(676) == a.simplify() a = Expression('*', Symbol("foo"), Constant(0), Symbol("boo")) assert Constant(0) == a.simplify()
def _idempotent(self): # (a & a) == a if self.type in ('&', '|', '&&', '||'): if any(count > 1 for count in list(self.children.values())): return Expression(self.type, *list(self.children.keys()))
# (a ^ a) == 0 if self.type == '^': if any(count > 1 for count in list(self.children.values())): return Expression( self.type, *(k for k, c in list(self.children.items()) if c % 2 != 0)) Expression.addSimplificationRule(_flatten, 'commutative semigroup (a*(b*c) == a*b*c)') Expression.addSimplificationRule(_idempotent, 'idempotent ((a&a) == a)') Expression.addSimplificationRule(_involution, 'involution ((a^a) == 0)') if __name__ == '__main__': import symbolic.simplify.recursive from symbolic.expression import Symbol Expression.setDebugSimplify(True) a = Symbol('foo') + Symbol('bar') + Symbol( 'baz') + Symbol('ma') * Symbol('maz') - Symbol('y') assert a.simplify() == Expression( '+', Symbol('foo'), Symbol('bar'), Symbol('baz'), Expression('*', Symbol('ma'), Symbol('maz')), -Symbol('y')) a = (Expression('&', Symbol('foo'), Symbol('bar'), Symbol('foo'), Symbol('baz'), Symbol('bar'), Symbol('bar')) & \ Expression('^', Symbol('foo'), Symbol('bar'), Symbol('foo'), Symbol('baz'), Symbol('bar'), Symbol('bar'))) assert a.simplify() == Expression( '&', Symbol('foo'), Symbol('bar'), Symbol('baz'), Expression('^', Symbol('bar'), Symbol('baz')))