1 // This is core/vnl/vnl_vector_fixed.h
2 #ifndef vnl_vector_fixed_h_
3 #define vnl_vector_fixed_h_
4 //:
5 // \file
6 // \brief Fixed length stack-stored vector
7 //
8 // The operators are inlined because (1) they are small and
9 // (2) we then have less explicit instantiation trouble.
10 //
11 // \author Andrew W. Fitzgibbon, Oxford RRG
12 // \date   04 Aug 96
13 //
14 // \verbatim
15 //  Modifications
16 //   LSB Manchester 16/3/01 Binary I/O added
17 //   Feb.2002 - Peter Vanroose - brief doxygen comment placed on single line
18 //   Oct.2002 - Amitha Perera - decoupled vnl_vector and vnl_vector_fixed for
19 //              space efficiency, removed necessity for vnl_vector_fixed_ref
20 //   Jun.2003 - Paul Smyth - added as_fixed_ref() to convert to fixed-size ref
21 //              removed duplicate cross_3d
22 //   Jun.2003 - Peter Vanroose - added cross_2d
23 //   Oct.2003 - Peter Vanroose - removed deprecated x(), y(), z(), t()
24 //   Mar.2009 - Peter Vanroose - added arg_min() and arg_max()
25 //   Oct.2010 - Peter Vanroose - mutators and setters now return *this
26 // \endverbatim
27 
28 #include <cstring>
29 #include <iosfwd>
30 #include <cassert>
31 #ifdef _MSC_VER
32 #  include <vcl_msvc_warnings.h>
33 #endif
34 #include "vnl_vector.h"
35 #include "vnl_vector_ref.h"
36 #include "vnl_c_vector.h"
37 #include "vnl_matrix.h" // outerproduct
38 #include <vnl/vnl_config.h> // for VNL_CONFIG_CHECK_BOUNDS
39 #include "vnl_error.h"
40 #include "vnl/vnl_export.h"
41 
42 template <class T, unsigned int n> class vnl_vector_fixed;
43 template <class T, unsigned int num_rows, unsigned int num_cols> class vnl_matrix_fixed;
44 
45 //: Fixed length stack-stored, space-efficient vector.
46 // vnl_vector_fixed is a fixed-length, stack storage vector. It has
47 // the same storage size as a C-style array. It is not related via
48 // inheritance to vnl_vector. However, it can be converted cheaply to
49 // a vnl_vector_ref.
50 //
51 // In most cases, a vnl_vector_fixed can be used where a vnl_vector is
52 // expected. There are some situations, however, when the automatic
53 // conversion cannot be applied. In those cases, you need to call the
54 // as_ref() method to perform an explicit conversion. This occurs most
55 // often when the called function is templated, since the user-defined
56 // conversion operators are then suppressed.
57 // \code
58 //    template<class T>
59 //    void do_something( const vnl_vector<T>& v );
60 //    ...
61 //    vnl_vector_fixed<double,4> my_vec;
62 //
63 //    do_something( my_vec );
64 //      // Error: no do_something( vnl_vector_fixed<double,4> ) found
65 //
66 //    do_something( my_vec.as_ref() );  // works
67 // \endcode
68 //
69 // Since the conversion operator creates a temporary vnl_vector_ref
70 // object, the conversion cannot be used directly to a function that
71 // expects a non-const vnl_vector reference. Use
72 // vnl_vector_ref::non_const method for this (and only this).
73 // \code
74 //    void mutator( vnl_vector<double>& v );
75 //    ...
76 //    vnl_vector_fixed<double,4> my_vec;
77 //    mutator( my_vec.as_ref().non_const() );
78 // \endcode
79 // If the mutator only accesses the data, all should be fine. If the
80 // mutator attempts to resize the vector, you are doomed.
81 //
82 // vnl_vector_fixed defines most of the operators defined by
83 // vnl_vector, and does so efficiently. If you try to mix
84 // vnl_vector_fixed and vnl_vector, however, you will probably get a
85 // vnl_vector result, with the corresponding malloc cost.
86 template <class T, unsigned int n>
87 class VNL_EXPORT vnl_vector_fixed
88 {
89  protected:
90   T data_[n];
91 
92  public:
93   typedef vnl_vector_fixed<T,n> self;
94   typedef size_t size_type;
95   // Compile-time accessible attribute to get the dimensionality of the vector.
96   enum { SIZE = n };
97 
98   // Don't out-of-line the constructors, as extra the function call
99   // adds a significant overhead. (memcpy is often implemented with a
100   // couple of assembly instructions.)
101 
102   //: Construct an uninitialized n-vector
103   vnl_vector_fixed() = default;
104 
105   //: Copy constructor
106   //  The dimensions must match.
107   vnl_vector_fixed( const vnl_vector_fixed<T,n>& rhs ) = default;
108   vnl_vector_fixed( vnl_vector_fixed<T,n>&& rhs ) = default;
109   //: Copy operator
110   vnl_vector_fixed<T,n>& operator=( const vnl_vector_fixed<T,n>& rhs ) = default;
111   vnl_vector_fixed<T,n>& operator=( vnl_vector_fixed<T,n>&& rhs ) = default;
112 
113 
114   //: Construct a fixed-n-vector copy of \a rhs.
115   //  The dimensions must match.
vnl_vector_fixed(const vnl_vector<T> & rhs)116   vnl_vector_fixed( const vnl_vector<T>& rhs )
117   {
118     assert( n == rhs.size() );
119     std::memcpy( data_, rhs.data_block(), sizeof data_ );
120   }
121 
122   //: Constructs n-vector with all elements initialised to \a v
vnl_vector_fixed(const T & v)123   explicit vnl_vector_fixed( const T& v ) { fill( v ); }
124 
125   //: Construct a fixed-n-vector initialized from \a datablck
126   //  The data \e must have enough data. No checks performed.
vnl_vector_fixed(const T * datablck)127   explicit vnl_vector_fixed( const T* datablck )
128   {
129     std::memcpy( data_, datablck, sizeof data_ );
130   }
131 
132   //: Convenience constructor for 2-D vectors
133   // While this constructor is sometimes useful, consider using
134   // vnl_double_2 or vnl_float_2 instead.
vnl_vector_fixed(const T & x0,const T & x1)135   vnl_vector_fixed( const T& x0, const T& x1 )
136   {
137     if ( n != 2 )
138     {
139       #ifndef NDEBUG
140       vnl_error_vector_dimension("vnl_vector_fixed()", 2, n);
141       #endif
142       return;
143     }
144 
145     data_[0] = x0; data_[1] = x1;
146   }
147 
148   //: Convenience constructor for 3-D vectors
149   // While this constructor is sometimes useful, consider using
150   // vnl_double_3 or vnl_float_3 instead.
vnl_vector_fixed(const T & x0,const T & x1,const T & x2)151   vnl_vector_fixed( const T& x0, const T& x1, const T& x2 )
152   {
153     if ( n != 3 )
154     {
155       #ifndef NDEBUG
156       vnl_error_vector_dimension("vnl_vector_fixed()", 3, n);
157       #endif
158       return;
159     }
160     data_[0] = x0; data_[1] = x1; data_[2] = x2;
161   }
162 
163   //: Convenience constructor for 4-D vectors
vnl_vector_fixed(const T & x0,const T & x1,const T & x2,const T & x3)164   vnl_vector_fixed( const T& x0, const T& x1, const T& x2, const T& x3 )
165   {
166     if ( n != 4 )
167     {
168       #ifndef NDEBUG
169       vnl_error_vector_dimension("vnl_vector_fixed()", 4, n);
170       #endif
171       return;
172     }
173     data_[0] = x0; data_[1] = x1; data_[2] = x2; data_[3] = x3;
174   }
175 
176   //: Copy data from a dynamic vector
177   // The dimensions must match.
178   vnl_vector_fixed<T,n>& operator=( const vnl_vector<T>& rhs) {
179     assert( n == rhs.size() );
180     std::memcpy( data_, rhs.data_block(), sizeof data_ );
181     return *this;
182   }
183 
184   //: Length of the vector.
185   // This is always \a n.
size()186   unsigned int size() const { return n; }
187 
188   //: Put value at given position in vector.
put(unsigned int i,T const & v)189   inline void put (unsigned int i, T const& v)
190   {
191 #if VNL_CONFIG_CHECK_BOUNDS
192     if (i >= this->size())           // If invalid index specified
193       vnl_error_vector_index("put", i); // Raise exception
194 #endif
195     this->data_[i] = v;
196   }
197 
198   //: Get value at element i
199   T get(unsigned int i) const;
200 
201   //: Set all values to v
fill(T const & v)202   vnl_vector_fixed& fill( T const& v )
203   {
204     for ( size_type i = 0; i < n; ++i )
205       this->data_[i] = v;
206     return *this;
207   }
208 
209   //: Sets elements to ptr[i]
210   //  Note: ptr[i] must be valid for i=0..size()-1
copy_in(T const * ptr)211   vnl_vector_fixed& copy_in( T const * ptr )
212   {
213     for ( size_type i = 0; i < n; ++i )
214       data_[i] = ptr[i];
215     return *this;
216   }
217 
218   //: Copy elements to ptr[i]
219   //  Note: ptr[i] must be valid for i=0..size()-1
copy_out(T * ptr)220   void copy_out( T* ptr ) const
221   {
222     for ( size_type i = 0; i < n; ++i )
223       ptr[i] = data_[i];
224   }
225 
226   //: Sets elements to ptr[i]
227   //  Note: ptr[i] must be valid for i=0..size()-1
set(T const * ptr)228   vnl_vector_fixed& set( T const *ptr ) { return copy_in(ptr); }
229 
230   //: Return reference to the element at specified index.
231   // There are assert style boundary checks - #define NDEBUG to turn them off.
232   T       & operator() (unsigned int i);
233 
234   //: Return reference to the element at specified index.
235   // There are assert style boundary checks - #define NDEBUG to turn them off.
236   T const & operator() (unsigned int i) const;
237 
238 
239   //: Return the i-th element
240   T& operator[] (const size_t i);
241 
242   //: Return the i-th element
243   const T& operator[] (const size_t i) const;
244 
245   //: Access the contiguous block storing the elements in the vector.
246   //  O(1).
247   //  data_block()[0] is the first element of the vector
248   T const* data_block() const;
249 
250   //: Access the contiguous block storing the elements in the vector.
251   //  O(1).
252   //  data_block()[0] is the first element of the vector
253   T      * data_block();
254 
255   //----------------------------------------------------------------------
256   // Conversion to vnl_vector_ref.
257 
258   // The const version of as_ref should return a const vnl_vector_ref
259   // so that the vnl_vector_ref::non_const() cannot be used on
260   // it. This prevents a const vnl_vector_fixed from being cast into a
261   // non-const vnl_vector reference, giving a slight increase in type safety.
262 
263   //: Explicit conversion to a vnl_vector_ref or vnl_vector.
264   // This is a cheap conversion for those functions that have an interface
265   // for vnl_vector but not for vnl_vector_fixed. There is also a
266   // conversion operator that should work most of the time.
267   // \sa vnl_vector_ref::non_const
as_ref()268   vnl_vector_ref<T> as_ref() { return vnl_vector_ref<T>( n, data_ ); }
as_ref()269   const vnl_vector_ref<T> as_ref() const { return vnl_vector_ref<T>( n, const_cast<T*>(data_) ); }
as_vector()270   vnl_vector<T> as_vector() const { return vnl_vector<T>(data_, n); }
271 
272   //: Cheap conversion to vnl_vector_ref
273   // Sometimes, such as with templated functions, the compiler cannot
274   // use this user-defined conversion. For those cases, use the
275   // explicit as_ref() method instead.
276 #if ! VXL_USE_HISTORICAL_IMPLICIT_CONVERSIONS
277   explicit operator const vnl_vector_ref<T>() const { return this->as_ref(); }
278 #else
279 #if VXL_LEGACY_FUTURE_REMOVE
280   VXL_DEPRECATED_MSG("Implicit cast conversion is dangerous.\nUSE: .as_vector() or .as_ref() member function for clarity.")
281 #endif
282   operator const vnl_vector_ref<T>() const { return this->as_ref(); } //Implicit for backwards compatibility
283 #endif
284   explicit operator vnl_vector<T>() const { return this->as_vector(); }
285   //----------------------------------------------------------------------
286 
287   //: Type defs for iterators
288   typedef T element_type;
289   //: Type defs for iterators
290   typedef T       *iterator;
291   //: Iterator pointing to start of data
begin()292   iterator begin() { return data_; }
293 
294   //: Iterator pointing to element beyond end of data
end()295   iterator end() { return data_+n; }
296 
297   //: Const iterator type
298   typedef T const *const_iterator;
299   //: Iterator pointing to start of data
begin()300   const_iterator begin() const { return data_; }
301   //: Iterator pointing to element beyond end of data
end()302   const_iterator end() const { return data_+n; }
303 
304   //: Analogous to std::array::front().
front()305   T& front() { return *data_; }
306   //: Analogous to std::array::back().
back()307   T& back() { return data_[n - 1]; }
308 
309   //: Analogous to std::array::front() (const overload).
front()310   const T& front() const { return *data_; }
311   //: Analogous to std::array::back() (const overload).
back()312   const T& back() const { return data_[n - 1]; }
313 
314   //: Apply f to each element.
315   // Returns a new vector with the result.
316   vnl_vector_fixed<T,n> apply(T (*f)(T));
317 
318   //: Apply f to each element.
319   // Returns a new vector with the result.
320   vnl_vector_fixed<T,n> apply(T (*f)(const T&));
321 
322   //:
323   vnl_vector_fixed<T,n>& operator+=( T s ) { self::add( data_, s, data_ ); return *this; }
324 
325   //:
326   vnl_vector_fixed<T,n>& operator-=( T s ) { self::sub( data_, s, data_ ); return *this; }
327 
328   //:
329   vnl_vector_fixed<T,n>& operator*=( T s ) { self::mul( data_, s, data_ ); return *this; }
330 
331   //:
332   vnl_vector_fixed<T,n>& operator/=( T s ) { self::div( data_, s, data_ ); return *this; }
333 
334   //:
335   vnl_vector_fixed<T,n>& operator+=( const vnl_vector_fixed<T,n>& v ) { self::add( data_, v.data_block(), data_ ); return *this; }
336 
337   //:
338   vnl_vector_fixed<T,n>& operator-=( const vnl_vector_fixed<T,n>& v ) { self::sub( data_, v.data_block(), data_ ); return *this; }
339 
340   //:
341   vnl_vector_fixed<T,n>& operator+=( const vnl_vector<T>& v )
342   {
343     assert( v.size() == n );
344     self::add( data_, v.data_block(), data_ ); return *this;
345   }
346 
347   //:
348   vnl_vector_fixed<T,n>& operator-=( const vnl_vector<T>& v )
349   {
350     assert( v.size() == n );
351     self::sub( data_, v.data_block(), data_ ); return *this;
352   }
353 
354   //:
355   vnl_vector_fixed<T,n> operator-() const
356   {
357     vnl_vector_fixed<T,n> result;
358     self::sub( (T)0, data_, result.data_ );
359     return result;
360   }
361 
362   //: Returns a subvector specified by the start index and length. O(n).
363   vnl_vector<T> extract (unsigned int len, unsigned int start=0) const
364   {
365   assert( start < n && start + len <= n );
366   return vnl_vector<T>( data_ + start, len );
367   }
368 
369   //: Replaces elements with index beginning at start, by values of v. O(n).
370   vnl_vector_fixed& update(vnl_vector<T> const&, unsigned int start=0);
371 
372   // norms etc
373   typedef typename vnl_c_vector<T>::abs_t abs_t;
374 
375   //: Return sum of squares of elements
squared_magnitude()376   abs_t squared_magnitude() const { return vnl_c_vector<T>::two_nrm2(begin(), size()); }
377 
378   //: Return magnitude (length) of vector
magnitude()379   abs_t magnitude() const { return two_norm(); }
380 
381   //: Return sum of absolute values of the elements
one_norm()382   abs_t one_norm() const { return vnl_c_vector<T>::one_norm(begin(), size()); }
383 
384   //: Return sqrt of sum of squares of values of elements
two_norm()385   abs_t two_norm() const { return vnl_c_vector<T>::two_norm(begin(), size()); }
386 
387   //: Return largest absolute element value
inf_norm()388   abs_t inf_norm() const { return vnl_c_vector<T>::inf_norm(begin(), size()); }
389 
390   //: Normalise by dividing through by the magnitude
normalize()391   vnl_vector_fixed<T,n>& normalize() { vnl_c_vector<T>::normalize(begin(), size()); return *this; }
392 
393   // These next 6 functions are should really be helper functions since they aren't
394   // really proper functions on a vector in a philosophical sense.
395 
396   //: Root Mean Squares of values
rms()397   abs_t rms     () const { return vnl_c_vector<T>::rms_norm(begin(), size()); }
398 
399   //: Smallest value
min_value()400   T min_value () const { return vnl_c_vector<T>::min_value(begin(), size()); }
401 
402   //: Largest value
max_value()403   T max_value () const { return vnl_c_vector<T>::max_value(begin(), size()); }
404 
405   //: Location of smallest value
arg_min()406   unsigned arg_min() const { return vnl_c_vector<T>::arg_min(begin(), size()); }
407 
408   //: Location of largest value
arg_max()409   unsigned arg_max() const { return vnl_c_vector<T>::arg_max(begin(), size()); }
410 
411   //: Mean of values in vector
mean()412   T mean() const { return vnl_c_vector<T>::mean(begin(), size()); }
413 
414   //: Sum of values in a vector
sum()415   T sum() const { return vnl_c_vector<T>::sum(begin(), size()); }
416 
417   //: Reverse the order of the elements
418   //  Element i swaps with element size()-1-i
419   vnl_vector_fixed& flip();
420 
421   //: Check that size()==sz if not, abort();
422   // This function does or tests nothing if NDEBUG is defined
assert_size(unsigned sz)423   void assert_size( unsigned sz ) const { assert( sz == n ); (void)sz; }
424 
425   //: Check that this is finite if not, abort();
426   // This function does or tests nothing if NDEBUG is defined
assert_finite()427   void assert_finite() const
428   {
429 #ifndef NDEBUG
430     assert_finite_internal();
431 #endif
432   }
433 
434   //: Return true if it's finite
435   bool is_finite() const;
436 
437   //: Return true iff all the entries are zero.
438   bool is_zero() const;
439 
440   //: Return true iff the size is zero.
empty()441   bool empty() const { return n==0; }
442 
443   //: Return true if *this == v
operator_eq(vnl_vector_fixed<T,n> const & v)444   bool operator_eq (vnl_vector_fixed<T,n> const& v) const
445   {
446     for ( size_type i = 0; i < n; ++i )
447       if ( (*this)[i] != v[i] )
448         return false;
449     return true;
450   }
451 
452   //: Return true if *this == v
operator_eq(vnl_vector<T> const & v)453   bool operator_eq (vnl_vector<T> const& v) const
454   {
455     assert( v.size() == n );
456     for ( size_type i = 0; i < n; ++i )
457       if ( (*this)[i] != v[i] )
458         return false;
459     return true;
460   }
461 
462 
463   //: Read from text stream
464   bool read_ascii(std::istream& s);
465 
466   //: Display the vector
467   // Output each element separated by a single space.
468   void print( std::ostream& s ) const;
469 
470  public:
471   // Helper routines for arithmetic. n is the size, and is the
472   // template parameter.
473 
add(const T * a,const T * b,T * r)474   inline static void add( const T* a, const T* b, T* r )
475   {
476     for ( unsigned int i=0; i < n; ++i,++r,++a,++b )
477       *r = *a + *b;
478   }
479 
add(const T * a,T b,T * r)480   inline static void add( const T* a, T b, T* r )
481   {
482     for ( unsigned int i=0; i < n; ++i,++r,++a )
483       *r = *a + b;
484   }
485 
sub(const T * a,const T * b,T * r)486   inline static void sub( const T* a, const T* b, T* r )
487   {
488     for ( unsigned int i=0; i < n; ++i,++r,++a,++b )
489       *r = *a - *b;
490   }
491 
sub(const T * a,T b,T * r)492   inline static void sub( const T* a, T b, T* r )
493   {
494     for ( unsigned int i=0; i < n; ++i,++r,++a )
495       *r = *a - b;
496   }
497 
sub(T a,const T * b,T * r)498   inline static void sub( T a, const T* b, T* r )
499   {
500     for ( unsigned int i=0; i < n; ++i,++r,++b )
501       *r = a - *b;
502   }
503 
mul(const T * a,const T * b,T * r)504   inline static void mul( const T* a, const T* b, T* r )
505   {
506     for ( unsigned int i=0; i < n; ++i,++r,++a,++b )
507       *r = *a * *b;
508   }
509 
mul(const T * a,T b,T * r)510   inline static void mul( const T* a, T b, T* r )
511   {
512     for ( unsigned int i=0; i < n; ++i,++r,++a )
513       *r = *a * b;
514   }
515 
div(const T * a,const T * b,T * r)516   inline static void div( const T* a, const T* b, T* r )
517   {
518     for ( unsigned int i=0; i < n; ++i,++r,++a,++b )
519       *r = *a / *b;
520   }
521 
div(const T * a,T b,T * r)522   inline static void div( const T* a, T b, T* r )
523   {
524     for ( unsigned int i=0; i < n; ++i,++r,++a )
525       *r = *a / b;
526   }
527 
528  private:
529   //: See assert_finite().
530   void assert_finite_internal() const;
531 };
532 
533 
534 // --- Vector-scalar operators ----------------------------------------
535 
536 //:
537 // \relatesalso vnl_vector_fixed
538 template<class T, unsigned int n>
539 inline vnl_vector_fixed<T,n> operator+( const vnl_vector_fixed<T,n>& v, T s )
540 {
541   vnl_vector_fixed<T,n> r;
542   vnl_vector_fixed<T,n>::add( v.data_block(), s, r.data_block() );
543   return r;
544 }
545 
546 //:
547 // \relatesalso vnl_vector_fixed
548 template<class T, unsigned int n>
549 inline vnl_vector_fixed<T,n> operator+( const T& s,
550                                         const vnl_vector_fixed<T,n>& v )
551 {
552   vnl_vector_fixed<T,n> r;
553   vnl_vector_fixed<T,n>::add( v.data_block(), s, r.data_block() );
554   return r;
555 }
556 
557 //:
558 // \relatesalso vnl_vector_fixed
559 template<class T, unsigned int n>
560 inline vnl_vector_fixed<T,n> operator-( const vnl_vector_fixed<T,n>& v, T s )
561 {
562   vnl_vector_fixed<T,n> r;
563   vnl_vector_fixed<T,n>::sub( v.data_block(), s, r.data_block() );
564   return r;
565 }
566 
567 //:
568 // \relatesalso vnl_vector_fixed
569 template<class T, unsigned int n>
570 inline vnl_vector_fixed<T,n> operator-( const T& s,
571                                         const vnl_vector_fixed<T,n>& v )
572 {
573   vnl_vector_fixed<T,n> r;
574   vnl_vector_fixed<T,n>::sub( s, v.data_block(), r.data_block() );
575   return r;
576 }
577 
578 //:
579 // \relatesalso vnl_vector_fixed
580 template<class T, unsigned int n>
581 inline vnl_vector_fixed<T,n> operator*( const vnl_vector_fixed<T,n>& v, T s )
582 {
583   vnl_vector_fixed<T,n> r;
584   vnl_vector_fixed<T,n>::mul( v.data_block(), s, r.data_block() );
585   return r;
586 }
587 
588 //:
589 // \relatesalso vnl_vector_fixed
590 template<class T, unsigned int n>
591 inline vnl_vector_fixed<T,n> operator*( const T& s,
592                                         const vnl_vector_fixed<T,n>& v )
593 {
594   vnl_vector_fixed<T,n> r;
595   vnl_vector_fixed<T,n>::mul( v.data_block(), s, r.data_block() );
596   return r;
597 }
598 
599 //:
600 // \relatesalso vnl_vector_fixed
601 template<class T, unsigned int n>
602 inline vnl_vector_fixed<T,n> operator/( const vnl_vector_fixed<T,n>& v, T s )
603 {
604   vnl_vector_fixed<T,n> r;
605   vnl_vector_fixed<T,n>::div( v.data_block(), s, r.data_block() );
606   return r;
607 }
608 
609 
610 // --- Vector-vector operators ----------------------------------------
611 //
612 // Includes overloads for the common case of mixing a fixed with a
613 // non-fixed. Because the operators are templated, the fixed will not
614 // be automatically converted to a non-fixed-ref. These do it for you.
615 
616 //:
617 // \relatesalso vnl_vector_fixed
618 template<class T, unsigned int n>
619 inline vnl_vector_fixed<T,n> operator+( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
620 {
621   vnl_vector_fixed<T,n> r;
622   vnl_vector_fixed<T,n>::add( a.data_block(), b.data_block(), r.data_block() );
623   return r;
624 }
625 
626 //:
627 // \relatesalso vnl_vector
628 // \relatesalso vnl_vector_fixed
629 template<class T, unsigned int n>
630 inline vnl_vector<T> operator+( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
631 {
632   return a.as_ref() + b;
633 }
634 
635 //:
636 // \relatesalso vnl_vector
637 // \relatesalso vnl_vector_fixed
638 template<class T, unsigned int n>
639 inline vnl_vector<T> operator+( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
640 {
641   return a + b.as_ref();
642 }
643 
644 //:
645 // \relatesalso vnl_vector_fixed
646 template<class T, unsigned int n>
647 inline vnl_vector_fixed<T,n> operator-( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
648 {
649   vnl_vector_fixed<T,n> r;
650   vnl_vector_fixed<T,n>::sub( a.data_block(), b.data_block(), r.data_block() );
651   return r;
652 }
653 
654 //:
655 // \relatesalso vnl_vector
656 // \relatesalso vnl_vector_fixed
657 template<class T, unsigned int n>
658 inline vnl_vector<T> operator-( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
659 {
660   return a.as_ref() - b;
661 }
662 
663 //:
664 // \relatesalso vnl_vector
665 // \relatesalso vnl_vector_fixed
666 template<class T, unsigned int n>
667 inline vnl_vector<T> operator-( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
668 {
669   return a - b.as_ref();
670 }
671 
672 //:
673 // \relatesalso vnl_vector_fixed
674 template<class T, unsigned int n>
element_product(const vnl_vector_fixed<T,n> & a,const vnl_vector_fixed<T,n> & b)675 inline vnl_vector_fixed<T,n> element_product( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
676 {
677   vnl_vector_fixed<T,n> r;
678   vnl_vector_fixed<T,n>::mul( a.data_block(), b.data_block(), r.data_block() );
679   return r;
680 }
681 
682 //:
683 // \relatesalso vnl_vector
684 // \relatesalso vnl_vector_fixed
685 template<class T, unsigned int n>
element_product(const vnl_vector_fixed<T,n> & a,const vnl_vector<T> & b)686 inline vnl_vector<T> element_product( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
687 {
688   assert( b.size() == n );
689   vnl_vector<T> r(n);
690   vnl_vector_fixed<T,n>::mul( a.data_block(), b.data_block(), r.data_block() );
691   return r;
692 }
693 
694 //:
695 // \relatesalso vnl_vector
696 // \relatesalso vnl_vector_fixed
697 template<class T, unsigned int n>
element_product(const vnl_vector<T> & a,const vnl_vector_fixed<T,n> & b)698 inline vnl_vector<T> element_product( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
699 {
700   assert( a.size() == n );
701   vnl_vector<T> r(n);
702   vnl_vector_fixed<T,n>::mul( a.data_block(), b.data_block(), r.data_block() );
703   return r;
704 }
705 
706 //:
707 // \relatesalso vnl_vector_fixed
708 template<class T, unsigned int n>
element_quotient(const vnl_vector_fixed<T,n> & a,const vnl_vector_fixed<T,n> & b)709 inline vnl_vector_fixed<T,n> element_quotient( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
710 {
711   vnl_vector_fixed<T,n> r;
712   vnl_vector_fixed<T,n>::div( a.data_block(), b.data_block(), r.data_block() );
713   return r;
714 }
715 
716 //:
717 // \relatesalso vnl_vector
718 // \relatesalso vnl_vector_fixed
719 template<class T, unsigned int n>
element_quotient(const vnl_vector_fixed<T,n> & a,const vnl_vector<T> & b)720 inline vnl_vector<T> element_quotient( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
721 {
722   assert( b.size() == n );
723   vnl_vector<T> r(n);
724   vnl_vector_fixed<T,n>::div( a.data_block(), b.data_block(), r.data_block() );
725   return r;
726 }
727 
728 //:
729 // \relatesalso vnl_vector
730 // \relatesalso vnl_vector_fixed
731 template<class T, unsigned int n>
element_quotient(const vnl_vector<T> & a,const vnl_vector_fixed<T,n> & b)732 inline vnl_vector<T> element_quotient( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
733 {
734   assert( a.size() == n );
735   vnl_vector<T> r(n);
736   vnl_vector_fixed<T,n>::div( a.data_block(), b.data_block(), r.data_block() );
737   return r;
738 }
739 
740 //:
741 // \relatesalso vnl_vector_fixed
742 template<class T, unsigned n>
dot_product(const vnl_vector_fixed<T,n> & a,const vnl_vector_fixed<T,n> & b)743 inline T dot_product( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
744 {
745   return dot_product( a.as_ref(), b.as_ref() );
746 }
747 
748 //:
749 // \relatesalso vnl_vector
750 // \relatesalso vnl_vector_fixed
751 template<class T, unsigned n>
dot_product(const vnl_vector_fixed<T,n> & a,const vnl_vector<T> & b)752 inline T dot_product( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
753 {
754   return dot_product( a.as_ref(), b );
755 }
756 
757 //:
758 // \relatesalso vnl_vector
759 // \relatesalso vnl_vector_fixed
760 template<class T, unsigned n>
dot_product(const vnl_vector<T> & a,const vnl_vector_fixed<T,n> & b)761 inline T dot_product( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
762 {
763   return dot_product( a, b.as_ref() );
764 }
765 
766 //:
767 // \relatesalso vnl_vector
768 // \relatesalso vnl_vector_fixed
769 template<class T, unsigned int n>
outer_product(const vnl_vector<T> & a,const vnl_vector_fixed<T,n> & b)770 inline vnl_matrix<T> outer_product( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
771 {
772   return outer_product( a, b.as_ref());
773 }
774 
775 //:
776 // \relatesalso vnl_vector
777 // \relatesalso vnl_vector_fixed
778 template<class T, unsigned int n>
outer_product(const vnl_vector_fixed<T,n> & a,const vnl_vector<T> & b)779 inline vnl_matrix<T> outer_product( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
780 {
781   return outer_product( a.as_ref(), b);
782 }
783 
784 //:
785 // \relatesalso vnl_vector_fixed
786 template<class T, unsigned n>
angle(const vnl_vector_fixed<T,n> & a,const vnl_vector_fixed<T,n> & b)787 inline T angle( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
788 {
789   return angle( a.as_ref(), b.as_ref() );
790 }
791 
792 //:
793 // \relatesalso vnl_vector
794 // \relatesalso vnl_vector_fixed
795 template<class T, unsigned n>
angle(const vnl_vector_fixed<T,n> & a,const vnl_vector<T> & b)796 inline T angle( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
797 {
798   return angle( a.as_ref(), b );
799 }
800 
801 //:
802 // \relatesalso vnl_vector
803 // \relatesalso vnl_vector_fixed
804 template<class T, unsigned n>
angle(const vnl_vector<T> & a,const vnl_vector_fixed<T,n> & b)805 inline T angle( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
806 {
807   return angle( a, b.as_ref() );
808 }
809 
810 
811 //:
812 // \relatesalso vnl_vector_fixed
813 template<class T, unsigned n>
vnl_vector_ssd(const vnl_vector_fixed<T,n> & a,const vnl_vector_fixed<T,n> & b)814 inline T vnl_vector_ssd( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
815 {
816   return vnl_vector_ssd( a.as_ref(), b.as_ref() );
817 }
818 
819 //:
820 // \relatesalso vnl_vector
821 // \relatesalso vnl_vector_fixed
822 template<class T, unsigned n>
vnl_vector_ssd(const vnl_vector_fixed<T,n> & a,const vnl_vector<T> & b)823 inline T vnl_vector_ssd( const vnl_vector_fixed<T,n>& a, const vnl_vector<T>& b )
824 {
825   return vnl_vector_ssd( a.as_ref(), b );
826 }
827 
828 //:
829 // \relatesalso vnl_vector
830 // \relatesalso vnl_vector_fixed
831 template<class T, unsigned n>
vnl_vector_ssd(const vnl_vector<T> & a,const vnl_vector_fixed<T,n> & b)832 inline T vnl_vector_ssd( const vnl_vector<T>& a, const vnl_vector_fixed<T,n>& b )
833 {
834   return vnl_vector_ssd( a, b.as_ref() );
835 }
836 
837 
838 //:
839 // \relatesalso vnl_vector_fixed
840 template<class T, unsigned int n>
841 inline bool operator==( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
842 {
843   return a.operator_eq(b);
844 }
845 
846 //:
847 // \relatesalso vnl_vector
848 // \relatesalso vnl_vector_fixed
849 template<class T, unsigned int n>
850 inline bool operator==( vnl_vector_fixed<T,n> const& a, vnl_vector<T> const& b )
851 {
852   return a.operator_eq(b);
853 }
854 
855 //:
856 // \relatesalso vnl_vector
857 // \relatesalso vnl_vector_fixed
858 template<class T, unsigned int n>
859 inline bool operator==( vnl_vector<T> const& a, vnl_vector_fixed<T,n> const& b )
860 {
861   return b.operator_eq(a);
862 }
863 
864 //:
865 // \relatesalso vnl_vector_fixed
866 template<class T, unsigned int n>
867 inline bool operator!=( const vnl_vector_fixed<T,n>& a, const vnl_vector_fixed<T,n>& b )
868 {
869   return ! a.operator_eq(b);
870 }
871 
872 //:
873 // \relatesalso vnl_vector
874 // \relatesalso vnl_vector_fixed
875 template<class T, unsigned int n>
876 inline bool operator!=( vnl_vector_fixed<T,n> const& a, vnl_vector<T> const& b )
877 {
878   return ! a.operator_eq(b);
879 }
880 
881 //:
882 // \relatesalso vnl_vector
883 // \relatesalso vnl_vector_fixed
884 template<class T, unsigned int n>
885 inline bool operator!=( vnl_vector<T> const& a, vnl_vector_fixed<T,n> const& b )
886 {
887   return ! b.operator_eq(a);
888 }
889 
890 
891 // --- I/O operators -------------------------------------------------
892 
893 
894 //:
895 // \relatesalso vnl_vector_fixed
896 template<class T, unsigned int n>
897 inline
898 std::ostream& operator<< ( std::ostream& ostr, const vnl_vector_fixed<T,n>& v )
899 {
900   v.print( ostr );
901   return ostr;
902 }
903 
904 //:
905 // \relatesalso vnl_vector_fixed
906 template<class T, unsigned int n>
907 inline
908 std::istream& operator>> ( std::istream& ostr, vnl_vector_fixed<T,n>& v )
909 {
910   v.read_ascii( ostr );
911   return ostr;
912 }
913 
914 #endif // vnl_vector_fixed_h_
915