# HG changeset patch # User dbateman # Date 1183711444 0 # Node ID babcbcc11ab66b4b5fc02e64b7bd37c71fa556c0 # Parent 77785733a18d9238aa8ea912f2054873eeda9549 [project @ 2007-07-06 08:44:04 by dbateman] diff -r 77785733a18d -r babcbcc11ab6 doc/ChangeLog --- a/doc/ChangeLog Mon Jul 02 20:19:38 2007 +0000 +++ b/doc/ChangeLog Fri Jul 06 08:44:04 2007 +0000 @@ -1,3 +1,7 @@ +2007-07-06 David Bateman + + * interpreter/arith.txi: Add accumarray. + 2007-06-25 John W. Eaton * interpreter/stats.txi: Reorganize sections and add introductory text. diff -r 77785733a18d -r babcbcc11ab6 doc/interpreter/arith.txi --- a/doc/interpreter/arith.txi Mon Jul 02 20:19:38 2007 +0000 +++ b/doc/interpreter/arith.txi Fri Jul 06 08:44:04 2007 +0000 @@ -190,6 +190,8 @@ @DOCSTRING(sumsq) +@DOCSTRING(accumarray) + @node Special Functions @section Special Functions diff -r 77785733a18d -r babcbcc11ab6 scripts/ChangeLog --- a/scripts/ChangeLog Mon Jul 02 20:19:38 2007 +0000 +++ b/scripts/ChangeLog Fri Jul 06 08:44:04 2007 +0000 @@ -1,3 +1,8 @@ +2007-07-06 David Bateman + + * general/accumarray.m: New function to create an array by + accumulating the elements. + 2007-06-29 Marcus W. Reble * optimization/sqp.m (sqp): New args, lb, ub, maxiter, and tolerance. diff -r 77785733a18d -r babcbcc11ab6 scripts/general/accumarray.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/general/accumarray.m Fri Jul 06 08:44:04 2007 +0000 @@ -0,0 +1,134 @@ +## Copyright (C) 2007 David Bateman +## +## This program 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 2 of the License, or +## (at your option) any later version. +## +## This program 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 program; if not, write to the Free Software +## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +## 02110-1301 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} accumarray (@var{subs}, @var{vals}, @var{sz}, @var{fun}, @var{fillval}, @var{issparse}) +## @deftypefnx {Function File} {} accumarray (@var{csubs}, @var{vals}, @dots{}) +## +## Creates an array by accumulating the elements of a vector into the +## positions of defined by their subscripts. The subscripts are defined by +## the rows of the matrix @var{subs} and the values by @var{vals}. Each row +## of @var{subs} corresponds to one of the values in @var{vals}. +## +## The size of the matrix will be determined by the subscripts themselves. +## However, if @var{sz} is defined it determines the matrix size. The length +## of @var{sz} must correspond to the number of columns in @var{subs}. +## +## The default action of @code{accumarray} is to sum the elements with the +## same subscripts. This behavior can be modified by defining the @var{fun} +## function. This should be a function or function handle that accepts a +## column vector and returns a scalar. The result of the function should not +## depend on the order of the subscripts. +## +## The elements of the returned array that have no subscripts assoicated with +## them are set to zero. Defining @var{fillval} to some other value allows +## these values to be defined. +## +## By default @code{accumarray} returns a full matrix. If @var{issparse} is +## logically true, then a sparse matrix is returned instead. +## +## An example of the use of @code{accumarray} is: +## +## @example +## @group +## accumarray ([1,1,1;2,1,2;2,3,2;2,1,2;2,3,2],101:105) +## @result{} ans(:,:,1) = [101, 0, 0; 0, 0, 0] +## ans(:,:,2) = [0, 0, 0; 206, 0, 208] +## @end group +## @end example +## @end deftypefn + +function A = accumarray (subs, val, sz, fun, fillval, isspar) + + if (nargin < 2 || nargin > 6) + print_usage (); + endif + + if (iscell(subs)) + subs = cell2mat (cellfun (@(x) x(:), subs, 'UniformOutput', false)); + endif + ndims = size (subs, 2); + + if (nargin < 3 || isempty (sz)) + sz = max (subs); + if (isscalar(sz)) + sz = [sz, 1]; + endif + else + if (length (sz) != ndims) + error ("accumarray: inconsistent dimensions"); + endif + endif + + if (nargin < 4 || isempty (fun)) + fun = @sum; + endif + + if (nargin < 5 || isempty (fillval)) + fillval = 0; + endif + + if (nargin < 6 || isempty (isspar)) + isspar = false; + endif + if (isspar) + if (ndims > 2) + error ("Can not have more than 2 dimensions in a sparse matrix"); + endif + endif + + [subs, idx] = sortrows (subs); + if (isscalar (val)) + val = val * ones (size (idx)); + else + val = val(idx); + endif + cidx = find([true; (sum (abs (diff (subs)), 2) != 0)]); + idx = cell (1, ndims); + for i = 1:ndims + idx{i} = subs (cidx, i); + endfor + x = cellfun (fun, mat2cell (val(:), diff ([cidx; length(val) + 1]))); + if (isspar && fillval == 0) + A = sparse (idx{1}, idx{2}, x, sz(1), sz(2)); + else + if (iscell (x)) + ## Why did matlab choose to reverse the order of the elements + x = cellfun (@(x) flipud(x(:)), x, 'UniformOutput', false); + A = cell (sz); + elseif (fillval == 0) + A = zeros (sz, class(x)); + else + A = fillval .* ones (sz); + endif + A (sub2ind (sz, idx{:})) = x; + endif +endfunction + +%!error (accumarray (1:5)) +%!error (accumarray ([1,2,3],1:2)) +%!assert (accumarray ([1;2;4;2;4],101:105), [101;206;0;208]) +%!assert (accumarray ([1,1,1;2,1,2;2,3,2;2,1,2;2,3,2],101:105),cat(3, [101,0,0;0,0,0],[0,0,0;206,0,208])) +%!assert (accumarray ([1,1,1;2,1,2;2,3,2;2,1,2;2,3,2],101:105,[],@(x)sin(sum(x))),sin(cat(3, [101,0,0;0,0,0],[0,0,0;206,0,208]))) +%!assert (accumarray ({[1 3 3 2 3 1 2 2 3 3 1 2],[3 4 2 1 4 3 4 2 2 4 3 4],[1 1 2 2 1 1 2 1 1 1 2 2]},101:112),cat(3,[0,0,207,0;0,108,0,0;0,109,0,317],[0,0,111,0;104,0,0,219;0,103,0,0])) +%!assert (accumarray ([1,1;2,1;2,3;2,1;2,3],101:105,[2,4],@max,NaN),[101,NaN,NaN,NaN;104,NaN,105,NaN]) +%!assert (accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],101:105,[2 4],@prod,0,true),sparse([1,2,2],[1,1,3],[101,10608,10815],2,4)) +%!assert (accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],1,[2,4]), [1,0,0,0;2,0,2,0]) +%!assert (accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],101:105,[2,4],@(x)length(x)>1),[false,false,false,false;true,false,true,false]) +%!test +%! A = accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],101:105,[2,4],@(x){x}); +%! assert (A{2},[104;102])