From 227f60ba07611606d5ddfdc2020139a4786dbe08 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 20 Nov 2006 23:23:45 -0500 Subject: [PATCH] [pymbolic @ inform@tiker.net-20061121042345-721a47327c3a8afa] Add working coefficient finder. Multiple fixes. --- src/__init__.py | 2 + src/mapper/coefficient_finder.py | 87 ++++++++++++++++++++++++++++++++ src/mapper/dependency.py | 4 +- src/mapper/evaluator.py | 22 ++++++-- src/polynomial.py | 6 +++ src/primitives.py | 4 ++ src/rational.py | 5 +- 7 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 src/mapper/coefficient_finder.py diff --git a/src/__init__.py b/src/__init__.py index 135e968..cafeb17 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -7,6 +7,7 @@ import pymbolic.mapper.dependency import pymbolic.mapper.substitutor import pymbolic.mapper.differentiator import pymbolic.mapper.expander +import pymbolic.mapper.coefficient_finder import pymbolic.primitives var = pymbolic.primitives.Variable @@ -24,6 +25,7 @@ get_dependencies = pymbolic.mapper.dependency.get_dependencies substitute = pymbolic.mapper.substitutor.substitute differentiate = pymbolic.mapper.differentiator.differentiate expand = pymbolic.mapper.expander.expand +find_coefficient = pymbolic.mapper.coefficient_finder.find_coefficient diff --git a/src/mapper/coefficient_finder.py b/src/mapper/coefficient_finder.py new file mode 100644 index 0000000..1b2f2c1 --- /dev/null +++ b/src/mapper/coefficient_finder.py @@ -0,0 +1,87 @@ +import pymbolic +from pymbolic.mapper import RecursiveMapper + + + +class CoefficientFinder(RecursiveMapper): + """Find the coefficient of `term' in `expr'. + + The expression to which this is applied should be fully expanded + and collected. See expander.py. + """ + + def __init__(self, term): + self.Term = term + + def map_constant(self,expr): + return 0 + + def map_leaf(self, expr): + if expr == self.Term: + return 1 + else: + return 0 + + map_call = map_leaf + map_subscript = map_leaf + map_lookup = map_leaf + map_variable = map_leaf + map_power = map_leaf + + def map_negation(self, expr): + return -self.rec(expr.child) + + def map_sum(self, expr): + return pymbolic.sum(self(child) for child in expr.children) + + def map_product(self, expr): + if expr == self.Term: + return 1 + + # FIXME this is dumber than necessary + child_coeffs = [self(child) for child in expr.children] + result = pymbolic.sum( + pymbolic.product(expr.children[:i]) + *mapped_child* + pymbolic.product(expr.children[(i+1):]) + for i, mapped_child in enumerate(child_coeffs) + if mapped_child) + return result + + def map_quotient(self, expr): + if expr == self.Term: + return 1 + + if self.Term == pymbolic.quotient(1, expr.denominator): + return expr.numerator + + return pymbolic.quotient(self(expr.numerator), expr.denominator) + + def map_polynomial(self, expr): + if expr == self.Term: + return 1 + + # FIXME this is incorrect in a good bunch of cases + from pymbolic.primitives import Power + + if expr.Base == self.Term: + return expr.get_coefficient(1) + elif isinstance(self.Term, Power) and self.Term.base == expr.base and \ + isinstance(expr.exponent, int): + return expr.get_coefficient(expr.exponent) + else: + return pymbolic.sum(self(coeff)*expr.base**exp + for exp, coeff in expr.data) + + + + + +def find_coefficient(expr, term): + """Find the coefficient of `term' in `expr'. + + The expression to which this is applied should be fully expanded + and collected. See expander.py. + """ + + return CoefficientFinder(term)(expr) diff --git a/src/mapper/dependency.py b/src/mapper/dependency.py index c9a7c67..13ba087 100644 --- a/src/mapper/dependency.py +++ b/src/mapper/dependency.py @@ -25,13 +25,13 @@ class DependencyMapper(CombineMapper): if self.IncludeCalls: return set([expr]) else: - return CombineMapper.map_subscript(self, expr) + return CombineMapper.map_call(self, expr) def map_lookup(self, expr, *args, **kwargs): if self.IncludeLookups: return set([expr]) else: - return CombineMapper.map_subscript(self, expr) + return CombineMapper.map_lookup(self, expr) def map_subscript(self, expr): if self.IncludeSubscripts: diff --git a/src/mapper/evaluator.py b/src/mapper/evaluator.py index ffc0255..b353d4b 100644 --- a/src/mapper/evaluator.py +++ b/src/mapper/evaluator.py @@ -1,5 +1,5 @@ from __future__ import division -import pymbolic.mapper +from pymbolic.mapper import RecursiveMapper @@ -10,7 +10,7 @@ class UnknownVariableError(Exception): -class EvaluationMapper(pymbolic.mapper.Mapper): +class EvaluationMapper(RecursiveMapper): def __init__(self, context={}): self.Context = context @@ -46,8 +46,8 @@ class EvaluationMapper(pymbolic.mapper.Mapper): result *= self.rec(child) return result - def map_rational(self, expr): - return self.rec(expr.numerator) / self.rec(expr.denominator) + def map_quotient(self, expr): + return pymbolic.quotient(self.rec(expr.numerator), self.rec(expr.denominator)) def map_power(self, expr): return self.rec(expr.base) ** self.rec(expr.exponent) @@ -63,6 +63,20 @@ class EvaluationMapper(pymbolic.mapper.Mapper): +class FloatEvaluationMapper(EvaluationMapper): + def map_constant(self, expr): + return float(expr) + + def map_rational(self, expr): + return self.rec(expr.numerator) / self.rec(expr.denominator) + + + + def evaluate(expression, context={}): return EvaluationMapper(context)(expression) + +def evaluate_to_float(expression, context={}): + return FloatEvaluationMapper(context)(expression) + diff --git a/src/polynomial.py b/src/polynomial.py index c50d9bd..e016808 100644 --- a/src/polynomial.py +++ b/src/polynomial.py @@ -254,6 +254,12 @@ class Polynomial(Expression): context = dict((dep, dep) for dep in deps) return pymbolic.evaluate(self, context) + def get_coefficient(self, sought_exp): + # FIXME use bisection + for exp, coeff in self.Data: + if exp == sought_exp: + return coeff + return 0 diff --git a/src/primitives.py b/src/primitives.py index 0f4f950..7ecfea4 100644 --- a/src/primitives.py +++ b/src/primitives.py @@ -86,6 +86,10 @@ class Expression(object): self._HashValue = self.invoke_mapper(HashMapper()) return self._HashValue + def __float__(self): + from pymbolic.mapper.evaluator import evaluate_to_float + return evaluate_to_float(self) + def __str__(self): from pymbolic.mapper.stringifier import StringifyMapper, PREC_NONE return StringifyMapper()(self, PREC_NONE) diff --git a/src/rational.py b/src/rational.py index 63446f7..48dad40 100644 --- a/src/rational.py +++ b/src/rational.py @@ -26,7 +26,7 @@ class Rational(primitives.Expression): def __neg__(self): return Rational(-self.Numerator, self.Denominator) - def __eq__(self): + def __eq__(self, other): if not isinstance(other, Rational): other = Rational(other) @@ -98,9 +98,6 @@ class Rational(primitives.Expression): def __pow__(self, other): return Rational(self.Denominator**other, self.Numerator**other) - def __float__(self): - return float(self.Numerator) / flaot(self.Denominator) - def __getinitargs__(self): return (self.Numerator, self.Denominator) -- GitLab