MOOCHO (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AbstractLinAlgPack_GenPermMatrixSliceOp.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 
50 
53  , BLAS_Cpp::Transp P_trans, const DVectorSlice& x )
54 {
55  using BLAS_Cpp::no_trans;
56  using BLAS_Cpp::trans;
57  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
59 
60  MtV_assert_sizes( P.rows(), P.cols(), P_trans, x.dim() );
61 
62  y->resize( BLAS_Cpp::rows( P.rows(), P.cols(), P_trans ), P.nz() );
63 
64  typedef SpVector::element_type ele_t;
65 
66  if( P.is_identity() ) {
67  for( size_type i = 1; i <= P.nz(); ++i ) {
68  const value_type x_j = x(i);
69  if( x_j != 0.0 )
70  y->add_element( ele_t( i, a * x_j ) );
71  }
72  }
73  else if( P_trans == no_trans ) {
74  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
75  const size_type
76  i = itr->row_i(),
77  j = itr->col_j();
78  const value_type x_j = x(j);
79  if( x_j != 0.0 )
80  y->add_element( ele_t( i, a * x_j ) );
81  }
82  }
83  else {
84  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
85  const size_type
86  j = itr->row_i(),
87  i = itr->col_j();
88  const value_type x_j = x(j);
89  if( x_j != 0.0 )
90  y->add_element( ele_t( i, a * x_j ) );
91  }
92  }
94  || ( P_trans == no_trans && P.ordered_by() == GPMSIP::BY_ROW )
95  || ( P_trans == trans && P.ordered_by() == GPMSIP::BY_COL ) )
96  {
97  y->assume_sorted(true);
98  }
99 }
100 
103  , BLAS_Cpp::Transp P_trans, const SpVectorSlice& x )
104 {
105  using BLAS_Cpp::no_trans;
106  using BLAS_Cpp::trans;
107  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
109  MtV_assert_sizes( P.rows(), P.cols(), P_trans, x.dim() );
110 
111  y->resize( BLAS_Cpp::rows( P.rows(), P.cols(), P_trans ), P.nz() );
112 
113  typedef SpVector::element_type ele_t;
114  const SpVectorSlice::element_type *ele_ptr;
115 
116  if( P.is_identity() ) {
117  AbstractLinAlgPack::add_elements( y, 1.0, x(1,P.nz()) );
118  AbstractLinAlgPack::Vt_S( &(*y)(), a );
119  }
120  else if( x.is_sorted() ) {
121  if( P_trans == no_trans ) {
122  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
123  const size_type
124  i = itr->row_i(),
125  j = itr->col_j();
126  if( ele_ptr = x.lookup_element(j) )
127  y->add_element( ele_t( i, a * ele_ptr->value() ) );
128  }
129  }
130  else {
131  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
132  const size_type
133  j = itr->row_i(),
134  i = itr->col_j();
135  if( ele_ptr = x.lookup_element(j) )
136  y->add_element( ele_t( i, a * ele_ptr->value() ) );
137  }
138  }
139  }
140  else {
141  TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: Implement the other cases!
142  }
144  || ( P_trans == no_trans && P.ordered_by() == GPMSIP::BY_ROW )
145  || ( P_trans == trans && P.ordered_by() == GPMSIP::BY_COL ) )
146  {
147  y->assume_sorted(true);
148  }
149 }
150 
153  , BLAS_Cpp::Transp P_trans, const DVectorSlice& x )
154 {
155  using BLAS_Cpp::no_trans;
156  using BLAS_Cpp::trans;
157  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
159 
160  Vp_MtV_assert_sizes( y->dim(), P.rows(), P.cols(), P_trans, x.dim() );
161 
162  typedef SpVector::element_type ele_t;
163 
164  const bool was_sorted = y->is_sorted();
165 
166  if( P.is_identity() ) {
167  for( size_type i = 1; i <= P.nz(); ++i ) {
168  const value_type x_j = x(i);
169  if( x_j != 0.0 )
170  y->add_element( ele_t( i, a * x_j ) );
171  }
172  }
173  else if( P_trans == no_trans ) {
174  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
175  const size_type
176  i = itr->row_i(),
177  j = itr->col_j();
178  const value_type x_j = x(j);
179  if( x_j != 0.0 )
180  y->add_element( ele_t( i, a * x_j ) );
181  }
182  }
183  else {
184  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
185  const size_type
186  j = itr->row_i(),
187  i = itr->col_j();
188  const value_type x_j = x(j);
189  if( x_j != 0.0 )
190  y->add_element( ele_t( i, a * x_j ) );
191  }
192  }
193  if( was_sorted &&
195  || ( P_trans == no_trans && P.ordered_by() == GPMSIP::BY_ROW )
196  || ( P_trans == trans && P.ordered_by() == GPMSIP::BY_COL ) ) )
197  {
198  y->assume_sorted(true);
199  }
200 }
201 
204  , BLAS_Cpp::Transp P_trans, const DVectorSlice& x, value_type b )
205 {
206  using DenseLinAlgPack::Vt_S;
208  Vp_MtV_assert_sizes( y->dim(), P.rows(), P.cols(), P_trans, x.dim() );
209  // y = b*y
210  if( b == 0.0 )
211  *y = 0.0;
212  else
213  Vt_S(y,b);
214  // y += a*op(P)*x
215  if( P.is_identity() ) {
216  if( b == 0.0 )
217  *y = 0.0;
218  else
219  DenseLinAlgPack::Vt_S( y, b );
220  DenseLinAlgPack::Vp_StV( &(*y)(1,P.nz()), a, x(1,P.nz()) );
221  }
222  else if( P_trans == BLAS_Cpp::no_trans ) {
223  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
224  const size_type
225  i = itr->row_i(),
226  j = itr->col_j();
227  (*y)(i) += a * x(j);
228  }
229  }
230  else {
231  for( GenPermMatrixSlice::const_iterator itr = P.begin(); itr != P.end(); ++itr ) {
232  const size_type
233  j = itr->row_i(),
234  i = itr->col_j();
235  (*y)(i) += a * x(j);
236  }
237  }
238 }
239 
242  , BLAS_Cpp::Transp P_trans, const SpVectorSlice& x, value_type b )
243 {
244  using BLAS_Cpp::no_trans;
245  using BLAS_Cpp::trans;
246  using BLAS_Cpp::rows;
247  using BLAS_Cpp::cols;
248  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
249  using DenseLinAlgPack::Vt_S;
251 
252  Vp_MtV_assert_sizes( y->dim(), P.rows(), P.cols(), P_trans, x.dim() );
253  // y = b*y
254  if( b == 0.0 )
255  *y = 0.0;
256  else
257  Vt_S(y,b);
258  // y += a*op(P)*x
259  if( P.is_identity() ) {
260  DenseLinAlgPack::Vt_S( y, b ); // takes care of b == 0.0 and y == NaN
261  AbstractLinAlgPack::Vp_StV( &(*y)(1,P.nz()), a, x(1,P.nz()) );
262  }
263  else if( x.is_sorted() ) {
264  const SpVectorSlice::difference_type x_off = x.offset();
265  if( P_trans == no_trans && P.ordered_by() == GPMSIP::BY_COL ) {
266  TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: implement this!
267  }
268  else if( ( P_trans == trans && P.ordered_by() == GPMSIP::BY_ROW )
270  {
272  P_itr = P.begin(),
273  P_end = P.end();
275  x_itr = x.begin(),
276  x_end = x.end();
277  while( P_itr != P_end && x_itr != x_end ) {
278  const size_type
279  i = rows(P_itr->row_i(),P_itr->col_j(),P_trans),
280  j = cols(P_itr->row_i(),P_itr->col_j(),P_trans);
281  if( j < x_itr->index() + x_off ) {
282  ++P_itr;
283  continue;
284  }
285  else if( j > x_itr->index() + x_off ) {
286  ++x_itr;
287  continue;
288  }
289  else { // they are equal
290  (*y)(i) += a * x_itr->value();
291  ++P_itr;
292  ++x_itr;
293  }
294  }
295  }
296  else {
297  TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: Implement what ever this case is?
298  }
299  }
300  else {
301  // Since things do not match up we will have to create a
302  // temporary dense copy of x to operate on.
303  TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: Implement this!
304  }
305 }
306 
307 namespace {
308 
310 ordered_by(
312  , BLAS_Cpp::Transp P_trans
313  )
314 {
315  using BLAS_Cpp::no_trans;
316  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
318  opP_ordered_by;
319  switch( P_ordered_by ) {
321  opP_ordered_by = GPMSIP::BY_ROW_AND_COL;
322  break;
323  case GPMSIP::BY_ROW:
324  opP_ordered_by = P_trans == no_trans ? GPMSIP::BY_ROW : GPMSIP::BY_COL;
325  break;
326  case GPMSIP::BY_COL:
327  opP_ordered_by = P_trans == no_trans ? GPMSIP::BY_COL : GPMSIP::BY_COL;
328  break;
329  case GPMSIP::UNORDERED:
330  opP_ordered_by = GPMSIP::UNORDERED;
331  break;
332  default:
333  TEUCHOS_TEST_FOR_EXCEPT(true); // Should never happen
334  }
335  return opP_ordered_by;
336 }
337 
338 } // end namespace
339 
341  const GenPermMatrixSlice &P1
342  ,BLAS_Cpp::Transp P1_trans
343  ,const GenPermMatrixSlice &P2
344  ,BLAS_Cpp::Transp P2_trans
345  ,size_type *Q_nz
346  ,const size_type Q_max_nz
347  ,size_type Q_row_i[]
348  ,size_type Q_col_j[]
350  )
351 {
352  using BLAS_Cpp::no_trans;
353  using BLAS_Cpp::trans;
354  using BLAS_Cpp::trans_not;
355  using BLAS_Cpp::rows;
356  using BLAS_Cpp::cols;
357  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
358  //
359  // Q = op(P1)*op(P2)
360  //
361  // There are several different possibilities for how to compute this
362  // intersection.
363  //
365  P1.rows(), P1.cols() , P1_trans, P2.rows(), P2.cols() , P2_trans );
366  //
367  const size_type
368  opP1_rows = rows(P1.rows(),P1.cols(),P1_trans),
369  opP1_cols = cols(P1.rows(),P1.cols(),P1_trans),
370  opP2_rows = rows(P2.rows(),P2.cols(),P2_trans),
371  opP2_cols = cols(P2.rows(),P2.cols(),P2_trans);
373  opP1_ordered_by = ordered_by(P1.ordered_by(),P1_trans),
374  opP2_ordered_by = ordered_by(P2.ordered_by(),P2_trans);
375  //
376  *Q_nz = 0;
377  // Either is zero?
378  if( !P1.nz() || !P2.nz() ) {
379  *Q_nz = 0;
380  if(Q)
381  Q->initialize(opP1_rows,opP2_cols,GenPermMatrixSlice::ZERO_MATRIX);
382  return;
383  }
384  // Both are identity?
385  if( P1.is_identity() && P2.is_identity() ) {
386  *Q_nz = P1.nz(); // Should be the same as P2.nz();
387  TEUCHOS_TEST_FOR_EXCEPT( !( P1.nz() == P2.nz() ) );
388  if(Q)
389  Q->initialize(opP1_rows,opP2_cols,GenPermMatrixSlice::IDENTITY_MATRIX);
390  return;
391  }
392  // One is identity?
393  if( P1.is_identity() || P2.is_identity() ) {
394  TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: Implement this but it is a little tricking?
395  return;
396  }
397  //
398  // Both are not identity or zero
399  //
400  if( ( opP1_ordered_by == GPMSIP::BY_COL || opP1_ordered_by == GPMSIP::BY_ROW_AND_COL )
401  && ( opP2_ordered_by == GPMSIP::BY_ROW || opP2_ordered_by == GPMSIP::BY_ROW_AND_COL ) )
402  {
403  // This is great! Both of the matrices are sorted and we don't need any temparary storage
404  if( Q_max_nz ) {
405  TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: Implement initializing Q_row_i, Q_col_j
406  }
407  else {
409  P1_itr = P1.begin(), // Should not throw exception!
410  P1_end = P1.end(),
411  P2_itr = P2.begin(), // Should not throw exception!
412  P2_end = P2.end();
413  while( P1_itr != P1_end && P2_itr != P2_end ) {
414  const size_type
415  opP1_col_j = cols(P1_itr->row_i(),P1_itr->col_j(),P1_trans),
416  opP2_row_i = rows(P2_itr->row_i(),P2_itr->col_j(),P2_trans);
417  if( opP1_col_j < opP2_row_i ) {
418  ++P1_itr;
419  continue;
420  }
421  if( opP1_col_j > opP2_row_i ) {
422  ++P2_itr;
423  continue;
424  }
425  ++(*Q_nz);
426  ++P1_itr;
427  ++P2_itr;
428  }
429  }
430  }
431  else {
432  //
433  // We will load the row indices of op(P1) or the column indices op(P1)
434  // indexed by column or row indices (whichever is smaller)
435  // into a temporary sorted buffer and then loop through the nonzeros of the other.
436  //
437  // First let's get reorder P1 and P2 so that we put the rows of P2 into a buffer
438  //
439  const GenPermMatrixSlice
440  &oP1 = opP1_cols > opP2_rows ? P1 : P2,
441  &oP2 = opP1_cols > opP2_rows ? P2 : P1;
442  const BLAS_Cpp::Transp
443  oP1_trans = opP1_cols > opP2_rows ? P1_trans : trans_not(P1_trans),
444  oP2_trans = opP1_cols > opP2_rows ? P2_trans : trans_not(P2_trans);
445  // Load the column indices of op(op(P2)) into a lookup array
446  typedef std::vector<size_type> oP2_col_j_lookup_t; // Todo: use tempoarary workspace
447  oP2_col_j_lookup_t oP2_col_j_lookup(rows(oP2.rows(),oP2.rows(),oP2_trans));
448  std::fill( oP2_col_j_lookup.begin(), oP2_col_j_lookup.end(), 0 );
449  {
451  itr = oP2.begin(), // Should not throw exception!
452  itr_end = oP2.end();
453  while( itr != itr_end ) {
454  oP2_col_j_lookup[rows(itr->row_i(),itr->col_j(),oP2_trans)]
455  = cols(itr->row_i(),itr->col_j(),oP2_trans);
456  }
457  }
458  // Loop through the columns of op(op(P1)) and look for matches
459  if( Q_max_nz ) {
460  TEUCHOS_TEST_FOR_EXCEPT(true); // ToDo: Implement initializing Q_row_i, Q_col_j
461  }
462  else {
464  itr = oP1.begin(), // Should not throw exception!
465  itr_end = oP1.end();
466  while( itr != itr_end ) {
467  const size_type
468  oP2_col_j = oP2_col_j_lookup[cols(itr->row_i(),itr->col_j(),oP1_trans)];
469  if(oP2_col_j)
470  ++(*Q_nz);
471  }
472  }
473 
474  }
475  // Setup Q
476  TEUCHOS_TEST_FOR_EXCEPT( !( Q == NULL ) ); // ToDo: Implement initializing Q
477 }
difference_type offset() const
Return the offset for the indexes (ith real index = begin()[i-1]->index() + offset()# ...
void Vp_StV(DVectorSlice *vs_lhs, value_type alpha, const DVectorSlice &vs_rhs)
vs_lhs += alpha * vs_rhs (BLAS xAXPY)
void resize(size_type size, size_type max_nz, difference_type offset=0)
Resize to #size# with a maximum of max_nz# non-zero elements.
size_type dim() const
Returns the number of elements of the VectorSliceTmpl.
void V_StMtV(SpVector *sv_lhs, value_type alpha, const GenPermMatrixSlice &P_rhs1, BLAS_Cpp::Transp P_rhs1_trans, const DVectorSlice &vs_rhs2)
sv_lhs = alpha * op(P_rhs1) * vs_rhs2.
size_type dim() const
Return the number of elements in the full vector.
void MtM_assert_sizes(size_type m_rhs1_rows, size_type m_rhs1_cols, BLAS_Cpp::Transp trans_rhs1, size_type m_rhs2_rows, size_type m_rhs2_cols, BLAS_Cpp::Transp trans_rhs2)
op(m_lhs) += op(m_rhs1)
void Vt_S(VectorMutable *v_lhs, const value_type &alpha)
v_lhs *= alpha
void Vp_StV(VectorMutable *v_lhs, const value_type &alpha, const Vector &v_rhs)
v_lhs = alpha * v_rhs + v_lhs
void initialize(index_type rows, index_type cols, EIdentityOrZero type)
Initialize an identity or zero permutation.
bool is_sorted() const
Return true if the sequence is sorted.
size_type rows(size_type rows, size_type cols, BLAS_Cpp::Transp _trans)
Return rows of a possible transposed matrix.
void add_element(element_type ele)
Add an unsorted element.
const_iterator end() const
Return the end of this->const_iterator_begin().
bool is_sorted() const
Return true if the sequence is assumed sorted.
Transposed.
Not transposed.
This is a full random access iterator for accessing row and colunmn indices.
size_type dim() const
Return the number of elements in the full vector.
const_iterator begin() const
Return a random access iterator for accessing which row and column that each nonzero 1...
void assume_sorted(bool assume_is_sorted)
Called by the client to inform this sparse vector object that the elements be assumed to be in sequen...
void Vp_StMtV(VectorMutable *v_lhs, value_type alpha, const MatrixOp &M_rhs1, BLAS_Cpp::Transp trans_rhs1, const Vector &v_rhs2, value_type beta=1.0)
v_lhs = alpha * op(M_rhs1) * v_rhs2 + beta * v_lhs (BLAS xGEMV)
Transp trans_not(Transp _trans)
Return the opposite of the transpose argument.
void Vt_S(DVectorSlice *vs_lhs, value_type alpha)
vs_lhs *= alpha (BLAS xSCAL) (*** Note that alpha == 0.0 is handeled as vs_lhs = 0.0)
void Vp_MtV_assert_sizes(size_type v_lhs_size, size_type m_rhs1_rows, size_type m_rhs1_cols, BLAS_Cpp::Transp trans_rhs1, size_type v_rhs2_size)
v_lhs += op(m_rhs1) * v_rhs2
void add_elements(SpVector *sv_lhs, value_type alpha, const DVectorSlice &vs_rhs, size_type offset=0, bool add_zeros=true)
Add elements from a dense vector to a sparse vector.
void MtV_assert_sizes(size_type m_rhs1_rows, size_type m_rhs1_cols, BLAS_Cpp::Transp trans_rhs1, size_type v_rhs2_size)
op(m_rhs1) * v_rhs2
void intersection(const GenPermMatrixSlice &P1, BLAS_Cpp::Transp P1_trans, const GenPermMatrixSlice &P2, BLAS_Cpp::Transp P2_trans, size_type *Q_nz, const size_type Q_max_nz=0, size_type Q_row_i[]=NULL, size_type Q_col_j[]=NULL, GenPermMatrixSlice *Q=NULL)
Find the intersection between two GenPermMatrixSlice objects.
Transp
TRANS.
size_type cols(size_type rows, size_type cols, BLAS_Cpp::Transp _trans)
Return columns of a possible transposed matrix.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
Concrete matrix type to represent general permutation (mapping) matrices.