changelog shortlog tags changeset files revisions annotate raw

scripts/general/accumarray.m

changeset 9846: 1d90fc211872
parent:1bf0ce0930be
author: John W. Eaton <jwe@octave.org>
date: Sat Nov 21 21:44:51 2009 -0500 (33 hours ago)
permissions: -rw-r--r--
description: configure.ac: report freetype, fontconfig, and fltk cflags and libs info
1## Copyright (C) 2007, 2008, 2009 David Bateman
2## Copyright (C) 2009 VZLU Prague
3##
4## This file is part of Octave.
5##
6## Octave is free software; you can redistribute it and/or modify it
7## under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 3 of the License, or (at
9## your option) any later version.
10##
11## Octave is distributed in the hope that it will be useful, but
12## WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14## General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with Octave; see the file COPYING. If not, see
18## <http://www.gnu.org/licenses/>.
19
20## -*- texinfo -*-
21## @deftypefn {Function File} {} accumarray (@var{subs}, @var{vals}, @var{sz}, @var{func}, @var{fillval}, @var{issparse})
22## @deftypefnx {Function File} {} accumarray (@var{csubs}, @var{vals}, @dots{})
23##
24## Create an array by accumulating the elements of a vector into the
25## positions defined by their subscripts. The subscripts are defined by
26## the rows of the matrix @var{subs} and the values by @var{vals}. Each row
27## of @var{subs} corresponds to one of the values in @var{vals}.
28##
29## The size of the matrix will be determined by the subscripts themselves.
30## However, if @var{sz} is defined it determines the matrix size. The length
31## of @var{sz} must correspond to the number of columns in @var{subs}.
32##
33## The default action of @code{accumarray} is to sum the elements with the
34## same subscripts. This behavior can be modified by defining the @var{func}
35## function. This should be a function or function handle that accepts a
36## column vector and returns a scalar. The result of the function should not
37## depend on the order of the subscripts.
38##
39## The elements of the returned array that have no subscripts associated with
40## them are set to zero. Defining @var{fillval} to some other value allows
41## these values to be defined.
42##
43## By default @code{accumarray} returns a full matrix. If @var{issparse} is
44## logically true, then a sparse matrix is returned instead.
45##
46## An example of the use of @code{accumarray} is:
47##
48## @example
49## @group
50## accumarray ([1,1,1;2,1,2;2,3,2;2,1,2;2,3,2], 101:105)
51## @result{} ans(:,:,1) = [101, 0, 0; 0, 0, 0]
52## ans(:,:,2) = [0, 0, 0; 206, 0, 208]
53## @end group
54## @end example
55## @end deftypefn
56
57function A = accumarray (subs, val, sz, func, fillval, isspar)
58
59 if (nargin < 2 || nargin > 6)
60 print_usage ();
61 endif
62
63 if (iscell (subs))
64 subs = cell2mat (cellfun (@(x) x(:), subs, "UniformOutput", false));
65 endif
66 ndims = size (subs, 2);
67
68 if (nargin < 5 || isempty (fillval))
69 fillval = 0;
70 endif
71
72 if (nargin < 6 || isempty (isspar))
73 isspar = false;
74 endif
75
76 if (isspar && ndims > 2)
77 error ("accumarray: sparse matrices limited to 2 dimensions");
78 endif
79
80 if (nargin < 4 || isempty (func))
81 func = @sum;
82 ## This is the fast summation case. Unlike the general case,
83 ## this case will be handled using an O(N) algorithm.
84
85 if (isspar && fillval == 0)
86 ## The "sparse" function can handle this case.
87
88 if ((nargin < 3 || isempty (sz)))
89 A = sparse (subs(:,1), subs(:,2), val);
90 elseif (length (sz) == 2)
91 A = sparse (subs(:,1), subs(:,2), val, sz(1), sz(2));
92 else
93 error ("accumarray: dimensions mismatch")
94 endif
95 else
96 ## This case is handled by an internal function.
97
98 if (ndims > 1)
99 if ((nargin < 3 || isempty (sz)))
100 sz = max (subs);
101 elseif (ndims != length (sz))
102 error ("accumarray: dimensions mismatch")
103 elseif (any (max (subs) > sz))
104 error ("accumarray: index out of range")
105 endif
106
107 ## Convert multidimensional subscripts.
108 subs = sub2ind (sz, mat2cell (subs, rows (subs), ones (1, ndims)){:});
109 elseif (nargin < 3)
110 ## In case of linear indexing, the fast built-in accumulator
111 ## will determine the extent for us.
112 sz = [];
113 endif
114
115 ## Call the built-in accumulator.
116 if (isempty (sz))
117 A = __accumarray_sum__ (subs, val);
118 else
119 A = __accumarray_sum__ (subs, val, prod (sz));
120 ## set proper shape.
121 A = reshape (A, sz);
122 endif
123
124 ## we fill in nonzero fill value.
125 if (fillval != 0)
126 mask = true (size (A));
127 mask(subs) = false;
128 A(mask) = fillval;
129 endif
130 endif
131
132 return
133 endif
134
135 if (nargin < 3 || isempty (sz))
136 sz = max (subs);
137 if (isscalar(sz))
138 sz = [sz, 1];
139 endif
140 elseif (length (sz) != ndims
141 && (ndims != 1 || length (sz) != 2 || sz(2) != 1))
142 error ("accumarray: inconsistent dimensions");
143 endif
144
145 [subs, idx] = sortrows (subs);
146
147 if (isscalar (val))
148 val = val * ones (size (idx));
149 else
150 val = val(idx);
151 endif
152 cidx = find ([true; (sum (abs (diff (subs)), 2) != 0)]);
153 idx = cell (1, ndims);
154 for i = 1:ndims
155 idx{i} = subs (cidx, i);
156 endfor
157 x = cellfun (func, mat2cell (val(:), diff ([cidx; length(val) + 1])));
158 if (isspar && fillval == 0)
159 A = sparse (idx{1}, idx{2}, x, sz(1), sz(2));
160 else
161 if (iscell (x))
162 ## Why did matlab choose to reverse the order of the elements
163 x = cellfun (@(x) flipud (x(:)), x, "UniformOutput", false);
164 A = cell (sz);
165 elseif (fillval == 0)
166 A = zeros (sz, class (x));
167 else
168 A = fillval .* ones (sz);
169 endif
170 A(sub2ind (sz, idx{:})) = x;
171 endif
172endfunction
173
174%!error (accumarray (1:5))
175%!error (accumarray ([1,2,3],1:2))
176%!assert (accumarray ([1;2;4;2;4],101:105), [101;206;0;208])
177%!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]))
178%!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])))
179%!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]))
180%!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])
181%!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))
182%!assert (accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],1,[2,4]), [1,0,0,0;2,0,2,0])
183%!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])
184%!test
185%! A = accumarray ([1 1; 2 1; 2 3; 2 1; 2 3],101:105,[2,4],@(x){x});
186%! assert (A{2},[104;102])