ViennaCL - The Vienna Computing Library  1.5.2
vector_operations.hpp
Go to the documentation of this file.
1 #ifndef VIENNACL_LINALG_HOST_BASED_VECTOR_OPERATIONS_HPP_
2 #define VIENNACL_LINALG_HOST_BASED_VECTOR_OPERATIONS_HPP_
3 
4 /* =========================================================================
5  Copyright (c) 2010-2014, Institute for Microelectronics,
6  Institute for Analysis and Scientific Computing,
7  TU Wien.
8  Portions of this software are copyright by UChicago Argonne, LLC.
9 
10  -----------------
11  ViennaCL - The Vienna Computing Library
12  -----------------
13 
14  Project Head: Karl Rupp rupp@iue.tuwien.ac.at
15 
16  (A list of authors and contributors can be found in the PDF manual)
17 
18  License: MIT (X11), see file LICENSE in the base directory
19 ============================================================================= */
20 
25 #include <cmath>
26 #include <algorithm> //for std::max and std::min
27 
28 #include "viennacl/forwards.h"
29 #include "viennacl/scalar.hpp"
30 #include "viennacl/tools/tools.hpp"
33 #include "viennacl/traits/size.hpp"
38 
39 
40 // Minimum vector size for using OpenMP on vector operations:
41 #ifndef VIENNACL_OPENMP_VECTOR_MIN_SIZE
42  #define VIENNACL_OPENMP_VECTOR_MIN_SIZE 5000
43 #endif
44 
45 namespace viennacl
46 {
47  namespace linalg
48  {
49  namespace host_based
50  {
51  namespace detail
52  {
53  template <typename NumericT>
54  NumericT flip_sign(NumericT val) { return -val; }
55  inline unsigned long flip_sign(unsigned long val) { return val; }
56  inline unsigned int flip_sign(unsigned int val) { return val; }
57  inline unsigned short flip_sign(unsigned short val) { return val; }
58  inline unsigned char flip_sign(unsigned char val) { return val; }
59  }
60 
61  //
62  // Introductory note: By convention, all dimensions are already checked in the dispatcher frontend. No need to double-check again in here!
63  //
64 
65  template <typename T, typename ScalarType1>
66  void av(vector_base<T> & vec1,
67  vector_base<T> const & vec2, ScalarType1 const & alpha, vcl_size_t /*len_alpha*/, bool reciprocal_alpha, bool flip_sign_alpha)
68  {
69  typedef T value_type;
70 
71  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
72  value_type const * data_vec2 = detail::extract_raw_pointer<value_type>(vec2);
73 
74  value_type data_alpha = alpha;
75  if (flip_sign_alpha)
76  data_alpha = detail::flip_sign(data_alpha);
77 
81 
84 
85  if (reciprocal_alpha)
86  {
87 #ifdef VIENNACL_WITH_OPENMP
88  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
89 #endif
90  for (long i = 0; i < static_cast<long>(size1); ++i)
91  data_vec1[i*inc1+start1] = data_vec2[i*inc2+start2] / data_alpha;
92  }
93  else
94  {
95 #ifdef VIENNACL_WITH_OPENMP
96  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
97 #endif
98  for (long i = 0; i < static_cast<long>(size1); ++i)
99  data_vec1[i*inc1+start1] = data_vec2[i*inc2+start2] * data_alpha;
100  }
101  }
102 
103 
104  template <typename T, typename ScalarType1, typename ScalarType2>
105  void avbv(vector_base<T> & vec1,
106  vector_base<T> const & vec2, ScalarType1 const & alpha, vcl_size_t /* len_alpha */, bool reciprocal_alpha, bool flip_sign_alpha,
107  vector_base<T> const & vec3, ScalarType2 const & beta, vcl_size_t /* len_beta */, bool reciprocal_beta, bool flip_sign_beta)
108  {
109  typedef T value_type;
110 
111  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
112  value_type const * data_vec2 = detail::extract_raw_pointer<value_type>(vec2);
113  value_type const * data_vec3 = detail::extract_raw_pointer<value_type>(vec3);
114 
115  value_type data_alpha = alpha;
116  if (flip_sign_alpha)
117  data_alpha = detail::flip_sign(data_alpha);
118 
119  value_type data_beta = beta;
120  if (flip_sign_beta)
121  data_beta = detail::flip_sign(data_beta);
122 
126 
129 
130  vcl_size_t start3 = viennacl::traits::start(vec3);
132 
133  if (reciprocal_alpha)
134  {
135  if (reciprocal_beta)
136  {
137 #ifdef VIENNACL_WITH_OPENMP
138  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
139 #endif
140  for (long i = 0; i < static_cast<long>(size1); ++i)
141  data_vec1[i*inc1+start1] = data_vec2[i*inc2+start2] / data_alpha + data_vec3[i*inc3+start3] / data_beta;
142  }
143  else
144  {
145 #ifdef VIENNACL_WITH_OPENMP
146  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
147 #endif
148  for (long i = 0; i < static_cast<long>(size1); ++i)
149  data_vec1[i*inc1+start1] = data_vec2[i*inc2+start2] / data_alpha + data_vec3[i*inc3+start3] * data_beta;
150  }
151  }
152  else
153  {
154  if (reciprocal_beta)
155  {
156 #ifdef VIENNACL_WITH_OPENMP
157  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
158 #endif
159  for (long i = 0; i < static_cast<long>(size1); ++i)
160  data_vec1[i*inc1+start1] = data_vec2[i*inc2+start2] * data_alpha + data_vec3[i*inc3+start3] / data_beta;
161  }
162  else
163  {
164 #ifdef VIENNACL_WITH_OPENMP
165  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
166 #endif
167  for (long i = 0; i < static_cast<long>(size1); ++i)
168  data_vec1[i*inc1+start1] = data_vec2[i*inc2+start2] * data_alpha + data_vec3[i*inc3+start3] * data_beta;
169  }
170  }
171  }
172 
173 
174  template <typename T, typename ScalarType1, typename ScalarType2>
175  void avbv_v(vector_base<T> & vec1,
176  vector_base<T> const & vec2, ScalarType1 const & alpha, vcl_size_t /*len_alpha*/, bool reciprocal_alpha, bool flip_sign_alpha,
177  vector_base<T> const & vec3, ScalarType2 const & beta, vcl_size_t /*len_beta*/, bool reciprocal_beta, bool flip_sign_beta)
178  {
179  typedef T value_type;
180 
181  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
182  value_type const * data_vec2 = detail::extract_raw_pointer<value_type>(vec2);
183  value_type const * data_vec3 = detail::extract_raw_pointer<value_type>(vec3);
184 
185  value_type data_alpha = alpha;
186  if (flip_sign_alpha)
187  data_alpha = detail::flip_sign(data_alpha);
188 
189  value_type data_beta = beta;
190  if (flip_sign_beta)
191  data_beta = detail::flip_sign(data_beta);
192 
196 
199 
200  vcl_size_t start3 = viennacl::traits::start(vec3);
202 
203  if (reciprocal_alpha)
204  {
205  if (reciprocal_beta)
206  {
207 #ifdef VIENNACL_WITH_OPENMP
208  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
209 #endif
210  for (long i = 0; i < static_cast<long>(size1); ++i)
211  data_vec1[i*inc1+start1] += data_vec2[i*inc2+start2] / data_alpha + data_vec3[i*inc3+start3] / data_beta;
212  }
213  else
214  {
215 #ifdef VIENNACL_WITH_OPENMP
216  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
217 #endif
218  for (long i = 0; i < static_cast<long>(size1); ++i)
219  data_vec1[i*inc1+start1] += data_vec2[i*inc2+start2] / data_alpha + data_vec3[i*inc3+start3] * data_beta;
220  }
221  }
222  else
223  {
224  if (reciprocal_beta)
225  {
226 #ifdef VIENNACL_WITH_OPENMP
227  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
228 #endif
229  for (long i = 0; i < static_cast<long>(size1); ++i)
230  data_vec1[i*inc1+start1] += data_vec2[i*inc2+start2] * data_alpha + data_vec3[i*inc3+start3] / data_beta;
231  }
232  else
233  {
234 #ifdef VIENNACL_WITH_OPENMP
235  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
236 #endif
237  for (long i = 0; i < static_cast<long>(size1); ++i)
238  data_vec1[i*inc1+start1] += data_vec2[i*inc2+start2] * data_alpha + data_vec3[i*inc3+start3] * data_beta;
239  }
240  }
241  }
242 
243 
244 
245 
252  template <typename T>
253  void vector_assign(vector_base<T> & vec1, const T & alpha, bool up_to_internal_size = false)
254  {
255  typedef T value_type;
256 
257  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
258 
262  vcl_size_t loop_bound = up_to_internal_size ? vec1.internal_size() : size1; //Note: Do NOT use traits::internal_size() here, because vector proxies don't require padding.
263 
264  value_type data_alpha = static_cast<value_type>(alpha);
265 
266 #ifdef VIENNACL_WITH_OPENMP
267  #pragma omp parallel for if (loop_bound > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
268 #endif
269  for (long i = 0; i < static_cast<long>(loop_bound); ++i)
270  data_vec1[i*inc1+start1] = data_alpha;
271  }
272 
273 
279  template <typename T>
281  {
282  typedef T value_type;
283 
284  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
285  value_type * data_vec2 = detail::extract_raw_pointer<value_type>(vec2);
286 
290 
293 
294 #ifdef VIENNACL_WITH_OPENMP
295  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
296 #endif
297  for (long i = 0; i < static_cast<long>(size1); ++i)
298  {
299  value_type temp = data_vec2[i*inc2+start2];
300  data_vec2[i*inc2+start2] = data_vec1[i*inc1+start1];
301  data_vec1[i*inc1+start1] = temp;
302  }
303  }
304 
305 
307 
313  template <typename T, typename OP>
316  {
317  typedef T value_type;
319 
320  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
321  value_type const * data_vec2 = detail::extract_raw_pointer<value_type>(proxy.lhs());
322  value_type const * data_vec3 = detail::extract_raw_pointer<value_type>(proxy.rhs());
323 
327 
329  vcl_size_t inc2 = viennacl::traits::stride(proxy.lhs());
330 
331  vcl_size_t start3 = viennacl::traits::start(proxy.rhs());
332  vcl_size_t inc3 = viennacl::traits::stride(proxy.rhs());
333 
334 #ifdef VIENNACL_WITH_OPENMP
335  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
336 #endif
337  for (long i = 0; i < static_cast<long>(size1); ++i)
338  OpFunctor::apply(data_vec1[i*inc1+start1], data_vec2[i*inc2+start2], data_vec3[i*inc3+start3]);
339  }
340 
346  template <typename T, typename OP>
349  {
350  typedef T value_type;
352 
353  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
354  value_type const * data_vec2 = detail::extract_raw_pointer<value_type>(proxy.lhs());
355 
359 
361  vcl_size_t inc2 = viennacl::traits::stride(proxy.lhs());
362 
363 #ifdef VIENNACL_WITH_OPENMP
364  #pragma omp parallel for if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
365 #endif
366  for (long i = 0; i < static_cast<long>(size1); ++i)
367  OpFunctor::apply(data_vec1[i*inc1+start1], data_vec2[i*inc2+start2]);
368  }
369 
370 
372 
373 
374  //implementation of inner product:
375  //namespace {
382  template <typename T, typename S3>
383  void inner_prod_impl(vector_base<T> const & vec1,
384  vector_base<T> const & vec2,
385  S3 & result)
386  {
387  typedef T value_type;
388 
389  value_type const * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
390  value_type const * data_vec2 = detail::extract_raw_pointer<value_type>(vec2);
391 
395 
398 
399  value_type temp = 0;
400 
401 #ifdef VIENNACL_WITH_OPENMP
402  #pragma omp parallel for reduction(+: temp) if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
403 #endif
404  for (long i = 0; i < static_cast<long>(size1); ++i)
405  temp += data_vec1[i*inc1+start1] * data_vec2[i*inc2+start2];
406 
407  result = temp; //Note: Assignment to result might be expensive, thus 'temp' is used for accumulation
408  }
409 
410  template <typename T>
412  vector_tuple<T> const & vec_tuple,
413  vector_base<T> & result)
414  {
415  typedef T value_type;
416 
417  value_type const * data_x = detail::extract_raw_pointer<value_type>(x);
418 
419  vcl_size_t start_x = viennacl::traits::start(x);
422 
423  std::vector<value_type> temp(vec_tuple.const_size());
424  std::vector<value_type const *> data_y(vec_tuple.const_size());
425  std::vector<vcl_size_t> start_y(vec_tuple.const_size());
426  std::vector<vcl_size_t> stride_y(vec_tuple.const_size());
427 
428  for (vcl_size_t j=0; j<vec_tuple.const_size(); ++j)
429  {
430  data_y[j] = detail::extract_raw_pointer<value_type>(vec_tuple.const_at(j));
431  start_y[j] = viennacl::traits::start(vec_tuple.const_at(j));
432  stride_y[j] = viennacl::traits::stride(vec_tuple.const_at(j));
433  }
434 
435  // Note: No OpenMP here because it cannot perform a reduction on temp-array. Savings in memory bandwidth are expected to still justify this approach...
436  for (vcl_size_t i = 0; i < size_x; ++i)
437  {
438  value_type entry_x = data_x[i*inc_x+start_x];
439  for (vcl_size_t j=0; j < vec_tuple.const_size(); ++j)
440  temp[j] += entry_x * data_y[j][i*stride_y[j]+start_y[j]];
441  }
442 
443  for (vcl_size_t j=0; j < vec_tuple.const_size(); ++j)
444  result[j] = temp[j]; //Note: Assignment to result might be expensive, thus 'temp' is used for accumulation
445  }
446 
447 
453  template <typename T, typename S2>
454  void norm_1_impl(vector_base<T> const & vec1,
455  S2 & result)
456  {
457  typedef T value_type;
458 
459  value_type const * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
460 
464 
465  value_type temp = 0;
466 
467 #ifdef VIENNACL_WITH_OPENMP
468  #pragma omp parallel for reduction(+: temp) if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
469 #endif
470  for (long i = 0; i < static_cast<long>(size1); ++i)
471  temp += static_cast<value_type>(std::fabs(static_cast<double>(data_vec1[i*inc1+start1]))); //casting to double in order to avoid problems if T is an integer type
472 
473  result = temp; //Note: Assignment to result might be expensive, thus 'temp' is used for accumulation
474  }
475 
481  template <typename T, typename S2>
482  void norm_2_impl(vector_base<T> const & vec1,
483  S2 & result)
484  {
485  typedef T value_type;
486 
487  value_type const * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
488 
492 
493  value_type temp = 0;
494  value_type data = 0;
495 
496 #ifdef VIENNACL_WITH_OPENMP
497  #pragma omp parallel for reduction(+: temp) private(data) if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
498 #endif
499  for (long i = 0; i < static_cast<long>(size1); ++i)
500  {
501  data = data_vec1[i*inc1+start1];
502  temp += data * data;
503  }
504 
505  result = std::sqrt(temp); //Note: Assignment to result might be expensive, thus 'temp' is used for accumulation
506  }
507 
513  template <typename T, typename S2>
514  void norm_inf_impl(vector_base<T> const & vec1,
515  S2 & result)
516  {
517  typedef T value_type;
518 
519  value_type const * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
520 
524 
525  value_type temp = 0;
526 
527  // Note: No max() reduction in OpenMP yet
528  for (vcl_size_t i = 0; i < size1; ++i)
529  temp = std::max<value_type>(temp, static_cast<value_type>(std::fabs(static_cast<double>(data_vec1[i*inc1+start1])))); //casting to double in order to avoid problems if T is an integer type
530 
531  result = temp; //Note: Assignment to result might be expensive, thus 'temp' is used for accumulation
532  }
533 
534  //This function should return a CPU scalar, otherwise statements like
535  // vcl_rhs[index_norm_inf(vcl_rhs)]
536  // are ambiguous
542  template <typename T>
544  {
545  typedef T value_type;
546 
547  value_type const * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
548 
552 
553  value_type temp = 0;
554  value_type data;
555  vcl_size_t index = start1;
556 
557  // Note: No suitable reduction in OpenMP yet
558  for (vcl_size_t i = 0; i < size1; ++i)
559  {
560  data = static_cast<value_type>(std::fabs(static_cast<double>(data_vec1[i*inc1+start1]))); //casting to double in order to avoid problems if T is an integer type
561  if (data > temp)
562  {
563  index = i;
564  temp = data;
565  }
566  }
567 
568  return index;
569  }
570 
571 
581  template <typename T>
583  vector_base<T> & vec2,
584  T alpha, T beta)
585  {
586  typedef T value_type;
587 
588  value_type * data_vec1 = detail::extract_raw_pointer<value_type>(vec1);
589  value_type * data_vec2 = detail::extract_raw_pointer<value_type>(vec2);
590 
594 
597 
598  value_type temp1 = 0;
599  value_type temp2 = 0;
600  value_type data_alpha = alpha;
601  value_type data_beta = beta;
602 
603 #ifdef VIENNACL_WITH_OPENMP
604  #pragma omp parallel for private(temp1, temp2) if (size1 > VIENNACL_OPENMP_VECTOR_MIN_SIZE)
605 #endif
606  for (long i = 0; i < static_cast<long>(size1); ++i)
607  {
608  temp1 = data_vec1[i*inc1+start1];
609  temp2 = data_vec2[i*inc2+start2];
610 
611  data_vec1[i*inc1+start1] = data_alpha * temp1 + data_beta * temp2;
612  data_vec2[i*inc2+start2] = data_alpha * temp2 - data_beta * temp1;
613  }
614  }
615 
616  } //namespace host_based
617  } //namespace linalg
618 } //namespace viennacl
619 
620 
621 #endif
void vector_assign(vector_base< T > &vec1, const T &alpha, bool up_to_internal_size=false)
Assign a constant value to a vector (-range/-slice)
Definition: vector_operations.hpp:253
VectorType const & const_at(vcl_size_t i) const
Definition: vector.hpp:1174
void avbv_v(vector_base< T > &vec1, vector_base< T > const &vec2, ScalarType1 const &alpha, vcl_size_t, bool reciprocal_alpha, bool flip_sign_alpha, vector_base< T > const &vec3, ScalarType2 const &beta, vcl_size_t, bool reciprocal_beta, bool flip_sign_beta)
Definition: vector_operations.hpp:175
std::size_t vcl_size_t
Definition: forwards.h:58
void av(vector_base< T > &vec1, vector_base< T > const &vec2, ScalarType1 const &alpha, vcl_size_t, bool reciprocal_alpha, bool flip_sign_alpha)
Definition: vector_operations.hpp:66
Generic size and resize functionality for different vector and matrix types.
void inner_prod_impl(vector_base< T > const &vec1, vector_base< T > const &vec2, S3 &result)
Computes the inner product of two vectors - implementation. Library users should call inner_prod(vec1...
Definition: vector_operations.hpp:383
Extracts the underlying OpenCL start index handle from a vector, a matrix, an expression etc...
Various little tools used here and there in ViennaCL.
void element_op(matrix_base< NumericT, F > &A, matrix_expression< const matrix_base< NumericT, F >, const matrix_base< NumericT, F >, op_element_binary< OP > > const &proxy)
Implementation of the element-wise operations A = B .* C and A = B ./ C (using MATLAB syntax) ...
Definition: matrix_operations.hpp:604
vcl_size_t size1(MatrixType const &mat)
Generic routine for obtaining the number of rows of a matrix (ViennaCL, uBLAS, etc.)
Definition: size.hpp:216
Worker class for decomposing expression templates.
Definition: op_applier.hpp:43
result_of::size_type< viennacl::vector_base< T > >::type stride(viennacl::vector_base< T > const &s)
Definition: stride.hpp:46
This file provides the forward declarations for the main types used within ViennaCL.
result_of::size_type< T >::type start1(T const &obj)
Definition: start.hpp:64
Determines row and column increments for matrices and matrix proxies.
An expression template class that represents a binary operation that yields a vector.
Definition: forwards.h:181
vcl_size_t index_norm_inf(vector_base< T > const &vec1)
Computes the index of the first entry that is equal to the supremum-norm in modulus.
Definition: vector_operations.hpp:543
vcl_size_t size(VectorType const &vec)
Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.)
Definition: size.hpp:144
result_of::size_type< T >::type start2(T const &obj)
Definition: start.hpp:83
Tuple class holding pointers to multiple vectors. Mainly used as a temporary object returned from vie...
Definition: forwards.h:211
void plane_rotation(vector_base< T > &vec1, vector_base< T > &vec2, T alpha, T beta)
Computes a plane rotation of two vectors.
Definition: vector_operations.hpp:582
result_of::size_type< T >::type start(T const &obj)
Definition: start.hpp:43
NumericT flip_sign(NumericT val)
Definition: vector_operations.hpp:54
Common base class for dense vectors, vector ranges, and vector slices.
Definition: forwards.h:205
void vector_swap(vector_base< T > &vec1, vector_base< T > &vec2)
Swaps the contents of two vectors, data is copied.
Definition: vector_operations.hpp:280
All the predicates used within ViennaCL. Checks for expressions to be vectors, etc.
void avbv(vector_base< T > &vec1, vector_base< T > const &vec2, ScalarType1 const &alpha, vcl_size_t, bool reciprocal_alpha, bool flip_sign_alpha, vector_base< T > const &vec3, ScalarType2 const &beta, vcl_size_t, bool reciprocal_beta, bool flip_sign_beta)
Definition: vector_operations.hpp:105
Common routines for single-threaded or OpenMP-enabled execution on CPU.
void norm_1_impl(vector_base< T > const &vec1, S2 &result)
Computes the l^1-norm of a vector.
Definition: vector_operations.hpp:454
A tag class representing element-wise binary operations (like multiplication) on vectors or matrices...
Definition: forwards.h:86
Defines the action of certain unary and binary operators and its arguments (for host execution)...
A tag class representing element-wise unary operations (like sin()) on vectors or matrices...
Definition: forwards.h:90
Implementation of the ViennaCL scalar class.
size_type internal_size() const
Returns the internal length of the vector, which is given by size() plus the extra memory due to padd...
Definition: vector.hpp:841
Simple enable-if variant that uses the SFINAE pattern.
void norm_2_impl(vector_base< T > const &vec1, S2 &result)
Computes the l^2-norm of a vector - implementation.
Definition: vector_operations.hpp:482
void norm_inf_impl(vector_base< T > const &vec1, S2 &result)
Computes the supremum-norm of a vector.
Definition: vector_operations.hpp:514
vcl_size_t const_size() const
Definition: vector.hpp:1171