CppAD: A C++ Algorithmic Differentiation Package  20171217
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
color_symmetric.hpp
Go to the documentation of this file.
1 # ifndef CPPAD_LOCAL_COLOR_SYMMETRIC_HPP
2 # define CPPAD_LOCAL_COLOR_SYMMETRIC_HPP
3 
4 # include <cppad/configure.hpp>
6 
7 /* --------------------------------------------------------------------------
8 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
9 
10 CppAD is distributed under multiple licenses. This distribution is under
11 the terms of the
12  Eclipse Public License Version 1.0.
13 
14 A copy of this license is included in the COPYING file of this distribution.
15 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
16 -------------------------------------------------------------------------- */
17 
18 namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
19 /*!
20 \file color_symmetric.hpp
21 Coloring algorithm for a symmetric sparse matrix.
22 */
23 // --------------------------------------------------------------------------
24 /*!
25 CppAD algorithm for determining which rows of a symmetric sparse matrix can be
26 computed together.
27 
28 \tparam VectorSize
29 is a simple vector class with elements of type size_t.
30 
31 \tparam VectorSet
32 is a vector_of_sets class.
33 
34 \param pattern [in]
35 Is a representation of the sparsity pattern for the matrix.
36 
37 \param row [in/out]
38 is a vector specifying which row indices to compute.
39 
40 \param col [in/out]
41 is a vector, with the same size as row,
42 that specifies which column indices to compute.
43 \n
44 \n
45 Input:
46 For each valid index \c k, the index pair
47 <code>(row[k], col[k])</code> must be present in the sparsity pattern.
48 It may be that some entries in the sparsity pattern do not need to be computed;
49 i.e, do not appear in the set of
50 <code>(row[k], col[k])</code> entries.
51 \n
52 \n
53 Output:
54 On output, some of row and column indices may have been swapped
55 \code
56  std::swap( row[k], col[k] )
57 \endcode
58 So the the the color for row[k] can be used to compute entry
59 (row[k], col[k]).
60 
61 \param color [out]
62 is a vector with size m.
63 The input value of its elements does not matter.
64 Upon return, it is a coloring for the rows of the sparse matrix.
65 Note that if color[i] == m, then there is no index k for which
66 row[k] == i (for the return value of row).
67 \n
68 \n
69 Fix any (i, j) in the sparsity pattern.
70 Suppose that there is a row index i1 with
71 i1 != i, color[i1] == color[i] and (i1, j) is in the sparsity pattern.
72 If follows that for all j1 with
73 j1 != j and color[j1] == color[j],
74 (j1, i ) is not in the sparsity pattern.
75 \n
76 \n
77 This routine tries to minimize, with respect to the choice of colors,
78 the maximum, with respect to k, of <code>color[ row[k] ]</code>.
79 */
80 template <class VectorSet>
82  const VectorSet& pattern ,
85  CppAD::vector<size_t>& color )
86 {
87  size_t K = row.size();
88  size_t m = pattern.n_set();
89  CPPAD_ASSERT_UNKNOWN( m == pattern.end() );
90  CPPAD_ASSERT_UNKNOWN( color.size() == m );
91  CPPAD_ASSERT_UNKNOWN( col.size() == K );
92 
93  // row, column pairs that appear in ( row[k], col[k] )
94  CppAD::vector< std::set<size_t> > pair_needed(m);
95  std::set<size_t>::iterator itr1, itr2;
96  for(size_t k1 = 0; k1 < K; k1++)
97  { CPPAD_ASSERT_UNKNOWN( pattern.is_element(row[k1], col[k1]) );
98  pair_needed[ row[k1] ].insert( col[k1] );
99  pair_needed[ col[k1] ].insert( row[k1] );
100  }
101 
102  // order the rows decending by number of pairs needed
103  CppAD::vector<size_t> key(m), order2row(m);
104  for(size_t i1 = 0; i1 < m; i1++)
105  { CPPAD_ASSERT_UNKNOWN( pair_needed[i1].size() <= m );
106  key[i1] = m - pair_needed[i1].size();
107  }
108  CppAD::index_sort(key, order2row);
109 
110  // mapping from order index to row index
111  CppAD::vector<size_t> row2order(m);
112  for(size_t o1 = 0; o1 < m; o1++)
113  row2order[ order2row[o1] ] = o1;
114 
115  // initial coloring
116  color.resize(m);
117  size_t c1 = 0;
118  for(size_t o1 = 0; o1 < m; o1++)
119  { size_t i1 = order2row[o1];
120  if( pair_needed[i1].empty() )
121  color[i1] = m;
122  else
123  color[i1] = c1++;
124  }
125 
126  // which colors are forbidden for this row
127  CppAD::vector<bool> forbidden(m);
128 
129  // must start with row zero so that we remove results computed for it
130  for(size_t o1 = 0; o1 < m; o1++) // for each row that appears (in order)
131  if( color[ order2row[o1] ] < m )
132  { size_t i1 = order2row[o1];
133  c1 = color[i1];
134 
135  // initial all colors as ok for this row
136  // (value of forbidden for c > c1 does not matter)
137  for(size_t c2 = 0; c2 <= c1; c2++)
138  forbidden[c2] = false;
139 
140  // -----------------------------------------------------
141  // Forbid grouping with rows that would destroy results that are
142  // needed for this row.
143  itr1 = pair_needed[i1].begin();
144  while( itr1 != pair_needed[i1].end() )
145  { // entry (i1, j1) is needed for this row
146  size_t j1 = *itr1;
147 
148  // Forbid rows i2 != i1 that have non-zero sparsity at (i2, j1).
149  // Note that this is the same as non-zero sparsity at (j1, i2)
150  typename VectorSet::const_iterator pattern_itr(pattern, j1);
151  size_t i2 = *pattern_itr;
152  while( i2 != pattern.end() )
153  { size_t c2 = color[i2];
154  if( c2 < c1 )
155  forbidden[c2] = true;
156  i2 = *(++pattern_itr);
157  }
158  itr1++;
159  }
160  // -----------------------------------------------------
161  // Forbid grouping with rows that this row would destroy results for
162  for(size_t o2 = 0; o2 < o1; o2++)
163  { size_t i2 = order2row[o2];
164  size_t c2 = color[i2];
165  itr2 = pair_needed[i2].begin();
166  while( itr2 != pair_needed[i2].end() )
167  { size_t j2 = *itr2;
168  // row i2 needs pair (i2, j2).
169  // Forbid grouping with i1 if (i1, j2) has non-zero sparsity
170  if( pattern.is_element(i1, j2) )
171  forbidden[c2] = true;
172  itr2++;
173  }
174  }
175 
176  // pick the color with smallest index
177  size_t c2 = 0;
178  while( forbidden[c2] )
179  { c2++;
180  CPPAD_ASSERT_UNKNOWN( c2 <= c1 );
181  }
182  color[i1] = c2;
183 
184  // no longer need results that are computed by this row
185  itr1 = pair_needed[i1].begin();
186  while( itr1 != pair_needed[i1].end() )
187  { size_t j1 = *itr1;
188  if( row2order[j1] > o1 )
189  { itr2 = pair_needed[j1].find(i1);
190  if( itr2 != pair_needed[j1].end() )
191  { pair_needed[j1].erase(itr2);
192  if( pair_needed[j1].empty() )
193  color[j1] = m;
194  }
195  }
196  itr1++;
197  }
198  }
199 
200  // determine which sparsity entries need to be reflected
201  for(size_t k1 = 0; k1 < row.size(); k1++)
202  { size_t i1 = row[k1];
203  size_t j1 = col[k1];
204  itr1 = pair_needed[i1].find(j1);
205  if( itr1 == pair_needed[i1].end() )
206  { row[k1] = j1;
207  col[k1] = i1;
208 # ifndef NDEBUG
209  itr1 = pair_needed[j1].find(i1);
210  CPPAD_ASSERT_UNKNOWN( itr1 != pair_needed[j1].end() );
211 # endif
212  }
213  }
214  return;
215 }
216 
217 // --------------------------------------------------------------------------
218 /*!
219 Colpack algorithm for determining which rows of a symmetric sparse matrix
220 can be computed together.
221 
222 \copydetails CppAD::local::color_symmetric_cppad
223 */
224 template <class VectorSet>
226  const VectorSet& pattern ,
227  CppAD::vector<size_t>& row ,
228  CppAD::vector<size_t>& col ,
229  CppAD::vector<size_t>& color )
230 {
231 # if ! CPPAD_HAS_COLPACK
232  CPPAD_ASSERT_UNKNOWN(false);
233  return;
234 # else
235  size_t i, j, k;
236  size_t m = pattern.n_set();
237  CPPAD_ASSERT_UNKNOWN( m == pattern.end() );
238  CPPAD_ASSERT_UNKNOWN( row.size() == col.size() );
239 
240  // Determine number of non-zero entries in each row
241  CppAD::vector<size_t> n_nonzero(m);
242  size_t n_nonzero_total = 0;
243  for(i = 0; i < m; i++)
244  { n_nonzero[i] = 0;
245  typename VectorSet::const_iterator pattern_itr(pattern, i);
246  j = *pattern_itr;
247  while( j != pattern.end() )
248  { n_nonzero[i]++;
249  j = *(++pattern_itr);
250  }
251  n_nonzero_total += n_nonzero[i];
252  }
253 
254  // Allocate memory and fill in Adolc sparsity pattern
255  CppAD::vector<unsigned int*> adolc_pattern(m);
256  CppAD::vector<unsigned int> adolc_memory(m + n_nonzero_total);
257  size_t i_memory = 0;
258  for(i = 0; i < m; i++)
259  { adolc_pattern[i] = adolc_memory.data() + i_memory;
261  std::numeric_limits<unsigned int>::max() >= n_nonzero[i],
262  "Matrix is too large for colpack"
263  );
264  adolc_pattern[i][0] = static_cast<unsigned int>( n_nonzero[i] );
265  typename VectorSet::const_iterator pattern_itr(pattern, i);
266  j = *pattern_itr;
267  k = 1;
268  while(j != pattern.end() )
269  {
271  std::numeric_limits<unsigned int>::max() >= j,
272  "Matrix is too large for colpack"
273  );
274  adolc_pattern[i][k++] = static_cast<unsigned int>( j );
275  j = *(++pattern_itr);
276  }
277  CPPAD_ASSERT_UNKNOWN( k == 1 + n_nonzero[i] );
278  i_memory += k;
279  }
280  CPPAD_ASSERT_UNKNOWN( i_memory == m + n_nonzero_total );
281 
282  // Must use an external routine for this part of the calculation because
283  // ColPack/ColPackHeaders.h has as 'using namespace std' at global level.
284  cppad_colpack_symmetric(color, m, adolc_pattern);
285 
286  // determine which sparsity entries need to be reflected
287  for(size_t k1 = 0; k1 < row.size(); k1++)
288  { size_t i1 = row[k1];
289  size_t j1 = col[k1];
290  bool reflect = false;
291  for(size_t i2 = 0; i2 < m; i2++)
292  if( (i1 != i2) & (color[i1]==color[i2]) )
293  { for(size_t k2 = 1; k2 <= adolc_pattern[i2][0]; k2++)
294  { size_t j2 = adolc_pattern[i2][k2];
295  reflect |= (j1 == j2);
296  }
297  }
298  if( reflect )
299  { row[k1] = j1;
300  col[k1] = i1;
301  }
302  }
303  return;
304 # endif // CPPAD_HAS_COLPACK
305 }
306 
307 } } // END_CPPAD_LOCAL_NAMESPACE
308 
309 # endif
#define CPPAD_ASSERT_KNOWN(exp, msg)
Check that exp is true, if not print msg and terminate execution.
Type * data(void)
raw pointer to the data
Definition: vector.hpp:391
void resize(size_t n)
change the number of elements in this vector.
Definition: vector.hpp:399
size_t size(void) const
number of elements currently in this vector.
Definition: vector.hpp:387
void index_sort(const VectorKey &keys, VectorSize &ind)
Compute the indices that sort a vector of keys.
Definition: index_sort.hpp:140
#define CPPAD_ASSERT_UNKNOWN(exp)
Check that exp is true, if not terminate execution.
void color_symmetric_cppad(const VectorSet &pattern, CppAD::vector< size_t > &row, CppAD::vector< size_t > &col, CppAD::vector< size_t > &color)
CppAD algorithm for determining which rows of a symmetric sparse matrix can be computed together...
void color_symmetric_colpack(const VectorSet &pattern, CppAD::vector< size_t > &row, CppAD::vector< size_t > &col, CppAD::vector< size_t > &color)
Colpack algorithm for determining which rows of a symmetric sparse matrix can be computed together...