details: http://hg.sympy.org/sympy/rev/e4bd1b23bc34 changeset: 1836:e4bd1b23bc34 user: Andy R. Terrel <[EMAIL PROTECTED]> date: Fri Oct 17 08:33:24 2008 +0200 description: This patch implements computation for antiderivatives, and integration for one variable with limits.
diffs (157 lines): diff -r 1ec456a9f32a -r e4bd1b23bc34 sympy/functions/elementary/piecewise.py --- a/sympy/functions/elementary/piecewise.py Fri Oct 17 08:33:19 2008 +0200 +++ b/sympy/functions/elementary/piecewise.py Fri Oct 17 08:33:24 2008 +0200 @@ -103,6 +103,89 @@ new_ecpairs.append( (new_expr, new_cond) ) return Piecewise(*new_ecpairs) + def _eval_integral(self,x): + from sympy.integrals import integrate + return Piecewise(*[(integrate(expr, x),cond) \ + for expr, cond in self.args]) + + def _eval_interval(self, sym, ab): + """Evaluates the function along the sym in a given interval ab""" + # FIXME: Currently only supports conds of type sym < Num, or Num < sym + int_expr = [] + a, b = ab + mul = 1 + if a > b: + a = ab[1]; b = ab[0]; mul = -1 + default = None + + # Determine what intervals the expr,cond pairs affect. + # 1) If cond is True, then log it as default + # 1.1) Currently if cond can't be evaluated, throw NotImplentedError. + # 2) For each inequality, if previous cond defines part of the interval + # update the new conds interval. + # - eg x < 1, x < 3 -> [oo,1],[1,3] instead of [oo,1],[oo,3] + # 3) Sort the intervals to make it easier to find correct exprs + for expr, cond in self.args: + if type(cond) == bool: + if cond: + default = expr + break + else: + continue + curr = list(cond.args) + if cond.args[0] == sym: + curr[0] = S.NegativeInfinity + elif cond.args[1] == sym: + curr[1] = S.Infinity + else: + raise NotImplementedError, \ + "Currently only supporting evaluation with only "\ + "sym on one side fo the relation." + curr = [max(a,curr[0]),min(b,curr[1])] + for n in xrange(len(int_expr)): + if self.__eval_cond(curr[0] < int_expr[n][1]) and \ + self.__eval_cond(curr[0] >= int_expr[n][0]): + curr[0] = int_expr[n][1] + if self.__eval_cond(curr[1] > int_expr[n][0]) and \ + self.__eval_cond(curr[1] <= int_expr[n][1]): + curr[1] = int_expr[n][0] + if self.__eval_cond(curr[0] < curr[1]): + int_expr.append(curr+[expr]) + int_expr.sort(lambda x,y:1 if x[0] > y[0] else -1) + + # Add holes to list of intervals if there is a default value, + # otherwise raise a ValueError. + holes = [] + curr_low = a + for int_a, int_b, expr in int_expr: + if curr_low < int_a: + holes.append([curr_low, min(b,int_a), default]) + curr_low = int_b + if curr_low > b: + break + if holes and default != None: + int_expr.extend(holes) + elif holes and default == None: + raise ValueError, "Called interval evaluation over piecewise "\ + "function on undefined intervals %s" %\ + ", ".join([str((h[0],h[1])) for h in holes]) + + # Finally run through the intervals and sum the evaluation. + ret_fun = 0 + for int_a, int_b, expr in int_expr: + B = expr.subs(sym, min(b,int_b)) + if B is S.NaN: + B = limit(expr, sym, min(b,int_b)) + if B is S.NaN: + return self + A = expr.subs(sym, max(a,int_a)) + if A is S.NaN: + A = limit(expr, sym, max(a,int_a)) + if A is S.NaN: + return self + ret_fun += B - A + return mul * ret_fun + def _eval_derivative(self, s): return Piecewise(*[(diff(expr,s),cond) for expr, cond in self.args]) diff -r 1ec456a9f32a -r e4bd1b23bc34 sympy/functions/elementary/tests/test_piecewise.py --- a/sympy/functions/elementary/tests/test_piecewise.py Fri Oct 17 08:33:19 2008 +0200 +++ b/sympy/functions/elementary/tests/test_piecewise.py Fri Oct 17 08:33:24 2008 +0200 @@ -59,3 +59,26 @@ assert p + f == f + p assert p + dp == dp + p assert p - dp == -(dp - p) + + # Test _eval_interval + f1 = x*y + 2 + f2 = x*y**2 + 3 + peval = Piecewise( (f1, x<0), (f2, x>0)) + peval_interval = f1.subs(x,0) - f1.subs(x,-1) + f2.subs(x,1) - f2.subs(x,0) + assert peval._eval_interval(x,(-1,1)) == peval_interval + + # Test integration + p_int = Piecewise((-x,x < -1), (x**3/3.0, x < 0), (-x + x*log(x), x >= 0)) + assert integrate(p,x) == p_int + p = Piecewise((x, x < 1),(x**2, -1 <= x),(x,3<x)) + assert integrate(p,(x,-2,2)) == 5.0/6.0 + assert integrate(p,(x,2,-2)) == -5.0/6.0 + p = Piecewise((0, x < 0), (1,x < 1), (0, x < 2), (1, x < 3), (0, True)) + assert integrate(p, (x,-oo,oo)) == 2 + p = Piecewise((x, x < -10),(x**2, x <= -1),(x, 1 < x)) + exception_called = False + try: + integrate(p,(x,-2,2)) + except ValueError: + exception_called = True + assert exception_called diff -r 1ec456a9f32a -r e4bd1b23bc34 sympy/integrals/integrals.py --- a/sympy/integrals/integrals.py Fri Oct 17 08:33:19 2008 +0200 +++ b/sympy/integrals/integrals.py Fri Oct 17 08:33:24 2008 +0200 @@ -9,7 +9,7 @@ from sympy.series import limit from sympy.polys import Poly from sympy.solvers import solve -from sympy.functions import DiracDelta, Heaviside +from sympy.functions import DiracDelta, Heaviside, Piecewise class Integral(Basic): """Represents unevaluated integral.""" @@ -132,6 +132,10 @@ if ab is None: function = antideriv else: + if isinstance(antideriv,Piecewise): + function = antideriv._eval_interval(x,ab) + continue + a,b = ab A = antideriv.subs(x, a) @@ -241,6 +245,10 @@ # see Polynomial for details. if isinstance(f, Poly): return f.integrate(x) + + # Piecewise antiderivatives need to call special integrate. + if isinstance(f,Piecewise): + return f._eval_integral(x) # let's cut it short if `f` does not depend on `x` if not f.has(x): --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sympy-commits" group. To post to this group, send email to sympy-commits@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sympy-commits?hl=en -~----------~----~----~----~------~----~------~--~---