MOOCHO (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AbstractLinAlgPack_GenPermMatrixSlice.cpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization
5 // Copyright (2003) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #include <assert.h>
43 
44 #include <sstream>
45 #include <functional>
46 #include <algorithm>
47 
49 #include "Teuchos_Assert.hpp"
50 
51 #ifdef _WINDOWS
52 
53 namespace std {
54 
55 // Help some compilers lookup the function.
56 inline
57 void swap(
62  )
63 {
65 }
66 
67 } // end namespace std
68 
69 #endif // _WINDOWS
70 
71 namespace {
72 
73 //
74 template< class T >
75 inline
76 T my_min( const T& v1, const T& v2 ) { return v1 < v2 ? v1 : v2; }
77 
78 // Return a string with the same name as the enumeration
79 const char* ordered_by_str(
81 {
82  switch( ordered_by ) {
84  return "BY_ROW";
86  return "BY_COL";
88  return "BY_ROW_AND_COL";
90  return "UNORDERED";
91  }
92  TEUCHOS_TEST_FOR_EXCEPT(true); // should never be executed
93  return 0;
94 }
95 
96 // Define function objects for comparing by row and by column
97 
98 template<class T>
99 struct imp_row_less
100  : public std::binary_function<
101  AbstractLinAlgPack::GenPermMatrixSliceIteratorPack::row_col_value_type<T>
102  ,AbstractLinAlgPack::GenPermMatrixSliceIteratorPack::row_col_value_type<T>
103  ,bool
104  >
105 {
106  bool operator()(
109  )
110  {
111  return v1.row_i_ < v2.row_i_;
112  }
113 };
114 
115 template<class T>
116 struct imp_col_less
117  : public std::binary_function<
118  AbstractLinAlgPack::GenPermMatrixSliceIteratorPack::row_col_value_type<T>
119  ,AbstractLinAlgPack::GenPermMatrixSliceIteratorPack::row_col_value_type<T>
120  ,bool
121  >
122 {
123  bool operator()(
126  )
127  {
128  return v1.col_j_ < v2.col_j_;
129  }
130 };
131 
132 } // end namespace
133 
134 //#ifdef _WINDOWS
135 //namespace std {
136 // using imp_row_less;
137 //}
138 //#endif // _WINDOWS
139 
140 namespace AbstractLinAlgPack {
141 
143  : rows_(0), cols_(0), nz_(0)
144 {}
145 
147 {
148  rows_ = rows;
149  cols_ = cols;
150  nz_ = type == IDENTITY_MATRIX ? my_min(rows,cols) : 0;
152  row_i_ = NULL;
153  col_j_ = NULL; // Don't need to be set but might as well for safely
154  row_off_ = 0; // ...
155  col_off_ = 0; // ...
156 }
157 
160  ,size_type cols
161  ,size_type nz
162  ,difference_type row_off
163  ,difference_type col_off
164  ,EOrderedBy ordered_by
165  ,const size_type row_i[]
166  ,const size_type col_j[]
167  ,bool test_setup
168  )
169 {
170  namespace GPMSIP = GenPermMatrixSliceIteratorPack;
171 
172  if( test_setup ) {
173  std::ostringstream omsg;
174  omsg << "\nGenPermMatrixSlice::initialize(...) : Error: ";
175  // Validate the input data (at least partially)
176  validate_input_data(rows,cols,nz,row_off,col_off,ordered_by,row_i,col_j,omsg);
177  // Validate the ordering and uniquness
178  const size_type *ordered_sequence = NULL;
179  if( ordered_by == GPMSIP::BY_ROW || ordered_by == GPMSIP::BY_ROW_AND_COL ) {
180  for( size_type k = 1; k < nz; ++k ) {
182  row_i[k-1] >= row_i[k], std::invalid_argument
183  ,"GenPermMatrixSlice::initialize(...) : Error: "
184  "row_i[" << k-1 << "] = " << row_i[k-1]
185  << " >= row_i[" << k << "] = " << row_i[k]
186  << "\nThis is not sorted by row!" );
187  }
188  }
189  if( ordered_by == GPMSIP::BY_COL || ordered_by == GPMSIP::BY_ROW_AND_COL ) {
190  for( size_type k = 1; k < nz; ++k ) {
192  col_j[k-1] >= col_j[k], std::invalid_argument
193  ,"GenPermMatrixSlice::initialize(...) : Error: "
194  "col_j[" << k-1 << "] = " << col_j[k-1]
195  << " >= col_j[" << k << "] = " << col_j[k]
196  << "\nThis is not sorted by column!" );
197  }
198  }
199  }
200  // Set the members
201  rows_ = rows;
202  cols_ = cols;
203  nz_ = nz;
204  row_off_ = row_off;
205  col_off_ = col_off;
207  row_i_ = nz ? row_i : NULL;
208  col_j_ = nz ? col_j : NULL;
209 }
210 
213  ,size_type cols
214  ,size_type nz
215  ,difference_type row_off
216  ,difference_type col_off
217  ,EOrderedBy ordered_by
218  ,size_type row_i[]
219  ,size_type col_j[]
220  ,bool test_setup
221  )
222 {
223  namespace GPMSIP = GenPermMatrixSliceIteratorPack;
225  ordered_by == GPMSIP::BY_ROW_AND_COL, std::invalid_argument
226  ,"GenPermMatrixSlice::initialize_and_sort(...) : Error, "
227  "ordered_by == GPMSIP::BY_ROW_AND_COL, we can not sort by row and column!" );
228  if( test_setup ) {
229  std::ostringstream omsg;
230  omsg << "\nGenPermMatrixSlice::initialize_and_sort(...) : Error:\n";
231  // Validate the input data (at least partially)
232  validate_input_data(rows,cols,nz,row_off,col_off,ordered_by,row_i,col_j,omsg);
233  }
234 
235  // Sort by row or column
236  typedef GPMSIP::row_col_iterator<size_type> row_col_itr_t;
237  row_col_itr_t
238  row_col_itr = row_col_itr_t( row_off, col_off, row_i, col_j, nz );
239  if( ordered_by == GPMSIP::BY_ROW ) {
240  std::stable_sort( row_col_itr, row_col_itr + nz
241  , imp_row_less<size_type>() );
242  }
243  else if( ordered_by == GPMSIP::BY_COL ) {
244  std::stable_sort( row_col_itr, row_col_itr + nz
245  , imp_col_less<size_type>() );
246  }
247 
248  initialize(rows,cols,nz,row_off,col_off,ordered_by,row_i,col_j,test_setup);
249 }
250 
252 {
253  this->initialize( gpms.rows_, gpms.cols_, gpms.nz_, gpms.row_off_
254  , gpms.col_off_, gpms.ordered_by_, gpms.row_i_, gpms.col_j_
255  , false );
256 }
257 
259 {
260  namespace QPMSIP = GenPermMatrixSliceIteratorPack;
261  if( col_j < 1 || cols_ < col_j )
262  std::out_of_range(
263  "GenPermMatrixSlice::lookup_row_i(col_j) : Error, "
264  "col_j is out of bounds" );
265  if(!nz_)
266  return 0;
267  if(is_identity())
268  return col_j <= nz_ ? col_j : 0;
269  const size_type
270  *itr = NULL;
272  itr = std::lower_bound( col_j_, col_j_ + nz_, col_j );
273  else
274  itr = std::find( col_j_, col_j_ + nz_, col_j );
275  return (itr != col_j_ + nz_ && *itr == col_j) ? row_i_[itr - col_j_] : 0;
276 }
277 
279 {
280  namespace QPMSIP = GenPermMatrixSliceIteratorPack;
281  if( row_i < 1 || rows_ < row_i )
282  std::out_of_range(
283  "GenPermMatrixSlice::lookup_col_j(row_i) : Error, "
284  "row_i is out of bounds" );
285  if(!nz_)
286  return 0;
287  if(is_identity())
288  return row_i <= nz_ ? row_i : 0;
289  const size_type
290  *itr = NULL;
292  itr = std::lower_bound( row_i_, row_i_ + nz_, row_i );
293  else
294  itr = std::find( row_i_, row_i_ + nz_, row_i );
295  return (itr != row_i_ + nz_ && *itr == row_i) ? col_j_[itr - row_i_] : 0;
296 }
297 
299 {
302 }
303 
305 {
308 }
309 
311  const Range1D& rng, EOrderedBy ordered_by ) const
312 {
313  namespace GPMSIP = GenPermMatrixSliceIteratorPack;
314 
316 
317  // Validate the input
319  ordered_by == GPMSIP::BY_ROW_AND_COL, std::invalid_argument
320  ,"GenPermMatrixSlice::initialize_and_sort(...) : Error, "
321  "ordered_by == GPMSIP::BY_ROW_AND_COL, we can not sort by row and column!" );
323  rng.full_range(), std::logic_error,
324  "GenPermMatrixSlice::create_submatrix(...) : Error, "
325  "The range argument can not be rng.full_range() == true" );
327  ordered_by == GPMSIP::BY_ROW && rng.ubound() > rows(), std::logic_error
328  ,"GenPermMatrixSlice::create_submatrix(...) : Error, "
329  "rng.ubound() can not be larger than this->rows()" );
331  ordered_by == GPMSIP::BY_COL && rng.ubound() > cols(), std::logic_error
332  ,"GenPermMatrixSlice::create_submatrix(...) : Error, "
333  "rng.ubound() can not be larger than this->cols()" );
335  ordered_by == GPMSIP::UNORDERED, std::logic_error
336  ,"GenPermMatrixSlice::create_submatrix(...) : Error, "
337  "You can have ordered_by == GPMSIP::UNORDERED" );
338 
339  // Find the upper and lower k for row[k], col[k] indices
340  size_type
341  k_l = 0, // zero based
342  k_u = nz() + 1; // zero based (== nz + 1 flag that there are no nonzeros to even search)
343  size_type
344  rows = 0,
345  cols = 0;
347  row_off = 0,
348  col_off = 0;
349  switch( ordered_by ) {
350  case GPMSIP::BY_ROW:
351  case GPMSIP::BY_COL:
352  {
353  TEUCHOS_TEST_FOR_EXCEPTION(
355  && ( nz() > 1 && ordered_by != this->ordered_by() )
356  ,std::logic_error
357  ,"GenPermMatrixSlice::create_submatrix(...) : Error, "
358  << "nz = " << nz() << " > 1 and "
359  << "ordered_by = " << ordered_by_str(ordered_by)
360  << " != this->ordered_by() = "
361  << ordered_by_str(this->ordered_by()) );
362  // Search the rows or the columns.
363  const size_type
364  *search_k = NULL;
366  search_k_off;
367  if( ordered_by == GPMSIP::BY_ROW ) {
368  search_k = row_i_; // may be null
369  search_k_off = row_off_;
370  rows = rng.size();
371  cols = this->cols();
372  row_off = row_off_ - (difference_type)(rng.lbound() - 1);
373  col_off = col_off_;
374  }
375  else { // BY_COL
376  search_k = col_j_; // may be null
377  search_k_off = col_off_;
378  rows = this->rows();
379  cols = rng.size();
380  row_off = row_off_;
381  col_off = col_off_ - (difference_type)(rng.lbound() - 1);;
382  }
383  if( search_k ) {
384  const size_type
385  *l = std::lower_bound( search_k, search_k + nz()
386  , rng.lbound() - search_k_off );
387  k_l = l - search_k;
388  // If we did not find the lower bound in the range, don't even bother
389  // looking for the upper bound.
390  if( k_l != nz() ) {
391  const size_type
392  *u = std::upper_bound( search_k, search_k + nz()
393  , rng.ubound() - search_k_off );
394  k_u = u - search_k;
395  // Here, if there are any nonzero elements in this range then
396  // k_u - k_l > 0 will always be true!
397  }
398  }
399  break;
400  }
401  case GPMSIP::UNORDERED:
403  }
404  GenPermMatrixSlice gpms;
405  if( k_u - k_l > 0 && k_u != nz() + 1 ) {
406  gpms.initialize(
407  rows, cols
408  , k_u - k_l
409  , row_off, col_off
410  , ordered_by
411  , row_i_ + k_l
412  , col_j_ + k_l
413  );
414  }
415  else {
416  gpms.initialize(
417  rows, cols
418  , 0
419  , row_off, col_off
420  , ordered_by
421  , NULL
422  , NULL
423  );
424  }
425  return gpms;
426 }
427 
428 // static members
429 
432  ,size_type cols
433  ,size_type nz
434  ,difference_type row_off
435  ,difference_type col_off
436  ,EOrderedBy ordered_by
437  ,const size_type row_i[]
438  ,const size_type col_j[]
439  ,std::ostringstream &omsg
440  )
441 {
442  namespace GPMSIP = GenPermMatrixSliceIteratorPack;
443 
445  nz > rows * cols, std::invalid_argument
446  ,omsg.str() << "nz = " << nz << " can not be greater than rows * cols = "
447  << rows << " * " << cols << " = " << rows * cols );
448 
449  // First see if everything is in range.
450  for( size_type k = 0; k < nz; ++k ) {
452  row_i[k] + row_off < 1 || rows < row_i[k] + row_off, std::invalid_argument
453  ,omsg.str() << "row_i[" << k << "] + row_off = " << row_i[k] << " + " << row_off
454  << " = " << (row_i[k] + row_off)
455  << " is out of range [1,rows] = [1," << rows << "]" );
457  col_j[k] + col_off < 1 || cols < col_j[k] + col_off, std::invalid_argument
458  ,omsg.str() << "col_j[" << k << "] + col_off = " << col_j[k] << " + " << col_off
459  << " = " << (col_j[k] + col_off)
460  << " is out of range [1,cols] = [1," << cols << "]" );
461  }
462 
463  // ToDo: Technically, we need to validate that the nonzero elements row_i[k], col_j[k] are
464  // unique but this is much harder to do!
465 
466 }
467 
468 // private
469 
471 {
473  is_identity(), std::logic_error
474  ,"GenPermMatrixSlice::validate_not_identity() : "
475  "Error, this->is_identity() is true" );
476 }
477 
478 } // end namespace AbstractLinAlgPack
GenPermMatrixSlice()
Construct to an uninitialzied, unsized matrix.
Teuchos::Ordinal size_type
Typedef for the size type of elements that are used by the library.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Index size() const
Return the size of the range (ubound() - lbound() + 1)
void initialize(index_type rows, index_type cols, EIdentityOrZero type)
Initialize an identity or zero permutation.
Index ubound() const
Return upper bound of the range.
size_type rows(size_type rows, size_type cols, BLAS_Cpp::Transp _trans)
Return rows of a possible transposed matrix.
const_iterator end() const
Return the end of this->const_iterator_begin().
void bind(const GenPermMatrixSlice &gpms)
Bind the view of another GenPermMatrixSlice object.
. One-based subregion index range class.
This is a full random access iterator for accessing row and colunmn indices.
static void validate_input_data(index_type rows, index_type cols, index_type nz, difference_type row_off, difference_type col_off, EOrderedBy ordered_by, const index_type row_i[], const index_type col_j[], std::ostringstream &omsg)
const GenPermMatrixSlice create_submatrix(const Range1D &rng, EOrderedBy ordered_by) const
Create a submatrix by row, by column.
const_iterator begin() const
Return a random access iterator for accessing which row and column that each nonzero 1...
bool full_range() const
Returns true if the range represents the entire region (constructed from Range1D()) ...
Index lbound() const
Return lower bound of the range.
void swap(row_col_value_type< T > &v1, row_col_value_type< T > &v2)
Swap row_col_value_type<T> objects.
External storage of a row and column indice. This is required for creating a temporary in an assignme...
size_type cols(size_type rows, size_type cols, BLAS_Cpp::Transp _trans)
Return columns of a possible transposed matrix.
const f_int f_dbl_prec const f_int f_int const f_int f_int const f_dbl_prec & u
index_type lookup_row_i(index_type col_j) const
Lookup the ith row index for the nonzero entry in the jth column if it exists.
void initialize_and_sort(index_type rows, index_type cols, index_type nz, difference_type row_off, difference_type col_off, EOrderedBy ordered_by, index_type row_i[], index_type col_j[], bool test_setup=false)
Initialize and sort.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
index_type lookup_col_j(index_type row_i) const
Lookup the jth column index for the nonzero entry in the ith row if it exists.
Concrete matrix type to represent general permutation (mapping) matrices.
GenPermMatrixSliceIteratorPack::row_col_iterator< const index_type > const_iterator