imate
C++/CUDA Reference
Loading...
Searching...
No Matches
c_orthogonalization.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// Imports
14// =======
15
17#include <cstdlib> // abort
18#include <iostream> // std::cerr, std::endl
19#include <cmath> // std::sqrt, std::fabs
20#include <limits> // std::numeric_limits
21#include "../_c_basic_algebra/c_vector_operations.h" // cVectorOperations
22#include "../_random_generator/random_array_generator.h" // RandomArrayGene...
23#include "../_random_generator/random_number_generator.h" // RandomNumberGe...
24
25
26// ====================
27// gram schmidt process
28// ====================
29
123
124template <typename DataType>
126 const DataType* V,
127 const LongIndexType vector_size,
128 const IndexType num_vectors,
129 const IndexType last_vector,
130 const FlagType num_ortho,
131 DataType* v)
132{
133 // Determine how many previous vectors to orthogonalize against
134 IndexType num_steps;
135 if ((num_ortho == 0) || (num_vectors < 2))
136 {
137 // No orthogonalization is performed
138 return;
139 }
140 else if ((num_ortho < 0) ||
141 (num_ortho > static_cast<FlagType>(num_vectors)))
142 {
143 // Orthogonalize against all vectors
144 num_steps = num_vectors;
145 }
146 else
147 {
148 // Orthogonalize against only the last num_ortho vectors
149 num_steps = num_ortho;
150 }
151
152 // Vectors can be orthogonalized at most to the full basis of the vector
153 // space. Thus, num_steps cannot be larger than the dimension of vector
154 // space, which is vector_size.
155 if (num_steps > static_cast<IndexType>(vector_size))
156 {
157 num_steps = vector_size;
158 }
159
160 IndexType i;
161 DataType inner_prod;
162 DataType norm;
163 DataType norm_v;
164 DataType epsilon = std::numeric_limits<DataType>::epsilon();
165 DataType distance2;
166
167 // Iterate over vectors
168 for (IndexType step=0; step < num_steps; ++step)
169 {
170 // i is the index of a column vector in V to orthogonalize v against it
171 if ((last_vector % num_vectors) >= step)
172 {
173 i = (last_vector % num_vectors) - step;
174 }
175 else
176 {
177 // Wrap around negative indices from the end of column index
178 i = (last_vector % num_vectors) - step + num_vectors;
179 }
180
181 // Norm of j-th vector
183 &V[vector_size*i], vector_size);
184
185 // Check norm
186 if (norm < epsilon * static_cast<DataType>(std::sqrt(vector_size)))
187 {
188 std::cerr << "WARNING: norm of the given vector is too small. " \
189 << "Cannot orthogonalize against zero vector. " \
190 << "Skipping." << std::endl;
191 continue;
192 }
193
194 // Projection
196 &V[vector_size*i], v, vector_size);
197
198 // scale for subtraction
199 DataType scale = inner_prod / (norm * norm);
200
201 // If scale is 1, it is possible that vector v and j-th vector are
202 // identical (or close).
203 if (static_cast<DataType>(std::abs(
204 static_cast<DataType>(std::abs(scale)) - \
205 static_cast<DataType>(1.0))) <= \
206 static_cast<DataType>(2.0) * epsilon)
207 {
208 // Norm of the vector v
210 v, vector_size);
211
212 // Compute distance between the j-th vector and vector v
213 distance2 = norm_v*norm_v - \
214 static_cast<DataType>(2.0)*inner_prod + norm*norm;
215
216 // If distance is zero, do not reorthogonalize i-th against
217 // the j-th vector.
218 if (distance2 < \
219 static_cast<DataType>(2.0) * epsilon * \
220 static_cast<DataType>(vector_size))
221 {
222 continue;
223 }
224 }
225
226 // Subtraction
228 &V[vector_size*i], vector_size, scale, v);
229 }
230}
231
232
233// =====================
234// orthogonalize vectors
235// =====================
236
273
274template <typename DataType>
276 DataType* vectors,
277 const LongIndexType vector_size,
278 const IndexType num_vectors)
279{
280 // Do nothing if there is only one vector
281 if (num_vectors < 2)
282 {
283 return;
284 }
285
286 IndexType i = 0;
287 IndexType j;
288 IndexType start_j;
289 DataType inner_prod;
290 DataType norm_j;
291 DataType norm_i;
292 DataType epsilon = std::numeric_limits<DataType>::epsilon();
293 IndexType success = 1;
294 IndexType max_num_trials = 20;
295 IndexType num_trials = 0;
296 IndexType num_threads = 1;
297 RandomNumberGenerator random_number_generator(num_threads);
298
299 while (i < num_vectors)
300 {
301 if ((success == 0) && (num_trials >= max_num_trials))
302 {
303 std::cerr << "ERROR: Cannot orthogonalize vectors after " \
304 << num_trials << " trials. Aborting." \
305 << std::endl;
306 abort();
307 }
308
309 // Reset on new trial (if it was set to 0 before to start a new trial)
310 success = 1;
311
312 // j iterates on previous vectors in a window of at most vector_size
313 if (static_cast<LongIndexType>(i) > vector_size)
314 {
315 // When vector_size is smaller than i, it is fine to cast to signed
316 start_j = i - static_cast<IndexType>(vector_size);
317 }
318 else
319 {
320 start_j = 0;
321 }
322
323 // Reorthogonalize against previous vectors
324 for (j=start_j; j < i; ++j)
325 {
326 // Norm of the j-th vector
328 &vectors[j*vector_size], vector_size);
329
330 // Check norm
331 if (norm_j < \
332 epsilon * static_cast<DataType>(std::sqrt(vector_size)))
333 {
334 std::cerr << "WARNING: norm of the given vector is too " \
335 << " small. Cannot reorthogonalize against zero" \
336 << "vector. Skipping."
337 << std::endl;
338 continue;
339 }
340
341 // Projecting i-th vector to j-th vector
343 &vectors[i*vector_size], &vectors[j*vector_size],
344 vector_size);
345
346 // Scale of subtraction
347 DataType scale = inner_prod / (norm_j * norm_j);
348
349 // Subtraction
351 &vectors[vector_size*j], vector_size, scale,
352 &vectors[vector_size*i]);
353
354 // Norm of the i-th vector
356 &vectors[i*vector_size], vector_size);
357
358 // If the norm is too small, regenerate the i-th vector randomly
359 if (norm_i < \
360 epsilon * static_cast<DataType>(std::sqrt(vector_size)))
361 {
362 // Regenerate new random vector for i-th vector
364 random_number_generator, &vectors[i*vector_size],
365 vector_size, num_threads);
366
367 // Repeat the reorthogonalization for i-th vector against
368 // all previous vectors again.
369 success = 0;
370 ++num_trials;
371 break;
372 }
373 }
374
375 if (success == 1)
376 {
377 ++i;
378
379 // Reset if num_trials was incremented before.
380 num_trials = 0;
381 }
382 }
383}
384
385
386// ===============================
387// Explicit template instantiation
388// ===============================
389
390template class cOrthogonalization<float>;
391template class cOrthogonalization<double>;
static void generate_random_array(RandomNumberGenerator &random_number_generator, DataType *array, const LongIndexType array_size, const IndexType num_threads)
Generates a pseudo-random array with Rademacher distribution where elements are either +1 or -1.
Generates 64-bit integers on multiple parallel threads.
A static class for orthogonalization of vector bases. This class acts as a templated namespace,...
static void gram_schmidt_process(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 void orthogonalize_vectors(DataType *vectors, const LongIndexType vector_size, const IndexType num_vectors)
Orthogonalizes set of vectors mutually using modified Gram-Schmidt process.
static DataType inner_product(const DataType *RESTRICT vector1, const DataType *RESTRICT vector2, const LongIndexType vector_size)
Computes Euclidean inner product of two vectors.
static void subtract_scaled_vector(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.
static DataType euclidean_norm(const DataType *RESTRICT vector, const LongIndexType vector_size)
Computes the Euclidean norm of a 1D array.
int LongIndexType
Definition types.h:60
int FlagType
Definition types.h:68
int IndexType
Definition types.h:65