MOOCHO (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AbstractLinAlgPack_SparseVectorOpDef.hpp
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 // The declarations for these functions is in the file AbstractLinAlgPack_SparseVectorOpDecl.hpp
43 // but because of a bug with the MS VC++ 5.0 compiler you can not use
44 // namespace qualification with definitions of previously declared
45 // nonmember template funcitons. By not including the declarations
46 // and by including this file for automatic instantiation, then
47 // if the function prototypes are not the same then a compile
48 // time error is more likely to occur. Otherwise you could have
49 // to settle for a compile-time warning that the funciton has
50 // not been defined or a link-time error that the definition
51 // could not be found which will be the case when explicit
52 // instantiation is used.
53 
54 // ToDo: 6/9/98 Finish upgrade
55 
56 #ifndef SPARSE_VECTOR_OP_DEF_H
57 #define SPARSE_VECTOR_OP_DEF_H
58 
62 #include "DenseLinAlgPack_DMatrixAsTriSym.hpp" // also included in AbstractLinAlgPack_SparseVectorOpDef.hpp
65 
66 namespace {
67 template< class T >
68 inline
69 T my_my_max( const T& v1, const T& v2 ) { return v1 > v2 ? v1 : v2; }
70 template< class T >
71 inline
72 T my_my_min( const T& v1, const T& v2 ) { return v1 < v2 ? v1 : v2; }
73 } // end namespace
74 
75 namespace AbstractLinAlgPack {
76 
80 
83 
84 namespace SparseVectorUtilityPack {
85 template<class T_SpVec>
86 value_type imp_dot2_V_V_SV(const DVectorSlice& vs1, const DVectorSlice& vs2, const T_SpVec& sv);
87 }
88 
89 // result = dot(vs_rhs1,sv_rhs2)
90 template<class T_SpVec>
91 value_type dot_V_SV(const DVectorSlice& vs_rhs1, const T_SpVec& sv_rhs2) {
92  VopV_assert_sizes(vs_rhs1.dim(),sv_rhs2.dim());
93  value_type result = 0.0;
94  typename T_SpVec::difference_type offset = sv_rhs2.offset();
95  for(typename T_SpVec::const_iterator iter = sv_rhs2.begin(); iter != sv_rhs2.end(); ++iter)
96  result += vs_rhs1(iter->index()+offset) * iter->value();
97  return result;
98 }
99 
100 // result = dot(sv_rhs1,vs_rhs2). Just call the above in reverse order
101 template<class T_SpVec>
102 value_type dot_SV_V(const T_SpVec& sv_rhs1, const DVectorSlice& vs_rhs2) {
103  return dot_V_SV(vs_rhs2,sv_rhs1);
104 }
105 
106 // result = ||sv_rhs||1
107 template<class T_SpVec>
108 value_type norm_1_SV(const T_SpVec& sv_rhs) {
109  typename T_SpVec::element_type::value_type result = 0.0;
110  for(typename T_SpVec::const_iterator iter = sv_rhs.begin(); iter != sv_rhs.end(); ++iter)
111  result += ::fabs(iter->value());
112  return result;
113 }
114 
115 // result = ||sv_rhs||2
116 template<class T_SpVec>
117 value_type norm_2_SV(const T_SpVec& sv_rhs) {
118  typename T_SpVec::element_type::value_type result = 0.0;
119  for(typename T_SpVec::const_iterator iter = sv_rhs.begin(); iter != sv_rhs.end(); ++iter)
120  result += (iter->value()) * (iter->value());
121  return result;
122 }
123 
124 // result = ||sv_rhs||inf
125 template<class T_SpVec>
126 value_type norm_inf_SV(const T_SpVec& sv_rhs) {
127  typename T_SpVec::element_type::value_type result = 0.0;
128  for(typename T_SpVec::const_iterator iter = sv_rhs.begin(); iter != sv_rhs.end(); ++iter)
129  result = my_my_max(result,std::fabs(iter->value()));
130  return result;
131 }
132 
133 // result = max(sv_rhs)
134 template<class T_SpVec>
135 value_type max_SV(const T_SpVec& sv_rhs) {
136  typename T_SpVec::element_type::value_type result = 0.0;
137  for(typename T_SpVec::const_iterator iter = sv_rhs.begin(); iter != sv_rhs.end(); ++iter)
138  result = my_my_max(iter->value(),result);
139  return result;
140 }
141 
142 // result = min(sv_rhs)
143 template<class T_SpVec>
144 value_type min_SV(const T_SpVec& sv_rhs) {
145  typename T_SpVec::element_type::value_type result = 0.0;
146  for(typename T_SpVec::const_iterator iter = sv_rhs.begin(); iter != sv_rhs.end(); ++iter)
147  result = my_my_min(result,iter->value());
148  return result;
149 }
150 
151 // vs_lhs += alpha * sv_rhs (BLAS xAXPY)
152 template<class T_SpVec>
153 void Vt_S( T_SpVec* sv_lhs, value_type alpha )
154 {
155  if( alpha == 1.0 ) return;
156  for(typename T_SpVec::iterator iter = sv_lhs->begin(); iter != sv_lhs->end(); ++iter)
157  iter->value() *= alpha;
158 }
159 
160 // vs_lhs += alpha * sv_rhs (BLAS xAXPY)
161 template<class T_SpVec>
162 void Vp_StSV(DVectorSlice* vs_lhs, value_type alpha, const T_SpVec& sv_rhs)
163 {
164  Vp_V_assert_sizes(vs_lhs->dim(),sv_rhs.dim());
165  typename T_SpVec::difference_type offset = sv_rhs.offset();
166  for(typename T_SpVec::const_iterator iter = sv_rhs.begin(); iter != sv_rhs.end(); ++iter)
167  (*vs_lhs)(iter->index() + offset) += alpha * iter->value();
168 }
169 
170 // vs_lhs += alpha * op(gms_rhs1) * sv_rhs2 (BLAS xGEMV) (time = O(sv_rhs2.nz() * vs_lhs.dim())
171 template<class T_SpVec>
172 void Vp_StMtSV(DVectorSlice* pvs_lhs, value_type alpha, const DMatrixSlice& gms_rhs1
173  , BLAS_Cpp::Transp trans_rhs1, const T_SpVec& sv_rhs2)
174 {
175 #ifdef _WINDOWS
176  using DenseLinAlgPack::Vp_StV; // MS VC++ 6.0 needs help with the name lookups
177 #endif
178  DVectorSlice& vs_lhs = *pvs_lhs;
179 
180  Vp_MtV_assert_sizes(vs_lhs.dim(),gms_rhs1.rows(),gms_rhs1.cols(),trans_rhs1
181  , sv_rhs2.dim());
182 
183  // Perform the operation by iterating through the sparse vector and performing
184  // all of the operations on it.
185  //
186  // For sparse element e we do the following:
187  //
188  // vs_lhs += alpha * e.value() * gms_rhs1.col(e.index());
189 
190  typename T_SpVec::difference_type offset = sv_rhs2.offset();
191 
192  for(typename T_SpVec::const_iterator sv_rhs2_itr = sv_rhs2.begin(); sv_rhs2_itr != sv_rhs2.end(); ++sv_rhs2_itr)
193  DenseLinAlgPack::Vp_StV( &vs_lhs, alpha * sv_rhs2_itr->value()
194  , col( gms_rhs1, trans_rhs1, sv_rhs2_itr->index() + offset ) );
195 }
196 
197 // vs_lhs += alpha * op(tri_rhs1) * sv_rhs2 (BLAS xTRMV)
198 template<class T_SpVec>
199 void Vp_StMtSV(DVectorSlice* pvs_lhs, value_type alpha, const DMatrixSliceTri& tri_rhs1
200  , BLAS_Cpp::Transp trans_rhs1, const T_SpVec& sv_rhs2)
201 {
202  DVectorSlice &vs_lhs = *pvs_lhs;
203 
204  Vp_MtV_assert_sizes(vs_lhs.dim(),tri_rhs1.rows(),tri_rhs1.cols(),trans_rhs1
205  , sv_rhs2.dim());
206 
207  // Get the effective matrix
208  BLAS_Cpp::Uplo effective_uplo;
209  if( (tri_rhs1.uplo() == BLAS_Cpp::lower && trans_rhs1 == BLAS_Cpp::no_trans) ||
210  (tri_rhs1.uplo() == BLAS_Cpp::upper && trans_rhs1 == BLAS_Cpp::trans) )
211  {
212  effective_uplo = BLAS_Cpp::lower;
213  }
214  else { // must be effective upper
215  effective_uplo = BLAS_Cpp::upper;
216  }
217 
218  size_type n = tri_rhs1.gms().rows(); // should be same as cols()
219 
220  // Implement the operation by looping through the sparse vector only once
221  // and performing the row operations. This gives a time = O(n * sv_rhs2.nz())
222  typename T_SpVec::difference_type offset = sv_rhs2.offset();
223  for(typename T_SpVec::const_iterator sv_itr = sv_rhs2.begin(); sv_itr != sv_rhs2.end(); ++sv_itr)
224  {
225  size_type j = sv_itr->index() + offset;
226 
227  // For the nonzero element j = sv_itr->index() we perfom the following
228  // operations.
229  //
230  // Lower:
231  // [\] [\ 0 0 0] [\]
232  // [#] += [\ # 0 0] * [#] jth element
233  // [#] [\ # \ 0] [\]
234  // [#] [\ # \ \] [\]
235  // jth
236  // col
237  //
238  // Upper:
239  // [#] [\ # \ \] [\]
240  // [#] += [0 # \ \] * [#] jth element
241  // [\] [0 0 \ \] [\]
242  // [\] [0 0 0 \] [\]
243  // jth
244  // col
245  //
246  // If we were told that is it is unit diagonal then we will adjust
247  // accordingly.
248 
249  size_type j_adjusted = j; // will be adjusted for unit diagonal
250 
251  switch(effective_uplo) {
252  case BLAS_Cpp::lower: {
253  if(tri_rhs1.diag() == BLAS_Cpp::unit)
254  {
255  // Make the adjustment for unit diaganal
256  ++j_adjusted;
257  vs_lhs(j) += alpha * sv_itr->value(); // diagonal element is one
258  }
259  // vs_lhs(j,n) = vs_lhs(j,n) + alpha * sv_itr->value() * tri_rhs1.col(j)(j,n)
260  if(j_adjusted <= n)
261  {
262  DenseLinAlgPack::Vp_StV( &vs_lhs(j_adjusted,n), alpha * sv_itr->value()
263  ,col(tri_rhs1.gms(),trans_rhs1,j)(j_adjusted,n) );
264  }
265  break;
266  }
267  case BLAS_Cpp::upper: {
268  if(tri_rhs1.diag() == BLAS_Cpp::unit)
269  {
270  // Make the adjustment for unit diaganal
271  --j_adjusted;
272  vs_lhs(j) += alpha * sv_itr->value(); // diagonal element is one
273  }
274  // vs_lhs(1,j) = vs_lhs(1,j) + alpha * sv_itr->value() * tri_rhs1.col(j)(1,j)
275  if(j_adjusted > 0)
276  {
277  DenseLinAlgPack::Vp_StV( &vs_lhs(1,j_adjusted), alpha * sv_itr->value()
278  ,col(tri_rhs1.gms(),trans_rhs1,j)(1,j_adjusted) );
279  }
280  break;
281  }
282  }
283  }
284 }
285 
286 // vs_lhs += alpha * op(sym_rhs1) * sv_rhs2 (BLAS xSYMV)
287 template<class T_SpVec>
288 void Vp_StMtSV(DVectorSlice* pvs_lhs, value_type alpha, const DMatrixSliceSym& sym_rhs1
289  , BLAS_Cpp::Transp trans_rhs1, const T_SpVec& sv_rhs2)
290 {
291  DVectorSlice& vs_lhs = *pvs_lhs;
292 
293  Vp_MtV_assert_sizes(vs_lhs.dim(),sym_rhs1.rows(),sym_rhs1.cols(),trans_rhs1
294  , sv_rhs2.dim());
295 
296  size_type size = sv_rhs2.dim();
297  switch(sym_rhs1.uplo()) {
298  case BLAS_Cpp::lower: {
299  DVectorSlice::iterator vs_lhs_itr; size_type i;
300  for(vs_lhs_itr = vs_lhs.begin(), i = 1; i <= size; ++i)
301  {
302  if(i < size) {
303  *vs_lhs_itr++ +=
304  alpha *
306  sym_rhs1.gms().row(i)(1,i)
307  ,sym_rhs1.gms().col(i)(i+1,size)
308  ,sv_rhs2);
309  }
310  else
311  *vs_lhs_itr++ += alpha *
312  dot_V_SV(sym_rhs1.gms().row(i),sv_rhs2);
313  }
314  break;
315  }
316  case BLAS_Cpp::upper: {
317  DVectorSlice::iterator vs_lhs_itr; size_type i;
318  for(vs_lhs_itr = vs_lhs.begin(), i = 1; i <= size; ++i)
319  {
320  if(i > 1) {
321  *vs_lhs_itr++ +=
322  alpha *
324  sym_rhs1.gms().col(i)(1,i-1)
325  ,sym_rhs1.gms().row(i)(i,size)
326  ,sv_rhs2);
327  }
328  else
329  *vs_lhs_itr++ += alpha * dot_V_SV(sym_rhs1.gms().row(i),sv_rhs2);
330  }
331  break;
332  }
333  }
334 }
335 
336 namespace SparseVectorUtilityPack {
337 
338 // Implementation for the product of a concatonated dense vector with a
339 // sparse vector. Used for symetric matrix mulitplication.
340 // In Matlab notation: result = [vs1' , vs2' ] * sv
341 // where split = vs1.dim(), vs2.dim() == sv.dim() - split
342 //
343 // time = O(sv.nz()), space = O(1)
344 //
345 template<class T_SpVec>
346 value_type imp_dot2_V_V_SV(const DVectorSlice& vs1, const DVectorSlice& vs2, const T_SpVec& sv)
347 {
348  size_type split = vs1.dim();
349  value_type result = 0;
350  typename T_SpVec::difference_type offset = sv.offset();
351  for(typename T_SpVec::const_iterator sv_itr = sv.begin(); sv_itr != sv.end(); ++sv_itr) {
352  typename T_SpVec::element_type::indice_type curr_indice = sv_itr->index()+offset;
353  if(curr_indice <= split)
354  result += vs1(curr_indice) * sv_itr->value();
355  else
356  result += vs2(curr_indice - split) * sv_itr->value();
357  }
358  return result;
359 }
360 
361 } // end namespace SparseVectorUtilityPack
362 
363 } // end namespace AbstractLinAlgPack
364 
365 #endif // SPARSE_VECTOR_OP_DEF_H
DVectorSlice row(DMatrixSlice &gms, BLAS_Cpp::Transp trans, size_type i)
void Vp_StSV(DVectorSlice *vs_lhs, value_type alpha, const T_SpVec &sv_rhs)
vs_lhs += alpha * sv_rhs (BLAS xAXPY)
void Vp_StV(DVectorSlice *vs_lhs, value_type alpha, const DVectorSlice &vs_rhs)
vs_lhs += alpha * vs_rhs (BLAS xAXPY)
size_type dim() const
Returns the number of elements of the VectorSliceTmpl.
void Vt_S(VectorMutable *v_lhs, const value_type &alpha)
v_lhs *= alpha
size_type cols() const
Return the number of columns.
value_type min_SV(const T_SpVec &sv_rhs)
result = min(sv_rhs)
void Vp_StMtSV(DVectorSlice *vs_lhs, value_type alpha, const DMatrixSlice &gms_rhs1, BLAS_Cpp::Transp trans_rhs1, const T_SpVec &sv_rhs2)
vs_lhs += alpha * op(gms_rhs1) * sv_rhs2 (BLAS xGEMV)
value_type norm_1_SV(const T_SpVec &sv_rhs)
result = ||sv_rhs||1 (BLAS xASUM)
C++ Standard Library compatable iterator class for accesing nonunit stride arrays of data...
Transposed.
std::vector< std::string > split(const std::string &str, const std::string &delimiters, const size_t start=0)
value_type norm_inf_SV(const T_SpVec &sv_rhs)
result = ||sv_rhs||inf (BLAS IxAMAX)
value_type norm_2_SV(const T_SpVec &sv_rhs)
result = ||sv_rhs||2 (BLAS xNRM2)
void Vp_V_assert_sizes(size_type v_lhs_size, size_type v_rhs_size)
v_lhs += op v_rhs
Not transposed.
value_type imp_dot2_V_V_SV(const DVectorSlice &vs1, const DVectorSlice &vs2, const T_SpVec &sv)
DVectorSlice col(DMatrixSlice &gms, BLAS_Cpp::Transp trans, size_type j)
void VopV_assert_sizes(size_type v_rhs1_size, size_type v_rhs2_size)
v_rhs1 op v_rhs2
DenseLinAlgPack::VectorSliceTmpl< value_type > DVectorSlice
size_type rows() const
Return the number of rows.
value_type max_SV(const T_SpVec &sv_rhs)
result = max(sv_rhs)
AbstractLinAlgPack::value_type value_type
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
value_type dot_SV_V(const T_SpVec &sv_rhs1, const DVectorSlice &vs_rhs2)
result = dot(sv_rhs1,vs_rhs2) (BLAS xDOT)
value_type dot_V_SV(const DVectorSlice &vs_rhs1, const T_SpVec &sv_rhs2)
result = dot(vs_rhs1,sv_rhs2) (BLAS xDOT)
DVectorSlice col(size_type j)
Return DVectorSlice object representing the jth column (1-based; 1,2,..,#this->cols()#, or throw std::out_of_range)
Transp
TRANS.
int n
DVectorSlice row(size_type i)
Return DVectorSlice object representing the ith row (1-based; 1,2,..,#this->rows()#, or throw std::out_of_range)