1 # ifndef CPPAD_LOCAL_SPARSE_INTERNAL_HPP
2 # define CPPAD_LOCAL_SPARSE_INTERNAL_HPP
3 /* --------------------------------------------------------------------------
4 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-19 Bradley M. Bell
5
6 CppAD is distributed under the terms of the
7 Eclipse Public License Version 2.0.
8
9 This Source Code may also be made available under the following
10 Secondary License when the conditions for such availability set forth
11 in the Eclipse Public License, Version 2.0 are satisfied:
12 GNU General Public License, Version 2.0 or later.
13 ---------------------------------------------------------------------------- */
14
15 // necessary definitions
16 # include <cppad/local/define.hpp>
17 # include <cppad/local/sparse/pack_setvec.hpp>
18 # include <cppad/local/sparse/list_setvec.hpp>
19 # include <cppad/local/sparse/svec_setvec.hpp>
20
21 // BEGIN_CPPAD_LOCAL_SPARSE_NAMESPACE
22 namespace CppAD { namespace local { namespace sparse {
23
24 /*!
25 \file sparse_internal.hpp
26 Routines that enable code to be independent of which internal spasity pattern
27 is used.
28 */
29 // ---------------------------------------------------------------------------
30 /*!
31 Template structure used obtain the internal sparsity pattern type
32 form the corresponding element type.
33 The general form is not valid, must use a specialization.
34
35 \tparam Element_type
36 type of an element in the sparsity structrue.
37
38 \par <code>internal_pattern<Element_type>::pattern_type</code>
39 is the type of the corresponding internal sparsity pattern.
40 */
41 template <class Element_type> struct internal_pattern;
42 /// Specilization for bool elements.
43 template <>
44 struct internal_pattern<bool>
45 {
46 typedef sparse::pack_setvec pattern_type;
47 };
48 /// Specilization for <code>std::set<size_t></code> elements.
49 template <>
50 struct internal_pattern< std::set<size_t> >
51 {
52 typedef list_setvec pattern_type;
53 };
54 // ---------------------------------------------------------------------------
55 /*!
56 Update the internal sparsity pattern for a sub-set of rows
57
58 \tparam SizeVector
59 The type used for index sparsity patterns. This is a simple vector
60 with elements of type size_t.
61
62 \tparam InternalSparsitiy
63 The type used for intenal sparsity patterns. This can be either
64 sparse::pack_setvec or list_setvec.
65
66 \param zero_empty
67 If this is true, the internal sparstity pattern corresponds to row zero
68 must be empty on input and will be emtpy output; i.e., any corresponding
69 values in pattern_in will be ignored.
70
71 \param input_empty
72 If this is true, the initial sparsity pattern for row
73 internal_index[i] is empty for all i.
74 In this case, one is setting the sparsity patterns; i.e.,
75 the output pattern in row internal_index[i] is the corresponding
76 entries in pattern.
77
78 \param transpose
79 If this is true, pattern_in is transposed.
80
81 \param internal_index
82 This specifies the sub-set of rows in internal_pattern that we are updating.
83 If traspose is false (true),
84 this is the mapping from row (column) index in pattern_in to the corresponding
85 row index in the internal_pattern.
86
87 \param internal_pattern
88 On input, the number of sets internal_pattern.n_set(),
89 and possible elements internal_pattern.end(), have been set.
90 If input_empty is true, and all of the sets
91 in internal_index are empty on input.
92 On output, the entries in pattern_in are added to internal_pattern.
93 To be specific, suppose transpose is false, and (i, j) is a possibly
94 non-zero entry in pattern_in, the entry (internal_index[i], j) is added
95 to internal_pattern.
96 On the other hand, if transpose is true,
97 the entry (internal_index[j], i) is added to internal_pattern.
98
99 \param pattern_in
100 This is the sparsity pattern for variables,
101 or its transpose, depending on the value of transpose.
102 */
103 template <class SizeVector, class InternalSparsity>
set_internal_pattern(bool zero_empty,bool input_empty,bool transpose,const pod_vector<size_t> & internal_index,InternalSparsity & internal_pattern,const sparse_rc<SizeVector> & pattern_in)104 void set_internal_pattern(
105 bool zero_empty ,
106 bool input_empty ,
107 bool transpose ,
108 const pod_vector<size_t>& internal_index ,
109 InternalSparsity& internal_pattern ,
110 const sparse_rc<SizeVector>& pattern_in )
111 {
112 size_t nr = internal_index.size();
113 # ifndef NDEBUG
114 size_t nc = internal_pattern.end();
115 if( transpose )
116 { CPPAD_ASSERT_UNKNOWN( pattern_in.nr() == nc );
117 CPPAD_ASSERT_UNKNOWN( pattern_in.nc() == nr );
118 }
119 else
120 { CPPAD_ASSERT_UNKNOWN( pattern_in.nr() == nr );
121 CPPAD_ASSERT_UNKNOWN( pattern_in.nc() == nc );
122 }
123 if( input_empty ) for(size_t i = 0; i < nr; i++)
124 { size_t i_var = internal_index[i];
125 CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
126 }
127 # endif
128 const SizeVector& row( pattern_in.row() );
129 const SizeVector& col( pattern_in.col() );
130 size_t nnz = row.size();
131 for(size_t k = 0; k < nnz; k++)
132 { size_t r = row[k];
133 size_t c = col[k];
134 if( transpose )
135 std::swap(r, c);
136 //
137 size_t i_var = internal_index[r];
138 CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
139 CPPAD_ASSERT_UNKNOWN( c < nc );
140 bool ignore = zero_empty && i_var == 0;
141 if( ! ignore )
142 internal_pattern.post_element( internal_index[r], c );
143 }
144 // process posts
145 for(size_t i = 0; i < nr; ++i)
146 internal_pattern.process_post( internal_index[i] );
147 }
148 template <class InternalSparsity>
set_internal_pattern(bool zero_empty,bool input_empty,bool transpose,const pod_vector<size_t> & internal_index,InternalSparsity & internal_pattern,const vectorBool & pattern_in)149 void set_internal_pattern(
150 bool zero_empty ,
151 bool input_empty ,
152 bool transpose ,
153 const pod_vector<size_t>& internal_index ,
154 InternalSparsity& internal_pattern ,
155 const vectorBool& pattern_in )
156 { size_t nr = internal_index.size();
157 size_t nc = internal_pattern.end();
158 # ifndef NDEBUG
159 CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr * nc );
160 if( input_empty ) for(size_t i = 0; i < nr; i++)
161 { size_t i_var = internal_index[i];
162 CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
163 }
164 # endif
165 for(size_t i = 0; i < nr; i++)
166 { for(size_t j = 0; j < nc; j++)
167 { bool flag = pattern_in[i * nc + j];
168 if( transpose )
169 flag = pattern_in[j * nr + i];
170 if( flag )
171 { size_t i_var = internal_index[i];
172 CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
173 CPPAD_ASSERT_UNKNOWN( j < nc );
174 bool ignore = zero_empty && i_var == 0;
175 if( ! ignore )
176 internal_pattern.post_element( i_var, j);
177 }
178 }
179 }
180 // process posts
181 for(size_t i = 0; i < nr; ++i)
182 internal_pattern.process_post( internal_index[i] );
183 return;
184 }
185 template <class InternalSparsity>
set_internal_pattern(bool zero_empty,bool input_empty,bool transpose,const pod_vector<size_t> & internal_index,InternalSparsity & internal_pattern,const vector<bool> & pattern_in)186 void set_internal_pattern(
187 bool zero_empty ,
188 bool input_empty ,
189 bool transpose ,
190 const pod_vector<size_t>& internal_index ,
191 InternalSparsity& internal_pattern ,
192 const vector<bool>& pattern_in )
193 { size_t nr = internal_index.size();
194 size_t nc = internal_pattern.end();
195 # ifndef NDEBUG
196 CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr * nc );
197 if( input_empty ) for(size_t i = 0; i < nr; i++)
198 { size_t i_var = internal_index[i];
199 CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
200 }
201 # endif
202 for(size_t i = 0; i < nr; i++)
203 { for(size_t j = 0; j < nc; j++)
204 { bool flag = pattern_in[i * nc + j];
205 if( transpose )
206 flag = pattern_in[j * nr + i];
207 if( flag )
208 { size_t i_var = internal_index[i];
209 CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
210 CPPAD_ASSERT_UNKNOWN( j < nc );
211 bool ignore = zero_empty && i_var == 0;
212 if( ! ignore )
213 internal_pattern.post_element( i_var, j);
214 }
215 }
216 }
217 // process posts
218 for(size_t i = 0; i < nr; ++i)
219 internal_pattern.process_post( internal_index[i] );
220 return;
221 }
222 template <class InternalSparsity>
set_internal_pattern(bool zero_empty,bool input_empty,bool transpose,const pod_vector<size_t> & internal_index,InternalSparsity & internal_pattern,const vector<std::set<size_t>> & pattern_in)223 void set_internal_pattern(
224 bool zero_empty ,
225 bool input_empty ,
226 bool transpose ,
227 const pod_vector<size_t>& internal_index ,
228 InternalSparsity& internal_pattern ,
229 const vector< std::set<size_t> >& pattern_in )
230 { size_t nr = internal_index.size();
231 size_t nc = internal_pattern.end();
232 # ifndef NDEBUG
233 if( input_empty ) for(size_t i = 0; i < nr; i++)
234 { size_t i_var = internal_index[i];
235 CPPAD_ASSERT_UNKNOWN( internal_pattern.number_elements(i_var) == 0 );
236 }
237 # endif
238 if( transpose )
239 { CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nc );
240 for(size_t j = 0; j < nc; j++)
241 { std::set<size_t>::const_iterator itr( pattern_in[j].begin() );
242 while( itr != pattern_in[j].end() )
243 { size_t i = *itr;
244 size_t i_var = internal_index[i];
245 CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
246 CPPAD_ASSERT_UNKNOWN( j < nc );
247 bool ignore = zero_empty && i_var == 0;
248 if( ! ignore )
249 internal_pattern.post_element( i_var, j);
250 ++itr;
251 }
252 }
253 }
254 else
255 { CPPAD_ASSERT_UNKNOWN( pattern_in.size() == nr );
256 for(size_t i = 0; i < nr; i++)
257 { std::set<size_t>::const_iterator itr( pattern_in[i].begin() );
258 while( itr != pattern_in[i].end() )
259 { size_t j = *itr;
260 size_t i_var = internal_index[i];
261 CPPAD_ASSERT_UNKNOWN( i_var < internal_pattern.n_set() );
262 CPPAD_ASSERT_UNKNOWN( j < nc );
263 bool ignore = zero_empty && i_var == 0;
264 if( ! ignore )
265 internal_pattern.post_element( i_var, j);
266 ++itr;
267 }
268 }
269 }
270 // process posts
271 for(size_t i = 0; i < nr; ++i)
272 internal_pattern.process_post( internal_index[i] );
273 return;
274 }
275 // ---------------------------------------------------------------------------
276 /*!
277 Get sparsity pattern for a sub-set of variables
278
279 \tparam SizeVector
280 The type used for index sparsity patterns. This is a simple vector
281 with elements of type size_t.
282
283 \tparam InternalSparsitiy
284 The type used for intenal sparsity patterns. This can be either
285 sparse::pack_setvec or list_setvec.
286
287 \param transpose
288 If this is true, pattern_out is transposed.
289
290 \param internal_index
291 If transpose is false (true)
292 this is the mapping from row (column) an index in pattern_out
293 to the corresponding row index in internal_pattern.
294
295 \param internal_pattern
296 This is the internal sparsity pattern.
297
298 \param pattern_out
299 The input value of pattern_out does not matter.
300 Upon return it is an index sparsity pattern for each of the variables
301 in internal_index, or its transpose, depending on the value of transpose.
302 */
303 template <class SizeVector, class InternalSparsity>
get_internal_pattern(bool transpose,const pod_vector<size_t> & internal_index,const InternalSparsity & internal_pattern,sparse_rc<SizeVector> & pattern_out)304 void get_internal_pattern(
305 bool transpose ,
306 const pod_vector<size_t>& internal_index ,
307 const InternalSparsity& internal_pattern ,
308 sparse_rc<SizeVector>& pattern_out )
309 { typedef typename InternalSparsity::const_iterator iterator;
310 // number variables
311 size_t nr = internal_index.size();
312 // column size of interanl sparstiy pattern
313 size_t nc = internal_pattern.end();
314 // determine nnz, the number of possibly non-zero index pairs
315 size_t nnz = 0;
316 for(size_t i = 0; i < nr; i++)
317 { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
318 iterator itr(internal_pattern, internal_index[i]);
319 size_t j = *itr;
320 while( j < nc )
321 { ++nnz;
322 j = *(++itr);
323 }
324 }
325 // transposed
326 if( transpose )
327 { pattern_out.resize(nc, nr, nnz);
328 //
329 size_t k = 0;
330 for(size_t i = 0; i < nr; i++)
331 { iterator itr(internal_pattern, internal_index[i]);
332 size_t j = *itr;
333 while( j < nc )
334 { pattern_out.set(k++, j, i);
335 j = *(++itr);
336 }
337 }
338 return;
339 }
340 // not transposed
341 pattern_out.resize(nr, nc, nnz);
342 //
343 size_t k = 0;
344 for(size_t i = 0; i < nr; i++)
345 { iterator itr(internal_pattern, internal_index[i]);
346 size_t j = *itr;
347 while( j < nc )
348 { pattern_out.set(k++, i, j);
349 j = *(++itr);
350 }
351 }
352 return;
353 }
354 template <class InternalSparsity>
get_internal_pattern(bool transpose,const pod_vector<size_t> & internal_index,const InternalSparsity & internal_pattern,vectorBool & pattern_out)355 void get_internal_pattern(
356 bool transpose ,
357 const pod_vector<size_t>& internal_index ,
358 const InternalSparsity& internal_pattern ,
359 vectorBool& pattern_out )
360 { typedef typename InternalSparsity::const_iterator iterator;
361 // number variables
362 size_t nr = internal_index.size();
363 //
364 // column size of interanl sparstiy pattern
365 size_t nc = internal_pattern.end();
366 //
367 pattern_out.resize(nr * nc);
368 for(size_t ij = 0; ij < nr * nc; ij++)
369 pattern_out[ij] = false;
370 //
371 for(size_t i = 0; i < nr; i++)
372 { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
373 iterator itr(internal_pattern, internal_index[i]);
374 size_t j = *itr;
375 while( j < nc )
376 { if( transpose )
377 pattern_out[j * nr + i] = true;
378 else
379 pattern_out[i * nc + j] = true;
380 j = *(++itr);
381 }
382 }
383 return;
384 }
385 template <class InternalSparsity>
get_internal_pattern(bool transpose,const pod_vector<size_t> & internal_index,const InternalSparsity & internal_pattern,vector<bool> & pattern_out)386 void get_internal_pattern(
387 bool transpose ,
388 const pod_vector<size_t>& internal_index ,
389 const InternalSparsity& internal_pattern ,
390 vector<bool>& pattern_out )
391 { typedef typename InternalSparsity::const_iterator iterator;
392 // number variables
393 size_t nr = internal_index.size();
394 //
395 // column size of interanl sparstiy pattern
396 size_t nc = internal_pattern.end();
397 //
398 pattern_out.resize(nr * nc);
399 for(size_t ij = 0; ij < nr * nc; ij++)
400 pattern_out[ij] = false;
401 //
402 for(size_t i = 0; i < nr; i++)
403 { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
404 iterator itr(internal_pattern, internal_index[i]);
405 size_t j = *itr;
406 while( j < nc )
407 { if( transpose )
408 pattern_out[j * nr + i] = true;
409 else
410 pattern_out[i * nc + j] = true;
411 j = *(++itr);
412 }
413 }
414 return;
415 }
416 template <class InternalSparsity>
get_internal_pattern(bool transpose,const pod_vector<size_t> & internal_index,const InternalSparsity & internal_pattern,vector<std::set<size_t>> & pattern_out)417 void get_internal_pattern(
418 bool transpose ,
419 const pod_vector<size_t>& internal_index ,
420 const InternalSparsity& internal_pattern ,
421 vector< std::set<size_t> >& pattern_out )
422 { typedef typename InternalSparsity::const_iterator iterator;
423 // number variables
424 size_t nr = internal_index.size();
425 //
426 // column size of interanl sparstiy pattern
427 size_t nc = internal_pattern.end();
428 //
429 if( transpose )
430 pattern_out.resize(nc);
431 else
432 pattern_out.resize(nr);
433 for(size_t k = 0; k < pattern_out.size(); k++)
434 pattern_out[k].clear();
435 //
436 for(size_t i = 0; i < nr; i++)
437 { CPPAD_ASSERT_UNKNOWN( internal_index[i] < internal_pattern.n_set() );
438 iterator itr(internal_pattern, internal_index[i]);
439 size_t j = *itr;
440 while( j < nc )
441 { if( transpose )
442 pattern_out[j].insert(i);
443 else
444 pattern_out[i].insert(j);
445 j = *(++itr);
446 }
447 }
448 return;
449 }
450
451
452
453 } } } // END_CPPAD_LOCAL_SPARSE_NAMESPACE
454
455 # endif
456