imate
C++/CUDA Reference
c_vector_operations.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: Copyright 2021, Siavash Ameli <sameli@berkeley.edu>
3  * SPDX-License-Identifier: BSD-3-Clause
4  * SPDX-FileType: SOURCE
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the license found in the LICENSE.txt file in the root
8  * directory of this source tree.
9  */
10 
11 
12 // =======
13 // Headers
14 // =======
15 
16 #include "./c_vector_operations.h"
17 #include <cmath> // sqrt
18 #include "../_definitions/definitions.h" // USE_CBLAS
19 
20 #if (USE_CBLAS == 1)
21  #include "./cblas_interface.h"
22 #endif
23 
24 
25 // ===========
26 // copy vector
27 // ===========
28 
37 
38 template <typename DataType>
40  const DataType* input_vector,
41  const LongIndexType vector_size,
42  DataType* output_vector)
43 {
44  #if (USE_CBLAS == 1)
45 
46  // Using Openblas
47  int incx = 1;
48  int incy = 1;
49 
50  cblas_interface::xcopy(vector_size, input_vector, incx, output_vector,
51  incy);
52 
53  #else
54 
55  // Not using OpenBlas
56  for (LongIndexType i=0; i < vector_size; ++i)
57  {
58  output_vector[i] = input_vector[i];
59  }
60 
61  #endif
62 }
63 
64 // ==================
65 // copy scaled vector
66 // ==================
67 
79 
80 template <typename DataType>
82  const DataType* input_vector,
83  const LongIndexType vector_size,
84  const DataType scale,
85  DataType* output_vector)
86 {
87  #if (USE_CBLAS == 1)
88 
89  // Using OpenBlas
90  int incx = 1;
91  int incy = 1;
92 
93  cblas_interface::xcopy(vector_size, input_vector, incx, output_vector,
94  incy);
95 
96  cblas_interface::xscal(vector_size, scale, output_vector, incy);
97 
98  #else
99 
100  // Not using OpenBlas
101  for (LongIndexType i=0; i < vector_size; ++i)
102  {
103  output_vector[i] = scale * input_vector[i];
104  }
105 
106  #endif
107 }
108 
109 
110 // ======================
111 // subtract scaled vector
112 // ======================
113 
133 
134 template <typename DataType>
136  const DataType* input_vector,
137  const LongIndexType vector_size,
138  const DataType scale,
139  DataType* output_vector)
140 {
141 
142  #if (USE_CBLAS == 1)
143 
144  // Using OpenBlas
145  int incx = 1;
146  int incy = 1;
147 
148  DataType neg_scale = -scale;
149  cblas_interface::xaxpy(vector_size, neg_scale, input_vector, incx,
150  output_vector, incy);
151 
152  #else
153 
154  // Not using OpenBlas
155  if (scale == 0.0)
156  {
157  return;
158  }
159 
160  for (LongIndexType i=0; i < vector_size; ++i)
161  {
162  output_vector[i] -= scale * input_vector[i];
163  }
164 
165  #endif
166 }
167 
168 
169 // =============
170 // inner product
171 // =============
172 
202 
203 template <typename DataType>
205  const DataType* vector1,
206  const DataType* vector2,
207  const LongIndexType vector_size)
208 {
209  #if (USE_CBLAS == 1)
210 
211  // Using OpenBlas
212  int incx = 1;
213  int incy = 1;
214 
215  DataType inner_prod = cblas_interface::xdot(vector_size, vector1, incx,
216  vector2, incy);
217 
218  return inner_prod;
219 
220  #else
221 
222  // Not using OpenBlas
223  long double inner_prod = 0.0;
224  LongIndexType chunk = 5;
225  LongIndexType vector_size_chunked = vector_size - (vector_size % chunk);
226 
227  for (LongIndexType i=0; i < vector_size_chunked; i += chunk)
228  {
229  inner_prod += vector1[i] * vector2[i] +
230  vector1[i+1] * vector2[i+1] +
231  vector1[i+2] * vector2[i+2] +
232  vector1[i+3] * vector2[i+3] +
233  vector1[i+4] * vector2[i+4];
234  }
235 
236  for (LongIndexType i=vector_size_chunked; i < vector_size; ++i)
237  {
238  inner_prod += vector1[i] * vector2[i];
239  }
240 
241  return static_cast<DataType>(inner_prod);
242 
243  #endif
244 }
245 
246 
247 // ==============
248 // euclidean norm
249 // ==============
250 
279 
280 template <typename DataType>
282  const DataType* vector,
283  const LongIndexType vector_size)
284 {
285  #if (USE_CBLAS == 1)
286 
287  // Using OpenBlas
288  int incx = 1;
289 
290  DataType norm = cblas_interface::xnrm2(vector_size, vector, incx);
291 
292  return norm;
293 
294  #else
295 
296  // Compute norm squared
297  long double norm2 = 0.0;
298  LongIndexType chunk = 5;
299  LongIndexType vector_size_chunked = vector_size - (vector_size % chunk);
300 
301  for (LongIndexType i=0; i < vector_size_chunked; i += chunk)
302  {
303  norm2 += vector[i] * vector[i] +
304  vector[i+1] * vector[i+1] +
305  vector[i+2] * vector[i+2] +
306  vector[i+3] * vector[i+3] +
307  vector[i+4] * vector[i+4];
308  }
309 
310  for (LongIndexType i=vector_size_chunked; i < vector_size; ++i)
311  {
312  norm2 += vector[i] * vector[i];
313  }
314 
315  // Norm
316  DataType norm = sqrt(static_cast<DataType>(norm2));
317 
318  return norm;
319 
320  #endif
321 }
322 
323 
324 // =========================
325 // normalize vector in place
326 // =========================
327 
336 
337 template <typename DataType>
339  DataType* vector,
340  const LongIndexType vector_size)
341 {
342  #if (USE_CBLAS == 1)
343 
344  // Norm of vector
346  vector, vector_size);
347 
348  // Normalize in place
349  DataType scale = 1.0 / norm;
350  int incx = 1;
351  cblas_interface::xscal(vector_size, scale, vector, incx);
352 
353  return norm;
354 
355  #else
356 
357  // Norm of vector
358  DataType norm = cVectorOperations<DataType>::euclidean_norm(vector,
359  vector_size);
360 
361  // Normalize in place
362  for (LongIndexType i=0; i < vector_size; ++i)
363  {
364  vector[i] /= norm;
365  }
366 
367  return norm;
368 
369  #endif
370 }
371 
372 
373 // =========================
374 // normalize vector and copy
375 // =========================
376 
387 
388 template <typename DataType>
390  const DataType* vector,
391  const LongIndexType vector_size,
392  DataType* output_vector)
393 {
394  #if (USE_CBLAS == 1)
395 
396  // Norm of vector
398  vector, vector_size);
399 
400  // Normalize to output
401  DataType scale = 1.0 / norm;
402  cVectorOperations<DataType>::copy_scaled_vector(vector, vector_size, scale,
403  output_vector);
404 
405  return norm;
406 
407  #else
408 
409  // Norm of vector
410  DataType norm = cVectorOperations<DataType>::euclidean_norm(vector,
411  vector_size);
412 
413  // Normalize to output
414  for (LongIndexType i=0; i < vector_size; ++i)
415  {
416  output_vector[i] = vector[i] / norm;
417  }
418 
419  return norm;
420 
421  #endif
422 }
423 
424 
425 // ===============================
426 // Explicit template instantiation
427 // ===============================
428 
429 template class cVectorOperations<float>;
430 template class cVectorOperations<double>;
431 template class cVectorOperations<long double>;
A static class for vector operations, similar to level-1 operations of the BLAS library....
static void copy_vector(const DataType *input_vector, const LongIndexType vector_size, DataType *output_vector)
Copies a vector to a new vector. Result is written in-place.
static void copy_scaled_vector(const DataType *input_vector, const LongIndexType vector_size, const DataType scale, DataType *output_vector)
Scales a vector and stores to a new vector.
static void subtract_scaled_vector(const DataType *input_vector, const LongIndexType vector_size, const DataType scale, DataType *output_vector)
Subtracts the scaled input vector from the output vector.
static DataType normalize_vector_in_place(DataType *vector, const LongIndexType vector_size)
Normalizes a vector based on Euclidean 2-norm. The result is written in-place.
static DataType inner_product(const DataType *vector1, const DataType *vector2, const LongIndexType vector_size)
Computes Euclidean inner product of two vectors.
static DataType euclidean_norm(const DataType *vector, const LongIndexType vector_size)
Computes the Euclidean norm of a 1D array.
static DataType normalize_vector_and_copy(const DataType *vector, const LongIndexType vector_size, DataType *output_vector)
Normalizes a vector based on Euclidean 2-norm. The result is written into another vector.
int LongIndexType
Definition: types.h:60