AbstractLinAlgPack_VectorMutableBlocked.cpp

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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
Generated on Wed Apr 13 10:09:16 2011 for AbstractLinAlgPack: C++ Interfaces For Vectors, Matrices And Related Linear Algebra Objects by  doxygen 1.6.3