Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

piecewise functions and integration / arithmetic do not play well together #1773

Closed
williamstein opened this issue Jan 14, 2008 · 26 comments
Closed

Comments

@williamstein
Copy link
Contributor

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

CC: @kcrisman @jondo @vbraun @slel @mkoeppe @eviatarbach @rwst

Component: calculus

Author: Marcelo Forets

Branch/Commit: fe8304e

Reviewer: Volker Braun

Issue created by migration from https://trac.sagemath.org/ticket/1773

@williamstein williamstein added this to the sage-5.11 milestone Jan 14, 2008
@williamstein williamstein self-assigned this Jan 14, 2008
@garyfurnish garyfurnish mannequin assigned garyfurnish and unassigned williamstein Mar 16, 2008
@rlmill
Copy link
Mannequin

rlmill mannequin commented Jan 22, 2009

comment:2

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

@rlmill
Copy link
Mannequin

rlmill mannequin commented Jan 22, 2009

comment:3

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?

@kcrisman
Copy link
Member

comment:5

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

@kcrisman
Copy link
Member

comment:6

Replying to @rlmill:

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              

@jdemeyer jdemeyer modified the milestones: sage-5.11, sage-5.12 Aug 13, 2013
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.1, sage-6.2 Jan 30, 2014
@ppurka
Copy link
Member

ppurka commented Feb 23, 2014

Dependencies: #14801

@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.2, sage-6.3 May 6, 2014
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.3, sage-6.4 Aug 10, 2014
@mkoeppe
Copy link
Contributor

mkoeppe commented Jun 25, 2016

comment:13

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)

@mkoeppe mkoeppe modified the milestones: sage-6.4, sage-7.3 Jun 25, 2016
@rwst
Copy link

rwst commented Jun 26, 2016

comment:14

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

@mforets
Copy link
Mannequin

mforets mannequin commented May 7, 2017

comment:15

@rwst: 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

@mforets
Copy link
Mannequin

mforets mannequin commented May 7, 2017

Branch: u/mforets/1773

@mforets
Copy link
Mannequin

mforets mannequin commented May 7, 2017

Commit: 115c198

@mforets mforets mannequin added the s: needs review label May 7, 2017
@mforets
Copy link
Mannequin

mforets mannequin commented May 7, 2017

comment:16

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.

@rwst
Copy link

rwst commented May 8, 2017

comment:17

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)

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented May 8, 2017

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

41c5796pass independent variable

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented May 8, 2017

Changed commit from 115c198 to 41c5796

@mforets
Copy link
Mannequin

mforets mannequin commented May 8, 2017

comment:19

Replying to @rwst:

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].

@mforets
Copy link
Mannequin

mforets mannequin commented Jul 10, 2017

Author: Marcelo Forets

@fchapoton
Copy link
Contributor

Changed dependencies from #14801 to none

@fchapoton
Copy link
Contributor

comment:21

does not apply

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented May 31, 2018

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

20cb4f4add pow method to piecewise
ffea990pass independent variable

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented May 31, 2018

Changed commit from 41c5796 to ffea990

@videlec
Copy link
Contributor

videlec commented Aug 3, 2018

comment:23

update milestone 8.3 -> 8.4

@videlec videlec modified the milestones: sage-8.3, sage-8.4 Aug 3, 2018
@fchapoton
Copy link
Contributor

Changed branch from u/mforets/1773 to public/ticket/1773

@fchapoton
Copy link
Contributor

New commits:

fe8304eadd pow method to piecewise

@fchapoton
Copy link
Contributor

Changed commit from ffea990 to fe8304e

@vbraun
Copy link
Member

vbraun commented Dec 17, 2018

Reviewer: Volker Braun

@vbraun
Copy link
Member

vbraun commented Dec 23, 2018

Changed branch from public/ticket/1773 to fe8304e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants