1%% Copyright (C) 2014-2016 Colin B. Macdonald
2%%
3%% This file is part of OctSymPy.
4%%
5%% OctSymPy is free software; you can redistribute it and/or modify
6%% it under the terms of the GNU General Public License as published
7%% by the Free Software Foundation; either version 3 of the License,
8%% or (at your option) any later version.
9%%
10%% This software is distributed in the hope that it will be useful,
11%% but WITHOUT ANY WARRANTY; without even the implied warranty
12%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13%% the GNU General Public License for more details.
14%%
15%% You should have received a copy of the GNU General Public
16%% License along with this software; see the file COPYING.
17%% If not, see <http://www.gnu.org/licenses/>.
18
19%% -*- texinfo -*-
20%% @documentencoding UTF-8
21%% @defmethod  @@sym limit (@var{expr}, @var{x}, @var{a}, @var{dir})
22%% @defmethodx @@sym limit (@var{expr}, @var{x}, @var{a})
23%% @defmethodx @@sym limit (@var{expr}, @var{a})
24%% @defmethodx @@sym limit (@var{expr})
25%% Evaluate symbolic limits.
26%%
27%% The limit of @var{expr} as @var{x} tends to @var{a} from
28%% @var{dir}.  @var{dir} can be @code{left} or @code{right}.
29%%
30%% Examples:
31%% @example
32%% @group
33%% syms x
34%% L = limit(sin(x)/x, x, 0)
35%%   @result{} L = (sym) 1
36%% L = limit(1/x, x, sym(inf))
37%%   @result{} L = (sym) 0
38%% L = limit(1/x, x, 0, 'left')
39%%   @result{} L = (sym) -∞
40%% L = limit(1/x, x, 0, 'right')
41%%   @result{} L = (sym) ∞
42%% @end group
43%% @end example
44%%
45%% If @var{x} is omitted, @code{symvar} is used to determine the
46%% variable.  If @var{a} is omitted, it defaults to 0.
47%%
48%% @var{dir} defaults to @code{right}.  Note this is different from
49%% Matlab's Symbolic Math Toolbox which returns @code{NaN} for
50%% @code{limit(1/x, x, 0)}
51%% (and @code{+/-inf} if you specify @code{left/right}).  I'm not
52%% sure how to get this nicer behaviour from SymPy.
53%% FIXME: this is https://github.com/cbm755/octsympy/issues/74
54%%
55%% @seealso{@@sym/diff}
56%% @end defmethod
57
58
59function L = limit(f, x, a, dir)
60
61  if (nargin > 4 || nargin < 1)
62    print_usage ();
63  end
64
65  f = sym(f);
66  if (nargin < 4)
67    dir= 'right';
68  end
69  if (nargin == 2)
70    a = x;
71    x = symvar(f, 1);
72  end
73  if (nargin == 1)
74    x = symvar(f, 1);
75    a = 0;
76  end
77
78  switch (lower (dir))
79    case {'left' '-'}
80      pdir = '-';
81    case {'right' '+'}
82      pdir = '+';
83    otherwise
84      print_usage ();
85  end
86
87  if (isempty (x))
88    L = f;
89    return
90  end
91
92  L = elementwise_op ('lambda f, x, a, dir: f.limit(x, a, dir=dir)', ...
93                      sym(f), sym(x), sym(a), pdir);
94end
95
96
97%!error <Invalid> limit (sym(1), 2, 3, 4, 5)
98
99%!shared x, oo
100%! syms x
101%! oo = sym(inf);
102
103%!assert (isa (limit(x, x, pi), 'sym'))
104
105%!assert (isequal (limit(x, x, pi), sym(pi)))
106
107%!assert (isequal (limit(sin(x)/x, x, 0), 1))
108
109%!test
110%! % left/right-hand limit
111%! assert (isequal (limit(1/x, x, 0, 'right'), oo))
112%! assert (isequal (limit(1/x, x, 0), oo))
113%! assert (isequal (limit(1/x, x, 0, 'left'), -oo))
114%! assert (isequal (limit(1/x, x, oo), 0))
115%! assert (isequal (limit(sign(x), x, 0, 'left'), -1))
116%! assert (isequal (limit(sign(x), x, 0, 'right'), 1))
117%! assert (isequal (limit(sign(x), x, 0, '-'), -1))
118%! assert (isequal (limit(sign(x), x, 0, '+'), 1))
119
120%!test
121%! % matrix
122%! syms y
123%! A = [x 1/x x*y];
124%! B = sym([3 sym(1)/3 3*y]);
125%! assert (isequal (limit(A, x, 3), B))
126
127%!test
128%! % omitting arguments
129%! syms a
130%! assert (isequal (limit(a), 0))
131%! assert (isequal (limit(a*x+a+2), a+2))
132%! assert (isequal (limit(a*x+a+2, 6), 7*a+2))
133
134%!test
135%! % constants
136%! assert (isequal (limit(sym(6)), 6))
137%! assert (isequal (limit(sym(6), 7), 6))
138%! assert (isequal (limit([sym(6) sym(2)], 7), [6 2]))
139
140%!test
141%! % double constant, with sym limit
142%! a = limit (6, sym(0));
143%! assert (isa (a, 'sym'))
144%! assert (isequal (a, sym(6)))
145