AbstractLinAlgPack: C++ Interfaces For Vectors, Matrices And Related Linear Algebra Objects  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
AbstractLinAlgPack_GenPermMatrixSliceOp.cpp
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 "AbstractLinAlgPack_GenPermMatrixSliceOp.hpp"
45 #include "AbstractLinAlgPack_SpVectorOp.hpp"
46 #include "AbstractLinAlgPack_SpVectorClass.hpp"
47 #include "DenseLinAlgPack_DVectorClass.hpp"
48 #include "AbstractLinAlgPack_LinAlgOpPackHack.hpp"
49 #include "DenseLinAlgPack_AssertOp.hpp"
50 
51 void AbstractLinAlgPack::V_StMtV(
52  SpVector* y, value_type a, const GenPermMatrixSlice& P
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;
58  using DenseLinAlgPack::MtV_assert_sizes;
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  }
93  if( P.ordered_by() == GPMSIP::BY_ROW_AND_COL
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 
101 void AbstractLinAlgPack::V_StMtV(
102  SpVector* y, value_type a, const GenPermMatrixSlice& P
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;
108  using DenseLinAlgPack::MtV_assert_sizes;
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  }
143  if( P.ordered_by() == GPMSIP::BY_ROW_AND_COL
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 
152  SpVector* y, value_type a, const GenPermMatrixSlice& P
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;
158  using DenseLinAlgPack::Vp_MtV_assert_sizes;
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 &&
194  ( P.ordered_by() == GPMSIP::BY_ROW_AND_COL
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 
203  DVectorSlice* y, value_type a, const GenPermMatrixSlice& P
204  , BLAS_Cpp::Transp P_trans, const DVectorSlice& x, value_type b )
205 {
206  using DenseLinAlgPack::Vt_S;
207  using DenseLinAlgPack::Vp_MtV_assert_sizes;
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 
241  DVectorSlice* y, value_type a, const GenPermMatrixSlice& P
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;
250  using DenseLinAlgPack::Vp_MtV_assert_sizes;
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 )
269  || P.ordered_by() == GPMSIP::BY_ROW_AND_COL )
270  {
271  GenPermMatrixSlice::const_iterator
272  P_itr = P.begin(),
273  P_end = P.end();
274  SpVectorSlice::const_iterator
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 
309 AbstractLinAlgPack::GenPermMatrixSliceIteratorPack::EOrderedBy
310 ordered_by(
311  AbstractLinAlgPack::GenPermMatrixSliceIteratorPack::EOrderedBy P_ordered_by
312  , BLAS_Cpp::Transp P_trans
313  )
314 {
315  using BLAS_Cpp::no_trans;
316  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
317  GPMSIP::EOrderedBy
318  opP_ordered_by;
319  switch( P_ordered_by ) {
320  case GPMSIP::BY_ROW_AND_COL:
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 
340 void AbstractLinAlgPack::intersection(
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[]
349  ,GenPermMatrixSlice *Q
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  //
364  DenseLinAlgPack::MtM_assert_sizes(
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);
372  GPMSIP::EOrderedBy
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 {
408  GenPermMatrixSlice::const_iterator
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  {
450  GenPermMatrixSlice::const_iterator
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 {
463  GenPermMatrixSlice::const_iterator
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 }
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
size_type rows(size_type rows, size_type cols, BLAS_Cpp::Transp _trans)
size_t size_type
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)
Transp
size_type cols(size_type rows, size_type cols, BLAS_Cpp::Transp _trans)
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)