imate
C++/CUDA Reference
Loading...
Searching...
No Matches
cu_golub_kahn_bidiagonalization.cu
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
17#include "../_cu_definitions/cu_types.h" // __nv_fp8_e5m2, __nv_fp8_e4m3,
18 // __half, __nv_bfloat16
19#include <cmath> // std::sqrt
20#include "../_cu_basic_algebra/cu_vector_operations.h" // cuVectorOperations
21#include "../_cu_trace_estimator/cu_orthogonalization.h" // cuOrthogonaliza...
22#include "../_cuda_utilities/cuda_api.h" // CudaAPI
23#include "../_cu_arithmetics/cu_arithmetics.h" // cu_arithmetics
24
25// Avoid CUBLAS numeration value not handled in switch [-Wswitch-enum] warning
26#ifdef _MSC_VER
27 #pragma warning(push, 0) // Suppress all warnings from the followings
28 #include <cublas_v2.h> // cublasHandle_t
29 #pragma warning(pop) // Restore previous warning level
30#elif defined(__INTEL_LLVM_COMPILER) || defined(__INTEL_COMPILER)
31 #pragma warning(push, 0)
32 #include <cublas_v2.h> // cublasHandle_t
33 #pragma warning(pop)
34#elif defined(__GNUC__) || defined(__clang__)
35 #pragma GCC diagnostic push
36 #pragma GCC diagnostic ignored "-Wswitch-enum"
37 #include <cublas_v2.h> // cublasHandle_t
38 #pragma GCC diagnostic pop
39#else
40 #include <cublas_v2.h> // cublasHandle_t
41#endif
42
43
44// ============================
45// golub-kahn bidiagonalization
46// ============================
47
131
132template <typename DataType>
135 const DataType* v,
136 const LongIndexType n,
137 const IndexType m,
138 const DataType lanczos_tol,
139 const FlagType orthogonalize,
140 DataType* alpha,
141 DataType* beta)
142{
143 // Get cublas handle
144 cublasHandle_t cublas_handle = A->get_cublas_handle();
145
146 // buffer_size is number of last orthogonal vectors to keep in buffers U, V
147 IndexType buffer_size;
148 if (orthogonalize == 0)
149 {
150 // At least two vectors must be stored in buffer for Lanczos recursion
151 buffer_size = 2;
152 }
153 else if ((orthogonalize < 0) ||
154 (orthogonalize > static_cast<FlagType>(m) - 1))
155 {
156 // Using full re-orthogonalization, keep all of the m vectors in buffer
157 buffer_size = m;
158 }
159 else
160 {
161 // Orthogonalize with less than m vectors (0 < orthogonalize < m-1)
162 // plus one vector for the latest (the j-th) vector
163 buffer_size = orthogonalize + 1;
164 }
165
166 // Allocate 2D array (as 1D array, and coalesced row-wise) to store
167 // the last buffer_size of orthogonalized vectors of length n. New vectors
168 // are stored by cycling through the buffer to replace with old ones.
169 DataType* device_U = CudaAPI<DataType>::alloc(n * buffer_size);
170 DataType* device_V = CudaAPI<DataType>::alloc(n * buffer_size);
171
172 // Normalize vector v and copy to v_old
173 CudaAPI<DataType>::copy_to_device(v, n, &device_V[0]);
175 cublas_handle, &device_V[0], n);
176
177 // Declare iterators
178 IndexType j;
179 IndexType lanczos_size = 0;
180 IndexType num_ortho;
181
182 // Golub-Kahn iteration
183 for (j=0; j < m; ++j)
184 {
185 // Counter for the non-zero size of alpha and beta
186 ++lanczos_size;
187
188 // u_new = A.dot(v_old)
189 A->dot(&device_V[(j % buffer_size)*n], &device_U[(j % buffer_size)*n]);
190
191 // Performing: u_new[i] = u_new[i] - beta[j] * u_old[i]
192 if (j > 0)
193 {
195 cublas_handle,
196 &device_U[((j-1) % buffer_size)*n], n, beta[j-1],
197 &device_U[(j % buffer_size)*n]);
198 }
199
200 // orthogonalize u_new against previous vectors
201 if (orthogonalize != 0)
202 {
203 // Find how many column vectors are filled so far in the buffer V
204 if (j < buffer_size)
205 {
206 num_ortho = j;
207 }
208 else
209 {
210 num_ortho = buffer_size - 1;
211 }
212
213 // Gram-Schmidt process
214 if (j > 0)
215 {
217 cublas_handle, &device_U[0], n, buffer_size,
218 (j-1)%buffer_size, num_ortho,
219 &device_U[(j % buffer_size)*n]);
220 }
221 }
222
223 // Normalize u_new and set its norm to alpha[j]
225 cublas_handle, &device_U[(j % buffer_size)*n], n);
226
227 // Performing: v_new = A.T.dot(u_new) - alpha[j] * v_old
228 A->transpose_dot(&device_U[(j % buffer_size)*n],
229 &device_V[((j+1) % buffer_size)*n]);
230
231 // Performing: v_new[i] = v_new[i] - alpha[j] * v_old[i]
233 cublas_handle, &device_V[(j % buffer_size)*n], n, alpha[j],
234 &device_V[((j+1) % buffer_size)*n]);
235
236 // orthogonalize v_new against previous vectors
237 if (orthogonalize != 0)
238 {
240 cublas_handle, &device_V[0], n, buffer_size, j%buffer_size,
241 num_ortho, &device_V[((j+1) % buffer_size)*n]);
242 }
243
244 // Update beta as the norm of v_new
246 cublas_handle, &device_V[((j+1) % buffer_size)*n], n);
247
248 // Exit criterion when the vector r is zero. If each component of a
249 // zero vector has the tolerance epsilon, (which is called lanczos_tol
250 // here), the tolerance of norm of r is epsilon times sqrt of n.
251 if (beta[j] < cu_arithmetics::mul(
252 lanczos_tol,
254 static_cast<double>(std::sqrt(n)))
255 )
256 )
257 {
258 break;
259 }
260 }
261
262 // Free dynamic memory
263 CudaAPI<DataType>::del(device_U);
264 CudaAPI<DataType>::del(device_V);
265
266 return lanczos_size;
267}
268
269
270// ===============================
271// Explicit template instantiation
272// ===============================
273
274// golub kahn bidiagonalization (__nv_fp8_e5m2)
275#if defined(USE_CUDA_FP8_E5M2) && (USE_CUDA_FP8_E5M2 == 1)
276 template IndexType cu_golub_kahn_bidiagonalization<__nv_fp8_e5m2>(
278 const __nv_fp8_e5m2* v,
279 const LongIndexType n,
280 const IndexType m,
281 const __nv_fp8_e5m2 lanczos_tol,
282 const FlagType orthogonalize,
283 __nv_fp8_e5m2* alpha,
284 __nv_fp8_e5m2* beta);
285#endif
286
287// golub kahn bidiagonalization (__nv_fp8_e5m2)
288#if defined(USE_CUDA_FP8_E4M3) && (USE_CUDA_FP8_E4M3 == 1)
289 template IndexType cu_golub_kahn_bidiagonalization<__nv_fp8_e4m3>(
291 const __nv_fp8_e4m3* v,
292 const LongIndexType n,
293 const IndexType m,
294 const __nv_fp8_e4m3 lanczos_tol,
295 const FlagType orthogonalize,
296 __nv_fp8_e4m3* alpha,
297 __nv_fp8_e4m3* beta);
298#endif
299
300// golub kahn bidiagonalization (__half)
301#if defined(USE_CUDA_FP16) && (USE_CUDA_FP16 == 1)
302 template IndexType cu_golub_kahn_bidiagonalization<__half>(
304 const __half* v,
305 const LongIndexType n,
306 const IndexType m,
307 const __half lanczos_tol,
308 const FlagType orthogonalize,
309 __half* alpha,
310 __half* beta);
311#endif
312
313// golub kahn bidiagonalization (__nv_bfloat16)
314#if defined(USE_CUDA_BF16) && (USE_CUDA_BF16 == 1)
315 template IndexType cu_golub_kahn_bidiagonalization<__nv_bfloat16>(
317 const __nv_bfloat16* v,
318 const LongIndexType n,
319 const IndexType m,
320 const __nv_bfloat16 lanczos_tol,
321 const FlagType orthogonalize,
322 __nv_bfloat16* alpha,
323 __nv_bfloat16* beta);
324#endif
325
326// golub kahn bidiagonalization (float)
327#if defined(USE_CUDA_FP32) && (USE_CUDA_FP32 == 1)
330 const float* v,
331 const LongIndexType n,
332 const IndexType m,
333 const float lanczos_tol,
334 const FlagType orthogonalize,
335 float* alpha,
336 float* beta);
337#endif
338
339// golub kahn bidiagonalization (double)
340#if defined(USE_CUDA_FP64) && (USE_CUDA_FP64 == 1)
343 const double* v,
344 const LongIndexType n,
345 const IndexType m,
346 const double lanczos_tol,
347 const FlagType orthogonalize,
348 double* alpha,
349 double* beta);
350#endif
static ArrayType * alloc(const size_t array_size)
Allocates memory on gpu device. This function creates a pointer and returns it.
Definition cuda_api.cu:39
static void del(void *device_array)
Deletes memory on gpu device if its pointer is not NULL, then sets the pointer to NULL.
Definition cuda_api.cu:169
static void copy_to_device(const ArrayType *host_array, const size_t array_size, ArrayType *device_array)
Copies memory on host to device memory.
Definition cuda_api.cu:145
Base class for linear operators. This class serves as interface for all derived classes.
virtual void dot(const DataType *vector, DataType *product)=0
cublasHandle_t get_cublas_handle() const
This function returns a reference to the cublasHandle_t object. The object will be created,...
virtual void transpose_dot(const DataType *vector, DataType *product)=0
static void gram_schmidt_process(cublasHandle_t cublas_handle, const DataType *V, const LongIndexType vector_size, const IndexType num_vectors, const IndexType last_vector, const FlagType num_ortho, DataType *r)
Modified Gram-Schmidt orthogonalization process to orthogonalize the vector v against a subset of the...
static DataType normalize_vector_in_place(cublasHandle_t cublas_handle, DataType *RESTRICT vector, const LongIndexType vector_size)
Normalizes a vector based on Euclidean 2-norm. The result is written in-place.
static void subtract_scaled_vector(cublasHandle_t cublas_handle, const DataType *RESTRICT input_vector, const LongIndexType vector_size, const DataType scale, DataType *RESTRICT output_vector)
Subtracts the scaled input vector from the output vector.
template IndexType cu_golub_kahn_bidiagonalization< double >(cuLinearOperator< double > *A, const double *v, const LongIndexType n, const IndexType m, const double lanczos_tol, const FlagType orthogonalize, double *alpha, double *beta)
IndexType cu_golub_kahn_bidiagonalization(cuLinearOperator< DataType > *A, const DataType *v, const LongIndexType n, const IndexType m, const DataType lanczos_tol, const FlagType orthogonalize, DataType *alpha, DataType *beta)
Bi-diagonalizes the positive-definite matrix A using Golub-Kahn-Lanczos method.
template IndexType cu_golub_kahn_bidiagonalization< float >(cuLinearOperator< float > *A, const float *v, const LongIndexType n, const IndexType m, const float lanczos_tol, const FlagType orthogonalize, float *alpha, float *beta)
__host__ __device__ DataType mul(const DataType x, const DataType y)
Multiply two floating point numbers in round-to-nearest-even mode.
__host__ __device__ DataType abs(const DataType x)
Absolute value of a floating point number.
int LongIndexType
Definition types.h:60
int FlagType
Definition types.h:68
int IndexType
Definition types.h:65