%% Copyright (C) 2014-2016, 2019 Colin B. Macdonald
%%
%% This file is part of OctSymPy.
%%
%% OctSymPy is free software; you can redistribute it and/or modify
%% it under the terms of the GNU General Public License as published
%% by the Free Software Foundation; either version 3 of the License,
%% or (at your option) any later version.
%%
%% This software is distributed in the hope that it will be useful,
%% but WITHOUT ANY WARRANTY; without even the implied warranty
%% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
%% the GNU General Public License for more details.
%%
%% You should have received a copy of the GNU General Public
%% License along with this software; see the file COPYING.
%% If not, see .
%% -*- texinfo -*-
%% @documentencoding UTF-8
%% @defmethod @@sym symsum (@var{f}, @var{n}, @var{a}, @var{b})
%% @defmethodx @@sym symsum (@var{f}, @var{n}, [@var{a} @var{b}])
%% @defmethodx @@sym symsum (@var{f}, @var{a}, @var{b})
%% @defmethodx @@sym symsum (@var{f}, [@var{a} @var{b}])
%% @defmethodx @@sym symsum (@var{f}, @var{n})
%% @defmethodx @@sym symsum (@var{f})
%% Symbolic summation.
%%
%% The sum of the expression @var{f} for @var{n} from @var{a} to
%% @var{b}. When @var{n} is omitted it is determined using
%% @code{symvar} and defaults to @code{x} if @var{f} is constant. The
%% limits @var{a} and @var{b} default to 0 and @var{n} - 1
%% respectively.
%%
%% @example
%% @group
%% syms n m
%% symsum(1/n^2, n, 1, m)
%% @result{} (sym) harmonic(m, 2)
%%
%% symsum(exp(2*n)/sin(n), n, 2*m, 6*m)
%% @result{} (sym)
%% 6⋅m
%% ____
%% ╲
%% ╲ 2⋅n
%% ╲ ℯ
%% ╱ ──────
%% ╱ sin(n)
%% ╱
%% ‾‾‾‾
%% n = 2⋅m
%% @end group
%% @end example
%%
%% @seealso{@@sym/symprod, @@sym/sum}
%% @end defmethod
function S = symsum(f, n, a, b)
if (nargin > 4)
print_usage ();
end
idx1.type = '()';
idx1.subs = {1};
idx2.type = '()';
idx2.subs = {2};
if (nargin == 1)
n = symvar(f, 1);
if (isempty(n))
n = sym('x');
end
a = sym(0);
b = n - 1;
elseif (nargin == 2) && (length(n) == 2)
f = sym(f);
%a = n(1); % issue #17
%b = n(2);
a = subsref(n, idx1);
b = subsref(n, idx2);
n = symvar(f, 1);
if (isempty(n))
n = sym('x');
end
elseif (nargin == 2)
f = sym(f);
n = sym(n);
a = sym(0);
b = n - 1;
elseif (nargin == 3) && (length(a) == 2)
f = sym(f);
n = sym(n);
%b = a(2); % issue #17
%a = a(1);
b = subsref(a, idx2);
a = subsref(a, idx1);
elseif (nargin == 3)
f = sym(f);
b = a;
a = n;
n = symvar(f, 1);
if (isempty(n))
n = sym('x');
end
else
f = sym(f);
n = sym(n);
a = sym(a);
b = sym(b);
end
cmd = { '(f, n, a, b) = _ins'
'S = sp.summation(f, (n, a, b))'
'return S,' };
S = pycall_sympy__ (cmd, sym(f), sym(n), sym(a), sym(b));
end
%!error symsum (sym(1), 2, 3, 4, 5)
%!test
%! % finite sums
%! syms n
%! assert (isequal (symsum(n,n,1,10), 55))
%! assert(isa(symsum(n,n,1,10), 'sym'))
%! assert (isequal (symsum(n,n,sym(1),sym(10)), 55))
%! assert (isequal (symsum(n,n,sym(1),sym(10)), 55))
%! assert (isequal (symsum(1/n,n,1,10), sym(7381)/2520))
%!test
%! % negative limits
%! syms n
%! assert (isequal (symsum(n,n,-3,3), sym(0)))
%! assert (isequal (symsum(n,n,-3,0), sym(-6)))
%! assert (isequal (symsum(n,n,-3,-1), sym(-6)))
%!test
%! % one input
%! syms n
%! f = symsum (n);
%! g = n^2/2 - n/2;
%! assert (isequal (f, g))
%! f = symsum (2*n);
%! g = n^2 - n;
%! assert (isequal (f, g))
%!test
%! % constant input
%! f = symsum (sym(2));
%! syms x
%! g = 2*x;
%! assert (isequal (f, g))
%!test
%! % two inputs
%! syms n
%! f = symsum (2*n, n);
%! g = n^2 - n;
%! assert (isequal (f, g))
%!test
%! % two inputs, second is range
%! syms n
%! f = symsum (n, [1 6]);
%! g = 21;
%! assert (isequal (f, g))
%! f = symsum (n, [sym(1) 6]);
%! g = 21;
%! assert (isequal (f, g))
%! f = symsum (2*n, [1 6]);
%! g = 2*21;
%! assert (isequal (f, g))
%!test
%! % three inputs, last is range
%! syms n
%! f = symsum (2*n, n, [1 4]);
%! g = sym(20);
%! assert (isequal (f, g))
%! f = symsum (2*n, n, [sym(1) 4]);
%! g = sym(20);
%! assert (isequal (f, g))
%! f = symsum (2, n, [sym(1) 4]);
%! g = sym(8);
%! assert (isequal (f, g))
%!test
%! % three inputs, no range
%! syms n
%! f = symsum (2*n, 1, 4);
%! g = sym(20);
%! assert (isequal (f, g))
%! f = symsum (5, sym(1), 3);
%! g = sym(15);
%! assert (isequal (f, g))
%!test
%! % ok to use double's for arguments in infinite series
%! syms n oo
%! assert(isequal(symsum(1/n^2,n,1,oo), sym(pi)^2/6))
%! assert(isequal(symsum(1/n^2,n,1,inf), sym(pi)^2/6))
%!test
%! % should be oo because 1 is real but seems to be
%! % zoo/oo depending on sympy version
%! syms n oo
%! zoo = sym('zoo');
%! assert (isequal (symsum(1/n,n,1,oo), oo) || ...
%! isequal (symsum(1/n,n,1,oo), zoo))