Limit of piecewise function

This exact question has been asked before (8 years ago, 2 years ago). So here goes, perhaps things have changed?

f(x) = piecewise([[(0,1),x],[[1,2],x/2]])
limit(f(x),x=1/2)


(Note that I'm not even looking at the point where the discontinuity occurs.)

I get the following error message

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/var/folders/mt/4xjm_x515mxdjkm49zmplt240000gq/T/ipykernel_84420/3847661288.py in <module>
----> 1 limit(f(x),x=Integer(1)/Integer(2))

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/calculus/calculus.py in limit(ex, dir, taylor, algorithm, **argv)
1409     if algorithm == 'maxima':
1410         if dir is None:
-> 1411             l = maxima.sr_limit(ex, v, a)
1412         elif dir in dir_plus:
1413             l = maxima.sr_limit(ex, v, a, 'plus')

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/interfaces/maxima_lib.py in sr_limit(self, expr, v, a, dir)
985             elif dir == "minus":
986                 L.append(max_minus)
--> 987             return max_to_sr(maxima_eval(([max_limit], L)))
988         except RuntimeError as error:
989             s = str(error)

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/interfaces/maxima_lib.py in max_to_sr(expr)
1708             op=max_op_dict[op_max]
1709         max_args=cdr(expr)
-> 1710         args=[max_to_sr(a) for a in max_args]
1711         return op(*args)
1712     elif expr.symbolp():

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/interfaces/maxima_lib.py in <listcomp>(.0)
1708             op=max_op_dict[op_max]
1709         max_args=cdr(expr)
-> 1710         args=[max_to_sr(a) for a in max_args]
1711         return op(*args)
1712     elif expr.symbolp():

/private/var/tmp/sage-9.6-current/local/var/lib/sage/venv-python3.10.3/lib/python3.10/site-packages/sage/interfaces/maxima_lib.py in max_to_sr(expr)
1709         max_args=cdr(expr)
1710         args=[max_to_sr(a) for a in max_args]
-> 1711         return op(*args)
1712     elif expr.symbolp():
1713         if not(expr in max_sym_dict):

TypeError: PiecewiseFunction.__call__() takes 2 positional arguments but 3 were given

edit retag close merge delete

Correct conversion of piecewise functions to maxima is not implemented.

( 2022-06-22 15:44:45 +0100 )edit

And there is a bug in libgiac conversion

sage: f(x) = piecewise([[(0,1),x],[[1,2],x/2]])
sage: f
x |--> piecewise(x|-->x on (0, 1), x|-->1/2*x on [1, 2]; x)
sage: giac(f)
piecewise(((sageVARx>0) and (1>sageVARx)),sageVARx,((sageVARx>=1) and (2>=sageVARx)),sageVARx/2)
sage: libgiac(f)
piecewise([0,1,x,[1,2],1/2*x],sageVARx)

( 2022-06-22 16:24:43 +0100 )edit

Sort by » oldest newest most voted

You can rely on Sympy instead of Maxima or you can extract the expression at the corresponding point and then compute the limit:

sage: f(x) = piecewise([[(0,1),x],[[1,2],x/2]])
sage: limit(f(x),x=1/2,algorithm="sympy")
1/2
sage: limit(f(x).expression_at(1/2),x=1/2)
1/2


Edit: It is clear that endpoints of the different pieces and points in the interior of a piece cannot receive the same treatment. For the latter, it suffices to compute a limit, as usual, of the corresponding function piece. For the former, one should compute and compare one sided limits. So, a complete solution could be obtained by defining a function that considers the different cases. As a proof of concept, such a function could be similar to the following one:

def p_limit(f, x0, eps=10^(-10), algorithm="maxima"):
if x0 in f.end_points():
funs = [f.expression_at(x0+s*eps) for s in [-1,1]]
lims = [limit(fun, x=x0, dir=s, algorithm=algorithm)
for fun,s in zip(funs,["-","+"])]
if lims[0]==lims[1]:
return lims[0]
else:
return "undefined"
else:
return limit(f.expression_at(x0), x=x0, algorithm=algorithm)


Let us test it:

sage: f = piecewise([[(-infinity,-pi), sin(2*x)],
....:                [(-pi,0), sin(x)/x],
....:                [[0,0], 1],
....:                [(0,pi/2), x/tan(x)],
....:                [[pi/2,pi/2], 0],
....:                [(pi/2,+infinity), cos(x)]])
....:
sage: for x0 in [-9*pi/8, -pi, 0, pi/3, pi/2, 3*pi]:
....:     print("The limit at ", x0, " is ", p_limit(f,x0))
....:
The limit at  -9/8*pi  is  -1/2*sqrt(2)
The limit at  -pi  is  0
The limit at  0  is  1
The limit at  1/3*pi  is  1/9*sqrt(3)*pi
The limit at  1/2*pi  is  0
The limit at  3*pi  is  -1


One more test:

sage: f = piecewise([[[-4,-1], 2*x^2],
....:                [(-1,0), (x^2-1)/(x^2+x)],
....:                [(0,1), -log(x)],
....:                [[1,2], x^2]])
....:
sage: for x0 in [-2, -1, -0.5, 0, 1]:
....:     print("The limit at ", x0, " is ", p_limit(f,x0))
....:
The limit at  -2  is  8
The limit at  -1  is  2
The limit at  -0.500000000000000  is  3.0
The limit at  0  is  +Infinity
The limit at  1  is  undefined

more

@Juanjo : Where does expression_at comes from ?

( 2022-06-22 10:06:10 +0100 )edit

Thanks for your answer! I'm not sure I understand but I'll research "simpy" and expression_at. However: It seems like neither of these provides a full solution, because look what happens when I say

limit(f(x),x=1,algorithm="sympy")


... It still returns 1/2, when really it should say something along the lines of "undefined".

Given this, I guess what this is doing is to replace the piecewise function with the part that is relevant at the evaluated point, which is okay only when the function is continuous at that point.

( 2022-06-22 10:39:24 +0100 )edit

Further evidence that this is what's happening:

f(x) = piecewise([[(0,1),x],[(1,2),x]])
limit(f(x).expression_at(1),x=1)


Here, we'd want Sage to return "1" even though the function is not defined at x=1. But it gives an error. I can't copy the error because it exceeds the character limit. But the important part is:

ValueError: point is not in the domain


If instead I use the "sympy" code, I get another long error message ending with

AttributeError: 'ExprCondPair' object has no attribute '_eval_is_meromorphic'

( 2022-06-22 10:43:08 +0100 )edit

@Emmanuel Charpentier: It is one of the methods defined for piecewise functions. I found it here.

( 2022-06-25 01:05:55 +0100 )edit

( 2022-06-25 01:08:00 +0100 )edit