6770
|
1 ## Copyright (C) 2007 David Bateman |
|
2 ## |
7016
|
3 ## This file is part of Octave. |
6770
|
4 ## |
7016
|
5 ## Octave is free software; you can redistribute it and/or modify it |
|
6 ## under the terms of the GNU General Public License as published by |
|
7 ## the Free Software Foundation; either version 3 of the License, or (at |
|
8 ## your option) any later version. |
|
9 ## |
|
10 ## Octave is distributed in the hope that it will be useful, but |
|
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 ## General Public License for more details. |
6770
|
14 ## |
|
15 ## You should have received a copy of the GNU General Public License |
7016
|
16 ## along with Octave; see the file COPYING. If not, see |
|
17 ## <http://www.gnu.org/licenses/>. |
6770
|
18 |
|
19 ## -*- texinfo -*- |
|
20 ## @deftypefn {Function File} {} accumarray (@var{subs}, @var{vals}, @var{sz}, @var{fun}, @var{fillval}, @var{issparse}) |
|
21 ## @deftypefnx {Function File} {} accumarray (@var{csubs}, @var{vals}, @dots{}) |
|
22 ## |
|
23 ## Creates an array by accumulating the elements of a vector into the |
|
24 ## positions of defined by their subscripts. The subscripts are defined by |
|
25 ## the rows of the matrix @var{subs} and the values by @var{vals}. Each row |
|
26 ## of @var{subs} corresponds to one of the values in @var{vals}. |
|
27 ## |
|
28 ## The size of the matrix will be determined by the subscripts themselves. |
|
29 ## However, if @var{sz} is defined it determines the matrix size. The length |
|
30 ## of @var{sz} must correspond to the number of columns in @var{subs}. |
|
31 ## |
|
32 ## The default action of @code{accumarray} is to sum the elements with the |
|
33 ## same subscripts. This behavior can be modified by defining the @var{fun} |
|
34 ## function. This should be a function or function handle that accepts a |
|
35 ## column vector and returns a scalar. The result of the function should not |
|
36 ## depend on the order of the subscripts. |
|
37 ## |
|
38 ## The elements of the returned array that have no subscripts assoicated with |
|
39 ## them are set to zero. Defining @var{fillval} to some other value allows |
|
40 ## these values to be defined. |
|
41 ## |
|
42 ## By default @code{accumarray} returns a full matrix. If @var{issparse} is |
|
43 ## logically true, then a sparse matrix is returned instead. |
|
44 ## |
|
45 ## An example of the use of @code{accumarray} is: |
|
46 ## |
|
47 ## @example |
|
48 ## @group |
|
49 ## accumarray ([1,1,1;2,1,2;2,3,2;2,1,2;2,3,2],101:105) |
|
50 ## @result{} ans(:,:,1) = [101, 0, 0; 0, 0, 0] |
|
51 ## ans(:,:,2) = [0, 0, 0; 206, 0, 208] |
|
52 ## @end group |
|
53 ## @end example |
|
54 ## @end deftypefn |
|
55 |
|
56 function A = accumarray (subs, val, sz, fun, fillval, isspar) |
|
57 |
|
58 if (nargin < 2 || nargin > 6) |
|
59 print_usage (); |
|
60 endif |
|
61 |
|
62 if (iscell(subs)) |
|
63 subs = cell2mat (cellfun (@(x) x(:), subs, 'UniformOutput', false)); |
|
64 endif |
|
65 ndims = size (subs, 2); |
|
66 |
|
67 if (nargin < 3 || isempty (sz)) |
|
68 sz = max (subs); |
|
69 if (isscalar(sz)) |
|
70 sz = [sz, 1]; |
|
71 endif |
|
72 else |
|
73 if (length (sz) != ndims) |
|
74 error ("accumarray: inconsistent dimensions"); |
|
75 endif |
|
76 endif |
|
77 |
|
78 if (nargin < 4 || isempty (fun)) |
|
79 fun = @sum; |
|
80 endif |
|
81 |
|
82 if (nargin < 5 || isempty (fillval)) |
|
83 fillval = 0; |
|
84 endif |
|
85 |
|
86 if (nargin < 6 || isempty (isspar)) |
|
87 isspar = false; |
|
88 endif |
|
89 if (isspar) |
|
90 if (ndims > 2) |
|
91 error ("Can not have more than 2 dimensions in a sparse matrix"); |
|
92 endif |
|
93 endif |
|
94 |
|
95 [subs, idx] = sortrows (subs); |
|
96 if (isscalar (val)) |
|
97 val = val * ones (size (idx)); |
|
98 else |
|
99 val = val(idx); |
|
100 endif |
|
101 cidx = find([true; (sum (abs (diff (subs)), 2) != 0)]); |
|
102 idx = cell (1, ndims); |
|
103 for i = 1:ndims |
|
104 idx{i} = subs (cidx, i); |
|
105 endfor |
|
106 x = cellfun (fun, mat2cell (val(:), diff ([cidx; length(val) + 1]))); |
|
107 if (isspar && fillval == 0) |
|
108 A = sparse (idx{1}, idx{2}, x, sz(1), sz(2)); |
|
109 else |
|
110 if (iscell (x)) |
|
111 ## Why did matlab choose to reverse the order of the elements |
|
112 x = cellfun (@(x) flipud(x(:)), x, 'UniformOutput', false); |
|
113 A = cell (sz); |
|
114 elseif (fillval == 0) |
|
115 A = zeros (sz, class(x)); |
|
116 else |
|
117 A = fillval .* ones (sz); |
|
118 endif |
|
119 A (sub2ind (sz, idx{:})) = x; |
|
120 endif |
|
121 endfunction |
|
122 |
|
123 %!error (accumarray (1:5)) |
|
124 %!error (accumarray ([1,2,3],1:2)) |
|
125 %!assert (accumarray ([1;2;4;2;4],101:105), [101;206;0;208]) |
|
126 %!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])) |
|
127 %!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]))) |
|
128 %!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])) |
|
129 %!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]) |
|
130 %!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)) |
|
131 %!assert (accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],1,[2,4]), [1,0,0,0;2,0,2,0]) |
|
132 %!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]) |
|
133 %!test |
|
134 %! A = accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],101:105,[2,4],@(x){x}); |
|
135 %! assert (A{2},[104;102]) |