annotate liboctave/util/accumulate.cc @ 19007:4f0d0b212fd6 draft

WIP
author David Spies <dnspies@gmail.com>
date Wed, 11 Jun 2014 16:59:46 -0600
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
19007
David Spies <dnspies@gmail.com>
parents:
diff changeset
1 /*
David Spies <dnspies@gmail.com>
parents:
diff changeset
2
David Spies <dnspies@gmail.com>
parents:
diff changeset
3 Copyright (C) 2014 David Spies
David Spies <dnspies@gmail.com>
parents:
diff changeset
4
David Spies <dnspies@gmail.com>
parents:
diff changeset
5 This file is part of Octave.
David Spies <dnspies@gmail.com>
parents:
diff changeset
6
David Spies <dnspies@gmail.com>
parents:
diff changeset
7 Octave is free software; you can redistribute it and/or modify it
David Spies <dnspies@gmail.com>
parents:
diff changeset
8 under the terms of the GNU General Public License as published by the
David Spies <dnspies@gmail.com>
parents:
diff changeset
9 Free Software Foundation; either version 3 of the License, or (at your
David Spies <dnspies@gmail.com>
parents:
diff changeset
10 option) any later version.
David Spies <dnspies@gmail.com>
parents:
diff changeset
11
David Spies <dnspies@gmail.com>
parents:
diff changeset
12 Octave is distributed in the hope that it will be useful, but WITHOUT
David Spies <dnspies@gmail.com>
parents:
diff changeset
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
David Spies <dnspies@gmail.com>
parents:
diff changeset
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
David Spies <dnspies@gmail.com>
parents:
diff changeset
15 for more details.
David Spies <dnspies@gmail.com>
parents:
diff changeset
16
David Spies <dnspies@gmail.com>
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
David Spies <dnspies@gmail.com>
parents:
diff changeset
18 along with Octave; see the file COPYING. If not, see
David Spies <dnspies@gmail.com>
parents:
diff changeset
19 <http://www.gnu.org/licenses/>.
David Spies <dnspies@gmail.com>
parents:
diff changeset
20
David Spies <dnspies@gmail.com>
parents:
diff changeset
21 */
David Spies <dnspies@gmail.com>
parents:
diff changeset
22
David Spies <dnspies@gmail.com>
parents:
diff changeset
23 // A template for functions which accumulate all the values along
David Spies <dnspies@gmail.com>
parents:
diff changeset
24 // the rows or columns of a matrix into a single row or column vector
David Spies <dnspies@gmail.com>
parents:
diff changeset
25 // (more generally removing one dimension of a many-dimensional matrix)
David Spies <dnspies@gmail.com>
parents:
diff changeset
26 // Functions which should call this one:
David Spies <dnspies@gmail.com>
parents:
diff changeset
27 // min, max, sum, product, any, all
David Spies <dnspies@gmail.com>
parents:
diff changeset
28 //
David Spies <dnspies@gmail.com>
parents:
diff changeset
29 // TODO: Allow possible second return value for min and max
David Spies <dnspies@gmail.com>
parents:
diff changeset
30 #include "dim-vector.h"
David Spies <dnspies@gmail.com>
parents:
diff changeset
31 #include "Array.h"
David Spies <dnspies@gmail.com>
parents:
diff changeset
32
David Spies <dnspies@gmail.com>
parents:
diff changeset
33 // TODO Support any/all with short-circuiting
David Spies <dnspies@gmail.com>
parents:
diff changeset
34 enum fun_type
David Spies <dnspies@gmail.com>
parents:
diff changeset
35 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
36 min, max, sum, prod
David Spies <dnspies@gmail.com>
parents:
diff changeset
37 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
38
David Spies <dnspies@gmail.com>
parents:
diff changeset
39 const bool MIN = false;
David Spies <dnspies@gmail.com>
parents:
diff changeset
40 const bool MAX = true;
David Spies <dnspies@gmail.com>
parents:
diff changeset
41
David Spies <dnspies@gmail.com>
parents:
diff changeset
42 const int SUM = 0;
David Spies <dnspies@gmail.com>
parents:
diff changeset
43 const int PROD = 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
44
David Spies <dnspies@gmail.com>
parents:
diff changeset
45 const int COL_ACCUM = 0;
David Spies <dnspies@gmail.com>
parents:
diff changeset
46 const int ROW_ACCUM = 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
47
David Spies <dnspies@gmail.com>
parents:
diff changeset
48 // Pairs a value together with its index along the
David Spies <dnspies@gmail.com>
parents:
diff changeset
49 // accumulated dimension
David Spies <dnspies@gmail.com>
parents:
diff changeset
50 template<typename T>
David Spies <dnspies@gmail.com>
parents:
diff changeset
51 struct Elem
David Spies <dnspies@gmail.com>
parents:
diff changeset
52 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
53 const octave_idx_type accum_index;
David Spies <dnspies@gmail.com>
parents:
diff changeset
54 const T value;
David Spies <dnspies@gmail.com>
parents:
diff changeset
55 Elem (octave_idx_type accum_index, T value) :
David Spies <dnspies@gmail.com>
parents:
diff changeset
56 accum_index (accum_index), value (value) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
57 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
58
David Spies <dnspies@gmail.com>
parents:
diff changeset
59 //Chooses < or > based on template argument
David Spies <dnspies@gmail.com>
parents:
diff changeset
60 //(but only uses < operation)
David Spies <dnspies@gmail.com>
parents:
diff changeset
61 template<typename E, bool MinOrMax>
David Spies <dnspies@gmail.com>
parents:
diff changeset
62 bool
David Spies <dnspies@gmail.com>
parents:
diff changeset
63 exceeds (E v1, E v2) { return (MinOrMax == MIN) ? v1 < v2 : v2 < v1; }
David Spies <dnspies@gmail.com>
parents:
diff changeset
64
David Spies <dnspies@gmail.com>
parents:
diff changeset
65 template<typename E, bool MinOrMax>
David Spies <dnspies@gmail.com>
parents:
diff changeset
66 struct FullMMAccum
David Spies <dnspies@gmail.com>
parents:
diff changeset
67 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
68 public:
David Spies <dnspies@gmail.com>
parents:
diff changeset
69
David Spies <dnspies@gmail.com>
parents:
diff changeset
70 Array<Elem<E> > res;
David Spies <dnspies@gmail.com>
parents:
diff changeset
71 Array<double> ind;
David Spies <dnspies@gmail.com>
parents:
diff changeset
72
David Spies <dnspies@gmail.com>
parents:
diff changeset
73 FullMMAccum (const dim_vector& dims) : res (dims), ind (dims, 0) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
74
David Spies <dnspies@gmail.com>
parents:
diff changeset
75 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
76 add (octave_idx_type to_index, Elem<E> rhs)
David Spies <dnspies@gmail.com>
parents:
diff changeset
77 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
78 if (ind (to_index) == 0 || exceeds<E, MinOrMax> (rhs.value, res (to_index)))
David Spies <dnspies@gmail.com>
parents:
diff changeset
79 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
80 ind (to_index) = rhs.index + 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
81 res (to_index) = rhs.value;
David Spies <dnspies@gmail.com>
parents:
diff changeset
82 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
83 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
84
David Spies <dnspies@gmail.com>
parents:
diff changeset
85 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
86 post_process (void)
David Spies <dnspies@gmail.com>
parents:
diff changeset
87 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
88 return octave_value_list (res, ind);
David Spies <dnspies@gmail.com>
parents:
diff changeset
89 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
90 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
91
David Spies <dnspies@gmail.com>
parents:
diff changeset
92 // TODO Separate Sum and Prod
David Spies <dnspies@gmail.com>
parents:
diff changeset
93 // for short-circuiting Prod
David Spies <dnspies@gmail.com>
parents:
diff changeset
94 template<typename E, int SorP>
David Spies <dnspies@gmail.com>
parents:
diff changeset
95 struct FullSPAccum
David Spies <dnspies@gmail.com>
parents:
diff changeset
96 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
97
David Spies <dnspies@gmail.com>
parents:
diff changeset
98 Array<E> res;
David Spies <dnspies@gmail.com>
parents:
diff changeset
99
David Spies <dnspies@gmail.com>
parents:
diff changeset
100 FullSPAccum (const dim_vector& dims) : res (dims, SorP) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
101
David Spies <dnspies@gmail.com>
parents:
diff changeset
102 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
103 add (octave_idx_type to_index, Elem<E> rhs)
David Spies <dnspies@gmail.com>
parents:
diff changeset
104 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
105 if (SorP == PROD)
David Spies <dnspies@gmail.com>
parents:
diff changeset
106 res (to_index) *= rhs.value;
David Spies <dnspies@gmail.com>
parents:
diff changeset
107 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
108 res (to_index) += rhs.value;
David Spies <dnspies@gmail.com>
parents:
diff changeset
109 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
110
David Spies <dnspies@gmail.com>
parents:
diff changeset
111 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
112 post_process ()
David Spies <dnspies@gmail.com>
parents:
diff changeset
113 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
114 return octave_value_list (res);
David Spies <dnspies@gmail.com>
parents:
diff changeset
115 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
116 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
117
David Spies <dnspies@gmail.com>
parents:
diff changeset
118 template<typename E, bool MinOrMax>
David Spies <dnspies@gmail.com>
parents:
diff changeset
119 struct SparseMMAccum
David Spies <dnspies@gmail.com>
parents:
diff changeset
120 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
121 private:
David Spies <dnspies@gmail.com>
parents:
diff changeset
122 FullMMAccum<E, MinOrMax> my_accum;
David Spies <dnspies@gmail.com>
parents:
diff changeset
123 public:
David Spies <dnspies@gmail.com>
parents:
diff changeset
124 SparseMMAccum (dim_vector dims) : my_accum (dims) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
125
David Spies <dnspies@gmail.com>
parents:
diff changeset
126 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
127 add (octave_idx_type ind, Elem<E> value)
David Spies <dnspies@gmail.com>
parents:
diff changeset
128 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
129 my_accum.add (ind, value);
David Spies <dnspies@gmail.com>
parents:
diff changeset
130 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
131
David Spies <dnspies@gmail.com>
parents:
diff changeset
132 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
133 post_process (void)
David Spies <dnspies@gmail.com>
parents:
diff changeset
134 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
135 return octave_value_list (Sparse<E> (my_accum.res), my_accum.ind);
David Spies <dnspies@gmail.com>
parents:
diff changeset
136 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
137 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
138
David Spies <dnspies@gmail.com>
parents:
diff changeset
139 // TODO Separate Sum and Prod
David Spies <dnspies@gmail.com>
parents:
diff changeset
140 // for short-circuiting Prod
David Spies <dnspies@gmail.com>
parents:
diff changeset
141 template<typename E, int SorP>
David Spies <dnspies@gmail.com>
parents:
diff changeset
142 struct SparseSPAccum
David Spies <dnspies@gmail.com>
parents:
diff changeset
143 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
144 private:
David Spies <dnspies@gmail.com>
parents:
diff changeset
145 FullSPAccum<E, SorP> my_accum;
David Spies <dnspies@gmail.com>
parents:
diff changeset
146 public:
David Spies <dnspies@gmail.com>
parents:
diff changeset
147 SparseSPAccum (dim_vector dims) : my_accum (dims) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
148
David Spies <dnspies@gmail.com>
parents:
diff changeset
149 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
150 add (octave_idx_type ind, Elem<E> value)
David Spies <dnspies@gmail.com>
parents:
diff changeset
151 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
152 my_accum.add (ind, value);
David Spies <dnspies@gmail.com>
parents:
diff changeset
153 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
154
David Spies <dnspies@gmail.com>
parents:
diff changeset
155 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
156 post_process (void)
David Spies <dnspies@gmail.com>
parents:
diff changeset
157 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
158 return octave_value_list (Sparse<E> (my_accum.res));
David Spies <dnspies@gmail.com>
parents:
diff changeset
159 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
160 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
161
David Spies <dnspies@gmail.com>
parents:
diff changeset
162 template<typename E>
David Spies <dnspies@gmail.com>
parents:
diff changeset
163 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
164 sparseColumn (octave_idx_type height,
David Spies <dnspies@gmail.com>
parents:
diff changeset
165 std::vector<std::pair<octave_idx_type, E> > vec)
David Spies <dnspies@gmail.com>
parents:
diff changeset
166 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
167 Sparse<E> res = Sparse<E> (height, 1, vec.size ());
David Spies <dnspies@gmail.com>
parents:
diff changeset
168 res.xcidx (0) = 0;
David Spies <dnspies@gmail.com>
parents:
diff changeset
169 res.xcidx (1) = vec.size ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
170 for (size_t i = 0; i < vec.size; ++i)
David Spies <dnspies@gmail.com>
parents:
diff changeset
171 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
172 res.xridx (i) = vec[i].first;
David Spies <dnspies@gmail.com>
parents:
diff changeset
173 res.xdata (i) = vec[i].second;
David Spies <dnspies@gmail.com>
parents:
diff changeset
174 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
175 return octave_value_list (res);
David Spies <dnspies@gmail.com>
parents:
diff changeset
176 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
177
David Spies <dnspies@gmail.com>
parents:
diff changeset
178 template<typename E, bool MinOrMax>
David Spies <dnspies@gmail.com>
parents:
diff changeset
179 struct TallMMAccum
David Spies <dnspies@gmail.com>
parents:
diff changeset
180 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
181 private:
David Spies <dnspies@gmail.com>
parents:
diff changeset
182 const octave_idx_type height;
David Spies <dnspies@gmail.com>
parents:
diff changeset
183 std::vector<std::pair<octave_idx_type, E> > res_vec;
David Spies <dnspies@gmail.com>
parents:
diff changeset
184
David Spies <dnspies@gmail.com>
parents:
diff changeset
185 public:
David Spies <dnspies@gmail.com>
parents:
diff changeset
186 TallMMAccum (octave_idx_type height) : height (height) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
187
David Spies <dnspies@gmail.com>
parents:
diff changeset
188 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
189 add_term (octave_idx_type row, Elem<E> value)
David Spies <dnspies@gmail.com>
parents:
diff changeset
190 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
191 res_vec.push_back (std::pair (row, value.value));
David Spies <dnspies@gmail.com>
parents:
diff changeset
192 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
193
David Spies <dnspies@gmail.com>
parents:
diff changeset
194 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
195 join_term (Elem<E> value)
David Spies <dnspies@gmail.com>
parents:
diff changeset
196 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
197 if (exceeds<E, MinOrMax> (value.value, res_vec.back ().second))
David Spies <dnspies@gmail.com>
parents:
diff changeset
198 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
199 res_vec.back ().second = value.value;
David Spies <dnspies@gmail.com>
parents:
diff changeset
200 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
201 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
202
David Spies <dnspies@gmail.com>
parents:
diff changeset
203 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
204 post_process (void)
David Spies <dnspies@gmail.com>
parents:
diff changeset
205 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
206 return sparseColumn (height, res_vec);
David Spies <dnspies@gmail.com>
parents:
diff changeset
207 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
208 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
209
David Spies <dnspies@gmail.com>
parents:
diff changeset
210 template<typename E, int SorP>
David Spies <dnspies@gmail.com>
parents:
diff changeset
211 struct TallSPAccum
David Spies <dnspies@gmail.com>
parents:
diff changeset
212 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
213 private:
David Spies <dnspies@gmail.com>
parents:
diff changeset
214 const octave_idx_type height;
David Spies <dnspies@gmail.com>
parents:
diff changeset
215 std::vector<std::pair<octave_idx_type, E> > res_vec;
David Spies <dnspies@gmail.com>
parents:
diff changeset
216
David Spies <dnspies@gmail.com>
parents:
diff changeset
217 public:
David Spies <dnspies@gmail.com>
parents:
diff changeset
218 TallSPAccum (octave_idx_type height) : height (height) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
219
David Spies <dnspies@gmail.com>
parents:
diff changeset
220 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
221 add_term (octave_idx_type row, Elem<E> value)
David Spies <dnspies@gmail.com>
parents:
diff changeset
222 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
223 res_vec.push_back (std::pair (row, value.value));
David Spies <dnspies@gmail.com>
parents:
diff changeset
224 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
225
David Spies <dnspies@gmail.com>
parents:
diff changeset
226 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
227 join_term (Elem<E> value)
David Spies <dnspies@gmail.com>
parents:
diff changeset
228 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
229 res_vec.back ().second += value.value;
David Spies <dnspies@gmail.com>
parents:
diff changeset
230 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
231
David Spies <dnspies@gmail.com>
parents:
diff changeset
232 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
233 post_process ()
David Spies <dnspies@gmail.com>
parents:
diff changeset
234 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
235 return sparseColumn (height, res_vec);
David Spies <dnspies@gmail.com>
parents:
diff changeset
236 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
237 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
238
David Spies <dnspies@gmail.com>
parents:
diff changeset
239 // M is the type of matrix. Right now I'm only handling
David Spies <dnspies@gmail.com>
parents:
diff changeset
240 // Array or Sparse. TODO What other types must I handle?
David Spies <dnspies@gmail.com>
parents:
diff changeset
241 template<typename M>
David Spies <dnspies@gmail.com>
parents:
diff changeset
242 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
243 accumulate (const M& matrix, int dim, int nargout, fun_type t)
David Spies <dnspies@gmail.com>
parents:
diff changeset
244 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
245 if (dim < 0)
David Spies <dnspies@gmail.com>
parents:
diff changeset
246 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
247 // TODO Raise exception: how?
David Spies <dnspies@gmail.com>
parents:
diff changeset
248 assert(false);
David Spies <dnspies@gmail.com>
parents:
diff changeset
249 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
250 else if (dim >= matrix.ndims ())
David Spies <dnspies@gmail.com>
parents:
diff changeset
251 return octave_value_list (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
252 // TODO Add is_sparse to SparseMatrix
David Spies <dnspies@gmail.com>
parents:
diff changeset
253 // Is there another way to check?
David Spies <dnspies@gmail.com>
parents:
diff changeset
254 else if (M::is_sparse)
David Spies <dnspies@gmail.com>
parents:
diff changeset
255 return select_sparse_accumulate<M::element_type> (matrix, dim, t, nargout);
David Spies <dnspies@gmail.com>
parents:
diff changeset
256 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
257 return select_full_accumulate<M::element_type> (matrix, dim, t);
David Spies <dnspies@gmail.com>
parents:
diff changeset
258 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
259
David Spies <dnspies@gmail.com>
parents:
diff changeset
260 template<typename E>
David Spies <dnspies@gmail.com>
parents:
diff changeset
261 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
262 select_full_accumulate (const Array<E>& matrix, int dim, fun_type t)
David Spies <dnspies@gmail.com>
parents:
diff changeset
263 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
264 // TODO Deal with h = 0 and w = 0
David Spies <dnspies@gmail.com>
parents:
diff changeset
265 switch (t)
David Spies <dnspies@gmail.com>
parents:
diff changeset
266 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
267 case min:
David Spies <dnspies@gmail.com>
parents:
diff changeset
268 return full_accumulate<E, FullMMAccum<E, MIN> > (matrix, dim);
David Spies <dnspies@gmail.com>
parents:
diff changeset
269 case max:
David Spies <dnspies@gmail.com>
parents:
diff changeset
270 return full_accumulate<E, FullMMAccum<E, MAX> > (matrix, dim);
David Spies <dnspies@gmail.com>
parents:
diff changeset
271 case sum:
David Spies <dnspies@gmail.com>
parents:
diff changeset
272 return full_accumulate<E, FullSPAccum<E, SUM> > (matrix, dim);
David Spies <dnspies@gmail.com>
parents:
diff changeset
273 case prod:
David Spies <dnspies@gmail.com>
parents:
diff changeset
274 return full_accumulate<E, FullSPAccum<E, PROD> > (matrix, dim);
David Spies <dnspies@gmail.com>
parents:
diff changeset
275 default:
David Spies <dnspies@gmail.com>
parents:
diff changeset
276 assert(false);
David Spies <dnspies@gmail.com>
parents:
diff changeset
277 // TODO Raise exception instead?
David Spies <dnspies@gmail.com>
parents:
diff changeset
278 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
279 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
280
David Spies <dnspies@gmail.com>
parents:
diff changeset
281 // Change dim to a template parameter
David Spies <dnspies@gmail.com>
parents:
diff changeset
282 template<typename E>
David Spies <dnspies@gmail.com>
parents:
diff changeset
283 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
284 select_sparse_accumulate (const Sparse<E>& matrix, int dim, fun_type t,
David Spies <dnspies@gmail.com>
parents:
diff changeset
285 int nargout)
David Spies <dnspies@gmail.com>
parents:
diff changeset
286 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
287 switch (dim)
David Spies <dnspies@gmail.com>
parents:
diff changeset
288 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
289 case ROW_ACCUM:
David Spies <dnspies@gmail.com>
parents:
diff changeset
290 return select_sparse_accumulate<E, ROW_ACCUM> (matrix, t, nargout);
David Spies <dnspies@gmail.com>
parents:
diff changeset
291 case COL_ACCUM:
David Spies <dnspies@gmail.com>
parents:
diff changeset
292 return select_sparse_accumulate<E, COL_ACCUM> (matrix, t, nargout);
David Spies <dnspies@gmail.com>
parents:
diff changeset
293 default:
David Spies <dnspies@gmail.com>
parents:
diff changeset
294 // This was already checked by accumulate
David Spies <dnspies@gmail.com>
parents:
diff changeset
295 assert(false);
David Spies <dnspies@gmail.com>
parents:
diff changeset
296 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
297 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
298
David Spies <dnspies@gmail.com>
parents:
diff changeset
299 // Accumulating over the columns of a sparse matrix is simple.
David Spies <dnspies@gmail.com>
parents:
diff changeset
300 // The rows are a little more complicated
David Spies <dnspies@gmail.com>
parents:
diff changeset
301 // There are two possible algorithms for accumulating over
David Spies <dnspies@gmail.com>
parents:
diff changeset
302 // the rows of a sparse matrix
David Spies <dnspies@gmail.com>
parents:
diff changeset
303 // the simple one runs in O(h+nnz) and just
David Spies <dnspies@gmail.com>
parents:
diff changeset
304 // constructs a full result vector (which can
David Spies <dnspies@gmail.com>
parents:
diff changeset
305 // be converted to a sparse vector).
David Spies <dnspies@gmail.com>
parents:
diff changeset
306 // The tricky one uses a heap to construct a sparse
David Spies <dnspies@gmail.com>
parents:
diff changeset
307 // result vector directly and runs in O(w+nnz*log(w)).
David Spies <dnspies@gmail.com>
parents:
diff changeset
308 // We need to look at matrix's dimensions to see
David Spies <dnspies@gmail.com>
parents:
diff changeset
309 // which one will work faster. If the matrix
David Spies <dnspies@gmail.com>
parents:
diff changeset
310 // is tall and sparse enough, we use the second one.
David Spies <dnspies@gmail.com>
parents:
diff changeset
311
David Spies <dnspies@gmail.com>
parents:
diff changeset
312 template<typename E, int dim>
David Spies <dnspies@gmail.com>
parents:
diff changeset
313 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
314 select_sparse_accumulate (const Sparse<E>& matrix, fun_type t, int nargout)
David Spies <dnspies@gmail.com>
parents:
diff changeset
315 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
316 octave_idx_type w = matrix.cols ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
317 octave_idx_type h = matrix.rows ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
318 octave_idx_type nnz = matrix.nnz ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
319 //TODO Deal with h = 0 and w = 0
David Spies <dnspies@gmail.com>
parents:
diff changeset
320 // For perfect optimality there should probably be some constants
David Spies <dnspies@gmail.com>
parents:
diff changeset
321 // before each of these terms (determined by extensive profiling).
David Spies <dnspies@gmail.com>
parents:
diff changeset
322 // But for big-O optimality, just making this comparison is good
David Spies <dnspies@gmail.com>
parents:
diff changeset
323 // enough.
David Spies <dnspies@gmail.com>
parents:
diff changeset
324 // Using float log because being precise isn't important.
David Spies <dnspies@gmail.com>
parents:
diff changeset
325 if (nargout == 1 && dim == ROW_ACCUM && w + nnz * log2f ((float) w) < h + nnz)
David Spies <dnspies@gmail.com>
parents:
diff changeset
326 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
327 switch (t)
David Spies <dnspies@gmail.com>
parents:
diff changeset
328 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
329 case min:
David Spies <dnspies@gmail.com>
parents:
diff changeset
330 return sparse_tall_row_accum<E, TallMMAccum<E, MIN> > (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
331 case max:
David Spies <dnspies@gmail.com>
parents:
diff changeset
332 return sparse_tall_row_accum<E, TallMMAccum<E, MAX> > (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
333 case sum:
David Spies <dnspies@gmail.com>
parents:
diff changeset
334 return sparse_tall_row_accum<E, TallSPAccum<E, SUM> > (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
335 case prod:
David Spies <dnspies@gmail.com>
parents:
diff changeset
336 return sparse_tall_row_accum<E, TallSPAccum<E, PROD> > (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
337 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
338 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
339 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
340 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
341 switch (t)
David Spies <dnspies@gmail.com>
parents:
diff changeset
342 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
343 case min:
David Spies <dnspies@gmail.com>
parents:
diff changeset
344 return sparse_normal_accum<E, SparseMMAccum<E, MIN>, dim> (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
345 case max:
David Spies <dnspies@gmail.com>
parents:
diff changeset
346 return sparse_normal_accum<E, SparseMMAccum<E, MAX>, dim> (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
347 case sum:
David Spies <dnspies@gmail.com>
parents:
diff changeset
348 return sparse_normal_accum<E, SparseSPAccum<E, SUM>, dim> (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
349 case prod:
David Spies <dnspies@gmail.com>
parents:
diff changeset
350 return sparse_normal_accum<E, SparseSPAccum<E, PROD>, dim> (matrix);
David Spies <dnspies@gmail.com>
parents:
diff changeset
351 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
352 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
353 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
354
David Spies <dnspies@gmail.com>
parents:
diff changeset
355 // excluded_indexer takes a dim_vector v and an "excluded dimension" d
David Spies <dnspies@gmail.com>
parents:
diff changeset
356 // and iterates over the indices 0 to n (where n = v.numel()) while
David Spies <dnspies@gmail.com>
parents:
diff changeset
357 // simultaneously maintaining an iterator over (v excluding d) meaning
David Spies <dnspies@gmail.com>
parents:
diff changeset
358 // the index resulting from removing the dth element from v.
David Spies <dnspies@gmail.com>
parents:
diff changeset
359 // ex. let v = [3,4,5] and d = 1
David Spies <dnspies@gmail.com>
parents:
diff changeset
360 // then we can use an excluded_indexer to iterate over the pairs
David Spies <dnspies@gmail.com>
parents:
diff changeset
361 // from_idx to_idx
David Spies <dnspies@gmail.com>
parents:
diff changeset
362 //
David Spies <dnspies@gmail.com>
parents:
diff changeset
363 // 0 0 (= [0,0,0], [0,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
364 // 1 1 (= [1,0,0], [1,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
365 // 2 2 (= [2,0,0], [2,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
366 // 3 0 (= [0,1,0], [0,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
367 // 4 1 (= [1,1,0], [1,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
368 // 5 2 (= [2,1,0], [2,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
369 // 6 0 (= [0,2,0], [0,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
370 // 7 1 (= [1,2,0], [1,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
371 // 8 2 (= [2,2,0], [2,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
372 // 9 0 (= [0,3,0], [0,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
373 // 10 1 (= [1,3,0], [1,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
374 // 11 2 (= [2,3,0], [2,0])
David Spies <dnspies@gmail.com>
parents:
diff changeset
375 // 12 3 (= [0,0,1], [0,1])
David Spies <dnspies@gmail.com>
parents:
diff changeset
376 // 13 4 (= [1,0,1], [1,1])
David Spies <dnspies@gmail.com>
parents:
diff changeset
377 // 14 5 (= [2,0,1], [2,1])
David Spies <dnspies@gmail.com>
parents:
diff changeset
378 // 15 3 (= [0,1,1], [0,1])
David Spies <dnspies@gmail.com>
parents:
diff changeset
379 // ...etc...
David Spies <dnspies@gmail.com>
parents:
diff changeset
380 // 58 13 (= [1,3,4], [1,3])
David Spies <dnspies@gmail.com>
parents:
diff changeset
381 // 59 14 (= [2,3,4], [2,4])
David Spies <dnspies@gmail.com>
parents:
diff changeset
382 //
David Spies <dnspies@gmail.com>
parents:
diff changeset
383 // This is done extremely efficiently using only incrementing and subtraction
David Spies <dnspies@gmail.com>
parents:
diff changeset
384 // (no multiplication,division modulo etc.) and is the most spatial-locality
David Spies <dnspies@gmail.com>
parents:
diff changeset
385 // friendly way to iterate over the two matrices.
David Spies <dnspies@gmail.com>
parents:
diff changeset
386
David Spies <dnspies@gmail.com>
parents:
diff changeset
387 struct excluded_indexer
David Spies <dnspies@gmail.com>
parents:
diff changeset
388 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
389 private:
David Spies <dnspies@gmail.com>
parents:
diff changeset
390 const octave_idx_type before_size;
David Spies <dnspies@gmail.com>
parents:
diff changeset
391 const octave_idx_type between_size;
David Spies <dnspies@gmail.com>
parents:
diff changeset
392
David Spies <dnspies@gmail.com>
parents:
diff changeset
393 octave_idx_type from_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
394 octave_idx_type to_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
395
David Spies <dnspies@gmail.com>
parents:
diff changeset
396 octave_idx_type before_ctr;
David Spies <dnspies@gmail.com>
parents:
diff changeset
397 octave_idx_type between_ctr;
David Spies <dnspies@gmail.com>
parents:
diff changeset
398
David Spies <dnspies@gmail.com>
parents:
diff changeset
399 public:
David Spies <dnspies@gmail.com>
parents:
diff changeset
400
David Spies <dnspies@gmail.com>
parents:
diff changeset
401 excluded_indexer (const dim_vector& sizes, int dim) :
David Spies <dnspies@gmail.com>
parents:
diff changeset
402 before_size (product_prefix (sizes, dim)), between_size (sizes (dim)),
David Spies <dnspies@gmail.com>
parents:
diff changeset
403 from_idx (0), to_idx (0), before_ctr (0), between_ctr (0) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
404
David Spies <dnspies@gmail.com>
parents:
diff changeset
405 // Returns the index for the input (larger) matrix
David Spies <dnspies@gmail.com>
parents:
diff changeset
406 octave_idx_type
David Spies <dnspies@gmail.com>
parents:
diff changeset
407 get_from_idx (void) const
David Spies <dnspies@gmail.com>
parents:
diff changeset
408 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
409 return from_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
410 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
411
David Spies <dnspies@gmail.com>
parents:
diff changeset
412 // Returns the index for the output (smaller) matrix
David Spies <dnspies@gmail.com>
parents:
diff changeset
413 octave_idx_type
David Spies <dnspies@gmail.com>
parents:
diff changeset
414 get_to_idx (void) const
David Spies <dnspies@gmail.com>
parents:
diff changeset
415 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
416 return to_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
417 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
418
David Spies <dnspies@gmail.com>
parents:
diff changeset
419 octave_idx_type
David Spies <dnspies@gmail.com>
parents:
diff changeset
420 get_accum_idx (void) const
David Spies <dnspies@gmail.com>
parents:
diff changeset
421 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
422 return between_ctr;
David Spies <dnspies@gmail.com>
parents:
diff changeset
423 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
424
David Spies <dnspies@gmail.com>
parents:
diff changeset
425 // Increments both indices and then subtracts from
David Spies <dnspies@gmail.com>
parents:
diff changeset
426 // the output index if necessary
David Spies <dnspies@gmail.com>
parents:
diff changeset
427 void
David Spies <dnspies@gmail.com>
parents:
diff changeset
428 operator++ (void)
David Spies <dnspies@gmail.com>
parents:
diff changeset
429 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
430 ++from_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
431 ++to_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
432 ++before_ctr;
David Spies <dnspies@gmail.com>
parents:
diff changeset
433 if (before_ctr == before_size)
David Spies <dnspies@gmail.com>
parents:
diff changeset
434 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
435 before_ctr = 0;
David Spies <dnspies@gmail.com>
parents:
diff changeset
436 ++between_ctr;
David Spies <dnspies@gmail.com>
parents:
diff changeset
437 if (between_ctr == between_size)
David Spies <dnspies@gmail.com>
parents:
diff changeset
438 between_ctr = 0;
David Spies <dnspies@gmail.com>
parents:
diff changeset
439 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
440 to_idx -= before_size;
David Spies <dnspies@gmail.com>
parents:
diff changeset
441 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
442 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
443
David Spies <dnspies@gmail.com>
parents:
diff changeset
444 // Compares the input index with from_size
David Spies <dnspies@gmail.com>
parents:
diff changeset
445 bool
David Spies <dnspies@gmail.com>
parents:
diff changeset
446 operator< (octave_idx_type from_size) const
David Spies <dnspies@gmail.com>
parents:
diff changeset
447 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
448 return from_idx < from_size;
David Spies <dnspies@gmail.com>
parents:
diff changeset
449 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
450 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
451
David Spies <dnspies@gmail.com>
parents:
diff changeset
452 // Accumulate method for full matrices
David Spies <dnspies@gmail.com>
parents:
diff changeset
453 // Accumulator takes a dimension in its constructor. It supports methods
David Spies <dnspies@gmail.com>
parents:
diff changeset
454 // void add(octave_idx_type, Elem<E>) and octave_value_list post_process()
David Spies <dnspies@gmail.com>
parents:
diff changeset
455 template<typename E, typename Accumulator>
David Spies <dnspies@gmail.com>
parents:
diff changeset
456 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
457 full_accumulate (const Array<E>& matrix, int dim)
David Spies <dnspies@gmail.com>
parents:
diff changeset
458 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
459 const dim_vector sizes = matrix.get_dims ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
460 dim_vector res_dims = sizes;
David Spies <dnspies@gmail.com>
parents:
diff changeset
461 res_dims (dim) = 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
462 // TODO Can I do this? Is it safe to mutate a dim_vector
David Spies <dnspies@gmail.com>
parents:
diff changeset
463 // Does (res_dims = sizes) make a copy or copy the pointer?
David Spies <dnspies@gmail.com>
parents:
diff changeset
464 Accumulator res (res_dims);
David Spies <dnspies@gmail.com>
parents:
diff changeset
465 octave_idx_type from_numel = sizes.numel ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
466 octave_idx_type to_numel = res_dims.numel ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
467 for (excluded_indexer i (sizes, dim); i < from_numel; ++i)
David Spies <dnspies@gmail.com>
parents:
diff changeset
468 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
469 res.add (i.get_to_idx (),
David Spies <dnspies@gmail.com>
parents:
diff changeset
470 Elem<E> (i.get_accum_idx (), matrix.xelem (i.get_from_idx ())));
David Spies <dnspies@gmail.com>
parents:
diff changeset
471 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
472 return res.post_process ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
473 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
474
David Spies <dnspies@gmail.com>
parents:
diff changeset
475 // Takes the product of the first dim dimensions of sizes
David Spies <dnspies@gmail.com>
parents:
diff changeset
476 octave_idx_type
David Spies <dnspies@gmail.com>
parents:
diff changeset
477 product_prefix (const dim_vector& sizes, int dim)
David Spies <dnspies@gmail.com>
parents:
diff changeset
478 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
479 assert(dim <= sizes.ndims ());
David Spies <dnspies@gmail.com>
parents:
diff changeset
480 octave_idx_type res = 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
481 for (int i = 0; i < dim; ++i)
David Spies <dnspies@gmail.com>
parents:
diff changeset
482 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
483 res *= sizes (i);
David Spies <dnspies@gmail.com>
parents:
diff changeset
484 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
485 return res;
David Spies <dnspies@gmail.com>
parents:
diff changeset
486 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
487
David Spies <dnspies@gmail.com>
parents:
diff changeset
488 template<typename E, typename Accumulator, int accum_dir>
David Spies <dnspies@gmail.com>
parents:
diff changeset
489 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
490 sparse_normal_accum (const Sparse<E>& matrix)
David Spies <dnspies@gmail.com>
parents:
diff changeset
491 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
492 assert(accum_dir == 1 || accum_dir == 0);
David Spies <dnspies@gmail.com>
parents:
diff changeset
493 dim_vector accum_dims = matrix.dims ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
494 octave_idx_type idx_size = accum_dims (1 - accum_dir);
David Spies <dnspies@gmail.com>
parents:
diff changeset
495 octave_idx_type accum_size = accum_dims (accum_dir);
David Spies <dnspies@gmail.com>
parents:
diff changeset
496 accum_dims (accum_dir) = 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
497 Accumulator res (accum_dims);
David Spies <dnspies@gmail.com>
parents:
diff changeset
498 std::vector<octave_idx_type> known_mex (idx_size, 0);
David Spies <dnspies@gmail.com>
parents:
diff changeset
499 for (octave_idx_type col = 0; col < matrix.cols (); ++col)
David Spies <dnspies@gmail.com>
parents:
diff changeset
500 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
501 for (octave_idx_type i = matrix.cidx (col); i < matrix.cidx (col + 1);
David Spies <dnspies@gmail.com>
parents:
diff changeset
502 ++i)
David Spies <dnspies@gmail.com>
parents:
diff changeset
503 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
504 octave_idx_type res_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
505 octave_idx_type accum_idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
506 if (accum_dir == COL_ACCUM)
David Spies <dnspies@gmail.com>
parents:
diff changeset
507 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
508 res_idx = col;
David Spies <dnspies@gmail.com>
parents:
diff changeset
509 accum_idx = matrix.ridx (i);
David Spies <dnspies@gmail.com>
parents:
diff changeset
510 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
511 else if (accum_dir == ROW_ACCUM)
David Spies <dnspies@gmail.com>
parents:
diff changeset
512 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
513 res_idx = matrix.ridx (i);
David Spies <dnspies@gmail.com>
parents:
diff changeset
514 accum_idx = col;
David Spies <dnspies@gmail.com>
parents:
diff changeset
515 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
516 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
517 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
518 assert(false);
David Spies <dnspies@gmail.com>
parents:
diff changeset
519 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
520 if (known_mex[res_idx] != (octave_idx_type) (-1))
David Spies <dnspies@gmail.com>
parents:
diff changeset
521 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
522 if (accum_idx == known_mex[res_idx])
David Spies <dnspies@gmail.com>
parents:
diff changeset
523 ++known_mex[res_idx];
David Spies <dnspies@gmail.com>
parents:
diff changeset
524 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
525 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
526 assert(accum_idx > known_mex[res_idx]);
David Spies <dnspies@gmail.com>
parents:
diff changeset
527 res.add (res_idx, Elem<E> (known_mex[res_idx], 0));
David Spies <dnspies@gmail.com>
parents:
diff changeset
528 known_mex[res_idx] = (octave_idx_type) (-1);
David Spies <dnspies@gmail.com>
parents:
diff changeset
529 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
530 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
531 res.add (res_idx, Elem<E> (accum_idx, matrix.data[i]));
David Spies <dnspies@gmail.com>
parents:
diff changeset
532 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
533 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
534 for (octave_idx_type i = 0; i < idx_size; ++i)
David Spies <dnspies@gmail.com>
parents:
diff changeset
535 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
536 if (known_mex[i] != (octave_idx_type) (-1) && known_mex[i] < accum_size)
David Spies <dnspies@gmail.com>
parents:
diff changeset
537 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
538 res.add (i, Elem<E> (known_mex[i], 0));
David Spies <dnspies@gmail.com>
parents:
diff changeset
539 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
540 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
541 return res.post_process ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
542 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
543
David Spies <dnspies@gmail.com>
parents:
diff changeset
544 // Knows everything about an index-value pair
David Spies <dnspies@gmail.com>
parents:
diff changeset
545 // in a sparse matrix (row, col, nnz_idx, value)
David Spies <dnspies@gmail.com>
parents:
diff changeset
546 template<typename E>
David Spies <dnspies@gmail.com>
parents:
diff changeset
547 struct SparseElem
David Spies <dnspies@gmail.com>
parents:
diff changeset
548 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
549 const octave_idx_type row;
David Spies <dnspies@gmail.com>
parents:
diff changeset
550 const octave_idx_type col;
David Spies <dnspies@gmail.com>
parents:
diff changeset
551 const E value;
David Spies <dnspies@gmail.com>
parents:
diff changeset
552 const octave_idx_type idx;
David Spies <dnspies@gmail.com>
parents:
diff changeset
553
David Spies <dnspies@gmail.com>
parents:
diff changeset
554 SparseElem (octave_idx_type row, octave_idx_type col, E value,
David Spies <dnspies@gmail.com>
parents:
diff changeset
555 octave_idx_type idx) :
David Spies <dnspies@gmail.com>
parents:
diff changeset
556 row (row), col (col), value (value), idx (idx) { }
David Spies <dnspies@gmail.com>
parents:
diff changeset
557
David Spies <dnspies@gmail.com>
parents:
diff changeset
558 bool
David Spies <dnspies@gmail.com>
parents:
diff changeset
559 operator< (const SparseElem<E> rhs) const
David Spies <dnspies@gmail.com>
parents:
diff changeset
560 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
561 return row < rhs.row || (row == rhs.row && col < rhs.col);
David Spies <dnspies@gmail.com>
parents:
diff changeset
562 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
563 };
David Spies <dnspies@gmail.com>
parents:
diff changeset
564
David Spies <dnspies@gmail.com>
parents:
diff changeset
565 template<typename E, typename TallAccumulator>
David Spies <dnspies@gmail.com>
parents:
diff changeset
566 octave_value_list
David Spies <dnspies@gmail.com>
parents:
diff changeset
567 tall_sparse_row_accum (const Sparse<E>& matrix)
David Spies <dnspies@gmail.com>
parents:
diff changeset
568 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
569 TallAccumulator res;
David Spies <dnspies@gmail.com>
parents:
diff changeset
570
David Spies <dnspies@gmail.com>
parents:
diff changeset
571 std::priority_queue<SparseElem<E> > nextItem;
David Spies <dnspies@gmail.com>
parents:
diff changeset
572 for (octave_idx_type col = 0; col < matrix.cols (); ++col)
David Spies <dnspies@gmail.com>
parents:
diff changeset
573 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
574 octave_idx_type idx = matrix.cidx[col];
David Spies <dnspies@gmail.com>
parents:
diff changeset
575 nextItem.push (
David Spies <dnspies@gmail.com>
parents:
diff changeset
576 SparseElem<E> (matrix.ridx[idx], col, matrix.data[idx], idx));
David Spies <dnspies@gmail.com>
parents:
diff changeset
577 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
578
David Spies <dnspies@gmail.com>
parents:
diff changeset
579 octave_idx_type current_row = -1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
580
David Spies <dnspies@gmail.com>
parents:
diff changeset
581 // mex is short for minimum excluded value.
David Spies <dnspies@gmail.com>
parents:
diff changeset
582 // (meaning the smallest nonnegative integer which is not
David Spies <dnspies@gmail.com>
parents:
diff changeset
583 // in a set. accum_mex is the mex of the columns containing
David Spies <dnspies@gmail.com>
parents:
diff changeset
584 // nonzero elements in the current row.
David Spies <dnspies@gmail.com>
parents:
diff changeset
585 // It's uncommon to find a use for the function
David Spies <dnspies@gmail.com>
parents:
diff changeset
586 // outside of combinatoric game theory. In this case,
David Spies <dnspies@gmail.com>
parents:
diff changeset
587 // a row contains a zero if accum_mex < width.
David Spies <dnspies@gmail.com>
parents:
diff changeset
588 octave_idx_type accum_mex;
David Spies <dnspies@gmail.com>
parents:
diff changeset
589
David Spies <dnspies@gmail.com>
parents:
diff changeset
590 // It's either macro or copy-paste. I chose the lesser
David Spies <dnspies@gmail.com>
parents:
diff changeset
591 // of two evils. If you don't like it, learn Lisp.
David Spies <dnspies@gmail.com>
parents:
diff changeset
592 // ***
David Spies <dnspies@gmail.com>
parents:
diff changeset
593 #define finish_row \
David Spies <dnspies@gmail.com>
parents:
diff changeset
594 if (current_row >= 0 \
David Spies <dnspies@gmail.com>
parents:
diff changeset
595 && accum_mex >= 0 \
David Spies <dnspies@gmail.com>
parents:
diff changeset
596 && accum_mex < matrix.cols ()) \
David Spies <dnspies@gmail.com>
parents:
diff changeset
597 res.join_term (Elem<E> (accum_mex, 0)); \
David Spies <dnspies@gmail.com>
parents:
diff changeset
598
David Spies <dnspies@gmail.com>
parents:
diff changeset
599 while (!nextItem.empty ())
David Spies <dnspies@gmail.com>
parents:
diff changeset
600 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
601 SparseElem<E> item = nextItem.front ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
602 nextItem.pop ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
603 if (item.row != current_row)
David Spies <dnspies@gmail.com>
parents:
diff changeset
604 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
605 // macro; see *** above
David Spies <dnspies@gmail.com>
parents:
diff changeset
606 finish_row;
David Spies <dnspies@gmail.com>
parents:
diff changeset
607
David Spies <dnspies@gmail.com>
parents:
diff changeset
608 current_row = item.row;
David Spies <dnspies@gmail.com>
parents:
diff changeset
609 if (item.col > 0)
David Spies <dnspies@gmail.com>
parents:
diff changeset
610 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
611 res.add_term (item.row, Elem<E> (0, 0));
David Spies <dnspies@gmail.com>
parents:
diff changeset
612 accum_mex = -1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
613 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
614 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
615 accum_mex = 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
616 res.add_term (item.row, Elem<E> (item.col, item.value));
David Spies <dnspies@gmail.com>
parents:
diff changeset
617 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
618 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
619 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
620 if (accum_mex != (octave_idx_type) (-1))
David Spies <dnspies@gmail.com>
parents:
diff changeset
621 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
622 if (item.col == accum_mex)
David Spies <dnspies@gmail.com>
parents:
diff changeset
623 ++accum_mex;
David Spies <dnspies@gmail.com>
parents:
diff changeset
624 else
David Spies <dnspies@gmail.com>
parents:
diff changeset
625 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
626 res.join_term (Elem<E> (accum_mex, 0));
David Spies <dnspies@gmail.com>
parents:
diff changeset
627 accum_mex = -1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
628 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
629 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
630 res.join_term (Elem<E> (item.col, item.value));
David Spies <dnspies@gmail.com>
parents:
diff changeset
631 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
632
David Spies <dnspies@gmail.com>
parents:
diff changeset
633 octave_idx_type idx = item.idx + 1;
David Spies <dnspies@gmail.com>
parents:
diff changeset
634 octave_idx_type col = item.col;
David Spies <dnspies@gmail.com>
parents:
diff changeset
635 if (idx < matrix.cidx[col + 1])
David Spies <dnspies@gmail.com>
parents:
diff changeset
636 {
David Spies <dnspies@gmail.com>
parents:
diff changeset
637 nextItem.push (
David Spies <dnspies@gmail.com>
parents:
diff changeset
638 SparseElem<E> (matrix.ridx[idx], col, matrix.data[idx], idx));
David Spies <dnspies@gmail.com>
parents:
diff changeset
639 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
640 }
David Spies <dnspies@gmail.com>
parents:
diff changeset
641
David Spies <dnspies@gmail.com>
parents:
diff changeset
642 // macro; see *** above
David Spies <dnspies@gmail.com>
parents:
diff changeset
643 finish_row;
David Spies <dnspies@gmail.com>
parents:
diff changeset
644
David Spies <dnspies@gmail.com>
parents:
diff changeset
645 #undef finish_row
David Spies <dnspies@gmail.com>
parents:
diff changeset
646
David Spies <dnspies@gmail.com>
parents:
diff changeset
647 return res.post_process ();
David Spies <dnspies@gmail.com>
parents:
diff changeset
648 }