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