ViennaCL - The Vienna Computing Library  1.6.1
Free open-source GPU-accelerated linear algebra and solver library.
vector_operations.hpp
Go to the documentation of this file.
1 #ifndef VIENNACL_LINALG_OPENCL_VECTOR_OPERATIONS_HPP_
2 #define VIENNACL_LINALG_OPENCL_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 
27 #include "viennacl/forwards.h"
29 #include "viennacl/ocl/device.hpp"
30 #include "viennacl/ocl/handle.hpp"
31 #include "viennacl/ocl/kernel.hpp"
32 #include "viennacl/scalar.hpp"
33 #include "viennacl/tools/tools.hpp"
39 #include "viennacl/traits/size.hpp"
43 
44 namespace viennacl
45 {
46 namespace linalg
47 {
48 namespace opencl
49 {
50 //
51 // Introductory note: By convention, all dimensions are already checked in the dispatcher frontend. No need to double-check again in here!
52 //
53 
54 template<typename NumericT, typename ScalarT1>
56  vector_base<NumericT> const & y, ScalarT1 const & alpha, vcl_size_t /* len_alpha */, bool reciprocal_alpha, bool flip_sign_alpha)
57 {
58  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(y).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
59  std::string kernel_name("assign_*v_**00");
60  bool is_scalar_cpu = is_cpu_scalar<ScalarT1>::value;
61  kernel_name[7] = is_scalar_cpu ? 'h' : 'd';
62  kernel_name[10] = flip_sign_alpha ? '1' : '0';
63  kernel_name[11] = reciprocal_alpha ? '1' : '0';
64 
65  scheduler::statement statement = scheduler::preset::av(scheduler::OPERATION_BINARY_ASSIGN_TYPE, &x, &y, &alpha, flip_sign_alpha, reciprocal_alpha);
66  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute(kernel_name, statement);
67 }
68 
69 
70 template<typename NumericT, typename ScalarT1, typename ScalarT2>
72  vector_base<NumericT> const & y, ScalarT1 const & alpha, vcl_size_t /* len_alpha */, bool reciprocal_alpha, bool flip_sign_alpha,
73  vector_base<NumericT> const & z, ScalarT2 const & beta, vcl_size_t /* len_beta */, bool reciprocal_beta, bool flip_sign_beta)
74 {
75  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(y).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
76  assert(viennacl::traits::opencl_handle(y).context() == viennacl::traits::opencl_handle(z).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
77 
78  std::string kernel_name("assign_*v*v_****");
79  bool is_scalar_cpu1 = is_cpu_scalar<ScalarT1>::value;
80  bool is_scalar_cpu2 = is_cpu_scalar<ScalarT2>::value;
81  kernel_name[7] = is_scalar_cpu1 ? 'h' : 'd';
82  kernel_name[9] = is_scalar_cpu2 ? 'h' : 'd';
83  kernel_name[12] = flip_sign_alpha ? '1' : '0';
84  kernel_name[13] = reciprocal_alpha ? '1' : '0';
85  kernel_name[14] = flip_sign_beta ? '1' : '0';
86  kernel_name[15] = reciprocal_beta ? '1' : '0';
87 
88  scheduler::statement statement = scheduler::preset::avbv(scheduler::OPERATION_BINARY_ASSIGN_TYPE, &x, &y, &alpha, flip_sign_alpha, reciprocal_alpha, &z, &beta, flip_sign_beta, reciprocal_beta);
89  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute(kernel_name, statement);
90 }
91 
92 
93 template<typename NumericT, typename ScalarT1, typename ScalarT2>
95  vector_base<NumericT> const & y, ScalarT1 const & alpha, vcl_size_t /* len_alpha */, bool reciprocal_alpha, bool flip_sign_alpha,
96  vector_base<NumericT> const & z, ScalarT2 const & beta, vcl_size_t /* len_beta */, bool reciprocal_beta, bool flip_sign_beta)
97 {
98  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(y).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
99  assert(viennacl::traits::opencl_handle(y).context() == viennacl::traits::opencl_handle(z).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
100 
101  std::string kernel_name("ip_add_*v*v_****");
102  bool is_scalar_cpu1 = is_cpu_scalar<ScalarT1>::value;
103  bool is_scalar_cpu2 = is_cpu_scalar<ScalarT2>::value;
104  kernel_name[7] = is_scalar_cpu1 ? 'h' : 'd';
105  kernel_name[9] = is_scalar_cpu2 ? 'h' : 'd';
106  kernel_name[12] = flip_sign_alpha ? '1' : '0';
107  kernel_name[13] = reciprocal_alpha ? '1' : '0';
108  kernel_name[14] = flip_sign_beta ? '1' : '0';
109  kernel_name[15] = reciprocal_beta ? '1' : '0';
110 
111  scheduler::statement statement = scheduler::preset::avbv(scheduler::OPERATION_BINARY_INPLACE_ADD_TYPE, &x, &y, &alpha, flip_sign_alpha, reciprocal_alpha, &z, &beta, flip_sign_beta, reciprocal_beta);
112  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute(kernel_name, statement);
113 }
114 
115 
122 template<typename NumericT>
123 void vector_assign(vector_base<NumericT> & x, const NumericT & alpha, bool up_to_internal_size = false)
124 {
127 
128  dynamic_cast<device_specific::vector_axpy_template*>(kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).template_of("assign_cpu"))->up_to_internal_size(up_to_internal_size);
129  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("assign_cpu", statement);
130 }
131 
132 
138 template<typename NumericT>
140 {
141  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(y).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
143  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("swap", statement);
144 }
145 
147 
153 template<typename NumericT, typename OP>
156 {
157  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(proxy.lhs()).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
158  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(proxy.rhs()).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
159 
161  scheduler::statement statement = scheduler::preset::binary_element_op(&x, &proxy.lhs(), &proxy.rhs(),TYPE);
163 }
164 
166 
172 template<typename NumericT, typename OP>
175 {
176  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(proxy.lhs()).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
177  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(proxy.rhs()).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
178 
180  scheduler::statement statement = scheduler::preset::unary_element_op(&x, &proxy.lhs(),TYPE);
182 
183 }
184 
186 
193 template<typename NumericT>
195  vector_base<NumericT> const & y,
196  scalar<NumericT> & result)
197 {
198  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(y).context() && bool("Vectors do not reside in the same OpenCL context. Automatic migration not yet supported!"));
199  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(result).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
200 
201  scheduler::statement statement = scheduler::preset::inner_prod(&result, &x, &y);
202  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("inner_prod", statement);
203 }
204 
205 namespace detail
206 {
207  template<typename NumericT>
209  {
211  ret.start = cl_uint(viennacl::traits::start(vec));
212  ret.stride = cl_uint(viennacl::traits::stride(vec));
213  ret.size = cl_uint(viennacl::traits::size(vec));
215  return ret;
216  }
217 }
218 
225 template<typename NumericT>
227  vector_tuple<NumericT> const & vec_tuple,
228  vector_base<NumericT> & result)
229 {
230  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(result).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
232 
233  vcl_size_t current_index = 0;
234  while (current_index < vec_tuple.const_size())
235  {
237 
238  vcl_size_t diff = vec_tuple.const_size() - current_index;
239  vcl_size_t upper_bound;
240  std::string kernel_prefix;
241  if (diff>=8) upper_bound = 8, kernel_prefix = "inner_prod_8";
242  else if (diff>=4) upper_bound = 4, kernel_prefix = "inner_prod_4";
243  else if (diff>=3) upper_bound = 3, kernel_prefix = "inner_prod_3";
244  else if (diff>=2) upper_bound = 2, kernel_prefix = "inner_prod_2";
245  else upper_bound = 1, kernel_prefix = "inner_prod_1";
246 
247  std::vector<range_t> ranges;
248  ranges.reserve(upper_bound);
249  for (unsigned int i = 0; i < upper_bound; ++i)
250  ranges.push_back(range_t(result, viennacl::range(current_index+i, current_index+i+1)));
251 
252  for (unsigned int i = 0; i < upper_bound; ++i)
253  statements.push_back(scheduler::preset::inner_prod(&ranges[i], &x, &vec_tuple.const_at(current_index+i)));
254 
256  current_index += upper_bound;
257  }
258 }
259 
260 
261 template<typename NumericT>
263  vector_base<NumericT> const & y,
264  NumericT & result)
265 {
267  inner_prod_impl(x, y, tmp);
268  result = tmp;
269 }
270 
271 
273 
279 template<typename NumericT>
281  scalar<NumericT> & result)
282 {
283  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(result).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
284 
285  scheduler::statement statement = scheduler::preset::norm_1(&result, &x);
286  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("norm_1", statement);
287 }
288 
294 template<typename NumericT>
296  NumericT & result)
297 {
299  norm_1_impl(x, tmp);
300  result = tmp;
301 }
302 
303 
304 
306 
307 
313 template<typename NumericT>
315  scalar<NumericT> & result)
316 {
317  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(result).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
318 
319  scheduler::statement statement = scheduler::preset::norm_2(&result, &x);
320  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("norm_2", statement);
321 }
322 
328 template<typename NumericT>
330  NumericT & result)
331 {
333  norm_2_impl(x, tmp);
334  result = tmp;
335 }
336 
337 
338 
340 
346 template<typename NumericT>
348  scalar<NumericT> & result)
349 {
350  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(result).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
351 
352  scheduler::statement statement = scheduler::preset::norm_inf(&result, &x);
353  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("norm_inf", statement);
354 }
355 
361 template<typename NumericT>
363  NumericT & result)
364 {
366  norm_inf_impl(x, tmp);
367  result = tmp;
368 }
369 
370 
372 
373 //This function should return a CPU scalar, otherwise statements like
374 // vcl_rhs[index_norm_inf(vcl_rhs)]
375 // are ambiguous
381 template<typename NumericT>
383 {
386  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("index_norm_inf", statement);
387  NumericT host_result = result;
388  return static_cast<cl_uint>(host_result);
389 }
390 
392 
398 template<typename NumericT>
400  scalar<NumericT> & result)
401 {
402  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(result).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
403 
404  scheduler::statement statement = scheduler::preset::max(&result, &x);
405  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("max", statement);
406 }
407 
413 template<typename NumericT>
415  NumericT & result)
416 {
418  max_impl(x, tmp);
419  result = tmp;
420 }
421 
422 
424 
430 template<typename NumericT>
432  scalar<NumericT> & result)
433 {
434  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(result).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
435 
436  scheduler::statement statement = scheduler::preset::min(&result, &x);
437  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("min", statement);
438 }
439 
445 template<typename NumericT>
447  NumericT & result)
448 {
450  min_impl(x, tmp);
451  result = tmp;
452 }
453 
454 
455 
456 //TODO: Special case x == y allows improvement!!
466 template<typename NumericT>
469  NumericT alpha, NumericT beta)
470 {
471  assert(viennacl::traits::opencl_handle(x).context() == viennacl::traits::opencl_handle(y).context() && bool("Operands do not reside in the same OpenCL context. Automatic migration not yet supported!"));
473 
475  kernels::vector<NumericT>::execution_handler(viennacl::traits::opencl_context(x)).execute("plane_rotation", statement);
476 }
477 
478 } //namespace opencl
479 } //namespace linalg
480 } //namespace viennacl
481 
482 
483 #endif
void min_cpu(vector_base< NumericT > const &x, NumericT &result)
Computes the supremum-norm of a vector.
cl_uint stride
Increment between integers.
Definition: kernel.hpp:50
void norm_2_cpu(vector_base< NumericT > const &x, NumericT &result)
Computes the l^1-norm of a vector with final reduction on CPU.
vcl_size_t const_size() const
Definition: vector.hpp:1129
static device_specific::execution_handler & execution_handler(viennacl::ocl::context &ctx)
Definition: vector.hpp:152
Helper class for packing four cl_uint numbers into a uint4 type for access inside an OpenCL kernel...
Definition: kernel.hpp:45
This class represents a single scalar value on the GPU and behaves mostly like a built-in scalar type...
Definition: forwards.h:226
void norm_1_cpu(vector_base< NumericT > const &x, NumericT &result)
Computes the l^1-norm of a vector with final reduction on CPU.
Represents an OpenCL device within ViennaCL.
void inner_prod_cpu(vector_base< NumericT > const &x, vector_base< NumericT > const &y, NumericT &result)
Generic size and resize functionality for different vector and matrix types.
void plane_rotation(vector_base< NumericT > &x, vector_base< NumericT > &y, NumericT alpha, NumericT beta)
Computes a plane rotation of two vectors.
void norm_inf_cpu(vector_base< NumericT > const &x, NumericT &result)
Computes the supremum-norm of a vector.
Extracts the underlying OpenCL start index handle from a vector, a matrix, an expression etc...
statement inner_prod(ScalarT const *s, vector_base< NumericT > const *x, vector_base< NumericT > const *y)
Definition: preset.hpp:212
cl_uint start
Starting value of the integer stride.
Definition: kernel.hpp:48
Various little tools used here and there in ViennaCL.
cl_uint index_norm_inf(vector_base< NumericT > const &x)
Computes the index of the first entry that is equal to the supremum-norm in modulus.
void norm_1_impl(vector_base< NumericT > const &x, scalar< NumericT > &result)
Computes the l^1-norm of a vector.
void avbv_v(vector_base< NumericT > &x, vector_base< NumericT > const &y, ScalarT1 const &alpha, vcl_size_t, bool reciprocal_alpha, bool flip_sign_alpha, vector_base< NumericT > const &z, ScalarT2 const &beta, vcl_size_t, bool reciprocal_beta, bool flip_sign_beta)
result_of::size_type< viennacl::vector_base< T > >::type stride(viennacl::vector_base< T > const &s)
Definition: stride.hpp:45
This file provides the forward declarations for the main types used within ViennaCL.
Determines row and column increments for matrices and matrix proxies.
void min_impl(vector_base< NumericT > const &x, scalar< NumericT > &result)
Computes the minimum of a vector.
statement max(scalar< NumericT > const *s, vector_base< NumericT > const *x)
Definition: preset.hpp:252
vcl_size_t internal_size(vector_base< NumericT > const &vec)
Helper routine for obtaining the buffer length of a ViennaCL vector.
Definition: size.hpp:268
An expression template class that represents a binary operation that yields a vector.
Definition: forwards.h:238
scheduler::statement avbv(scheduler::operation_node_type ASSIGN_OP, NumericT const *x, NumericT const *y, ScalarT1 const *a, bool flip_a, bool reciprocal_a, NumericT const *z, ScalarT2 const *b, bool flip_b, bool reciprocal_b)
Definition: preset.hpp:16
statement norm_2(scalar< NumericT > const *s, vector_base< NumericT > const *x)
Definition: preset.hpp:224
static device_specific::execution_handler & execution_handler(viennacl::ocl::context &ctx)
Definition: vector.hpp:191
void vector_assign(vector_base< NumericT > &x, const NumericT &alpha, bool up_to_internal_size=false)
Assign a constant value to a vector (-range/-slice)
cl_uint internal_size
Internal length of the buffer. Might be larger than 'size' due to padding.
Definition: kernel.hpp:54
Common implementations shared by OpenCL-based operations.
void element_op(matrix_base< NumericT > &A, matrix_expression< const matrix_base< NumericT >, const matrix_base< NumericT >, op_element_binary< OpT > > const &proxy)
Implementation of binary element-wise operations A = OP(B,C)
Main namespace in ViennaCL. Holds all the basic types such as vector, matrix, etc. and defines operations upon them.
Definition: cpu_ram.hpp:29
statement min(scalar< NumericT > const *s, vector_base< NumericT > const *x)
Definition: preset.hpp:259
statement binary_element_op(NumericT const *x, NumericT const *y, NumericT const *z, scheduler::operation_node_type TYPE)
Definition: preset.hpp:267
vcl_size_t size(VectorType const &vec)
Generic routine for obtaining the size of a vector (ViennaCL, uBLAS, etc.)
Definition: size.hpp:144
void max_impl(vector_base< NumericT > const &x, scalar< NumericT > &result)
Computes the maximum of a vector.
Helper struct for checking whether a type is a host scalar type (e.g. float, double) ...
Definition: forwards.h:447
Definition: blas3.hpp:36
Class for representing non-strided subvectors of a bigger vector x.
Definition: forwards.h:433
void max_cpu(vector_base< NumericT > const &x, NumericT &result)
Computes the supremum-norm of a vector.
Tuple class holding pointers to multiple vectors. Mainly used as a temporary object returned from vie...
Definition: forwards.h:268
void norm_2_impl(vector_base< NumericT > const &x, scalar< NumericT > &result)
Computes the l^2-norm of a vector - implementation using OpenCL summation at second step...
OpenCL kernel file for vector operations.
void inner_prod_impl(vector_base< NumericT > const &x, vector_base< NumericT > const &y, scalar< NumericT > &result)
Computes the inner product of two vectors - implementation. Library users should call inner_prod(x...
Implementation of a smart-pointer-like class for handling OpenCL handles.
result_of::size_type< T >::type start(T const &obj)
Definition: start.hpp:44
template_base * template_of(std::string const &key)
statement index_norm_inf(scalar< NumericT > const *s, vector_base< NumericT > const *x)
Definition: preset.hpp:238
statement norm_1(scalar< NumericT > const *s, vector_base< NumericT > const *x)
Definition: preset.hpp:218
statement norm_inf(scalar< NumericT > const *s, vector_base< NumericT > const *x)
Definition: preset.hpp:230
statement unary_element_op(NumericT const *x, NumericT const *y, scheduler::operation_node_type TYPE)
Definition: preset.hpp:288
scheduler::statement av(scheduler::operation_node_type ASSIGN_OP, NumericT const *x, NumericT const *y, ScalarT1 const *a, bool flip_a, bool reciprocal_a)
Definition: preset.hpp:71
std::size_t vcl_size_t
Definition: forwards.h:74
std::list< scheduler::statement > data_type
Definition: forwards.h:254
void norm_inf_impl(vector_base< NumericT > const &x, scalar< NumericT > &result)
Computes the supremum-norm of a vector.
operation_node_type
Enumeration for identifying the possible operations.
Definition: forwards.h:68
void vector_swap(vector_base< NumericT > &x, vector_base< NumericT > &y)
Swaps the contents of two vectors, data is copied.
All the predicates used within ViennaCL. Checks for expressions to be vectors, etc.
viennacl::context context(T const &t)
Returns an ID for the currently active memory domain of an object.
Definition: context.hpp:40
void av(vector_base< NumericT > &x, vector_base< NumericT > const &y, ScalarT1 const &alpha, vcl_size_t, bool reciprocal_alpha, bool flip_sign_alpha)
Representation of an OpenCL kernel in ViennaCL.
Represents a vector consisting of scalars 's' only, i.e. v[i] = s for all i. To be used as an initial...
Definition: vector_def.hpp:87
device_specific::statements_container swap(NumericT const *x, NumericT const *y)
Definition: preset.hpp:86
A range class that refers to an interval [start, stop), where 'start' is included, and 'stop' is excluded.
Definition: forwards.h:423
static device_specific::execution_handler & execution_handler(viennacl::ocl::context &ctx)
Definition: vector.hpp:98
void avbv(vector_base< NumericT > &x, vector_base< NumericT > const &y, ScalarT1 const &alpha, vcl_size_t, bool reciprocal_alpha, bool flip_sign_alpha, vector_base< NumericT > const &z, ScalarT2 const &beta, vcl_size_t, bool reciprocal_beta, bool flip_sign_beta)
VectorType const & const_at(vcl_size_t i) const
Definition: vector.hpp:1132
viennacl::ocl::packed_cl_uint make_layout(vector_base< NumericT > const &vec)
void execute(container_type::key_type const &key, statements_container const &statements)
A tag class representing element-wise binary operations (like multiplication) on vectors or matrices...
Definition: forwards.h:129
The main class for representing a statement such as x = inner_prod(y,z); at runtime.
Definition: forwards.h:504
Forward declarations of the implicit_vector_base, vector_base class.
Extracts the underlying OpenCL handle from a vector, a matrix, an expression etc. ...
scheduler::statement assign_cpu(vector_base< NumericT > const *x, implicit_vector_base< NumericT > const *y)
Definition: preset.hpp:106
device_specific::statements_container plane_rotation(vector_base< NumericT > const *x, vector_base< NumericT > const *y, NumericT const *a, NumericT const *b)
Definition: preset.hpp:78
const char * operator_string(scheduler::operation_node_type type)
ScalarType diff(ScalarType &s1, viennacl::scalar< ScalarType > &s2)
Definition: blas3_solve.cpp:69
A tag class representing element-wise unary operations (like sin()) on vectors or matrices...
Definition: forwards.h:133
Implementation of the ViennaCL scalar class.
Simple enable-if variant that uses the SFINAE pattern.
cl_uint size
Number of values in the stride.
Definition: kernel.hpp:52