function z = cumsimps(x,y,dim)
%CUMSIMPS Cumulative Simpson's numerical integration.
% Z = CUMSIMPS(Y) computes an approximation of the cumulative integral of
% Y via the Simpson's method (with unit spacing). To compute the integral
% for spacing different from one, multiply Z by the spacing increment.
%
% For vectors, CUMSIMPS(Y) is a vector containing the cumulative integral
% of Y. For matrices, CUMSIMPS(Y) is a matrix the same size as X with the
% cumulative integral over each column. For N-D arrays, CUMSIMPS(Y) works
% along the first non-singleton dimension.
%
% Z = CUMSIMPS(X,Y) computes the cumulative integral of Y with respect to
% X using Simpson's integration. X and Y must be vectors of the same
% length, or X must be a column vector and Y an array whose first
% non-singleton dimension is length(X). CUMSIMPS operates across this
% dimension.
%
% Z = CUMSIMPS(X,Y,DIM) or CUMSIMPS(Y,DIM) integrates along dimension DIM
% of Y. The length of X must be the same as size(Y,DIM).
%
% Examples:
% --------
% % The integral of cos(x) is sin(x)
% % Let us compare CUMTRAPZ and CUMSIMPS
% x = linspace(0,2*pi,20);
% y = cos(x);
% yt = cumtrapz(x,y);
% ys = cumsimps(x,y);
% % RMSE: root mean squared errors:
% sqrt(mean((yt-sin(x)).^2)) % returns 0.0063
% sqrt(mean((ys-sin(x)).^2)) % returns 1.2309e-004
%
% If Y = [0 1 2; 3 4 5; 6 7 8]
% then cumsimps(Y,1) is [0 0 0 and cumsimps(Y,2) is [0 0.5 2
% 1.5 2.5 3.5 0 3.5 8
% 6 8 10] 0 6.5 14]
%
%
% Class support for inputs X,Y:
% float: double, single
%
% -- Damien Garcia -- 09/2007, revised 11/2009
% directly adapted from CUMTRAPZ
%
% See also CUMSUM, CUMTRAPZ, SIMPS.
%% Make sure x and y are column vectors, or y is a matrix.
perm = []; nshifts = 0;
if nargin == 3, % cumsimps(x,y,dim)
perm = [dim:max(length(size(y)),dim) 1:dim-1];
y = permute(y,perm);
[m,n] = size(y);
elseif nargin==2 && isequal(size(y),[1 1]) % cumsimps(y,dim)
dim = y; y = x;
perm = [dim:max(length(size(y)),dim) 1:dim-1];
y = permute(y,perm);
[m,n] = size(y);
x = 1:m;
else
if nargin < 2, y = x; end
[y,nshifts] = shiftdim(y);
[m,n] = size(y);
if nargin < 2, x = 1:m; end
end
x = x(:);
if length(x) ~= m
error('MATLAB:cumsimps:LengthXMismatchY',...
'length(x) must equal length of first non-singleton dim of y.');
end
if m<3
error('MATLAB:cumsimps:LengthX',...
'length(x) must be at least 3.');
end
%%
z = zeros(size(y),class(y));
dx = repmat(diff(x,1,1),1,n);
dx1 = dx(1:end-1,:);
dx2 = dx(2:end,:);
alpha = (dx1+dx2)./dx1/6;
a0 = alpha.*(2*dx1-dx2);
a1 = alpha.*(dx1+dx2).^2./dx2;
a2 = alpha.*dx1./dx2.*(2*dx2-dx1);
%% First cumulative value
state0 = warning('query','MATLAB:nearlySingularMatrix');
state0 = state0.state;
warning('off','MATLAB:nearlySingularMatrix')
C = vander(x(1:3))\y(1:3,:);
z(2,:) = C(1,:).*(x(2,:).^3-x(1,:).^3)/3 +...
C(2,:).*(x(2,:).^2-x(1,:).^2)/2 +...
C(3,:).*dx(1,:);
warning(state0,'MATLAB:nearlySingularMatrix')
%% Other cumulative values
z(3:2:end,:) = cumsum(a0(1:2:end,:).*y(1:2:m-2,:) +...
a1(1:2:end,:).*y(2:2:m-1,:) +...
a2(1:2:end,:).*y(3:2:m,:),1);
z(4:2:end,:) = cumsum(a0(2:2:end,:).*y(2:2:m-2,:) +...
a1(2:2:end,:).*y(3:2:m-1,:) +...
a2(2:2:end,:).*y(4:2:m,:),1) +...
repmat(z(2,:),ceil((m-3)/2),1);
%% Resizing
siz = size(y); siz(1) = max(1,siz(1));
z = reshape(z,[ones(1,nshifts),siz]);
if ~isempty(perm), z = ipermute(z,perm); end