Opened 15 years ago

Closed 4 years ago

#1773 closed defect (fixed)

piecewise functions and integration / arithmetic do not play well together

Reported by: William Stein Owned by: Gary Furnish
Priority: major Milestone: sage-8.6
Component: calculus Keywords:
Cc: Karl-Dieter Crisman, Robert Pollak, Volker Braun, Samuel Lelièvre, Matthias Köppe, Eviatar Bach, Ralf Stephan Merged in:
Authors: Marcelo Forets Reviewers: Volker Braun
Report Upstream: N/A Work issues:
Branch: fe8304e (Commits, GitHub, GitLab) Commit: fe8304efd0d3b898932dfc0bb2b68a701a88fd41
Dependencies: Stopgaps:

Status badges

Description

On 1/13/08, Hector Villafuerte <> wrote:
> 
> I defined a piecewise function (specifically, a triangular wave) like this:
> 
> sage: f1(x) = -abs(x) + 1
> sage: f2(x) = abs(x - 2) - 1
> sage: tri_wave = piecewise([ [(-1,1), f1], [(1,3), f2]])
> 
> One can plot it and it looks very nice:
> 
> sage: tri_wave.plot()
> 
> But while calculating this integral I get "ValueError: Value not
> defined outside of domain."
> 
> sage: integrate(tri_wave(x)^2, x, -1, 3)
> 
> Is there a way to integrate piecewise-defined functions?
> As always, thanks for your help,

This is clearly broken.  As a band-aide, you can at least
numerically integrate as follows:

sage: integral_numerical(lambda x: tri_wave(x)^2, -1, 3)
(1.3333333333333333, 1.4765966227514582e-14)

The first output (1.3333...) is the answer, and the second is an error bound.

 -- William

Change History (26)

comment:1 Changed 15 years ago by Gary Furnish

Owner: changed from William Stein to Gary Furnish
Status: newassigned

comment:2 Changed 14 years ago by Robert Miller

This isn't specific to integrate. The problem is that piecewise functions don't play well with *symbolics*

sage: f1(x) = -abs(x) + 1
sage: f2(x) = abs(x - 2) - 1
sage: tri_wave = piecewise([ [(-1,1), f1], [(1,3), f2]])
sage: tri_wave(x)
SAME ERROR

comment:3 Changed 14 years ago by Robert Miller

What should maybe happen is in piecewise.py, in the __call__ method, if a SymbolicVariable? is passed in as x0, it should return a CallableSymbolicExpression? which just in turn calls back to the __call__ method again. Does this sound reasonable? If so, how would one implement this?

comment:4 Changed 12 years ago by Karl-Dieter Crisman

Cc: Karl-Dieter Crisman added
Report Upstream: N/A

comment:5 Changed 11 years ago by Karl-Dieter Crisman

See also #11225, which is about plotting - but sometimes this stuff causes plots to not work, of course.

comment:6 in reply to:  2 Changed 11 years ago by Karl-Dieter Crisman

Replying to rlm:

This isn't specific to integrate. The problem is that piecewise functions don't play well with *symbolics*

sage: f1(x) = -abs(x) + 1
sage: f2(x) = abs(x - 2) - 1
sage: tri_wave = piecewise([ [(-1,1), f1], [(1,3), f2]])
sage: tri_wave(x)
SAME ERROR

Or see what happens when we try to multiply piecewise and symbolic.

sage: f = Piecewise([[(0,pi/2),-1],[(pi/2,pi),2]]) 
sage: f*sin(x)
---------------------------------------------------------------------------
AttributeError              

comment:7 Changed 9 years ago by Jeroen Demeyer

Milestone: sage-5.11sage-5.12

comment:8 Changed 9 years ago by Robert Pollak

Cc: Robert Pollak added

comment:9 Changed 9 years ago by For batch modifications

Milestone: sage-6.1sage-6.2

comment:10 Changed 9 years ago by Punarbasu Purkayastha

Dependencies: #14801

comment:11 Changed 8 years ago by For batch modifications

Milestone: sage-6.2sage-6.3

comment:12 Changed 8 years ago by For batch modifications

Milestone: sage-6.3sage-6.4

comment:13 Changed 6 years ago by Matthias Köppe

Cc: Volker Braun Samuel Lelièvre Matthias Köppe Eviatar Bach Ralf Stephan added
Milestone: sage-6.4sage-7.3

While all the examples appearing in the comments are fixed with the new piecewise of #14801, the original bug example still fails (but with a different error message).

Cc'ing #14801's cc list.

sage: f1(x) = -abs(x) + 1
sage: f2(x) = abs(x - 2) - 1
sage: tri_wave = piecewise([ [(-1,1), f1], [(1,3), f2]])
sage: tri_wave.plot()
Launched png viewer for Graphics object consisting of 1 graphics primitive
sage: integrate(tri_wave(x)^2, x, -1, 3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-9387c34a513c> in <module>()
----> 1 integrate(tri_wave(x)**Integer(2), x, -Integer(1), Integer(3))

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/misc/functional.py in integral(x, *args, **kwds)
    663     """
    664     if hasattr(x, 'integral'):
--> 665         return x.integral(*args, **kwds)
    666     else:
    667         from sage.symbolic.ring import SR

/Users/mkoeppe/cvs/sage/src/sage/symbolic/expression.pyx in sage.symbolic.expression.Expression.integral (/Users/mkoeppe/cvs/sage/src/build/cythonized/sage/symbolic/expression.cpp:60225)()
  11484                     R = ring.SR
  11485             return R(integral(f, v, a, b, **kwds))
> 11486         return integral(self, *args, **kwds)
  11487 
  11488     integrate = integral

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/symbolic/integration/integral.py in integrate(expression, v, a, b, algorithm, hold)
    763         return indefinite_integral(expression, v, hold=hold)
    764     else:
--> 765         return definite_integral(expression, v, a, b, hold=hold)
    766 
    767 integral = integrate

/Users/mkoeppe/cvs/sage/src/sage/symbolic/function.pyx in sage.symbolic.function.BuiltinFunction.__call__ (/Users/mkoeppe/cvs/sage/src/build/cythonized/sage/symbolic/function.cpp:11170)()
    970             res = self._evalf_try_(*args)
    971             if res is None:
--> 972                 res = super(BuiltinFunction, self).__call__(
    973                         *args, coerce=coerce, hold=hold)
    974 

/Users/mkoeppe/cvs/sage/src/sage/symbolic/function.pyx in sage.symbolic.function.Function.__call__ (/Users/mkoeppe/cvs/sage/src/build/cythonized/sage/symbolic/function.cpp:6921)()
    481             for i from 0 <= i < len(args):
    482                 vec.push_back((<Expression>args[i])._gobj)
--> 483             res = g_function_evalv(self._serial, vec, hold)
    484         elif self._nargs == 1:
    485             res = g_function_eval1(self._serial,

/Users/mkoeppe/cvs/sage/src/sage/symbolic/function.pyx in sage.symbolic.function.BuiltinFunction._evalf_or_eval_ (/Users/mkoeppe/cvs/sage/src/build/cythonized/sage/symbolic/function.cpp:12417)()
   1059         res = self._evalf_try_(*args)
   1060         if res is None:
-> 1061             return self._eval0_(*args)
   1062         else:
   1063             return res

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/symbolic/integration/integral.py in _eval_(self, f, x, a, b)
    176         for integrator in self.integrators:
    177             try:
--> 178                 return integrator(*args)
    179             except NotImplementedError:
    180                 pass

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/symbolic/integration/external.py in maxima_integrator(expression, v, a, b)
     22         result = maxima.sr_integral(expression,v)
     23     else:
---> 24         result = maxima.sr_integral(expression, v, a, b)
     25     return result._sage_()
     26 

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/interfaces/maxima_lib.py in sr_integral(self, *args)
    796         """
    797         try:
--> 798             return max_to_sr(maxima_eval(([max_integrate],[sr_to_max(SR(a)) for a in args])))
    799         except RuntimeError as error:
    800             s = str(error)

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/interfaces/maxima_lib.py in max_to_sr(expr)
   1634         op_max=caar(expr)
   1635         if op_max in special_max_to_sage:
-> 1636             return special_max_to_sage[op_max](expr)
   1637         if not(op_max in max_op_dict):
   1638             op_max_str=maxprint(op_max).python()[1:-1]

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/interfaces/maxima_lib.py in dummy_integrate(expr)
   1428         integrate(f(x), x, 0, 10)
   1429     """
-> 1430     args=[max_to_sr(a) for a in cdr(expr)]
   1431     if len(args) == 4 :
   1432         return sage.symbolic.integration.integral.definite_integral(*args,

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/interfaces/maxima_lib.py in max_to_sr(expr)
   1651             op=max_op_dict[op_max]
   1652         max_args=cdr(expr)
-> 1653         args=[max_to_sr(a) for a in max_args]
   1654         return op(*args)
   1655     elif expr.symbolp():

/Users/mkoeppe/cvs/sage/local/lib/python2.7/site-packages/sage/interfaces/maxima_lib.py in max_to_sr(expr)
   1652         max_args=cdr(expr)
   1653         args=[max_to_sr(a) for a in max_args]
-> 1654         return op(*args)
   1655     elif expr.symbolp():
   1656         if not(expr in max_sym_dict):

TypeError: __call__() takes exactly 2 arguments (3 given)

comment:14 Changed 6 years ago by Ralf Stephan

The problem on first sight here is that operations on piecewise do not get translated to what is expected, i.e., squaring the pieces. Also it seems that Maxima does not convert them, nor is it considering loading pw.mac without which it simply knows nothing about piecewise functions. So we must either load this package when encountering piecewise in the Maxima interface then convert, or the expression must be simplified, i.e., the operations applied piecewise, probably by Pynac. Or both.

Of course, the integral member function is accessible with pure piecewise objects:

sage: tri_wave1 = piecewise([ [(-1,1), f1^2], [(1,3), f2^2]])
sage: tri_wave1.integral(definite=True)
4/3

comment:15 Changed 5 years ago by Marcelo Forets

Branch: u/mforets/1773
Commit: 115c198b1b2cf2bb63423d89dad14c402c055454
Status: newneeds_review

@rws: does adding a new __pow__ method in piecewise fix the issue or not? (cf. code+test added in this branch)


... well it doesn't work for the OP problem, but that's another thing (misuse?) i guess, since:

sage: integrate(piecewise([ [(-1,1), x], [(1,3), x^2]]), x, -1, 3)
...
ValueError: point 3 is not in the domain

although

sage: integrate(piecewise([ [(-1,1), x], [(1,3), x^2]]), x)
piecewise(x|-->1/2*x^2 - 1/2 on (-1, 1), x|-->1/3*x^3 - 1/3 on (1, 3); x)

and with the current patch one has:

sage: integrate(piecewise([ [(-1,1), x], [(1,3), x^2]])**2, x)
piecewise(x|-->1/3*x^3 + 1/3 on (-1, 1), x|-->1/5*x^5 + 7/15 on (1, 3); x)

New commits:

115c198add pow method to piecewise

comment:16 Changed 5 years ago by Marcelo Forets

Hmmm, what i've uploaded doesn't work well with symbolic expressions as exponents!

sage: f = piecewise([ [(-1,1), x], [(1,3), x^2]])
sage: k = var('k')
sage: f**k
piecewise(k|-->x^k on (-1, 1), k|-->(x^2)^k on (1, 3); k)

the independent variable is misunderstood.

comment:17 Changed 5 years ago by Ralf Stephan

This seems to depend on if the expression contains a lexicographically earlier symbol:

sage: f^y
piecewise(x|-->x^y on (-1, 1), x|-->(x^2)^y on (1, 3); x)
sage: f^k
piecewise(k|-->x^k on (-1, 1), k|-->(x^2)^k on (1, 3); k)
sage: f^z
piecewise(x|-->x^z on (-1, 1), x|-->(x^2)^z on (1, 3); x)
sage: f^t
piecewise(t|-->x^t on (-1, 1), t|-->(x^2)^t on (1, 3); t)
Last edited 5 years ago by Ralf Stephan (previous) (diff)

comment:18 Changed 5 years ago by git

Commit: 115c198b1b2cf2bb63423d89dad14c402c05545441c5796fe91dbb403f21978d836b2570633bca86

Branch pushed to git repo; I updated commit sha1. New commits:

41c5796pass independent variable

comment:19 in reply to:  17 Changed 5 years ago by Marcelo Forets

Replying to rws:

This seems to depend on if the expression contains a lexicographically earlier symbol:

sage: f^y
piecewise(x|-->x^y on (-1, 1), x|-->(x^2)^y on (1, 3); x)
sage: f^k
piecewise(k|-->x^k on (-1, 1), k|-->(x^2)^k on (1, 3); k)
sage: f^z
piecewise(x|-->x^z on (-1, 1), x|-->(x^2)^z on (1, 3); x)
sage: f^t
piecewise(t|-->x^t on (-1, 1), t|-->(x^2)^t on (1, 3); t)

Ok, i see. as a workaround i've specified the var argument to the constructor, which gives the same result as self.variables()[0].

comment:20 Changed 5 years ago by Marcelo Forets

Authors: Marcelo Forets

comment:21 Changed 4 years ago by Frédéric Chapoton

Dependencies: #14801
Milestone: sage-7.3sage-8.3
Status: needs_reviewneeds_work

does not apply

comment:22 Changed 4 years ago by git

Commit: 41c5796fe91dbb403f21978d836b2570633bca86ffea99058531a07c82012ec9f4fec5183d7a3fb6

Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:

20cb4f4add pow method to piecewise
ffea990pass independent variable

comment:23 Changed 4 years ago by Vincent Delecroix

Milestone: sage-8.3sage-8.4

update milestone 8.3 -> 8.4

comment:24 Changed 4 years ago by Frédéric Chapoton

Branch: u/mforets/1773public/ticket/1773
Commit: ffea99058531a07c82012ec9f4fec5183d7a3fb6fe8304efd0d3b898932dfc0bb2b68a701a88fd41
Milestone: sage-8.4sage-8.6
Status: needs_workneeds_review

New commits:

fe8304eadd pow method to piecewise

comment:25 Changed 4 years ago by Volker Braun

Reviewers: Volker Braun
Status: needs_reviewpositive_review

comment:26 Changed 4 years ago by Volker Braun

Branch: public/ticket/1773fe8304efd0d3b898932dfc0bb2b68a701a88fd41
Resolution: fixed
Status: positive_reviewclosed
Note: See TracTickets for help on using tickets.