|
AbstractLinAlgPack: C++ Interfaces For Vectors, Matrices And Related Linear Algebra Objects Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization 00005 // Copyright (2003) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // This library is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as 00012 // published by the Free Software Foundation; either version 2.1 of the 00013 // License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, but 00016 // WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00023 // USA 00024 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 00025 // 00026 // *********************************************************************** 00027 // @HEADER 00028 00029 #include <typeinfo> 00030 #include <algorithm> 00031 00032 #include "AbstractLinAlgPack_VectorMutableBlocked.hpp" 00033 #include "AbstractLinAlgPack_VectorMutableSubView.hpp" 00034 #include "AbstractLinAlgPack_VectorSpaceBlocked.hpp" 00035 #include "Teuchos_Workspace.hpp" 00036 #include "Teuchos_TestForException.hpp" 00037 #include "Teuchos_FancyOStream.hpp" 00038 00039 // Uncomment to ignore cache of reduction data 00040 //#define ALAP_VECTOR_MUTABLE_BLOCKED_IGNORE_CACHE_DATA 00041 00042 namespace { 00043 template< class T > 00044 inline 00045 T my_max( const T& v1, const T& v2 ) { return v1 > v2 ? v1 : v2; } 00046 template< class T > 00047 inline 00048 T my_min( const T& v1, const T& v2 ) { return v1 < v2 ? v1 : v2; } 00049 } // end namespace 00050 00051 namespace AbstractLinAlgPack { 00052 00053 VectorMutableBlocked::VectorMutableBlocked( 00054 VectorMutable::vec_mut_ptr_t* vecs 00055 ,const vec_space_comp_ptr_t& vec_space 00056 ) 00057 // The members will be initialized in this->has_changed() 00058 { 00059 initialize(vecs,vec_space); 00060 } 00061 00062 void VectorMutableBlocked::initialize( 00063 VectorMutable::vec_mut_ptr_t* vecs 00064 ,const vec_space_comp_ptr_t& vec_space 00065 ) 00066 { 00067 TEST_FOR_EXCEPTION( 00068 vec_space.get() == NULL, std::logic_error 00069 ,"VectorMutableBlocked::initialize(...): Error, Must be constructed from " 00070 "a non-null block vector space!" ); 00071 const int num_vec_spaces = vec_space->num_vector_spaces(); 00072 vecs_.resize(num_vec_spaces); 00073 std::copy(vecs,vecs+num_vec_spaces,vecs_.begin()); 00074 vec_space_ = vec_space; 00075 this->has_changed(); 00076 } 00077 00078 // overriddend form Vector 00079 00080 index_type VectorMutableBlocked::dim() const 00081 { 00082 return vec_space_->dim(); 00083 } 00084 00085 const VectorSpace& VectorMutableBlocked::space() const 00086 { 00087 return *vec_space_; 00088 } 00089 00090 void VectorMutableBlocked::apply_op( 00091 const RTOpPack::RTOp& op 00092 ,const size_t num_vecs, const Vector* vecs[] 00093 ,const size_t num_targ_vecs, VectorMutable* targ_vecs[] 00094 ,RTOpPack::ReductTarget *reduct_obj 00095 ,const index_type first_ele_in, const index_type sub_dim_in, const index_type global_offset_in 00096 ) const 00097 { 00098 using Teuchos::Workspace; 00099 Teuchos::WorkspaceStore* wss = Teuchos::get_default_workspace_store().get(); 00100 00101 const index_type 00102 n = this->dim(); 00103 00104 // Validate the compatibility of the vectors! 00105 #ifdef TEUCHOS_DEBUG 00106 TEST_FOR_EXCEPTION( 00107 !(1 <= first_ele_in && first_ele_in <= n), std::out_of_range 00108 ,"VectorMutableBlocked::apply_op(...): Error, " 00109 "first_ele_in = " << first_ele_in << " is not in range [1,"<<n<<"]" ); 00110 TEST_FOR_EXCEPTION( 00111 sub_dim_in < 0, std::invalid_argument 00112 ,"VectorMutableBlocked::apply_op(...): Error, " 00113 "sub_dim_in = " << sub_dim_in << " is not acceptable" ); 00114 TEST_FOR_EXCEPTION( 00115 global_offset_in < 0, std::invalid_argument 00116 ,"VectorMutableBlocked::apply_op(...): Error, " 00117 "global_offset_in = " << global_offset_in << " is not acceptable" ); 00118 TEST_FOR_EXCEPTION( 00119 sub_dim_in > 0 && sub_dim_in - (first_ele_in - 1) > n, std::length_error 00120 ,"VectorMutableBlocked::apply_op(...): Error, " 00121 "global_offset_in = " << global_offset_in << ", sub_dim_in = " << sub_dim_in 00122 << "first_ele_in = " << first_ele_in << " and n = " << n 00123 << " are not compatible" ); 00124 bool test_failed; 00125 {for(int k = 0; k < num_vecs; ++k) { 00126 test_failed = !this->space().is_compatible(vecs[k]->space()); 00127 TEST_FOR_EXCEPTION( 00128 test_failed, VectorSpace::IncompatibleVectorSpaces 00129 ,"VectorMutableBlocked::apply_op(...): Error vecs["<<k<<"]->space() " 00130 <<"of type \'"<<typeName(vecs[k]->space())<<"\' is not compatible with this " 00131 <<"\'VectorSpaceBlocked\' vector space!" 00132 ); 00133 }} 00134 {for(int k = 0; k < num_targ_vecs; ++k) { 00135 test_failed = !this->space().is_compatible(targ_vecs[k]->space()); 00136 TEST_FOR_EXCEPTION( 00137 test_failed, VectorSpace::IncompatibleVectorSpaces 00138 ,"VectorMutableBlocked::apply_op(...): Error targ_vecs["<<k<<"]->space() " 00139 <<"of type \'"<<typeName(vecs[k]->space())<<"\' is not compatible with this " 00140 <<"\'VectorSpaceBlocked\' vector space!" 00141 ); 00142 }} 00143 #endif 00144 00145 // Dynamic cast the pointers for the vector arguments 00146 Workspace<const VectorMutableBlocked*> 00147 vecs_args(wss,num_vecs); 00148 {for(int k = 0; k < num_vecs; ++k) { 00149 vecs_args[k] = dynamic_cast<const VectorMutableBlocked*>(vecs[k]); 00150 #ifdef TEUCHOS_DEBUG 00151 TEST_FOR_EXCEPTION( 00152 vecs_args[k] == NULL, VectorSpace::IncompatibleVectorSpaces 00153 ,"VectorMutableBlocked::apply_op(...): Error vecs["<<k<<"] " 00154 <<"of type \'"<<typeName(*vecs[k])<<"\' does not support the " 00155 <<"\'VectorMutableBlocked\' interface!" 00156 ); 00157 #endif 00158 }} 00159 Workspace<VectorMutableBlocked*> 00160 targ_vecs_args(wss,num_targ_vecs); 00161 {for(int k = 0; k < num_targ_vecs; ++k) { 00162 targ_vecs_args[k] = dynamic_cast<VectorMutableBlocked*>(targ_vecs[k]); 00163 #ifdef TEUCHOS_DEBUG 00164 TEST_FOR_EXCEPTION( 00165 targ_vecs_args[k] == NULL, VectorSpace::IncompatibleVectorSpaces 00166 ,"VectorMutableBlocked::apply_op(...): Error targ_vecs["<<k<<"] " 00167 <<"of type \'"<<typeName(*targ_vecs[k])<<"\' does not support the " 00168 <<"\'VectorMutableBlocked\' interface!" 00169 ); 00170 #endif 00171 }} 00172 00173 // Perform the reduction on each vector segment at a time. 00174 // ToDo: There could be a parallel version of this method! 00175 const index_type this_dim = this->dim(); 00176 const index_type sub_dim = ( sub_dim_in == 0 00177 ? this_dim - (first_ele_in - 1) 00178 : sub_dim_in ); 00179 index_type num_elements_remaining = sub_dim; 00180 const int num_vec_spaces = vec_space_->num_vector_spaces(); 00181 Workspace<const Vector*> 00182 sub_vecs(wss,num_vecs); 00183 Workspace<VectorMutable*> 00184 sub_targ_vecs(wss,num_targ_vecs); 00185 index_type g_off = -first_ele_in + 1; 00186 for(int k = 0; k < num_vec_spaces; ++k) { 00187 const index_type local_dim = vecs_[k]->dim(); 00188 if( g_off < 0 && -g_off > local_dim ) { 00189 g_off += local_dim; 00190 continue; 00191 } 00192 const index_type 00193 local_sub_dim = ( g_off >= 0 00194 ? my_min( local_dim, num_elements_remaining ) 00195 : my_min( local_dim + g_off, num_elements_remaining ) ); 00196 if( local_sub_dim <= 0 ) 00197 break; 00198 for( int i = 0; i < num_vecs; ++i ) // Fill constituent vectors for segment k 00199 sub_vecs[i] = vecs_args[i]->vecs_[k].get(); 00200 for( int j = 0; j < num_targ_vecs; ++j ) // Fill constituent target vectors for segment k 00201 sub_targ_vecs[j] = targ_vecs_args[j]->vecs_[k].get(); 00202 AbstractLinAlgPack::apply_op( 00203 op 00204 ,num_vecs,num_vecs?&sub_vecs[0]:NULL 00205 ,num_targ_vecs,num_targ_vecs?&sub_targ_vecs[0]:NULL 00206 ,reduct_obj 00207 ,g_off < 0 ? -g_off + 1 : 1 // first_ele 00208 ,local_sub_dim // sub_dim 00209 ,g_off < 0 ? global_offset_in : global_offset_in + g_off // global_offset 00210 ); 00211 g_off += local_dim; 00212 num_elements_remaining -= local_sub_dim; 00213 } 00214 TEST_FOR_EXCEPT( !( num_elements_remaining == 0 ) ); 00215 // Must allert all of the block vectors that they may have changed! 00216 {for(int k = 0; k < num_targ_vecs; ++k) { 00217 targ_vecs[k]->has_changed(); 00218 }} 00219 } 00220 00221 index_type VectorMutableBlocked::nz() const 00222 { 00223 if( nz_ < 0.0 ) { 00224 const int num_vec_spaces = vec_space_->num_vector_spaces(); 00225 nz_ = 0; 00226 for( int k = 0; k < num_vec_spaces; ++k ) 00227 nz_ += vecs_[k]->nz(); 00228 } 00229 return nz_; 00230 } 00231 00232 std::ostream& VectorMutableBlocked::output( 00233 std::ostream& out_arg, bool print_dim, bool newline 00234 ,index_type global_offset 00235 ) const 00236 { 00237 Teuchos::RCP<Teuchos::FancyOStream> out = Teuchos::getFancyOStream(Teuchos::rcp(&out_arg,false)); 00238 Teuchos::OSTab tab(out); 00239 if(print_dim) 00240 *out << this->dim() << std::endl; 00241 size_type off = global_offset; 00242 const int num_vec_spaces = vec_space_->num_vector_spaces(); 00243 for( int k = 0; k < num_vec_spaces; ++k ) { 00244 vecs_[k]->output(*out,false,false,off); 00245 off += vecs_[k]->dim(); 00246 } 00247 if(newline) 00248 *out << std::endl; 00249 return out_arg; 00250 } 00251 00252 value_type VectorMutableBlocked::get_ele(index_type i) const 00253 { 00254 int kth_vector_space = -1; 00255 index_type kth_global_offset = 0; 00256 vec_space_->get_vector_space_position(i,&kth_vector_space,&kth_global_offset); 00257 #ifdef TEUCHOS_DEBUG 00258 TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= vecs_.size() ) ); 00259 #endif 00260 return vecs_[kth_vector_space]->get_ele( i - kth_global_offset ); 00261 } 00262 00263 value_type VectorMutableBlocked::norm_1() const 00264 { 00265 #ifdef ALAP_VECTOR_MUTABLE_BLOCKED_IGNORE_CACHE_DATA 00266 if( true ) { 00267 #else 00268 if( norm_1_ < 0.0 ) { 00269 #endif 00270 const int num_vec_spaces = vec_space_->num_vector_spaces(); 00271 norm_1_ = 0.0; 00272 for( int k = 0; k < num_vec_spaces; ++k ) 00273 norm_1_ += vecs_[k]->norm_1(); 00274 } 00275 return norm_1_; 00276 } 00277 00278 value_type VectorMutableBlocked::norm_inf() const 00279 { 00280 #ifdef ALAP_VECTOR_MUTABLE_BLOCKED_IGNORE_CACHE_DATA 00281 if( true ) { 00282 #else 00283 if( norm_inf_ < 0.0 ) { 00284 #endif 00285 const int num_vec_spaces = vec_space_->num_vector_spaces(); 00286 norm_inf_ = 0.0; 00287 for( int k = 0; k < num_vec_spaces; ++k ) 00288 norm_inf_ = my_max( norm_inf_, vecs_[k]->norm_inf() ); 00289 } 00290 return norm_inf_; 00291 } 00292 00293 value_type VectorMutableBlocked::inner_product( const Vector& v ) const 00294 { 00295 return Vector::inner_product(v); // ToDo: Specialize? (why bother?) 00296 } 00297 00298 void VectorMutableBlocked::get_sub_vector( const Range1D& rng_in, RTOpPack::SubVector* sub_vec ) const 00299 { 00300 const Range1D 00301 rng = rng_in.full_range() ? Range1D( 1, this->dim()) : rng_in; 00302 int kth_vector_space = -1; 00303 index_type kth_global_offset = 0; 00304 vec_space_->get_vector_space_position(rng.lbound(),&kth_vector_space,&kth_global_offset); 00305 #ifdef TEUCHOS_DEBUG 00306 TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= vecs_.size() ) ); 00307 #endif 00308 if( rng.lbound() + rng.size() <= kth_global_offset + 1 + vecs_[kth_vector_space]->dim() ) { 00309 // This involves only one sub-vector so just return it. 00310 static_cast<const Vector*>(vecs_[kth_vector_space].get())->get_sub_vector( 00311 rng - kth_global_offset, sub_vec ); 00312 sub_vec->setGlobalOffset( sub_vec->globalOffset() + kth_global_offset ); 00313 } 00314 else { 00315 // Just let the default implementation handle this. ToDo: In the futrue 00316 // we could manually construct an explicit sub-vector that spanned 00317 // two or more consitituent vectors but this would be a lot of work. 00318 // However, this would require the use of temporary memory but 00319 // so what. 00320 Vector::get_sub_vector(rng_in,sub_vec); 00321 } 00322 } 00323 00324 void VectorMutableBlocked::free_sub_vector( RTOpPack::SubVector* sub_vec ) const 00325 { 00326 if( sub_vec->values() == NULL ) return; 00327 int kth_vector_space = -1; 00328 index_type kth_global_offset = 0; 00329 vec_space_->get_vector_space_position( 00330 sub_vec->globalOffset()+1,&kth_vector_space,&kth_global_offset); 00331 #ifdef TEUCHOS_DEBUG 00332 TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= vecs_.size() ) ); 00333 #endif 00334 if( sub_vec->globalOffset() + sub_vec->subDim() <= kth_global_offset + vecs_[kth_vector_space]->dim() ) { 00335 // This sub_vec was extracted from a single constituent vector 00336 sub_vec->setGlobalOffset( sub_vec->globalOffset() - kth_global_offset ); 00337 vecs_[kth_vector_space].get()->free_sub_vector(sub_vec); 00338 } 00339 else { 00340 // This sub_vec was created by the default implementation! 00341 Vector::free_sub_vector(sub_vec); 00342 } 00343 } 00344 00345 void VectorMutableBlocked::has_changed() const 00346 { 00347 nz_ = -1; // set to uninitalized! 00348 norm_1_ = norm_inf_ = -1.0; 00349 Vector::has_changed(); 00350 } 00351 00352 // overridden from VectorMutable 00353 00354 VectorMutable::vec_mut_ptr_t 00355 VectorMutableBlocked::sub_view( const Range1D& rng_in ) 00356 { 00357 namespace rcp = MemMngPack; 00358 const index_type dim = this->dim(); 00359 const Range1D rng = rng_in.full_range() ? Range1D(1,dim) : rng_in; 00360 // Validate the preconditions 00361 #ifdef TEUCHOS_DEBUG 00362 TEST_FOR_EXCEPTION( 00363 dim < rng.ubound(), std::out_of_range 00364 ,"VectorMutableBlocked::sub_view(...): Error, rng = " 00365 << "["<<rng.lbound()<<","<<rng.ubound()<<"] is not in range [1,"<<dim<<"]" ); 00366 #endif 00367 vecs_t &vecs = this->vecs_; // Need to examine in debugger! 00368 // See if the entire vector is being returned or just NULL 00369 if( rng.lbound() == 1 && rng.ubound() == dim ) { 00370 if( vecs.size() == 1 ) return vecs[0]->sub_view(Range1D()); 00371 else return Teuchos::rcp(this,false); 00372 } 00373 // From here on out we will return a view that could change the 00374 // elements of one or more of the constituent vectors so we had 00375 // better wipe out the cache 00376 this->has_changed(); 00377 // Get the position of the vector space object of interest 00378 int kth_vector_space = -1; 00379 index_type kth_global_offset = 0; 00380 vec_space_->get_vector_space_position(rng.lbound(),&kth_vector_space,&kth_global_offset); 00381 const VectorSpace::space_ptr_t* vector_spaces = vec_space_->vector_spaces(); 00382 const index_type* vec_spaces_offsets = vec_space_->vector_spaces_offsets(); 00383 #ifdef TEUCHOS_DEBUG 00384 TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= vecs.size() ) ); 00385 #endif 00386 if( rng.lbound() == kth_global_offset + 1 00387 && rng.size() == vec_spaces_offsets[kth_vector_space+1] - vec_spaces_offsets[kth_vector_space] ) 00388 // The client selected a whole single constituent vector. 00389 return vecs[kth_vector_space]->sub_view(Range1D()); 00390 if( rng.ubound() <= vec_spaces_offsets[kth_vector_space+1] ) 00391 // The client selected a sub-vector of a single consituent vector 00392 return vecs[kth_vector_space]->sub_view( rng - vec_spaces_offsets[kth_vector_space] ); 00393 // The client selected a sub-vector that spans two or more constituent vectors. 00394 // Get the position of the vector space object with the last element of interest 00395 int end_kth_vector_space = -1; 00396 index_type end_kth_global_offset = 0; 00397 vec_space_->get_vector_space_position(rng.ubound(),&end_kth_vector_space,&end_kth_global_offset); 00398 #ifdef TEUCHOS_DEBUG 00399 TEST_FOR_EXCEPT( !( 0 <= end_kth_vector_space && end_kth_vector_space <= vecs.size() ) ); 00400 TEST_FOR_EXCEPT( !( end_kth_vector_space > kth_vector_space ) ); 00401 #endif 00402 // Create a VectorWithOpMutableCompsiteStd object containing the relavant constituent vectors 00403 Teuchos::RCP<VectorMutableBlocked> 00404 vec_comp = Teuchos::rcp(new VectorMutableBlocked( 00405 &vecs[kth_vector_space] 00406 ,Teuchos::rcp(new VectorSpaceBlocked( 00407 &vector_spaces[kth_vector_space] 00408 ,end_kth_vector_space - kth_vector_space + 1 )) 00409 )); 00410 if( rng.lbound() == kth_global_offset + 1 00411 && rng.size() == vec_spaces_offsets[end_kth_vector_space+1] - vec_spaces_offsets[kth_vector_space] ) 00412 // The client selected exactly a contigous set of vectors 00413 return vec_comp; 00414 // The client selected some sub-set of elements in the contigous set of vectors 00415 return Teuchos::rcp( 00416 new VectorMutableSubView( 00417 vec_comp 00418 ,Range1D( 00419 rng.lbound()-vec_spaces_offsets[kth_vector_space] 00420 ,rng.ubound()-vec_spaces_offsets[kth_vector_space] ) 00421 ) ); 00422 } 00423 00424 void VectorMutableBlocked::axpy( value_type alpha, const Vector& x ) 00425 { 00426 VectorMutable::axpy(alpha,x); // ToDo: Specialize? (why bother?) 00427 this->has_changed(); 00428 } 00429 00430 VectorMutable& VectorMutableBlocked::operator=(value_type alpha) 00431 { 00432 const int num_vec_spaces = vec_space_->num_vector_spaces(); 00433 for( int k = 0; k < num_vec_spaces; ++k ) 00434 *vecs_[k] = alpha; 00435 this->has_changed(); 00436 return *this; 00437 } 00438 00439 VectorMutable& VectorMutableBlocked::operator=(const Vector& v) 00440 { 00441 VectorMutable::operator=(v); // ToDo: Specialize (why bother?) 00442 this->has_changed(); 00443 return *this; 00444 } 00445 00446 void VectorMutableBlocked::set_ele( index_type i, value_type val ) 00447 { 00448 int kth_vector_space = -1; 00449 index_type kth_global_offset = 0; 00450 vec_space_->get_vector_space_position(i,&kth_vector_space,&kth_global_offset); 00451 #ifdef TEUCHOS_DEBUG 00452 TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= vecs_.size() ) ); 00453 #endif 00454 vecs_[kth_vector_space]->set_ele( i - kth_global_offset, val ); 00455 this->has_changed(); 00456 } 00457 00458 void VectorMutableBlocked::set_sub_vector( const RTOpPack::SparseSubVector& sub_vec ) 00459 { 00460 int kth_vector_space = -1; 00461 index_type kth_global_offset = 0; 00462 vec_space_->get_vector_space_position( 00463 sub_vec.globalOffset()+1,&kth_vector_space,&kth_global_offset); 00464 #ifdef TEUCHOS_DEBUG 00465 TEST_FOR_EXCEPT( !( 0 <= kth_vector_space && kth_vector_space <= vecs_.size() ) ); 00466 #endif 00467 if( sub_vec.globalOffset() + sub_vec.subDim() <= kth_global_offset + vecs_[kth_vector_space]->dim() ) { 00468 // This sub-vector fits into a single constituent vector 00469 RTOpPack::SparseSubVector sub_vec_g = sub_vec; 00470 sub_vec_g.setGlobalOffset( sub_vec_g.globalOffset() - kth_global_offset ); 00471 vecs_[kth_vector_space]->set_sub_vector(sub_vec_g); 00472 } 00473 else { 00474 // Let the default implementation take care of this. ToDo: In the futrue 00475 // it would be possible to manualy set the relavent constituent 00476 // vectors with no temp memory allocations. 00477 VectorMutable::set_sub_vector(sub_vec); 00478 } 00479 this->has_changed(); 00480 } 00481 00482 void VectorMutableBlocked::assert_in_range(int k) const 00483 { 00484 assert_initialized(); 00485 TEST_FOR_EXCEPTION( 00486 k >= vec_space_->num_vector_spaces(), std::logic_error 00487 ,"VectorMutableBlocked::assert_in_range(k) : Error, k = " << k << " is not " 00488 "in range [0," << vec_space_->num_vector_spaces() << "]" ); 00489 } 00490 00491 void VectorMutableBlocked::assert_initialized() const 00492 { 00493 TEST_FOR_EXCEPTION(!vec_space_.get(),std::logic_error,"Error, this is not initalized!"); 00494 } 00495 00496 } // end namespace AbstractLinAlgPack
1.7.4