core/vnl/vnl_vector.txx
Go to the documentation of this file.
00001 // This is core/vnl/vnl_vector.txx
00002 #ifndef vnl_vector_txx_
00003 #define vnl_vector_txx_
00004 //:
00005 // \file
00006 // \author VDN
00007 // \date   Feb 21, 1992
00008 // \brief new lite version adapted from Matrix.h
00009 //
00010 // The parameterized vnl_vector<T> class implements 1D arithmetic vectors of a
00011 // user specified type. The only constraint placed on the type is that
00012 // it must overload the following operators: +, -, *, and /. Thus, it will
00013 // be possible to have a vnl_vector over vcl_complex<T>.  The vnl_vector<T>
00014 // class is static in size, that is once a vnl_vector<T> of a particular
00015 // size has been declared, elements cannot be added or removed. Using the
00016 // set_size() method causes the vector to resize, but the contents will be
00017 // lost.
00018 //
00019 // Each vector contains  a protected  data section  that has a  T* slot that
00020 // points to the  physical memory allocated  for the one  dimensional array. In
00021 // addition, an integer  specifies   the number  of  elements  for the
00022 // vector.  These values  are provided in the  constructors.
00023 //
00024 // Several constructors are provided. See .h file for descriptions.
00025 //
00026 // Methods   are  provided   for destructive   scalar   and vector  addition,
00027 // multiplication, check for equality  and inequality, fill, reduce, and access
00028 // and set individual elements.  Finally, both  the  input and output operators
00029 // are overloaded to allow for formatted input and output of vector elements.
00030 //
00031 // vnl_vector is a special type of matrix, and is implemented for space and time
00032 // efficiency. When vnl_vector is pre_multiplied by/with matrix, m*v, vnl_vector is
00033 // implicitly a column matrix. When vnl_vector is post_multiplied by/with matrix
00034 // v*m, vnl_vector is implicitly a row matrix.
00035 //
00036 
00037 #include "vnl_vector.h"
00038 
00039 #include <vcl_cstdlib.h> // abort()
00040 #include <vcl_cassert.h>
00041 #include <vcl_vector.h>
00042 #include <vcl_iostream.h>
00043 #include <vcl_algorithm.h>
00044 
00045 #include <vnl/vnl_math.h>
00046 #include <vnl/vnl_matrix.h>
00047 #include <vnl/vnl_numeric_traits.h>
00048 
00049 #include <vnl/vnl_c_vector.h>
00050 
00051 #include <vnl/vnl_sse.h>
00052 
00053 //--------------------------------------------------------------------------------
00054 
00055 #if VCL_HAS_SLICED_DESTRUCTOR_BUG
00056 // vnl_vector owns its data by default.
00057 # define vnl_vector_construct_hack() vnl_vector_own_data = 1
00058 #else
00059 # define vnl_vector_construct_hack()
00060 #endif
00061 
00062 // This macro allocates the dynamic storage used by a vnl_vector.
00063 
00064 #define vnl_vector_alloc_blah(size) \
00065 do { \
00066   this->num_elmts = (size); \
00067   this->data = size ? vnl_c_vector<T>::allocate_T(size) : 0; \
00068 } while (false)
00069 
00070 // This macro deallocates the dynamic storage used by a vnl_vector.
00071 #define vnl_vector_free_blah \
00072 do { \
00073   if (this->data) \
00074     vnl_c_vector<T>::deallocate(this->data, this->num_elmts); \
00075 } while (false)
00076 
00077 
00078 //: Creates a vector with specified length. O(n).
00079 // Elements are not initialized.
00080 
00081 template<class T>
00082 vnl_vector<T>::vnl_vector (unsigned len)
00083 {
00084   vnl_vector_construct_hack();
00085   vnl_vector_alloc_blah(len);
00086 }
00087 
00088 
00089 //: Creates a vector of specified length, and initialize all elements with value. O(n).
00090 
00091 template<class T>
00092 vnl_vector<T>::vnl_vector (unsigned len, T const& value)
00093 {
00094   vnl_vector_construct_hack();
00095   vnl_vector_alloc_blah(len);
00096   for (unsigned i = 0; i < len; i ++)           // For each element
00097     this->data[i] = value;                      // Assign initial value
00098 }
00099 
00100 //: Creates a vector of specified length and initialize first n elements with values. O(n).
00101 
00102 template<class T>
00103 vnl_vector<T>::vnl_vector (unsigned len, int n, T const values[])
00104 {
00105   vnl_vector_construct_hack();
00106   vnl_vector_alloc_blah(len);
00107   if (n > 0) {                                  // If user specified values
00108     for (unsigned i = 0; i < len && n; i++, n--)        // Initialize first n elements
00109       this->data[i] = values[i];                // with values
00110   }
00111 }
00112 
00113 #if VNL_CONFIG_LEGACY_METHODS // these constructors are deprecated and should not be used
00114 
00115 template<class T>
00116 vnl_vector<T>::vnl_vector (unsigned len, T const& px, T const& py)
00117 {
00118   VXL_DEPRECATED("vnl_vector<T>::vnl_vector(2, T const& px, T const& py)");
00119   assert(len==2);
00120   vnl_vector_construct_hack();
00121   vnl_vector_alloc_blah(2);
00122   this->data[0] = px;
00123   this->data[1] = py;
00124 }
00125 
00126 template<class T>
00127 vnl_vector<T>::vnl_vector (unsigned len, T const& px, T const& py, T const& pz)
00128 {
00129   VXL_DEPRECATED("vnl_vector<T>::vnl_vector(3, T const& px, T const& py, T const& pz)");
00130   assert(len==3);
00131   vnl_vector_construct_hack();
00132   vnl_vector_alloc_blah(3);
00133   this->data[0] = px;
00134   this->data[1] = py;
00135   this->data[2] = pz;
00136 }
00137 
00138 template<class T>
00139 vnl_vector<T>::vnl_vector (unsigned len, T const& px, T const& py, T const& pz, T const& pw)
00140 {
00141   VXL_DEPRECATED("vnl_vector<T>::vnl_vector(4, T const& px, T const& py, T const& pz, T const& pt)");
00142   assert(len==4);
00143   vnl_vector_construct_hack();
00144   vnl_vector_alloc_blah(4);
00145   this->data[0] = px;
00146   this->data[1] = py;
00147   this->data[2] = pz;
00148   this->data[3] = pw;
00149 }
00150 
00151 #endif // VNL_CONFIG_LEGACY_METHODS
00152 
00153 //: Creates a new copy of vector v. O(n).
00154 template<class T>
00155 vnl_vector<T>::vnl_vector (vnl_vector<T> const& v)
00156 {
00157   vnl_vector_construct_hack();
00158   vnl_vector_alloc_blah(v.num_elmts);
00159   for (unsigned i = 0; i < v.num_elmts; i ++)   // For each element in v
00160     this->data[i] = v.data[i];                  // Copy value
00161 }
00162 
00163 //: Creates a vector from a block array of data, stored row-wise.
00164 // Values in datablck are copied. O(n).
00165 
00166 template<class T>
00167 vnl_vector<T>::vnl_vector (T const* datablck, unsigned len)
00168 {
00169   vnl_vector_construct_hack();
00170   vnl_vector_alloc_blah(len);
00171   for (unsigned i = 0; i < len; ++i)    // Copy data from datablck
00172     this->data[i] = datablck[i];
00173 }
00174 
00175 //------------------------------------------------------------
00176 
00177 template<class T>
00178 vnl_vector<T>::vnl_vector (vnl_vector<T> const &u, vnl_vector<T> const &v, vnl_tag_add)
00179 {
00180   vnl_vector_construct_hack();
00181   vnl_vector_alloc_blah(u.num_elmts);
00182 #if VNL_CONFIG_CHECK_BOUNDS  && (!defined NDEBUG)
00183   if (u.size() != v.size())
00184     vnl_error_vector_dimension ("vnl_vector<>::vnl_vector(v, v, vnl_vector_add_tag)", u.size(), v.size());
00185 #endif
00186   for (unsigned int i=0; i<num_elmts; ++i)
00187     data[i] = u[i] + v[i];
00188 }
00189 
00190 template<class T>
00191 vnl_vector<T>::vnl_vector (vnl_vector<T> const &u, vnl_vector<T> const &v, vnl_tag_sub)
00192 {
00193   vnl_vector_construct_hack();
00194   vnl_vector_alloc_blah(u.num_elmts);
00195 #if VNL_CONFIG_CHECK_BOUNDS  && (!defined NDEBUG)
00196   if (u.size() != v.size())
00197     vnl_error_vector_dimension ("vnl_vector<>::vnl_vector(v, v, vnl_vector_sub_tag)", u.size(), v.size());
00198 #endif
00199   for (unsigned int i=0; i<num_elmts; ++i)
00200     data[i] = u[i] - v[i];
00201 }
00202 
00203 template<class T>
00204 vnl_vector<T>::vnl_vector (vnl_vector<T> const &u, T s, vnl_tag_mul)
00205 {
00206   vnl_vector_construct_hack();
00207   vnl_vector_alloc_blah(u.num_elmts);
00208   for (unsigned int i=0; i<num_elmts; ++i)
00209     data[i] = u[i] * s;
00210 }
00211 
00212 template<class T>
00213 vnl_vector<T>::vnl_vector (vnl_vector<T> const &u, T s, vnl_tag_div)
00214 {
00215   vnl_vector_construct_hack();
00216   vnl_vector_alloc_blah(u.num_elmts);
00217   for (unsigned int i=0; i<num_elmts; ++i)
00218     data[i] = u[i] / s;
00219 }
00220 
00221 template<class T>
00222 vnl_vector<T>::vnl_vector (vnl_vector<T> const &u, T s, vnl_tag_add)
00223 {
00224   vnl_vector_construct_hack();
00225   vnl_vector_alloc_blah(u.num_elmts);
00226   for (unsigned int i=0; i<num_elmts; ++i)
00227     data[i] = u[i] + s;
00228 }
00229 
00230 template<class T>
00231 vnl_vector<T>::vnl_vector (vnl_vector<T> const &u, T s, vnl_tag_sub)
00232 {
00233   vnl_vector_construct_hack();
00234   vnl_vector_alloc_blah(u.num_elmts);
00235   for (unsigned int i=0; i<num_elmts; ++i)
00236     data[i] = u[i] - s;
00237 }
00238 
00239 template<class T>
00240 vnl_vector<T>::vnl_vector (vnl_matrix<T> const &M, vnl_vector<T> const &v, vnl_tag_mul)
00241 {
00242   vnl_vector_construct_hack();
00243   vnl_vector_alloc_blah(M.rows());
00244 
00245 #ifndef NDEBUG
00246   if (M.cols() != v.size())
00247     vnl_error_vector_dimension ("vnl_vector<>::vnl_vector(M, v, vnl_vector_mul_tag)", M.cols(), v.size());
00248 #endif
00249   vnl_sse<T>::matrix_x_vector(M.begin(), v.begin(), this->begin(), M.rows(), M.cols());
00250 }
00251 
00252 template<class T>
00253 vnl_vector<T>::vnl_vector (vnl_vector<T> const &v, vnl_matrix<T> const &M, vnl_tag_mul)
00254 {
00255   vnl_vector_construct_hack();
00256   vnl_vector_alloc_blah(M.cols());
00257 #ifndef NDEBUG
00258   if (v.size() != M.rows())
00259     vnl_error_vector_dimension ("vnl_vector<>::vnl_vector(v, M, vnl_vector_mul_tag)", v.size(), M.rows());
00260 #endif
00261   vnl_sse<T>::vector_x_matrix(v.begin(), M.begin(), this->begin(),  M.rows(), M.cols());
00262 }
00263 
00264 template<class T>
00265 vnl_vector<T>::~vnl_vector()
00266 {
00267 #if VCL_HAS_SLICED_DESTRUCTOR_BUG
00268   if (data && vnl_vector_own_data) destroy();
00269 #else
00270   if (data) destroy();
00271 #endif
00272 }
00273 
00274 //: Frees up the array inside vector. O(1).
00275 
00276 template<class T>
00277 void vnl_vector<T>::destroy()
00278 {
00279   vnl_vector_free_blah;
00280 }
00281 
00282 template<class T>
00283 void vnl_vector<T>::clear()
00284 {
00285   if (data) {
00286     destroy();
00287     num_elmts = 0;
00288     data = 0;
00289   }
00290 }
00291 
00292 template<class T>
00293 bool vnl_vector<T>::set_size(unsigned n)
00294 {
00295   if (this->data) {
00296     // if no change in size, do not reallocate.
00297     if (this->num_elmts == n)
00298       return false;
00299 
00300     vnl_vector_free_blah;
00301     vnl_vector_alloc_blah(n);
00302   }
00303   else {
00304     // this happens if the vector is default constructed.
00305     vnl_vector_alloc_blah(n);
00306   }
00307   return true;
00308 }
00309 
00310 #undef vnl_vector_alloc_blah
00311 #undef vnl_vector_free_blah
00312 
00313 //------------------------------------------------------------
00314 
00315 //: Read a vnl_vector from an ascii vcl_istream.
00316 // If the vector has nonzero size on input, read that many values.
00317 // Otherwise, read to EOF.
00318 template <class T>
00319 bool vnl_vector<T>::read_ascii(vcl_istream& s)
00320 {
00321   bool size_known = (this->size() != 0);
00322   if (size_known) {
00323     for (unsigned i = 0; i < this->size(); ++i) {
00324       if ( ! (s >> (*this)(i)) ) {
00325         return false;
00326       }
00327     }
00328     return true;
00329   }
00330 
00331   // Just read until EOF
00332   vcl_vector<T> allvals;
00333   unsigned n = 0;
00334   T value;
00335   while ( s >> value ) {
00336     allvals.push_back(value);
00337     ++n;
00338   }
00339   this->set_size(n); //*this = vnl_vector<T>(n);
00340   for (unsigned i = 0; i < n; ++i)
00341     (*this)[i] = allvals[i];
00342   return true;
00343 }
00344 
00345 template <class T>
00346 vnl_vector<T> vnl_vector<T>::read(vcl_istream& s)
00347 {
00348   vnl_vector<T> V;
00349   V.read_ascii(s);
00350   return V;
00351 }
00352 
00353 //: Sets all elements of a vector to a specified fill value. O(n).
00354 
00355 template<class T>
00356 vnl_vector<T>&
00357 vnl_vector<T>::fill (T const& value)
00358 {
00359   for (unsigned i = 0; i < this->num_elmts; i++)
00360     this->data[i] = value;
00361   return *this;
00362 }
00363 
00364 //: Sets elements of a vector to those in an array. O(n).
00365 
00366 template<class T>
00367 vnl_vector<T>&
00368 vnl_vector<T>::copy_in (T const *ptr)
00369 {
00370   for (unsigned i = 0; i < num_elmts; ++i)
00371     data[i] = ptr[i];
00372   return *this;
00373 }
00374 
00375 //: Sets elements of an array to those in vector. O(n).
00376 
00377 template<class T>
00378 void vnl_vector<T>::copy_out (T *ptr) const
00379 {
00380   for (unsigned i = 0; i < num_elmts; ++i)
00381     ptr[i] = data[i];
00382 }
00383 
00384 //: Copies rhs vector into lhs vector. O(n).
00385 // Changes the dimension of lhs vector if necessary.
00386 
00387 template<class T>
00388 vnl_vector<T>& vnl_vector<T>::operator= (vnl_vector<T> const& rhs)
00389 {
00390   if (this != &rhs) { // make sure *this != m
00391     if (rhs.data) {
00392       if (this->num_elmts != rhs.num_elmts)
00393         this->set_size(rhs.size());
00394       for (unsigned i = 0; i < this->num_elmts; i++)
00395         this->data[i] = rhs.data[i];
00396     }
00397     else {
00398       // rhs is default-constructed.
00399       clear();
00400     }
00401   }
00402   return *this;
00403 }
00404 
00405 //: Increments all elements of vector with value. O(n).
00406 
00407 template<class T>
00408 vnl_vector<T>& vnl_vector<T>::operator+= (T value)
00409 {
00410   for (unsigned i = 0; i < this->num_elmts; i++)
00411     this->data[i] += value;
00412   return *this;
00413 }
00414 
00415 //: Multiplies all elements of vector with value. O(n).
00416 
00417 template<class T>
00418 vnl_vector<T>& vnl_vector<T>::operator*= (T value)
00419 {
00420   for (unsigned i = 0; i < this->num_elmts; i++)
00421     this->data[i] *= value;
00422   return *this;
00423 }
00424 
00425 //: Divides all elements of vector by value. O(n).
00426 
00427 template<class T>
00428 vnl_vector<T>& vnl_vector<T>::operator/= (T value)
00429 {
00430   for (unsigned i = 0; i < this->num_elmts; i++)
00431     this->data[i] /= value;
00432   return *this;
00433 }
00434 
00435 
00436 //: Mutates lhs vector with its addition with rhs vector. O(n).
00437 
00438 template<class T>
00439 vnl_vector<T>& vnl_vector<T>::operator+= (vnl_vector<T> const& rhs)
00440 {
00441 #ifndef NDEBUG
00442   if (this->num_elmts != rhs.num_elmts)
00443     vnl_error_vector_dimension ("operator+=", this->num_elmts, rhs.num_elmts);
00444 #endif
00445   for (unsigned i = 0; i < this->num_elmts; i++)
00446     this->data[i] += rhs.data[i];
00447   return *this;
00448 }
00449 
00450 
00451 //:  Mutates lhs vector with its subtraction with rhs vector. O(n).
00452 
00453 template<class T>
00454 vnl_vector<T>& vnl_vector<T>::operator-= (vnl_vector<T> const& rhs)
00455 {
00456 #ifndef NDEBUG
00457   if (this->num_elmts != rhs.num_elmts)
00458     vnl_error_vector_dimension ("operator-=", this->num_elmts, rhs.num_elmts);
00459 #endif
00460   for (unsigned i = 0; i < this->num_elmts; i++)
00461     this->data[i] -= rhs.data[i];
00462   return *this;
00463 }
00464 
00465 //: Pre-multiplies vector with matrix and stores result back in vector.
00466 // v = m * v. O(m*n). Vector is assumed a column matrix.
00467 
00468 template<class T>
00469 vnl_vector<T>& vnl_vector<T>::pre_multiply (vnl_matrix<T> const& m)
00470 {
00471 #ifndef NDEBUG
00472   if (m.columns() != this->num_elmts)           // dimensions do not match?
00473     vnl_error_vector_dimension ("operator*=", this->num_elmts, m.columns());
00474 #endif
00475   T* temp= vnl_c_vector<T>::allocate_T(m.rows()); // Temporary
00476   for (unsigned i = 0; i < m.rows(); i++) {     // For each index
00477     temp[i] = (T)0;                             // Initialize element value
00478     for (unsigned k = 0; k < this->num_elmts; k++)      // Loop over column values
00479       temp[i] += (m.get(i,k) * this->data[k]);  // Multiply
00480   }
00481   vnl_c_vector<T>::deallocate(this->data, this->num_elmts); // Free up the data space
00482   num_elmts = m.rows();                         // Set new num_elmts
00483   this->data = temp;                            // Pointer to new storage
00484   return *this;                                 // Return vector reference
00485 }
00486 
00487 //: Post-multiplies vector with matrix and stores result back in vector.
00488 // v = v * m. O(m*n). Vector is assumed a row matrix.
00489 
00490 template<class T>
00491 vnl_vector<T>& vnl_vector<T>::post_multiply (vnl_matrix<T> const& m)
00492 {
00493 #ifndef NDEBUG
00494   if (this->num_elmts != m.rows())              // dimensions do not match?
00495     vnl_error_vector_dimension ("operator*=", this->num_elmts, m.rows());
00496 #endif
00497   T* temp= vnl_c_vector<T>::allocate_T(m.columns()); // Temporary
00498   for (unsigned i = 0; i < m.columns(); i++) {  // For each index
00499     temp[i] = (T)0;                             // Initialize element value
00500     for (unsigned k = 0; k < this->num_elmts; k++) // Loop over column values
00501       temp[i] += (this->data[k] * m.get(k,i));  // Multiply
00502   }
00503   vnl_c_vector<T>::deallocate(this->data, num_elmts); // Free up the data space
00504   num_elmts = m.columns();                      // Set new num_elmts
00505   this->data = temp;                            // Pointer to new storage
00506   return *this;                                 // Return vector reference
00507 }
00508 
00509 
00510 //: Creates new vector containing the negation of THIS vector. O(n).
00511 
00512 template<class T>
00513 vnl_vector<T> vnl_vector<T>::operator- () const
00514 {
00515   vnl_vector<T> result(this->num_elmts);
00516   for (unsigned i = 0; i < this->num_elmts; i++)
00517     result.data[i] = - this->data[i];           // negate element
00518   return result;
00519 }
00520 
00521 #if 0 // commented out
00522 //: Returns new vector which is the multiplication of matrix m with column vector v. O(m*n).
00523 
00524 template<class T>
00525 vnl_vector<T> operator* (vnl_matrix<T> const& m, vnl_vector<T> const& v)
00526 {
00527 #ifndef NDEBUG
00528   if (m.columns() != v.size())                  // dimensions do not match?
00529     vnl_error_vector_dimension ("operator*", m.columns(), v.size());
00530 #endif
00531   vnl_vector<T> result(m.rows());               // Temporary
00532   for (unsigned i = 0; i < m.rows(); i++) {     // For each index
00533     result[i] = (T)0;                           // Initialize element value
00534     for (unsigned k = 0; k < v.size(); k++)     // Loop over column values
00535       result[i] += (m.get(i,k) * v[k]);         // Multiply
00536   }
00537   return result;
00538 }
00539 
00540 
00541 //: Returns new vector which is the multiplication of row vector v with matrix m. O(m*n).
00542 
00543 template<class T>
00544 vnl_vector<T> vnl_vector<T>::operator* (vnl_matrix<T> const&m) const
00545 {
00546   // rick@aai: casting away const avoids the following error (using gcc272)
00547   // at m.rows during instantiation of 'template class vnl_vector<double >;'
00548   // "cannot lookup method in incomplete type `const vnl_matrix<double>`"
00549   // For some reason, instantiating the following function prior to vnl_vector
00550   // also avoids the error.
00551   // template vnl_matrix<double> outer_product(vnl_vector<double> const&, vnl_vector<double> const&)
00552 
00553 #ifndef NDEBUG
00554   if (num_elmts != m.rows())                    // dimensions do not match?
00555     vnl_error_vector_dimension ("operator*", num_elmts, m.rows());
00556 #endif
00557   vnl_vector<T> result(m.columns());            // Temporary
00558   for (unsigned i = 0; i < m.columns(); i++) {  // For each index
00559     result.data[i] = (T)0;                      // Initialize element value
00560     for (unsigned k = 0; k < num_elmts; k++)    // Loop over column values
00561       result.data[i] += (data[k] * m.get(k,i)); // Multiply
00562   }
00563   return result;
00564 }
00565 #endif
00566 
00567 
00568 //: Replaces elements with index beginning at start, by values of v. O(n).
00569 
00570 template<class T>
00571 vnl_vector<T>& vnl_vector<T>::update (vnl_vector<T> const& v, unsigned start)
00572 {
00573   unsigned stop = start + v.size();
00574 #ifndef NDEBUG
00575   if ( stop > this->num_elmts)
00576     vnl_error_vector_dimension ("update", stop-start, v.size());
00577 #endif
00578   for (unsigned i = start; i < stop; i++)
00579     this->data[i] = v.data[i-start];
00580   return *this;
00581 }
00582 
00583 
00584 //: Returns a subvector specified by the start index and length. O(n).
00585 
00586 template<class T>
00587 vnl_vector<T> vnl_vector<T>::extract (unsigned len, unsigned start) const
00588 {
00589 #ifndef NDEBUG
00590   unsigned stop = start + len;
00591   if (this->num_elmts < stop)
00592     vnl_error_vector_dimension ("extract", stop-start, len);
00593 #endif
00594   vnl_vector<T> result(len);
00595   for (unsigned i = 0; i < len; i++)
00596     result.data[i] = data[start+i];
00597   return result;
00598 }
00599 
00600 //: Returns new vector whose elements are the products v1[i]*v2[i]. O(n).
00601 
00602 template<class T>
00603 vnl_vector<T> element_product (vnl_vector<T> const& v1, vnl_vector<T> const& v2)
00604 {
00605 #ifndef NDEBUG
00606   if (v1.size() != v2.size())
00607     vnl_error_vector_dimension ("element_product", v1.size(), v2.size());
00608 #endif
00609 
00610   vnl_vector<T> result(v1.size());
00611 
00612   vnl_sse<T>::element_product(v1.begin(), v2.begin(), result.begin(), v1.size());
00613 
00614   return result;
00615 }
00616 
00617 //: Returns new vector whose elements are the quotients v1[i]/v2[i]. O(n).
00618 
00619 template<class T>
00620 vnl_vector<T> element_quotient (vnl_vector<T> const& v1, vnl_vector<T> const& v2)
00621 {
00622 #ifndef NDEBUG
00623   if (v1.size() != v2.size())
00624     vnl_error_vector_dimension ("element_quotient", v1.size(), v2.size());
00625 #endif
00626   vnl_vector<T> result(v1.size());
00627   for (unsigned i = 0; i < v1.size(); i++)
00628     result[i] = v1[i] / v2[i];
00629   return result;
00630 }
00631 
00632 //:
00633 template <class T>
00634 vnl_vector<T> vnl_vector<T>::apply(T (*f)(T const&)) const
00635 {
00636   vnl_vector<T> ret(size());
00637   vnl_c_vector<T>::apply(this->data, num_elmts, f, ret.data);
00638   return ret;
00639 }
00640 
00641 //: Return the vector made by applying "f" to each element.
00642 template <class T>
00643 vnl_vector<T> vnl_vector<T>::apply(T (*f)(T)) const
00644 {
00645   vnl_vector<T> ret(num_elmts);
00646   vnl_c_vector<T>::apply(this->data, num_elmts, f, ret.data);
00647   return ret;
00648 }
00649 
00650 //: Returns the dot product of two nd-vectors, or [v1]*[v2]^T. O(n).
00651 
00652 template<class T>
00653 T dot_product (vnl_vector<T> const& v1, vnl_vector<T> const& v2)
00654 {
00655 #ifndef NDEBUG
00656   if (v1.size() != v2.size())
00657     vnl_error_vector_dimension ("dot_product", v1.size(), v2.size());
00658 #endif
00659   return vnl_c_vector<T>::dot_product(v1.begin(),
00660                                       v2.begin(),
00661                                       v1.size());
00662 }
00663 
00664 //: Hermitian inner product. O(n)
00665 
00666 template<class T>
00667 T inner_product (vnl_vector<T> const& v1, vnl_vector<T> const& v2)
00668 {
00669 #ifndef NDEBUG
00670   if (v1.size() != v2.size())
00671     vnl_error_vector_dimension ("inner_product", v1.size(), v2.size());
00672 #endif
00673   return vnl_c_vector<T>::inner_product(v1.begin(),
00674                                         v2.begin(),
00675                                         v1.size());
00676 }
00677 
00678 //: Returns the 'matrix element' <u|A|v> = u^t * A * v. O(mn).
00679 
00680 template<class T>
00681 T bracket(vnl_vector<T> const &u, vnl_matrix<T> const &A, vnl_vector<T> const &v)
00682 {
00683 #ifndef NDEBUG
00684   if (u.size() != A.rows())
00685     vnl_error_vector_dimension("bracket",u.size(),A.rows());
00686   if (A.columns() != v.size())
00687     vnl_error_vector_dimension("bracket",A.columns(),v.size());
00688 #endif
00689   T brak(0);
00690   for (unsigned i=0; i<u.size(); ++i)
00691     for (unsigned j=0; j<v.size(); ++j)
00692       brak += u[i]*A(i,j)*v[j];
00693   return brak;
00694 }
00695 
00696 //: Returns the nxn outer product of two nd-vectors, or [v1]^T*[v2]. O(n).
00697 
00698 template<class T>
00699 vnl_matrix<T> outer_product (vnl_vector<T> const& v1,
00700                              vnl_vector<T> const& v2) {
00701   vnl_matrix<T> out(v1.size(), v2.size());
00702   for (unsigned i = 0; i < out.rows(); i++)             // v1.column() * v2.row()
00703     for (unsigned j = 0; j < out.columns(); j++)
00704       out[i][j] = v1[i] * v2[j];
00705   return out;
00706 }
00707 
00708 
00709 //--------------------------------------------------------------------------------
00710 
00711 template <class T>
00712 vnl_vector<T>&
00713 vnl_vector<T>::flip()
00714 {
00715   for (unsigned i=0;i<num_elmts/2;i++) {
00716     T tmp=data[i];
00717     data[i]=data[num_elmts-1-i];
00718     data[num_elmts-1-i]=tmp;
00719   }
00720   return *this;
00721 }
00722 
00723 template <class T>
00724 void vnl_vector<T>::swap(vnl_vector<T> &that)
00725 {
00726   vcl_swap(this->num_elmts, that.num_elmts);
00727   vcl_swap(this->data, that.data);
00728 }
00729 
00730 //--------------------------------------------------------------------------------
00731 
00732 // Disable warning caused when T is complex<float>.  The static_cast
00733 // to real_t constructs a complex<float> from a double.
00734 #if defined(_MSC_VER)
00735 # pragma warning (push)
00736 # pragma warning (disable: 4244) /* conversion with loss of data */
00737 #endif
00738 
00739 // fsm : cos_angle should return a T, or a double-precision extension
00740 // of T. "double" is wrong since it won't work if T is complex.
00741 template <class T>
00742 T cos_angle(vnl_vector<T> const& a, vnl_vector<T> const& b)
00743 {
00744   typedef typename vnl_numeric_traits<T>::real_t real_t;
00745   typedef typename vnl_numeric_traits<T>::abs_t abs_t;
00746   typedef typename vnl_numeric_traits<abs_t>::real_t abs_r;
00747 
00748   real_t ab = inner_product(a,b);
00749   real_t a_b = static_cast<real_t>(
00750     vcl_sqrt( abs_r(a.squared_magnitude() * b.squared_magnitude()) ));
00751   return T( ab / a_b);
00752 }
00753 
00754 #if defined(_MSC_VER)
00755 # pragma warning (pop)
00756 #endif
00757 
00758 //: Returns smallest angle between two non-zero n-dimensional vectors. O(n).
00759 
00760 template<class T>
00761 double angle (vnl_vector<T> const& a, vnl_vector<T> const& b)
00762 {
00763   typedef typename vnl_numeric_traits<T>::abs_t abs_t;
00764   typedef typename vnl_numeric_traits<abs_t>::real_t abs_r;
00765   const abs_r c = abs_r( cos_angle(a, b) );
00766   // IMS: sometimes cos_angle returns 1+eps, which can mess up vcl_acos.
00767   if (c >= 1.0) return 0;
00768   if (c <= -1.0) return vnl_math::pi;
00769   return vcl_acos( c );
00770 }
00771 
00772 template <class T>
00773 bool vnl_vector<T>::is_finite() const
00774 {
00775   for (unsigned i = 0; i < this->size();++i)
00776     if (!vnl_math_isfinite( (*this)[i] ))
00777       return false;
00778 
00779   return true;
00780 }
00781 
00782 template <class T>
00783 bool vnl_vector<T>::is_zero() const
00784 {
00785   T const zero(0);
00786   for (unsigned i = 0; i < this->size();++i)
00787     if ( !( (*this)[i] == zero) )
00788       return false;
00789 
00790   return true;
00791 }
00792 
00793 template <class T>
00794 void vnl_vector<T>::assert_finite_internal() const
00795 {
00796   if (this->is_finite())
00797     return;
00798 
00799   vcl_cerr << __FILE__ ": *** NAN FEVER **\n" << *this;
00800   vcl_abort();
00801 }
00802 
00803 template <class T>
00804 void vnl_vector<T>::assert_size_internal(unsigned sz) const
00805 {
00806   if (this->size() != sz) {
00807     vcl_cerr << __FILE__ ": Size is " << this->size() << ". Should be " << sz << '\n';
00808     vcl_abort();
00809   }
00810 }
00811 
00812 template <class T>
00813 bool vnl_vector<T>::is_equal(vnl_vector<T> const& rhs, double tol) const
00814 {
00815   if (this == &rhs)                                         //Same object ? => equal.
00816     return true;
00817   
00818   if (this->size() != rhs.size())                           //Size different ?
00819     return false;                                         
00820   for (unsigned i = 0; i < size(); i++)                         
00821     if (vnl_math_abs(this->data[i] - rhs.data[i]) > tol)    //Element different ?
00822       return false;                                
00823   
00824   return true;                                   
00825   
00826 }
00827 
00828 template<class T>
00829 bool vnl_vector<T>::operator_eq (vnl_vector<T> const& rhs) const
00830 {
00831   if (this == &rhs)                               // same object => equal.
00832     return true;
00833 
00834   if (this->size() != rhs.size())                 // Size different ?
00835     return false;                                 // Then not equal.
00836   for (unsigned i = 0; i < size(); i++)           // For each index
00837     if (!(this->data[i] == rhs.data[i]))          // Element different ?
00838       return false;                               // Then not equal.
00839 
00840   return true;                                    // Else same; return true.
00841 }
00842 
00843 //--------------------------------------------------------------------------------
00844 
00845 //: Overloads the output operator to print a vector. O(n).
00846 
00847 template<class T>
00848 vcl_ostream& operator<< (vcl_ostream& s, vnl_vector<T> const& v)
00849 {
00850   for (unsigned i = 0; i+1 < v.size(); ++i)   // For each index in vector
00851     s << v[i] << ' ';                              // Output data element
00852   if (v.size() > 0)  s << v[v.size()-1];
00853   return s;
00854 }
00855 
00856 //: Read a vnl_vector from an ascii vcl_istream.
00857 // If the vector has nonzero size on input, read that many values.
00858 // Otherwise, read to EOF.
00859 template <class T>
00860 vcl_istream& operator>>(vcl_istream& s, vnl_vector<T>& M)
00861 {
00862   M.read_ascii(s); return s;
00863 }
00864 
00865 template <class T>
00866 void vnl_vector<T>::inline_function_tickler()
00867 {
00868   vnl_vector<T> v;
00869   // fsm: hacks to get 2.96/2.97/3.0 to instantiate the inline functions.
00870   v = T(3) + v;
00871   v = T(3) - v;
00872   v = T(3) * v;
00873 }
00874 
00875 
00876 //--------------------------------------------------------------------------------
00877 
00878 // The instantiation macros are split because some functions (angle, cos_angle)
00879 // shouldn't be instantiated for complex and/or integral types.
00880 
00881 #define VNL_VECTOR_INSTANTIATE_COMMON(T) \
00882 template class vnl_vector<T >; \
00883 /* arithmetic, comparison etc */ \
00884 VCL_INSTANTIATE_INLINE(vnl_vector<T > operator+(T const, vnl_vector<T > const &)); \
00885 VCL_INSTANTIATE_INLINE(vnl_vector<T > operator-(T const, vnl_vector<T > const &)); \
00886 VCL_INSTANTIATE_INLINE(vnl_vector<T > operator*(T const, vnl_vector<T > const &)); \
00887 template vnl_vector<T > operator*(vnl_matrix<T > const &, vnl_vector<T > const &); \
00888 /* element-wise */ \
00889 template vnl_vector<T > element_product(vnl_vector<T > const &, vnl_vector<T > const &); \
00890 template vnl_vector<T > element_quotient(vnl_vector<T > const &, vnl_vector<T > const &); \
00891 /* dot products, angles etc */ \
00892 template T inner_product(vnl_vector<T > const &, vnl_vector<T > const &); \
00893 template T dot_product(vnl_vector<T > const &, vnl_vector<T > const &); \
00894 template T bracket(vnl_vector<T > const &, vnl_matrix<T > const &, vnl_vector<T > const &); \
00895 template vnl_matrix<T > outer_product(vnl_vector<T > const &,vnl_vector<T > const &); \
00896 /* I/O */ \
00897 template vcl_ostream & operator<<(vcl_ostream &, vnl_vector<T > const &); \
00898 template vcl_istream & operator>>(vcl_istream &, vnl_vector<T >       &)
00899 
00900 #define VNL_VECTOR_INSTANTIATE(T) \
00901 VNL_VECTOR_INSTANTIATE_COMMON(T); \
00902 template T cos_angle(vnl_vector<T > const & , vnl_vector<T > const &); \
00903 template double angle(vnl_vector<T > const & , vnl_vector<T > const &)
00904 
00905 #define VNL_VECTOR_INSTANTIATE_COMPLEX(T) \
00906 VNL_VECTOR_INSTANTIATE_COMMON(T); \
00907 template T cos_angle(vnl_vector<T > const & , vnl_vector<T > const &)
00908 
00909 #endif // vnl_vector_txx_