Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALInference 4.1.9.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LALInferenceGenerateROQ.c
Go to the documentation of this file.
1/*
2 * LALInferenceCreateROQ.c: Reduced order quadrature basis and interpolant generation
3 *
4 * Copyright (C) 2014, 2016 Matthew Pitkin, Rory Smith
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with with program; see the file COPYING. If not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include <lal/LALInferenceGenerateROQ.h>
23#include <lal/XLALGSL.h>
24
25#ifndef _OPENMP
26#define omp ignore
27#endif
28
29
30/* internal function definitions */
31
32/* define function to project model vector onto the training set of models */
33void project_onto_basis(gsl_vector *weight,
34 gsl_matrix *RB,
35 gsl_matrix *TS,
36 gsl_matrix *projections,
37 INT4 idx);
38
39void complex_project_onto_basis(gsl_vector *weight,
40 gsl_matrix_complex *RB,
41 gsl_matrix_complex *TS,
42 gsl_matrix_complex *projections,
43 INT4 idx);
44
45/* the dot product of two real vectors scaled by a weighting factor */
46REAL8 weighted_dot_product(const gsl_vector *weight, gsl_vector *a, gsl_vector *b);
47
48/* the dot product of two complex vectors scaled by a weighting factor */
49gsl_complex complex_weighted_dot_product(const gsl_vector *weight, gsl_vector_complex *a, gsl_vector_complex *b);
50
51void normalise(const gsl_vector *weight, gsl_vector *a);
52void complex_normalise(const gsl_vector *weight, gsl_vector_complex *a);
53
54void normalise_training_set(gsl_vector *weight, gsl_matrix *TS);
55void complex_normalise_training_set(gsl_vector *weight, gsl_matrix_complex *TS);
56
57double normalisation(const gsl_vector *weight, gsl_vector *a);
58double complex_normalisation(const gsl_vector *weight, gsl_vector_complex *a);
59
60void modified_gs_complex(gsl_vector_complex *ru,
61 gsl_vector_complex *ortho_basis,
62 const gsl_matrix_complex *RB_space,
63 const gsl_vector *wQuad,
64 const int dim_RB);
65
66void iterated_modified_gm_complex(gsl_vector_complex *ru,
67 gsl_vector_complex *ortho_basis,
68 const gsl_matrix_complex *RB_space,
69 const gsl_vector *wQuad,
70 const int dim_RB);
71
72void modified_gs(gsl_vector *ru,
73 gsl_vector *ortho_basis,
74 const gsl_matrix *RB_space,
75 const gsl_vector *wQuad,
76 const int dim_RB);
77
78void iterated_modified_gm(gsl_vector *ru,
79 gsl_vector *ortho_basis,
80 const gsl_matrix *RB_space,
81 const gsl_vector *wQuad,
82 const int dim_RB);
83
84/* get the B_matrix */
85REAL8Array *B_matrix(gsl_matrix *V, gsl_matrix *RB);
86COMPLEX16Array *complex_B_matrix(gsl_matrix_complex *V, gsl_matrix_complex *RB);
87
88/* find the index of the absolute maximum value for a complex vector */
89int complex_vector_maxabs_index( gsl_vector_complex *c );
90
91
92/** \brief Function to project the training set onto a given basis vector
93 *
94 * This is an internal function to be used by \c LALInferenceCreateREAL8OrthonormalBasis
95 *
96 * @param[in] weight The normalisation weight(s) for the training set waveforms (e.g. time or frequency step(s) size)
97 * @param[in] RB The reduced basis set
98 * @param[in] TS The training set of waveforms
99 * @param[in] projections The set of projections (this is updated in this function)
100 * @param[in] idx The index of the reduced basis vector that the training set will project onto
101 */
102void project_onto_basis(gsl_vector *weight,
103 gsl_matrix *RB,
104 gsl_matrix *TS,
105 gsl_matrix *projections,
106 INT4 idx){
107 size_t row = 0;
108 gsl_vector_view basis;
109
110 XLAL_CALLGSL( basis = gsl_matrix_row(RB, idx) );
111
112 for ( row=0; row < TS->size1; row++ ){
113 double prod;
114 gsl_vector_view proj, model;
115 gsl_vector *basisscale;
116
117 XLAL_CALLGSL( proj = gsl_matrix_row(projections, row) );
118 XLAL_CALLGSL( basisscale = gsl_vector_calloc(TS->size2) );
119
120 XLAL_CALLGSL( model = gsl_matrix_row(TS, row) ); /* get model from training set */
121
122 prod = weighted_dot_product(weight, &basis.vector, &model.vector);
123
124 XLAL_CALLGSL( gsl_vector_memcpy(basisscale, &basis.vector) );
125 XLAL_CALLGSL( gsl_vector_scale(basisscale, prod) );
126 XLAL_CALLGSL( gsl_vector_add(&proj.vector, basisscale) );
127 XLAL_CALLGSL( gsl_vector_free(basisscale) );
128 }
129}
130
131
132/** \brief Function to project the complex training set onto a given basis vector
133 *
134 * This is an internal function to be used by \c LALInferenceCreateCOMPLEX16OrthonormalBasis
135 *
136 * @param[in] weight The normalisation weight(s) for the training set waveforms (e.g. time or frequency step(s) size)
137 * @param[in] RB The reduced basis set
138 * @param[in] TS The training set of waveforms
139 * @param[in] projections The set of projections (this is updated in this function)
140 * @param[in] idx The index of the reduced basis vector that the training set will project onto
141 */
142void complex_project_onto_basis(gsl_vector *weight,
143 gsl_matrix_complex *RB,
144 gsl_matrix_complex *TS,
145 gsl_matrix_complex *projections,
146 INT4 idx){
147 size_t row = 0;
148 gsl_vector_complex_view basis;
149
150 XLAL_CALLGSL( basis = gsl_matrix_complex_row(RB, idx) );
151
152 for ( row=0; row < TS->size1; row++ ){
153 gsl_complex cprod;
154 gsl_vector_complex_view proj, model;
155 gsl_vector_complex *basisscale;
156
157 XLAL_CALLGSL( proj = gsl_matrix_complex_row(projections, row) );
158 XLAL_CALLGSL( basisscale = gsl_vector_complex_calloc(TS->size2) );
159
160 XLAL_CALLGSL( model = gsl_matrix_complex_row(TS, row) ); /* get model from training set */
161
162 cprod = complex_weighted_dot_product(weight, &basis.vector, &model.vector);
163
164 XLAL_CALLGSL( gsl_vector_complex_memcpy(basisscale, &basis.vector) );
165 XLAL_CALLGSL( gsl_vector_complex_scale(basisscale, cprod) );
166 XLAL_CALLGSL( gsl_vector_complex_add(&proj.vector, basisscale) );
167 XLAL_CALLGSL( gsl_vector_complex_free(basisscale) );
168 }
169}
170
171
172/** \brief The dot product of two real vectors scaled by a given weight factor
173 *
174 * @param[in] weight A (set of) scaling factor(s) for the dot product
175 * @param[in] a The first vector
176 * @param[in] b The second vector
177 *
178 * @return The real dot product of the two vectors
179 */
180REAL8 weighted_dot_product(const gsl_vector *weight, gsl_vector *a, gsl_vector *b){
181 REAL8 dp;
182 gsl_vector *weighted;
183
184 XLAL_CHECK_REAL8( a->size == b->size, XLAL_EFUNC, "Size of input vectors are not the same.");
185
186 XLAL_CALLGSL( weighted = gsl_vector_calloc(a->size) );
187 XLAL_CALLGSL( gsl_vector_memcpy(weighted, a) );
188
189 /* multiply vector by weight */
190 if ( weight->size == 1 ){ /* just a single weight to scale with */
191 XLAL_CALLGSL( gsl_vector_scale(weighted, gsl_vector_get(weight, 0)) );
192 }
193 else if ( weight->size == a->size ){
194 XLAL_CALLGSL( gsl_vector_mul(weighted, weight) );
195 }
196 else{
197 XLAL_ERROR_REAL8( XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
198 }
199
200 /* get dot product */
201 XLAL_CALLGSL( gsl_blas_ddot(weighted, b, &dp) );
202
203 XLAL_CALLGSL( gsl_vector_free(weighted) );
204
205 return dp;
206}
207
208
209/** \brief The dot product of two complex vectors scaled by a given weight factor
210 *
211 * The dot product is produced using the complex conjugate of the first vector.
212 *
213 * @param[in] weight A real scaling factor for the dot product
214 * @param[in] a The first complex vector
215 * @param[in] b The second complex vector
216 *
217 * @return The absolute value of the complex dot product of the two vectors
218 */
219gsl_complex complex_weighted_dot_product(const gsl_vector *weight, gsl_vector_complex *a, gsl_vector_complex *b){
220 gsl_complex dp;
221 gsl_vector_complex *weighted;
222
223 if ( a->size != b->size ){ XLAL_PRINT_ERROR( "Size of input vectors are not the same." ); }
224
225 XLAL_CALLGSL( weighted = gsl_vector_complex_calloc(a->size) );
226 XLAL_CALLGSL( gsl_vector_complex_memcpy(weighted, a) );
227
228 /* multiply vector by weight */
229 if ( weight->size == 1 ){ /* just a single weight to scale with */
230 XLAL_CALLGSL( gsl_blas_zdscal(gsl_vector_get(weight, 0), weighted) );
231 }
232 else if ( weight->size == a->size ){
233 gsl_vector_view rview, iview;
234
235 XLAL_CALLGSL( rview = gsl_vector_complex_real(weighted) );
236 XLAL_CALLGSL( iview = gsl_vector_complex_imag(weighted) );
237
238 XLAL_CALLGSL( gsl_vector_mul(&rview.vector, weight) );
239 XLAL_CALLGSL( gsl_vector_mul(&iview.vector, weight) );
240 }
241 else{
242 XLAL_PRINT_ERROR( "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
243 }
244
245 /* get dot product (taking the complex conjugate of the first vector) */
246 XLAL_CALLGSL( gsl_blas_zdotc(weighted, b, &dp) );
247 XLAL_CALLGSL( gsl_vector_complex_free(weighted) );
248
249 return dp;
250}
251
252
253/** \brief Normalise a real vector with a given weighting
254 *
255 * @param[in] weight The weighting(s) in the normalisation (e.g. time of frequency step(s) between points)
256 * @param[in] a The vector to be normalise (this will be change by the function to return the
257 * normalised vector.
258 */
259void normalise(const gsl_vector *weight, gsl_vector *a){
260 double norm;
261
262 if ( weight->size == 1 ){
263 XLAL_CALLGSL( norm = gsl_blas_dnrm2(a) ); /* use GSL normalisation calculation function */
264 XLAL_CALLGSL( gsl_vector_scale(a, 1./(norm*sqrt(gsl_vector_get(weight, 0)))) );
265 }
266 else if ( weight->size == a->size ){
267 norm = 1./sqrt(weighted_dot_product(weight, a, a));
268 XLAL_CALLGSL( gsl_vector_scale(a, norm) );
269 }
270 else{
271 XLAL_ERROR_VOID( XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
272 }
273}
274
275
276/** \brief Normalise a complex vector with a given (real) weighting
277 *
278 * @param[in] weight The weighting(s) in the normalisation (e.g. time of frequency step(s) between points)
279 * @param[in] a The vector to be normalised (this will be change by the function to return the
280 * normalised vector).
281 */
282void complex_normalise(const gsl_vector *weight, gsl_vector_complex *a){
283 double norm;
284
285 if ( weight->size == 1 ){
286 XLAL_CALLGSL( norm = gsl_blas_dznrm2(a) ); /* use GSL normalisation calculation function */
287 XLAL_CALLGSL( gsl_blas_zdscal(1./(norm*sqrt(gsl_vector_get(weight, 0))), a) );
288 }
289 else if ( weight->size == a->size ){
290 norm = 1./sqrt(gsl_complex_abs(complex_weighted_dot_product(weight, a, a)));
291 XLAL_CALLGSL( gsl_blas_zdscal(norm, a) );
292 }
293 else{
294 XLAL_ERROR_VOID( XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
295 }
296}
297
298
299/** \brief Get normalisation constant for a real vector
300 *
301 * @param[in] weight The weighting(s) in the normalisation (e.g. time of frequency step(s) between points)
302 * @param[in] a The vector to calculate the normalisation constant for
303 *
304 * @return The normalisation
305 */
306double normalisation(const gsl_vector *weight, gsl_vector *a){
307 double norm;
308
309 if ( weight->size == 1 ){
310 XLAL_CALLGSL( norm = gsl_blas_dnrm2(a) ); /* use GSL normalisation calculation function */
311 norm *= sqrt(gsl_vector_get(weight, 0));
312 }
313 else if ( weight->size == a->size ){
314 norm = sqrt(fabs(weighted_dot_product(weight, a, a)));
315 }
316 else{
317 XLAL_ERROR_REAL8( XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
318 }
319
320 return norm;
321}
322
323
324/** \brief Get normalisation constant for a complex vector
325 *
326 * @param[in] weight The weighting(s) in the normalisation (e.g. time of frequency step(s) between points)
327 * @param[in] a The vector to calculate the normalisation constant for
328 *
329 * @return The normalisation
330 */
331double complex_normalisation(const gsl_vector *weight, gsl_vector_complex *a){
332 double norm;
333
334 if ( weight->size == 1 ){
335 XLAL_CALLGSL( norm = gsl_blas_dznrm2(a) ); /* use GSL normalisation calculation function */
336 norm *= sqrt(gsl_vector_get(weight, 0));
337 }
338 else if ( weight->size == a->size ){
339 norm = sqrt(gsl_complex_abs(complex_weighted_dot_product(weight, a, a)));
340 }
341 else{
342 XLAL_ERROR_REAL8( XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
343 }
344
345 return norm;
346}
347
348
349/** \brief Normalise the set of training waveforms
350 *
351 * This function will normalise a set of training waveforms. This will be used within the
352 * \c LALInferenceCreateREAL8OrthonormalBasis function.
353 *
354 * @param[in] weight The e.g. time/frequency step in the waveforms used to normalise the waveforms
355 * @param[in] TS The training set to be normalised.
356 */
357void normalise_training_set(gsl_vector *weight, gsl_matrix *TS){
358 gsl_vector_view rowview;
359 size_t i = 0;
360 for ( i=0; i<TS->size1; i++ ){
361 XLAL_CALLGSL( rowview = gsl_matrix_row(TS, i) );
362 normalise(weight, &rowview.vector);
363 }
364}
365
366
367/** \brief Normalise the set of complex training waveforms
368 *
369 * This function will normalise a set of complex training waveforms. This will be used within the
370 * \c LALInferenceCreateCOMPLEX16OrthonormalBasis function.
371 *
372 * @param[in] weight The e.g. time/frequency step in the waveforms used to normalise the waveforms
373 * @param[in] TS The training set to be normalised.
374 */
375void complex_normalise_training_set(gsl_vector *weight, gsl_matrix_complex *TS){
376 gsl_vector_complex_view rowview;
377 size_t i = 0;
378
379 for ( i=0; i<TS->size1; i++ ){
380 XLAL_CALLGSL( rowview = gsl_matrix_complex_row(TS, i) );
381 complex_normalise(weight, &rowview.vector);
382 }
383}
384
385
386/** \brief Get the interpolant of a reduced basis set
387 *
388 * This is used internally by \c LALInferenceCreateREALROQInterpolant when
389 * iteratively calculating the interpolation matrix.
390 *
391 * @param[in] V The matrix containing the basis vector points at the current interpolation nodes
392 * @param[in] RB The set of basis vectors
393 *
394 * @return The interpolant matrix
395 */
396REAL8Array *B_matrix(gsl_matrix *V, gsl_matrix *RB){
397 /* get inverse of V */
398 size_t n = V->size1;
399 gsl_matrix *invV, *LU;
400 gsl_permutation *p;
401 gsl_matrix_view subRB;
402 REAL8Array *B = NULL;
403 UINT4Vector *dims = NULL;
404
405 XLAL_CALLGSL( invV = gsl_matrix_alloc(n, n) );
406 int signum;
407
408 /* use LU decomposition to get inverse */
409 XLAL_CALLGSL( LU = gsl_matrix_alloc(n, n) );
410 XLAL_CALLGSL( gsl_matrix_memcpy(LU, V) );
411
412 XLAL_CALLGSL( p = gsl_permutation_alloc(n) );
413 XLAL_CALLGSL( gsl_linalg_LU_decomp(LU, p, &signum) );
414 XLAL_CALLGSL( gsl_linalg_LU_invert(LU, p, invV) );
415 XLAL_CALLGSL( gsl_permutation_free(p) );
416 XLAL_CALLGSL( gsl_matrix_free(LU) );
417
418 /* get B matrix */
419 dims = XLALCreateUINT4Vector( 2 );
420 dims->data[0] = n;
421 dims->data[1] = RB->size2;
422 B = XLALCreateREAL8Array( dims );
424 gsl_matrix_view Bview;
425 Bview = gsl_matrix_view_array(B->data, n, RB->size2);
426 XLAL_CALLGSL( subRB = gsl_matrix_submatrix(RB, 0, 0, n, RB->size2) );
427 XLAL_CALLGSL( gsl_blas_dgemm(CblasTrans, CblasNoTrans, 1.0, invV, &subRB.matrix, 0., &Bview.matrix) );
428
429 XLAL_CALLGSL( gsl_matrix_free(invV) );
430
431 return B;
432}
433
434
435/** \brief Get the interpolant of a complex reduced basis set
436 *
437 * This is used internally by \c LALInferenceCreateCOMPLEXROQInterpolant when
438 * iteratively calculating the interpolation matrix.
439 *
440 * @param[in] V The matrix containing the basis vector points at the current interpolation nodes
441 * @param[in] RB The set of basis vectors
442 *
443 * @return The interpolant matrix
444 */
445COMPLEX16Array *complex_B_matrix(gsl_matrix_complex *V, gsl_matrix_complex *RB){
446 /* get inverse of V */
447 size_t n = V->size1;
448 gsl_matrix_complex *invV, *LU;
449 gsl_permutation *p;
450 gsl_matrix_complex_view subRB;
451 COMPLEX16Array *B = NULL;
452 UINT4Vector *dims = NULL;
453
454 XLAL_CALLGSL( invV = gsl_matrix_complex_alloc(n, n) );
455 int signum;
456
457 /* use LU decomposition to get inverse */
458 XLAL_CALLGSL( LU = gsl_matrix_complex_alloc(n, n) );
459 XLAL_CALLGSL( gsl_matrix_complex_memcpy(LU, V) );
460
461 XLAL_CALLGSL( p = gsl_permutation_alloc(n) );
462 XLAL_CALLGSL( gsl_linalg_complex_LU_decomp(LU, p, &signum) );
463 XLAL_CALLGSL( gsl_linalg_complex_LU_invert(LU, p, invV) );
464 XLAL_CALLGSL( gsl_permutation_free(p) );
465 XLAL_CALLGSL( gsl_matrix_complex_free(LU) );
466
467 /* get B matrix */
468 dims = XLALCreateUINT4Vector( 2 );
469 dims->data[0] = n;
470 dims->data[1] = RB->size2;
471 B = XLALCreateCOMPLEX16Array( dims );
473 gsl_matrix_complex_view Bview;
474 Bview = gsl_matrix_complex_view_array((double *)B->data, n, RB->size2);
475 XLAL_CALLGSL( subRB = gsl_matrix_complex_submatrix(RB, 0, 0, n, RB->size2) );
476 XLAL_CALLGSL( gsl_blas_zgemm(CblasTrans, CblasNoTrans, GSL_COMPLEX_ONE, invV, &subRB.matrix, GSL_COMPLEX_ZERO, &Bview.matrix) );
477
478 XLAL_CALLGSL( gsl_matrix_complex_free(invV) );
479
480 return B;
481}
482
483/** \brief Get the index of the maximum absolute value for a complex vector
484 *
485 * @param[in] c A complex vector
486 *
487 * @return The index of the maximum absolute value of that vector
488 */
489int complex_vector_maxabs_index( gsl_vector_complex *c ){
490 double maxv = -INFINITY, absval = 0.;
491 int idx = 0;
492 size_t i = 0;
493
494 for ( i=0; i<c->size; i++ ){
495 XLAL_CALLGSL( absval = gsl_complex_abs(gsl_vector_complex_get(c, i)) );
496
497 if ( absval > maxv ){
498 maxv = absval;
499 idx = (int)i;
500 }
501 }
502
503 return idx;
504}
505
506
507/** \brief Modified Gram-Schmidt algorithm for complex data
508 *
509 * A modified Gram-Schmidt algorithm taken from the
510 * <a href="https://bitbucket.org/sfield83/greedycpp">greedycpp</a> code.
511 *
512 * @param[out] ru A 1-by-(\c dim_RB + 1) complex vector returning a slice of the R matrix
513 * @param[out] ortho_basis A complex vector returning the orthogonal basis vector
514 * @param[in] RB_space A complex matrix containing the existing set of orthonormal basis vectors
515 * @param[in] wQuad A vector of weights for the inner products
516 * @param[in] dim_RB The number of elements in the current \c RB_space
517 */
518void modified_gs_complex(gsl_vector_complex *ru,
519 gsl_vector_complex *ortho_basis,
520 const gsl_matrix_complex *RB_space,
521 const gsl_vector *wQuad,
522 const int dim_RB){
523 INT4 quad_num = RB_space->size2;
524 gsl_complex L2_proj;
525 gsl_vector_complex *basis;
526
527 basis = gsl_vector_complex_alloc(quad_num);
528
529 /* if not done, R matrix fills up below diagonal with .5 instead of 0 */
530 gsl_vector_complex_set_zero(ru);
531
532 for(INT4 i = 0; i < dim_RB; i++){
533 gsl_matrix_complex_get_row(basis, RB_space, i);
534
535 /* ortho_basis = ortho_basis - L2_proj*basis; */
536 L2_proj = complex_weighted_dot_product(wQuad, basis, ortho_basis);
537 gsl_vector_complex_set(ru, i, L2_proj);
538 gsl_vector_complex_scale(basis, L2_proj); /* basis <- basis*L2_proj */
539 gsl_vector_complex_sub(ortho_basis, basis); /* ortho <- ortho - basis */
540 }
541
542 double nrm = complex_normalisation(wQuad, ortho_basis);
543 gsl_complex nrmc;
544 GSL_SET_COMPLEX(&nrmc, nrm, 0.0);
545 gsl_vector_complex_set(ru, dim_RB, nrmc);
546
547 complex_normalise(wQuad, ortho_basis);
548
549 gsl_vector_complex_free(basis);
550}
551
552
553/** \brief Modified Gram-Schmidt algorithm for real data
554 *
555 * A modified Gram-Schmidt algorithm taken from the
556 * <a href="https://bitbucket.org/sfield83/greedycpp">greedycpp</a> code.
557 *
558 * @param[out] ru A 1-by-(\c dim_RB + 1) vector returning a slice of the R matrix
559 * @param[out] ortho_basis A vector returning the orthogonal basis vector
560 * @param[in] RB_space A matrix containing the existing set of orthonormal basis vectors
561 * @param[in] wQuad A vector of weights for the inner products
562 * @param[in] dim_RB The number of elements in the current \c RB_space
563 */
564void modified_gs(gsl_vector *ru,
565 gsl_vector *ortho_basis,
566 const gsl_matrix *RB_space,
567 const gsl_vector *wQuad,
568 const int dim_RB){
569 INT4 quad_num = RB_space->size2;
570 REAL8 L2_proj;
571 gsl_vector *basis;
572
573 basis = gsl_vector_alloc(quad_num);
574
575 /* if not done, R matrix fills up below diagonal with .5 instead of 0 */
576 gsl_vector_set_zero(ru);
577
578 for(INT4 i = 0; i < dim_RB; i++){
579 gsl_matrix_get_row(basis, RB_space, i);
580
581 /* ortho_basis = ortho_basis - L2_proj*basis; */
582 L2_proj = weighted_dot_product(wQuad, basis, ortho_basis);
583 gsl_vector_set(ru, i, L2_proj);
584 gsl_vector_scale(basis, L2_proj); /* basis <- basis*L2_proj */
585 gsl_vector_sub(ortho_basis, basis); /* ortho <- ortho - basis */
586 }
587
588 double nrm = normalisation(wQuad, ortho_basis);
589 gsl_vector_set(ru, dim_RB, nrm);
590
591 normalise(wQuad, ortho_basis);
592
593 gsl_vector_free(basis);
594}
595
596
597/** \brief Iterated modified Gram-Schmidt algorithm for complex data
598 *
599 * An iterated modified Gram-Schmidt algorithm taken from the
600 * <a href="https://bitbucket.org/sfield83/greedycpp">greedycpp</a> code. This uses the method
601 * given in \cite Hoffmann1989
602 *
603 * @param[out] ru A complex 1-by-(\c dim_RB + 1) vector returning a slice of the R matrix
604 * @param[out] ortho_basis A complex vector returning the orthogonal basis vector
605 * @param[in] RB_space A complex matrix containing the existing set of orthonormal basis vectors
606 * @param[in] wQuad A vector of weights for the inner products
607 * @param[in] dim_RB The number of elements in the current \c RB_space
608 */
609void iterated_modified_gm_complex(gsl_vector_complex *ru,
610 gsl_vector_complex *ortho_basis,
611 const gsl_matrix_complex *RB_space,
612 const gsl_vector *wQuad,
613 const int dim_RB){
614 REAL8 ortho_condition = .5; /* hard coded IMGS stopping condition */
615
616 INT4 quad_num = RB_space->size2;
617 INT4 r_size = ru->size;
618 REAL8 nrm_prev = complex_normalisation(wQuad, ortho_basis);
619 UINT4 flag = 0, iter = 0;
620 gsl_vector_complex *e,*r_last;
621 REAL8 nrm_current = 0.;
622 gsl_complex nrmc_current;
623
624 /* allocate memory */
625 e = gsl_vector_complex_alloc(quad_num);
626 r_last = gsl_vector_complex_alloc(r_size);
627
628 gsl_vector_complex_memcpy(e,ortho_basis);
629 complex_normalise(wQuad, e);
630
631 /* if not done, R matrix fills up below diagonal with .5 instead of 0 */
632 gsl_vector_complex_set_zero(ru);
633
634 while( !flag ){
635 gsl_vector_complex_memcpy(ortho_basis, e);
636 gsl_vector_complex_set_zero(r_last);
637
638 modified_gs_complex(r_last, ortho_basis, RB_space, wQuad, dim_RB);
639
640 gsl_vector_complex_add(ru, r_last);
641 nrmc_current = gsl_vector_complex_get(r_last, dim_RB);
642 nrm_current = GSL_REAL(nrmc_current);
643
644 gsl_vector_complex_scale(ortho_basis, nrmc_current);
645
646 if( nrm_current/nrm_prev <= ortho_condition ) {
647 nrm_prev = nrm_current;
648 iter = iter + 1;
649 gsl_vector_complex_memcpy(e, ortho_basis);
650 }
651 else{ flag = 1; }
652
653 nrm_current = complex_normalisation(wQuad, ortho_basis);
654 GSL_SET_COMPLEX(&nrmc_current, nrm_current, 0.0);
655 gsl_vector_complex_set(ru, dim_RB, nrmc_current);
656
657 complex_normalise(wQuad, ortho_basis);
658 }
659
660 gsl_vector_complex_free(e);
661 gsl_vector_complex_free(r_last);
662}
663
664
665/** \brief Iterated modified Gram-Schmidt algorithm for real data
666 *
667 * An iterated modified Gram-Schmidt algorithm taken from the
668 * <a href="https://bitbucket.org/sfield83/greedycpp">greedycpp</a> code. This uses the method
669 * given in \cite Hoffmann1989
670 *
671 * @param[out] ru A 1-by-(\c dim_RB + 1) vector returning a slice of the R matrix
672 * @param[out] ortho_basis A vector returning the orthogonal basis vector
673 * @param[in] RB_space A matrix containing the existing set of orthonormal basis vectors
674 * @param[in] wQuad A vector of weights for the inner products
675 * @param[in] dim_RB The number of elements in the current \c RB_space
676 */
677void iterated_modified_gm(gsl_vector *ru,
678 gsl_vector *ortho_basis,
679 const gsl_matrix *RB_space,
680 const gsl_vector *wQuad,
681 const int dim_RB){
682 REAL8 ortho_condition = .5; /* hard coded IMGS stopping condition */
683
684 INT4 quad_num = RB_space->size2;
685 INT4 r_size = ru->size;
686 REAL8 nrm_prev = normalisation(wQuad, ortho_basis);
687 UINT4 flag = 0, iter = 0;
688 gsl_vector *e,*r_last;
689 REAL8 nrm_current = 0.;
690
691 /* allocate memory */
692 e = gsl_vector_alloc(quad_num);
693 r_last = gsl_vector_alloc(r_size);
694
695 gsl_vector_memcpy(e,ortho_basis);
696 normalise(wQuad, e);
697
698 /* if not done, R matrix fills up below diagonal with .5 instead of 0 */
699 gsl_vector_set_zero(ru);
700
701 while( !flag ){
702 gsl_vector_memcpy(ortho_basis, e);
703 gsl_vector_set_zero(r_last);
704
705 modified_gs(r_last, ortho_basis, RB_space, wQuad, dim_RB);
706
707 gsl_vector_add(ru, r_last);
708 nrm_current = gsl_vector_get(r_last, dim_RB);
709
710 gsl_vector_scale(ortho_basis, nrm_current);
711
712 if( nrm_current/nrm_prev <= ortho_condition ) {
713 nrm_prev = nrm_current;
714 iter = iter + 1;
715 gsl_vector_memcpy(e, ortho_basis);
716 }
717 else{ flag = 1; }
718
719 nrm_current = normalisation(wQuad, ortho_basis);
720 gsl_vector_set(ru, dim_RB, nrm_current);
721
722 normalise(wQuad, ortho_basis);
723 }
724
725 gsl_vector_free(e);
726 gsl_vector_free(r_last);
727}
728
729/* main functions */
730
731/**
732 * \brief Create a orthonormal basis set from a training set of real waveforms
733 *
734 * Given a \c gsl_matrix containing a training set of real waveforms (where the waveforms
735 * are created at time or frequency steps seperated by \c delta) an orthonormal basis
736 * will be generated using the greedy binning Algorithm 1 of \cite FGHKT2014 . The stopping
737 * criteria for the algorithm is controlled by the \c tolerance value, which defined the
738 * maximum residual between the current basis set (at a given iteration) and the training
739 * set (and example tolerance is \f$10^{-12}\f$). In this function the training set will be
740 * normalised, so the input \c TS will be modified.
741 *
742 * If the \c RBin value is \c NULL then a new reduced basis will be formed from the given
743 * training set. However, if \c RBin already contains a previously produced basis, then this
744 * basis will be enriched with bases if possible using the new training set. <b>NOTE</b>: when
745 * using small tolerances enriching the basis in this way can lead to numerical precision issues,
746 * so in general you should use \c LALInferenceEnrichREAL8Basis for enrichment.
747 *
748 * @param[out] RBin A \c REAL8Array to return the reduced basis.
749 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
750 * This can be a vector containing just one value.
751 * @param[in] tolerance The tolerance used as a stopping criteria for the basis generation.
752 * @param[in] TS A \c REAL8Array matrix containing the complex training set, where the number of
753 * waveforms in the training set is given by the rows and the waveform points by the columns. This
754 * will be modified by this function, as the training set will be normalised.
755 * @param[out] greedypoints A \c UINT4Vector to return the indices of the training set rows that
756 * have been used to form the reduced basis.
757 *
758 * @return A \c REAL8 with the maximum projection error for the final reduced basis.
759 *
760 * \sa LALInferenceEnrichREAL8Basis
761 */
763 const REAL8Vector *delta,
764 REAL8 tolerance,
765 REAL8Array **TS,
766 UINT4Vector **greedypoints){
767 REAL8Array *ts = NULL;
768 ts = *TS; // pointer to training set
769
770 size_t cols = ts->dimLength->data[1], rows = ts->dimLength->data[0];
771
772 /* view of training set */
773 gsl_matrix_view TSview;
774 XLAL_CALLGSL( TSview = gsl_matrix_view_array((double *)ts->data, rows, cols) );
775
776 size_t max_RB = rows;
777
778 //REAL8 greedy_err[max_RB]; /* approximate error */
779 UINT4Vector *gpts = NULL;
780 gpts = XLALCreateUINT4Vector(max_RB); /* selected greedy points (row selection) */
781 *greedypoints = gpts;
782
783 REAL8 worst_err; /* errors in greedy sweep */
784 UINT4 worst_app = 0; /* worst error stored */
785 REAL8 tmpc; /* worst error temp */
786
787 gsl_vector *ts_el, *last_rb, *ortho_basis, *ru;
788 gsl_matrix *R_matrix;
789 REAL8 A_row_norms2[rows]; // || A(i,:) ||^2
790 REAL8 projection_norms2[rows];
791 REAL8 errors[rows]; // approximation errors at i^{th} sweep
792
793 REAL8Array *RB = NULL;
794 UINT4Vector *dims = NULL;
795 gsl_matrix_view RBview;
796
797 /* this memory should be freed here */
798 ts_el = gsl_vector_alloc(cols);
799 last_rb = gsl_vector_alloc(cols);
800 ortho_basis = gsl_vector_alloc(cols);
801 ru = gsl_vector_alloc(max_RB);
802
803 //project_coeff = gsl_matrix_alloc(max_RB,rows);
804 REAL8 projection_coeff;
805 R_matrix = gsl_matrix_alloc(max_RB, max_RB);
806
807 /* initialise projection norms with zeros */
808 for(size_t i=0; i<rows; ++i){ projection_norms2[i] = 0; }
809
810 gsl_vector_view deltaview;
811 XLAL_CALLGSL( deltaview = gsl_vector_view_array(delta->data, delta->length) );
812
813 /* normalise the training set */
814 normalise_training_set(&deltaview.vector, &TSview.matrix);
815
816 /* compute norm of each training space element */
817 for(size_t i=0; i<rows; ++i) {
818 gsl_matrix_get_row(ts_el, &TSview.matrix, i);
819 A_row_norms2[i] = normalisation(&deltaview.vector, ts_el);
820 }
821
822 /* initialize algorithm with first training set value */
823 dims = XLALCreateUINT4Vector( 2 );
824 dims->data[0] = 1; /* one row */
825 dims->data[1] = cols;
826 RB = XLALCreateREAL8Array( dims );
827 *RBin = RB;
828
829 XLAL_CALLGSL( RBview = gsl_matrix_view_array((double*)RB->data, 1, cols) );
830 gsl_matrix_get_row(ts_el, &TSview.matrix, 0);
831 gsl_matrix_set_row(&RBview.matrix, 0, ts_el);
832 tmpc = 1.;
833 gsl_matrix_set(R_matrix, 0, 0, tmpc); // assumes normalized solutions
834
835 gpts->data[0] = 0;
836 UINT4 dim_RB = 1;
837 //greedy_err[0] = 1.0;
838
839 /* loop to find reduced basis */
840 while( 1 ){
841 gsl_matrix_get_row(last_rb, &RBview.matrix, dim_RB-1); /* previous basis */
842
843 /* Compute overlaps of pieces of training set with rb_new */
844 for(size_t i = 0; i < rows; i++){
845 gsl_matrix_get_row(ts_el, &TSview.matrix, i);
846 projection_coeff = weighted_dot_product(&deltaview.vector, last_rb, ts_el);
847 projection_norms2[i] += (projection_coeff*projection_coeff);
848 errors[i] = A_row_norms2[i] - projection_norms2[i];
849 }
850
851 /* find worst represented training set element, and add to basis */
852 worst_err = 0.0;
853 for(size_t i = 0; i < rows; i++) {
854 if(worst_err < errors[i]) {
855 worst_err = errors[i];
856 worst_app = i;
857 }
858 }
859
860 // This block exists for cases when the reduced basis is being used during enrichment.
861 // It exists to make sure that all new training elements get added to the reduced basis
862 // even if their errors are very small.
863 if ( tolerance == 0. ){
864 // check if worst_app is already in gpts
865 UINT4 idxexists = 0;
866 for(size_t i = 0; i < dim_RB; i++) {
867 if ( worst_app == gpts->data[i] ){
868 idxexists = 1;
869 break;
870 }
871 }
872
873 // if it is, then just find the first index that is not in gpts already
874 if ( idxexists ){
875 UINT4 newidxexists = 0;
876 for (size_t i = 0; i < rows; i++){
877 newidxexists = 0;
878 for (size_t j = 0; j < dim_RB; j++){
879 if ( i == gpts->data[j] ){
880 newidxexists = 1;
881 break;
882 }
883 }
884 if ( !newidxexists ){
885 worst_app = i;
886 break;
887 }
888 }
889 }
890 }
891 //////////// end check ////////////
892
893 gpts->data[dim_RB] = worst_app;
894
895 /* add worst approximated solution to basis set */
896 gsl_matrix_get_row(ortho_basis, &TSview.matrix, worst_app);
897 iterated_modified_gm(ru, ortho_basis, &RBview.matrix, &deltaview.vector, dim_RB); /* use IMGS */
898
899 /* check normalisation of generated orthogonal basis is not NaN (cause by a new orthogonal basis
900 having zero residual with the current basis) - if this is the case do not add the new basis. */
901 if ( gsl_isnan(gsl_vector_get(ru, dim_RB)) ){ break; }
902
903 /* add to reduced basis */
904 dims->data[0] = dim_RB+1; /* add row */
905 RB = XLALResizeREAL8Array( RB, dims );
906
907 /* add on next basis */
908 XLAL_CALLGSL( RBview = gsl_matrix_view_array((double*)RB->data, dim_RB+1, cols) );
909
910 gsl_matrix_set_row(&RBview.matrix, dim_RB, ortho_basis);
911 gsl_matrix_set_row(R_matrix, dim_RB, ru);
912
913 ++dim_RB;
914
915 /* decide if another greedy sweep is needed */
916 if( (dim_RB == max_RB) || (worst_err < tolerance) || (rows == dim_RB) ){ break; }
917 }
918
919 gpts = XLALResizeUINT4Vector( gpts, dim_RB );
920
922 gsl_vector_free(ts_el);
923 gsl_vector_free(last_rb);
924 gsl_vector_free(ortho_basis);
925 gsl_vector_free(ru);
926 gsl_matrix_free(R_matrix);
927
928 return worst_err;
929}
930
931
932/**
933 * \brief Create a orthonormal basis set from a training set of complex waveforms
934 *
935 * Given a \c gsl_matrix containing a training set \c TS of complex waveforms (where the waveforms
936 * are created at time or frequency steps seperated by \c delta) an orthonormal basis
937 * will be generated using the greedy binning Algorithm 1 of \cite FGHKT2014 . The stopping
938 * criteria for the algorithm is controlled by the \c tolerance value, which is defined the
939 * maximum residual between the current basis set (at a given iteration) and the training
940 * set (and example tolerance is \f$10^{-12}\f$). In this function the training set will be
941 * normalised, so the input \c TS will be modified.
942 *
943 * If the \c RBin value is \c NULL then a new reduced basis will be formed from the given
944 * training set. However, if \c RBin already contains a previously produced basis, then this
945 * basis will be enriched with bases if possible using the new training set. <b>NOTE</b>: when
946 * using small tolerances enriching the basis in this way can lead to numerical precision issues,
947 * so in general you should use \c LALInferenceEnrichCOMPLEX16Basis for enrichment.
948 *
949 * Note that in this function we have to cast the \c COMPLEX16 array as a double to use
950 * \c gsl_matrix_view_array, which assume that the data is passed as a double array with
951 * memory laid out so that adjacent double memory blocks hold the corresponding real and
952 * imaginary parts.
953 *
954 * @param[out] RBin A \c COMPLEX16Array to return the reduced basis.
955 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
956 * This can be a vector containing just one value.
957 * @param[in] tolerance The tolerance used as a stopping criteria for the basis generation.
958 * @param[in] TS A \c COMPLEX16Array matrix containing the complex training set, where the number
959 * of waveforms in the training set is given by the rows and the waveform points by the columns.
960 * This will be modified by this function, as the training set will be normalised.
961 * @param[out] greedypoints A \c UINT4Vector to return the indices of the training set rows that
962 * have been used to form the reduced basis.
963 *
964 * @return A \c REAL8 with the maximum projection error for the final reduced basis.
965 *
966 * \sa LALInferenceEnrichCOMPLEX16Basis
967 */
969 const REAL8Vector *delta,
970 REAL8 tolerance,
971 COMPLEX16Array **TS,
972 UINT4Vector **greedypoints){
973 COMPLEX16Array *ts = NULL;
974 ts = *TS; // pointer to training set
975
976 size_t cols = ts->dimLength->data[1], rows = ts->dimLength->data[0];
977
978 /* view of training set */
979 gsl_matrix_complex_view TSview;
980 XLAL_CALLGSL( TSview = gsl_matrix_complex_view_array((double *)ts->data, rows, cols) );
981
982 size_t max_RB = rows;
983
984 UINT4Vector *gpts = NULL;
985 gpts = XLALCreateUINT4Vector(max_RB); /* selected greedy points (row selection) */
986 *greedypoints = gpts;
987
988 REAL8 worst_err; /* errors in greedy sweep */
989 UINT4 worst_app = 0; /* worst error stored */
990 gsl_complex tmpc; /* worst error temp */
991
992 gsl_vector_complex *ts_el, *last_rb, *ortho_basis, *ru;
993 gsl_matrix_complex *R_matrix;
994 REAL8 A_row_norms2[rows]; // || A(i,:) ||^2
995 REAL8 projection_norms2[rows];
996 REAL8 errors[rows]; // approximation errors at i^{th} sweep
997
998 COMPLEX16Array *RB = NULL;
999 UINT4Vector *dims = NULL;
1000 gsl_matrix_complex_view RBview;
1001
1002 /* this memory should be freed here */
1003 ts_el = gsl_vector_complex_alloc(cols);
1004 last_rb = gsl_vector_complex_alloc(cols);
1005 ortho_basis = gsl_vector_complex_alloc(cols);
1006 ru = gsl_vector_complex_alloc(max_RB);
1007
1008 //project_coeff = gsl_matrix_complex_alloc(max_RB,rows);
1009 gsl_complex projection_coeff;
1010 R_matrix = gsl_matrix_complex_alloc(max_RB, max_RB);
1011
1012 /* initialise projection norms with zeros */
1013 for(size_t i=0; i<rows; ++i){ projection_norms2[i] = 0; }
1014
1015 gsl_vector_view deltaview;
1016 XLAL_CALLGSL( deltaview = gsl_vector_view_array(delta->data, delta->length) );
1017
1018 /* normalise the training set */
1019 complex_normalise_training_set(&deltaview.vector, &TSview.matrix);
1020
1021 /* compute norm of each training space element */
1022 for(size_t i=0; i<rows; ++i) {
1023 gsl_matrix_complex_get_row(ts_el, &TSview.matrix, i);
1024 A_row_norms2[i] = complex_normalisation(&deltaview.vector, ts_el);
1025 }
1026
1027 /* initialize algorithm with first training set value */
1028 dims = XLALCreateUINT4Vector( 2 );
1029 dims->data[0] = 1; /* one row */
1030 dims->data[1] = cols;
1031 RB = XLALCreateCOMPLEX16Array( dims );
1032 *RBin = RB;
1033
1034 XLAL_CALLGSL( RBview = gsl_matrix_complex_view_array((double*)RB->data, 1, cols) );
1035 gsl_matrix_complex_get_row(ts_el, &TSview.matrix, 0);
1036 gsl_matrix_complex_set_row(&RBview.matrix, 0, ts_el);
1037 GSL_SET_COMPLEX(&tmpc, 1.0, 0.0);
1038 gsl_matrix_complex_set(R_matrix, 0, 0, tmpc); // assumes normalized solutions
1039
1040 gpts->data[0] = 0;
1041 UINT4 dim_RB = 1;
1042
1043 /* loop to find reduced basis */
1044 while( 1 ){
1045 gsl_matrix_complex_get_row(last_rb, &RBview.matrix, dim_RB-1); /* previous basis */
1046
1047 /* Compute overlaps of pieces of training set with rb_new */
1048 for(size_t i = 0; i < rows; i++){
1049 gsl_matrix_complex_get_row(ts_el, &TSview.matrix, i);
1050 projection_coeff = complex_weighted_dot_product(&deltaview.vector, last_rb, ts_el);
1051 projection_norms2[i] += (GSL_REAL(projection_coeff)*GSL_REAL(projection_coeff) + GSL_IMAG(projection_coeff)*GSL_IMAG(projection_coeff));
1052 errors[i] = A_row_norms2[i] - projection_norms2[i];
1053 }
1054
1055 /* find worst represented training set element, and add to basis */
1056 worst_err = 0.0;
1057 for(size_t i = 0; i < rows; i++) {
1058 if(worst_err < errors[i]) {
1059 worst_err = errors[i];
1060 worst_app = i;
1061 }
1062 }
1063
1064 // This block exists for cases when the reduced basis is being used during enrichment.
1065 // It exists to make sure that all new training elements get added to the reduced basis
1066 // even if their errors are very small.
1067 if ( tolerance == 0. ){
1068 // check if worst_app is already in gpts
1069 UINT4 idxexists = 0;
1070 for(size_t i = 0; i < dim_RB; i++) {
1071 if ( worst_app == gpts->data[i] ){
1072 idxexists = 1;
1073 break;
1074 }
1075 }
1076
1077 // if it is, then just find the first index that is not in gpts already
1078 if ( idxexists ){
1079 UINT4 newidxexists = 0;
1080 for (size_t i = 0; i < rows; i++){
1081 newidxexists = 0;
1082 for (size_t j = 0; j < dim_RB; j++){
1083 if ( i == gpts->data[j] ){
1084 newidxexists = 1;
1085 break;
1086 }
1087 }
1088 if ( !newidxexists ){
1089 worst_app = i;
1090 break;
1091 }
1092 }
1093 }
1094 }
1095 //////////// end check ////////////
1096
1097 gpts->data[dim_RB] = worst_app;
1098
1099 /* add worst approximated solution to basis set */
1100 gsl_matrix_complex_get_row(ortho_basis, &TSview.matrix, worst_app);
1101 iterated_modified_gm_complex(ru, ortho_basis, &RBview.matrix, &deltaview.vector, dim_RB); /* use IMGS */
1102
1103 /* check normalisation of generated orthogonal basis is not NaN (cause by a new orthogonal basis
1104 having zero residual with the current basis) - if this is the case do not add the new basis. */
1105 gsl_complex norm = gsl_vector_complex_get(ru, dim_RB);
1106 if ( gsl_isnan(GSL_REAL(norm)) ){ break; }
1107
1108 /* add to reduced basis */
1109 dims->data[0] = dim_RB+1; /* add row */
1110 RB = XLALResizeCOMPLEX16Array( RB, dims );
1111
1112 /* add on next basis */
1113 XLAL_CALLGSL( RBview = gsl_matrix_complex_view_array((double*)RB->data, dim_RB+1, cols) );
1114
1115 gsl_matrix_complex_set_row(&RBview.matrix, dim_RB, ortho_basis);
1116 gsl_matrix_complex_set_row(R_matrix, dim_RB, ru);
1117
1118 ++dim_RB;
1119
1120 /* decide if another greedy sweep is needed */
1121 if( (dim_RB == max_RB) || (worst_err < tolerance) || (rows == dim_RB) ){ break; }
1122 }
1123
1124 gpts = XLALResizeUINT4Vector( gpts, dim_RB );
1125
1127 gsl_vector_complex_free(ts_el);
1128 gsl_vector_complex_free(last_rb);
1129 gsl_vector_complex_free(ortho_basis);
1130 gsl_vector_complex_free(ru);
1131 gsl_matrix_complex_free(R_matrix);
1132
1133 return worst_err;
1134}
1135
1136
1137/**
1138 * \brief Validate the real reduced basis against another set of waveforms
1139 *
1140 * This function projects a set of waveforms onto the reduced basis and
1141 * checks that the residuals are within a given tolerance. It returns
1142 * the projection errors.
1143 *
1144 * Note that the projection error returned are the square of the residual
1145 * errors, as is used as the criterion for adding new bases in the reduced
1146 * basis generation function \c LALInferenceGenerateREAL8OrthonormalBasis.
1147 * This is different to the \c validation.cpp code in <a href="https://bitbucket.org/sfield83/greedycpp">greedycpp</a>,
1148 * which returns the square root of the value we return.
1149 *
1150 * @param[out] projerr The projection errors for each test waveform.
1151 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
1152 * This can be a vector containing just one value.
1153 * @param[in] RB The reduced basis set
1154 * @param[in] testmodels The set of waveform models to project onto the basis (these will
1155 * be changed by this function, as the waveforms will get normalised).
1156 *
1157 * \sa LALInferenceTestREAL8OrthonormalBasis
1158 */
1160 const REAL8Vector *delta,
1161 const REAL8Array *RB,
1162 REAL8Array **testmodels){
1163 XLAL_CHECK_VOID( delta != NULL, XLAL_EFUNC, "Vector of 'delta' values is NULL!" );
1164 XLAL_CHECK_VOID( RB != NULL, XLAL_EFUNC, "Reduced basis set array is NULL!" );
1165 XLAL_CHECK_VOID( RB->dimLength->length == 2, XLAL_EFUNC, "Reduced basis set array must have only two dimensions" );
1166
1167 REAL8Array *tm = NULL;
1168 tm = *testmodels;
1169
1170 size_t dlength = RB->dimLength->data[1], nts = tm->dimLength->data[0];
1171 size_t k = 0;
1172 gsl_vector *r_tmp, *testrow;
1173
1174 /* normalise the test set */
1175 gsl_vector_view deltaview;
1176 XLAL_CALLGSL( deltaview = gsl_vector_view_array(delta->data, delta->length) );
1177 gsl_matrix_view testmodelsview;
1178 XLAL_CALLGSL( testmodelsview = gsl_matrix_view_array(tm->data, nts, dlength) );
1179 normalise_training_set(&deltaview.vector, &testmodelsview.matrix);
1180
1181 gsl_matrix_view RBview;
1182 RBview = gsl_matrix_view_array(RB->data, RB->dimLength->data[0], dlength);
1183
1184 XLAL_CALLGSL( testrow = gsl_vector_alloc(dlength) );
1185 XLAL_CALLGSL( r_tmp = gsl_vector_alloc(RB->dimLength->data[0]) );
1186
1187 REAL8Vector *pe = NULL;
1188 pe = XLALCreateREAL8Vector( nts );
1189 *projerr = pe;
1190
1191 for ( k = 0; k < nts; k++ ){
1192 pe->data[k] = 0.;
1193 REAL8 r_tmp_nrm = 0.;
1194
1195 XLAL_CALLGSL( gsl_matrix_get_row(testrow, &testmodelsview.matrix, k) );
1196
1197 REAL8 nrm = normalisation(&deltaview.vector, testrow); // normalisation (should be 1 as test models are normalised)
1198
1199 // un-scale testrow
1200 if ( delta->length == 1 ){
1201 XLAL_CALLGSL( gsl_vector_scale(testrow, delta->data[0]) );
1202 }
1203 else if ( testrow->size == deltaview.vector.size ){
1204 XLAL_CALLGSL( gsl_vector_mul(testrow, &deltaview.vector) );
1205 }
1206 else{
1207 XLAL_ERROR_VOID(XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors.");
1208 }
1209
1210 // get projections
1211 XLAL_CALLGSL( gsl_blas_dgemv( CblasNoTrans, 1., &RBview.matrix, testrow, 0., r_tmp ) );
1212
1213 r_tmp_nrm = gsl_blas_dnrm2( r_tmp );
1214 pe->data[k] = nrm - r_tmp_nrm*r_tmp_nrm;
1215
1216 if ( pe->data[k] < 0. ) { pe->data[k] = 1.0e-16; } // floating point error can trigger this
1217 }
1218
1219 XLAL_CALLGSL( gsl_vector_free( testrow ) );
1220 XLAL_CALLGSL( gsl_vector_free( r_tmp ) );
1221}
1222
1223
1224/**
1225 * \brief Test the reduced basis against another set of waveforms
1226 *
1227 * This function projects a set of waveforms onto the reduced basis and
1228 * checks that the residuals are within a given tolerance
1229 *
1230 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
1231 * This can be a vector containing just one value.
1232 * @param[in] tolerance The allowed (squared) residual tolerence for the test waveforms
1233 * @param[in] RB The reduced basis set
1234 * @param[in] testmodels The set of waveform models to project onto the basis
1235 *
1236 * @return Returns \c XLAL_SUCCESS if all test waveforms meet the tolerance
1237 *
1238 * \sa LALInferenceValidateREAL8OrthonormalBasis
1239 */
1241 REAL8 tolerance,
1242 const REAL8Array *RB,
1243 REAL8Array **testmodels){
1244 XLAL_CHECK( delta != NULL, XLAL_EFUNC, "Vector of 'delta' values is NULL!" );
1245 XLAL_CHECK( RB != NULL, XLAL_EFUNC, "Reduced basis set array is NULL!" );
1246 XLAL_CHECK( RB->dimLength->length == 2, XLAL_EFUNC, "Reduced basis set array must have only two dimensions" );
1247 XLAL_CHECK( tolerance > 0, XLAL_EFUNC, "Tolerance is less than, or equal to, zero!" );
1248
1249 REAL8Array *tm = NULL;
1250 tm = *testmodels;
1251
1252 size_t nts = tm->dimLength->data[0], k = 0;
1253
1254 REAL8Vector *projerr = NULL;
1255
1256 LALInferenceValidateREAL8OrthonormalBasis(&projerr, delta, RB, testmodels);
1257
1258 for ( k = 0; k < nts; k++ ){
1259 /* check projection error against tolerance */
1260 if ( projerr->data[k] > tolerance ) {
1261 XLALDestroyREAL8Vector( projerr );
1262 return XLAL_FAILURE;
1263 }
1264 }
1265
1266 XLALDestroyREAL8Vector( projerr );
1267
1268 return XLAL_SUCCESS;
1269}
1270
1271/**
1272 * \brief Expand the real training waveforms with ones from a set of new training waveforms
1273 *
1274 * Expands an original set of training waveforms with waveforms from a new set a training waveforms
1275 * if, when projected onto the reduced basis, those new waveforms are greater than the given tolerance.
1276 * The reduced basis will then be recomputed using the expanded training set.
1277 *
1278 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
1279 * This can be a vector containing just one value.
1280 * @param[in] tolerance The allowed residual tolerence for the test waveforms
1281 * @param[in] RB The reduced basis set
1282 * @param[in] greedypoints The rows in \c testmodels that formed the reduced basis
1283 * @param[in] testmodels The set of waveform models used to produce the reduced basis (already normalised)
1284 * @param[in] testmodelsnew A new set of waveforms to project onto the current reduced basis (these will
1285 * be changed by this function, as the waveforms will get normalised when pass to
1286 * \c LALInferenceValidateREAL8OrthonormalBasis, and editted to contain the new set of training waveforms
1287 * from which the enriched basis was formed).
1288 *
1289 * @return Returns the maximum projection error of the new basis set
1290 */
1292 REAL8 tolerance,
1293 REAL8Array **RB,
1294 UINT4Vector **greedypoints,
1295 const REAL8Array *testmodels,
1296 REAL8Array **testmodelsnew){
1297 XLAL_CHECK( delta != NULL, XLAL_EFUNC, "Vector of 'delta' values is NULL!" );
1298 XLAL_CHECK( tolerance > 0, XLAL_EFUNC, "Tolerance is less than, or equal to, zero!" );
1299
1300 size_t dlength = testmodels->dimLength->data[1]; // length of training vectors
1301 size_t k = 0;
1302
1303 REAL8 maxprojerr = 0.;
1304
1305 REAL8Array *RBin = NULL;
1306 RBin = *RB;
1307 UINT4Vector *gp = NULL;
1308 gp = *greedypoints;
1309 REAL8Array *tm = NULL;
1310 tm = *testmodelsnew;
1311
1312 size_t nts = tm->dimLength->data[0]; // number of new training vectors
1313
1314 XLAL_CHECK_REAL8( dlength == tm->dimLength->data[1], XLAL_EFUNC, "New training set contains waveforms of different length to the original set!" );
1315
1316 gsl_vector_view deltaview;
1317 XLAL_CALLGSL( deltaview = gsl_vector_view_array(delta->data, delta->length) );
1318
1319 // get projection errors of new test model set against the reduced basis
1320 REAL8Vector *projerr = NULL;
1321 LALInferenceValidateREAL8OrthonormalBasis( &projerr, delta, *RB, testmodelsnew );
1322
1323 // check for errors outside the tolerance value, and reduced new training set accordingly
1324 size_t keepcounter = 0;
1325 gsl_matrix_view tmview;
1326 tmview = gsl_matrix_view_array(tm->data, nts, dlength);
1327 for ( k = 0; k < projerr->length; k++ ){
1328 if ( projerr->data[k] > tolerance ){
1329 if ( keepcounter != k ){
1330 gsl_vector_view row;
1331 row = gsl_matrix_row( &tmview.matrix, k );
1332
1333 // un-scale row (so that it works with the reduced basis generation function below)
1334 if ( delta->length == 1 ){
1335 XLAL_CALLGSL( gsl_vector_scale(&row.vector, delta->data[0]) );
1336 }
1337 else if ( row.vector.size == delta->length ){
1338 XLAL_CALLGSL( gsl_vector_mul(&row.vector, &deltaview.vector) );
1339 }
1340 else{
1341 XLAL_ERROR_REAL8(XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors.");
1342 }
1343
1344 gsl_matrix_set_row( &tmview.matrix, keepcounter, &row.vector ); // copy row to earlier in the matrix
1345 }
1346 keepcounter++;
1347 }
1348 }
1349
1350 XLALDestroyREAL8Vector( projerr );
1351
1352 if ( keepcounter == 0 ){ return maxprojerr; } // nothing was above the tolerance
1353
1354 // add vectors used to produce the original reduced basis
1356 dims->data[0] = RBin->dimLength->data[0] + keepcounter;
1357 dims->data[1] = dlength;
1358 tm = XLALResizeREAL8Array( tm, dims );
1359 tmview = gsl_matrix_view_array(tm->data, dims->data[0], dlength);
1360
1361 gsl_matrix_view otmview;
1362 otmview = gsl_matrix_view_array(testmodels->data, testmodels->dimLength->data[0], dlength); // view of original training set
1363 for ( k = 0; k < RBin->dimLength->data[0]; k++ ){
1364 gsl_vector_view row;
1365 row = gsl_matrix_row( &otmview.matrix, gp->data[k] );
1366
1367 // un-scale row (so that it works with the reduced basis generation function below)
1368 if ( delta->length == 1 ){
1369 XLAL_CALLGSL( gsl_vector_scale(&row.vector, delta->data[0]) );
1370 }
1371 else if ( row.vector.size == delta->length ){
1372 XLAL_CALLGSL( gsl_vector_mul(&row.vector, &deltaview.vector) );
1373 }
1374 else{
1375 XLAL_ERROR_REAL8(XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors.");
1376 }
1377
1378 gsl_matrix_set_row( &tmview.matrix, keepcounter + k, &row.vector );
1379 }
1380
1381 /* recalculate the reduced basis using the updated training set */
1382 XLALDestroyREAL8Array( *RB ); /* remove current basis, so it is rebuilt using the entire new training set */
1383 *RB = NULL;
1384 XLALDestroyUINT4Vector( *greedypoints );
1385 *greedypoints = NULL;
1386 maxprojerr = LALInferenceGenerateREAL8OrthonormalBasis(RB, delta, 0.0, &tm, greedypoints); // set tolerance to 0, so that points are always added
1387
1388 XLALDestroyUINT4Vector( dims );
1389
1390 return maxprojerr;
1391}
1392
1393
1394/**
1395 * \brief Validate the complex reduced basis against another set of waveforms
1396 *
1397 * This function projects a set of waveforms onto the reduced basis and
1398 * checks that the residuals are within a given tolerance. It returns
1399 * the projection errors.
1400 *
1401 * Note that the projection error returned are the square of the residual
1402 * errors, as is used as the criterion for adding new bases in the reduced
1403 * basis generation function \c LALInferenceGenerateCOMPLEX16OrthonormalBasis.
1404 * This is different to the \c validation.cpp code in <a href="https://bitbucket.org/sfield83/greedycpp">greedycpp</a>,
1405 * which returns the square root of the value we return.
1406 *
1407 * @param[out] projerr The projection errors (square of the residual) for each test waveform.
1408 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
1409 * This can be a vector containing just one value.
1410 * @param[in] RB The reduced basis set
1411 * @param[in] testmodels The set of waveform models to project onto the basis (these will
1412 * be changed by this function, as the waveforms will get normalised).
1413 *
1414 * \sa LALInferenceTestCOMPLEX16OrthonormalBasis
1415 */
1417 const REAL8Vector *delta,
1418 const COMPLEX16Array *RB,
1419 COMPLEX16Array **testmodels){
1420 XLAL_CHECK_VOID( delta != NULL, XLAL_EFUNC, "Vector of 'delta' values is NULL!" );
1421 XLAL_CHECK_VOID( RB != NULL, XLAL_EFUNC, "Reduced basis is NULL!" );
1422 XLAL_CHECK_VOID( RB->dimLength->length == 2, XLAL_EFUNC, "Reduced basis set does not have 2 dimensions!" );
1423
1424 COMPLEX16Array *tm = NULL;
1425 tm = *testmodels;
1426
1427 size_t dlength = RB->dimLength->data[1], nts = tm->dimLength->data[0];
1428 size_t k = 0, j = 0;
1429 gsl_vector_complex *r_tmp, *testrow;
1430
1431 /* normalise the test set */
1432 gsl_vector_view deltaview;
1433 XLAL_CALLGSL( deltaview = gsl_vector_view_array(delta->data, delta->length) );
1434 gsl_matrix_complex_view testmodelsview;
1435 XLAL_CALLGSL( testmodelsview = gsl_matrix_complex_view_array((double *)tm->data, nts, dlength) );
1436 complex_normalise_training_set(&deltaview.vector, &testmodelsview.matrix);
1437
1438 gsl_matrix_complex_view RBview;
1439 RBview = gsl_matrix_complex_view_array((double *)RB->data, RB->dimLength->data[0], dlength);
1440
1441 XLAL_CALLGSL( testrow = gsl_vector_complex_alloc(dlength) );
1442 XLAL_CALLGSL( r_tmp = gsl_vector_complex_alloc(RB->dimLength->data[0]) );
1443
1444 REAL8Vector *pe = NULL;
1445 pe = XLALCreateREAL8Vector( nts );
1446 *projerr = pe;
1447
1448 /* get projection errors for each test model */
1449 for ( k = 0; k < nts; k++ ){
1450 pe->data[k] = 0.;
1451 REAL8 r_tmp_nrm = 0.;
1452
1453 XLAL_CALLGSL( gsl_matrix_complex_get_row(testrow, &testmodelsview.matrix, k) );
1454
1455 REAL8 nrm = complex_normalisation(&deltaview.vector, testrow); // normalisation (should be 1 as test models are normalised)
1456
1457 // un-scale testrow (gsl_vector_complex_mul doesn't work when delta is a real vector)
1458 if ( delta->length == 1 || testrow->size == deltaview.vector.size ){
1459 for ( j = 0; j < dlength; j++ ){
1460 gsl_complex ctmp;
1461 XLAL_CALLGSL( ctmp = gsl_vector_complex_get( testrow, j ) );
1462 if ( delta->length == 1 ){
1463 XLAL_CALLGSL( ctmp = gsl_complex_mul_real( ctmp, delta->data[0] ) );
1464 }
1465 else{
1466 XLAL_CALLGSL( ctmp = gsl_complex_mul_real( ctmp, delta->data[j] ) );
1467 }
1468 XLAL_CALLGSL( gsl_vector_complex_set( testrow, j, ctmp ) );
1469 }
1470 }
1471 else{
1472 XLAL_ERROR_VOID( XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
1473 }
1474
1475 // get complex conjugate
1476 for ( j = 0; j < testrow->size; j++ ){ testrow->data[2*j+1] = -testrow->data[2*j+1]; }
1477
1478 // get projections
1479 XLAL_CALLGSL( gsl_blas_zgemv( CblasNoTrans, GSL_COMPLEX_ONE, &RBview.matrix, testrow, GSL_COMPLEX_ZERO, r_tmp ) );
1480
1481 r_tmp_nrm = gsl_blas_dznrm2(r_tmp);
1482 pe->data[k] = nrm - r_tmp_nrm*r_tmp_nrm;
1483
1484 if ( pe->data[k] < 0. ) { pe->data[k] = 1.0e-16; } // floating point error can trigger this
1485 }
1486
1487 XLAL_CALLGSL( gsl_vector_complex_free( testrow ) );
1488 XLAL_CALLGSL( gsl_vector_complex_free( r_tmp ) );
1489}
1490
1491
1492/**
1493 * \brief Test the reduced basis against another set of waveforms
1494 *
1495 * This function projects a set of waveforms onto the reduced basis and
1496 * checks that the residuals are within a given tolerance
1497 *
1498 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
1499 * This can be a vector containing just one value.
1500 * @param[in] tolerance The allowed residual (squared) tolerence for the test waveforms
1501 * @param[in] RB The reduced basis set
1502 * @param[in] testmodels The set of waveform models to project onto the basis
1503 *
1504 * @return Returns \c XLAL_SUCCESS if all test waveforms meet the tolerance
1505 *
1506 * \sa LALInferenceValidateCOMPLEX16OrthonormalBasis
1507 */
1509 REAL8 tolerance,
1510 const COMPLEX16Array *RB,
1511 COMPLEX16Array **testmodels){
1512 XLAL_CHECK( delta != NULL, XLAL_EFUNC, "Vector of 'delta' values is NULL!" );
1513 XLAL_CHECK( RB != NULL, XLAL_EFUNC, "Reduced basis is NULL!" );
1514 XLAL_CHECK( RB->dimLength->length == 2, XLAL_EFUNC, "Reduced basis set does not have 2 dimensions!" );
1515 XLAL_CHECK( tolerance > 0, XLAL_EFUNC, "Tolerance is less than, or equal to, zero!" );
1516
1517 COMPLEX16Array *tm = NULL;
1518 tm = *testmodels;
1519
1520 size_t nts = tm->dimLength->data[0], k = 0;
1521
1522 REAL8Vector *projerr = NULL;
1523
1524 LALInferenceValidateCOMPLEX16OrthonormalBasis(&projerr, delta, RB, testmodels);
1525
1526 for ( k = 0; k < nts; k++ ){
1527 /* check projection error against tolerance */
1528 if ( projerr->data[k] > tolerance ) {
1529 XLALDestroyREAL8Vector( projerr );
1530 return XLAL_FAILURE;
1531 }
1532 }
1533
1534 XLALDestroyREAL8Vector( projerr );
1535
1536 return XLAL_SUCCESS;
1537}
1538
1539
1540/**
1541 * \brief Expand the complex training waveforms with ones from a set of new training waveforms
1542 *
1543 * Expands an original set of training waveforms with waveforms from a new set a training waveforms
1544 * if, when projected onto the reduced basis, those new waveforms are greater than the given tolerance.
1545 * The reduced basis will then be recomputed using the expanded training set.
1546 *
1547 * @param[in] delta The time/frequency step(s) in the training set used to normalise the models.
1548 * This can be a vector containing just one value.
1549 * @param[in] tolerance The allowed residual tolerence for the test waveforms
1550 * @param[in] RB The reduced basis set
1551 * @param[in] greedypoints The rows in \c testmodels that formed the reduced basis
1552 * @param[in] testmodels The set of waveform models used to produce the reduced basis
1553 * @param[in] testmodelsnew A new set of waveforms to project onto the current reduced basis (these will
1554 * be changed by this function, as the waveforms will get normalised when pass to
1555 * \c LALInferenceValidateCOMPLEX16OrthonormalBasis, and editted to contain the new set of training waveforms
1556 * from which the enriched basis was formed)
1557 *
1558 * @return Returns the maximum projection error of the new basis set
1559 */
1561 REAL8 tolerance,
1562 COMPLEX16Array **RB,
1563 UINT4Vector **greedypoints,
1564 const COMPLEX16Array *testmodels,
1565 COMPLEX16Array **testmodelsnew){
1566 XLAL_CHECK( delta != NULL, XLAL_EFUNC, "Vector of 'delta' values is NULL!" );
1567 XLAL_CHECK( tolerance > 0, XLAL_EFUNC, "Tolerance is less than, or equal to, zero!" );
1568
1569 size_t dlength = testmodels->dimLength->data[1]; // length of training vectors
1570 size_t k = 0, j = 0;
1571
1572 REAL8 maxprojerr = 0.;
1573
1574 COMPLEX16Array *RBin = NULL;
1575 RBin = *RB;
1576 UINT4Vector *gp = NULL;
1577 gp = *greedypoints;
1578 COMPLEX16Array *tm = NULL;
1579 tm = *testmodelsnew;
1580
1581 size_t nts = tm->dimLength->data[0]; // number of new training vectors
1582
1583 XLAL_CHECK_REAL8( dlength == tm->dimLength->data[1], XLAL_EFUNC, "New training set contains waveforms of different length to the original set!" );
1584
1585 // get projection errors of new test model set against the reduced basis
1586 REAL8Vector *projerr = NULL;
1587 LALInferenceValidateCOMPLEX16OrthonormalBasis( &projerr, delta, *RB, testmodelsnew );
1588
1589 // check for errors outside the tolerance value, and reduced new training set accordingly
1590 size_t keepcounter = 0;
1591 gsl_matrix_complex_view tmview;
1592 tmview = gsl_matrix_complex_view_array((double *)tm->data, nts, dlength);
1593 for ( k = 0; k < projerr->length; k++ ){
1594 if ( projerr->data[k] > tolerance ){
1595 if ( keepcounter != k ){
1596 gsl_vector_complex_view row;
1597 row = gsl_matrix_complex_row( &tmview.matrix, k );
1598
1599 // un-scale row (so that this works with the RB generation function later)
1600 if ( delta->length == 1 || row.vector.size == delta->length ){
1601 for ( j = 0; j < row.vector.size; j++ ){
1602 gsl_complex ctmp;
1603 XLAL_CALLGSL( ctmp = gsl_vector_complex_get( &row.vector, j ) );
1604 if ( delta->length == 1 ){
1605 XLAL_CALLGSL( ctmp = gsl_complex_mul_real( ctmp, delta->data[0] ) );
1606 }
1607 else{
1608 XLAL_CALLGSL( ctmp = gsl_complex_mul_real( ctmp, delta->data[j] ) );
1609 }
1610 XLAL_CALLGSL( gsl_vector_complex_set( &row.vector, j, ctmp ) );
1611 }
1612 }
1613 else{
1614 XLAL_ERROR_REAL8( XLAL_EFUNC, "Vector of weights must either contain a single value, or be the same length as the other input vectors." );
1615 }
1616 gsl_matrix_complex_set_row( &tmview.matrix, keepcounter, &row.vector ); // copy row to earlier in the matrix
1617 }
1618 keepcounter++;
1619 }
1620 }
1621
1622 XLALDestroyREAL8Vector( projerr );
1623
1624 if ( keepcounter == 0 ){ return maxprojerr; } // nothing was above the tolerance
1625
1626 // add vectors used to produce the orgial reduced basis
1628 dims->data[0] = RBin->dimLength->data[0] + keepcounter;
1629 dims->data[1] = dlength;
1630 tm = XLALResizeCOMPLEX16Array( tm, dims );
1631 tmview = gsl_matrix_complex_view_array((double *)tm->data, dims->data[0], dlength);
1632
1633 gsl_matrix_complex_view otmview;
1634 otmview = gsl_matrix_complex_view_array((double *)testmodels->data, nts, dlength); // view of original training set
1635 for ( k = 0; k < RBin->dimLength->data[0]; k++ ){
1636 gsl_vector_complex_view row;
1637 row = gsl_matrix_complex_row( &otmview.matrix, gp->data[k] );
1638
1639 // un-scale row (so that this works with the RB generation function later)
1640 for ( j = 0; j < row.vector.size; j++ ){
1641 gsl_complex ctmp;
1642 XLAL_CALLGSL( ctmp = gsl_vector_complex_get( &row.vector, j ) );
1643 if ( delta->length == 1 ){
1644 XLAL_CALLGSL( ctmp = gsl_complex_mul_real( ctmp, delta->data[0] ) );
1645 }
1646 else{
1647 XLAL_CALLGSL( ctmp = gsl_complex_mul_real( ctmp, delta->data[j] ) );
1648 }
1649 XLAL_CALLGSL( gsl_vector_complex_set( &row.vector, j, ctmp ) );
1650 }
1651
1652 gsl_matrix_complex_set_row( &tmview.matrix, keepcounter + k, &row.vector );
1653 }
1654
1655 /* recalculate the reduced basis using the updated training set */
1656 XLALDestroyCOMPLEX16Array( *RB ); /* remove current basis, so it is rebuilt using the entire new training set */
1657 *RB = NULL;
1658 XLALDestroyUINT4Vector( *greedypoints );
1659 *greedypoints = NULL;
1660 maxprojerr = LALInferenceGenerateCOMPLEX16OrthonormalBasis(RB, delta, 0.0, &tm, greedypoints); // set tolerance to 0, so that points are always added
1661
1662 XLALDestroyUINT4Vector( dims );
1663
1664 return maxprojerr;
1665}
1666
1667
1668/**
1669 * \brief Create a real empirical interpolant from a set of orthonormal basis functions
1670 *
1671 * Given a real \c REAL8Array containing a set of orthonormal basis functions generate an
1672 * empirical intopolant, and set of interpolation points, using Algorithm 2 of
1673 * \cite FGHKT2014 .
1674 *
1675 * @param[in] RB The set of basis functions
1676 *
1677 * @return A \c LALInferenceREALROQInterpolant structure containing the interpolant and its nodes
1678 */
1680 XLAL_CHECK_NULL( RB != NULL, XLAL_EFUNC, "Reduced basis array is NULL!" );
1681
1682 size_t RBsize = RB->dimLength->data[0]; /* reduced basis size (no. of reduced bases) */
1683 size_t dlength = RB->dimLength->data[1]; /* length of each base */
1684 size_t i=1, j=0, k=0;
1685 REAL8 *V = XLALMalloc(sizeof(REAL8));
1686 gsl_matrix_view Vview;
1687
1689 int idmax = 0, newidx = 0;
1690
1691 /* get index of maximum absolute value of first basis */
1692 gsl_matrix_view RBview;
1693 RBview = gsl_matrix_view_array( RB->data, RBsize, dlength );
1694 gsl_vector_view firstbasis = gsl_matrix_row(&RBview.matrix, 0);
1695 XLAL_CALLGSL( idmax = (int)gsl_blas_idamax(&firstbasis.vector) ); /* function gets index of maximum absolute value */
1696
1697 interp->nodes = XLALMalloc(RBsize*sizeof(UINT4));
1698 interp->nodes[0] = idmax;
1699
1700 for ( i=1; i<RBsize; i++ ){
1701 gsl_vector *interpolant, *subbasis;
1702 gsl_vector_view subview;
1703
1704 Vview = gsl_matrix_view_array(V, i, i);
1705
1706 for ( j=0; j<i; j++ ){
1707 for ( k=0; k<i; k++ ){
1708 XLAL_CALLGSL( gsl_matrix_set(&Vview.matrix, k, j, gsl_matrix_get(&RBview.matrix, j, interp->nodes[k])) );
1709 }
1710 }
1711
1712 /* get B matrix */
1713 REAL8Array *B = B_matrix(&Vview.matrix, &RBview.matrix);
1714 gsl_matrix_view Bview;
1715 Bview = gsl_matrix_view_array(B->data, B->dimLength->data[0], B->dimLength->data[1]);
1716
1717 /* make empirical interpolant of basis */
1718 XLAL_CALLGSL( interpolant = gsl_vector_calloc(dlength) );
1719 XLAL_CALLGSL( subbasis = gsl_vector_calloc(i) );
1720 XLAL_CALLGSL( subview = gsl_matrix_row(&RBview.matrix, i) );
1721
1722 for ( k=0; k<i; k++ ){
1723 XLAL_CALLGSL( gsl_vector_set(subbasis, k, gsl_vector_get(&subview.vector, interp->nodes[k])) );
1724 }
1725
1726 XLAL_CALLGSL( gsl_blas_dgemv(CblasTrans, 1.0, &Bview.matrix, subbasis, 0., interpolant) );
1727
1728 /* get residuals of interpolant */
1729 XLAL_CALLGSL( gsl_vector_sub(interpolant, &subview.vector) );
1730
1731 XLAL_CALLGSL( newidx = (int)gsl_blas_idamax(interpolant) );
1732
1733 interp->nodes[i] = newidx;
1734
1735 XLAL_CALLGSL( gsl_vector_free(subbasis) );
1737 XLAL_CALLGSL( gsl_vector_free(interpolant) );
1738
1739 /* reallocate memory for V */
1740 V = XLALRealloc(V, (i+1)*(i+1)*sizeof(REAL8));
1741 }
1742
1743 /* get final B vector with all the indices */
1744 Vview = gsl_matrix_view_array(V, RBsize, RBsize);
1745 for( j=0; j<RBsize; j++ ){
1746 for( k=0; k<RBsize; k++ ){
1747 XLAL_CALLGSL( gsl_matrix_set(&Vview.matrix, k, j, gsl_matrix_get(&RBview.matrix, j, interp->nodes[k])) );
1748 }
1749 }
1750
1751 /* allocate memory for intpolant array */
1752 interp->B = B_matrix(&Vview.matrix, &RBview.matrix);
1753
1754 XLALFree(V);
1755
1756 return interp;
1757}
1758
1759
1760/**
1761 * \brief Create a complex empirical interpolant from a set of orthonormal basis functions
1762 *
1763 * Given a complex \c gsl_matrix_complex containing a set of orthonormal basis functions generate an
1764 * empirical intopolant, and set of interpolation points, using Algorithm 2 of
1765 * \cite FGHKT2014 .
1766 *
1767 * @param[in] RB The set of basis functions
1768 *
1769 * @return A \c LALInferenceCOMPLEXROQInterpolant structure containing the interpolant and its nodes
1770 */
1772 XLAL_CHECK_NULL( RB != NULL, XLAL_EFUNC, "Reduced basis array is NULL!" );
1773
1774 size_t RBsize = RB->dimLength->data[0]; /* reduced basis size (no. of reduced bases) */
1775 size_t dlength = RB->dimLength->data[1]; /* length of each base */
1776 size_t i=1, j=0, k=0;
1777 REAL8 *V = XLALMalloc(sizeof(COMPLEX16));
1778 gsl_matrix_complex_view Vview;
1779
1781 int idmax = 0, newidx = 0;
1782
1783 /* get index of maximum absolute value of first basis */
1784 gsl_matrix_complex_view RBview;
1785 RBview = gsl_matrix_complex_view_array((double *)RB->data, RBsize, dlength);
1786 gsl_vector_complex_view firstbasis = gsl_matrix_complex_row(&RBview.matrix, 0);
1787 idmax = complex_vector_maxabs_index(&firstbasis.vector);
1788
1789 interp->nodes = XLALMalloc(RBsize*sizeof(UINT4));
1790 interp->nodes[0] = idmax;
1791
1792 for ( i=1; i<RBsize; i++ ){
1793 gsl_vector_complex *interpolant, *subbasis;
1794 gsl_vector_complex_view subview;
1795
1796 Vview = gsl_matrix_complex_view_array(V, i, i);
1797
1798 for ( j=0; j<i; j++ ){
1799 for ( k=0; k<i; k++ ){
1800 XLAL_CALLGSL( gsl_matrix_complex_set(&Vview.matrix, k, j, gsl_matrix_complex_get(&RBview.matrix, j, interp->nodes[k])) );
1801 }
1802 }
1803
1804 /* get B matrix */
1805 COMPLEX16Array *B = complex_B_matrix(&Vview.matrix, &RBview.matrix);
1806 gsl_matrix_complex_view Bview;
1807 Bview = gsl_matrix_complex_view_array((double *)B->data, B->dimLength->data[0], B->dimLength->data[1]);
1808
1809 /* make empirical interpolant of basis */
1810 XLAL_CALLGSL( interpolant = gsl_vector_complex_calloc(dlength) );
1811 XLAL_CALLGSL( subbasis = gsl_vector_complex_calloc(i) );
1812 XLAL_CALLGSL( subview = gsl_matrix_complex_row(&RBview.matrix, i) );
1813
1814 for ( k=0; k<i; k++ ){
1815 XLAL_CALLGSL( gsl_vector_complex_set(subbasis, k, gsl_vector_complex_get(&subview.vector, interp->nodes[k])) );
1816 }
1817
1818 XLAL_CALLGSL( gsl_blas_zgemv(CblasTrans, GSL_COMPLEX_ONE, &Bview.matrix, subbasis, GSL_COMPLEX_ZERO, interpolant) );
1819
1820 /* get residuals of interpolant */
1821 XLAL_CALLGSL( gsl_vector_complex_sub(interpolant, &subview.vector) );
1822
1823 newidx = complex_vector_maxabs_index(interpolant);
1824
1825 interp->nodes[i] = newidx;
1826
1827 XLAL_CALLGSL( gsl_vector_complex_free(subbasis) );
1829 XLAL_CALLGSL( gsl_vector_complex_free(interpolant) );
1830
1831 /* reallocate memory for V */
1832 V = XLALRealloc(V, (i+1)*(i+1)*sizeof(COMPLEX16));
1833 }
1834
1835 /* get final B vector with all the indices */
1836 Vview = gsl_matrix_complex_view_array((double*)V, RBsize, RBsize);
1837 for( j=0; j<RBsize; j++ ){
1838 for( k=0; k<RBsize; k++ ){
1839 XLAL_CALLGSL( gsl_matrix_complex_set(&Vview.matrix, k, j, gsl_matrix_complex_get(&RBview.matrix, j, interp->nodes[k])) );
1840 }
1841 }
1842
1843 /* allocate memory for intpolant array */
1844 interp->B = complex_B_matrix(&Vview.matrix, &RBview.matrix);
1845
1846 XLALFree(V);
1847
1848 return interp;
1849}
1850
1851
1852/** \brief Create the weights for the ROQ interpolant for the linear data and model dot product <d|h>
1853 *
1854 * @param[in] B The interpolant matrix
1855 * @param[in] data The real data vector
1856 * @param[in] vars A vector of data noise variance values (or a single value) to weight the "weights"
1857 *
1858 * @return The vector of weights
1859 */
1861 REAL8Vector *weights = NULL;
1862 gsl_vector *datacopy;
1863
1864 /* get view of the interpolant matrix */
1865 gsl_matrix_view Bview;
1866 XLAL_CALLGSL( Bview = gsl_matrix_view_array(B->data, B->dimLength->data[0], B->dimLength->data[1]) );
1867
1868 /* get view of the data and variances */
1869 gsl_vector_view dataview, varsview;
1870 XLAL_CALLGSL( dataview = gsl_vector_view_array(data->data, data->length) );
1871 XLAL_CALLGSL( varsview = gsl_vector_view_array(vars->data, vars->length) );
1872
1873 XLAL_CHECK_NULL( vars->length == 1 || vars->length == B->dimLength->data[1], XLAL_EFUNC, "Vector of variance values is the wrong size" );
1874
1875 XLAL_CALLGSL( datacopy = gsl_vector_alloc(B->dimLength->data[1]) );
1876 XLAL_CALLGSL( gsl_vector_memcpy(datacopy, &dataview.vector) );
1877
1878 if ( vars->length == 1 ){ XLAL_CALLGSL( gsl_vector_scale( datacopy, 1./vars->data[0]) ); }
1879 else{ XLAL_CALLGSL( gsl_vector_div( datacopy, &varsview.vector ) ); }
1880
1881 /* create weights */
1882 weights = XLALCreateREAL8Vector( B->dimLength->data[0] );
1883 gsl_vector_view weightsview;
1884 XLAL_CALLGSL( weightsview = gsl_vector_view_array(weights->data, weights->length) );
1885 XLAL_CALLGSL( gsl_blas_dgemv(CblasNoTrans, 1.0, &Bview.matrix, datacopy, 0., &weightsview.vector) );
1886 XLAL_CALLGSL( gsl_vector_free( datacopy ) );
1887
1888 return weights;
1889}
1890
1891
1892/** \brief Create the weights for the ROQ interpolant for the model quadratic model term real(<h|h>).
1893 *
1894 * @param[in] B The interpolant matrix
1895 * @param[in] vars A vector of data noise variance values (or a single value) to weight the "weights"
1896 *
1897 * @return The vector of weights
1898 */
1900 REAL8Vector *weights = NULL;
1901 gsl_vector *vecones = gsl_vector_alloc(B->dimLength->data[1]);
1902 XLAL_CALLGSL( gsl_vector_set_all(vecones, 1.0) ); /* set all to 1 */
1903
1904 /* get view of the interpolant matrix */
1905 gsl_matrix_view Bview;
1906 XLAL_CALLGSL( Bview = gsl_matrix_view_array(B->data, B->dimLength->data[0], B->dimLength->data[1]) );
1907
1908 /* get view of the data and variances */
1909 gsl_vector_view varsview;
1910 XLAL_CALLGSL( varsview = gsl_vector_view_array(vars->data, vars->length) );
1911
1912 XLAL_CHECK_NULL( vars->length == 1 || vars->length == B->dimLength->data[1], XLAL_EFUNC, "Vector of variance values is the wrong size" );
1913
1914 if ( vars->length == 1 ){ XLAL_CALLGSL( gsl_vector_scale( vecones, 1./vars->data[0]) ); }
1915 else{ XLAL_CALLGSL( gsl_vector_div( vecones, &varsview.vector ) ); }
1916
1917 /* create weights */
1918 weights = XLALCreateREAL8Vector( B->dimLength->data[0] );
1919 gsl_vector_view weightsview;
1920 XLAL_CALLGSL( weightsview = gsl_vector_view_array(weights->data, weights->length) );
1921 XLAL_CALLGSL( gsl_blas_dgemv(CblasNoTrans, 1.0, &Bview.matrix, vecones, 0., &weightsview.vector) );
1922 XLAL_CALLGSL( gsl_vector_free( vecones ) );
1923
1924 return weights;
1925}
1926
1927
1928/** \brief Create the weights for the ROQ interpolant for the complex data and model dot product <d|h>
1929 *
1930 * @param[in] B The interpolant matrix
1931 * @param[in] data The complex data vector
1932 * @param[in] vars A vector of data noise variance values (or a single value) to weight the "weights"
1933 *
1934 * @return The vector of weights
1935 */
1937 COMPLEX16Vector *weights = NULL;
1938 gsl_vector_complex *conjdata;
1939 gsl_complex cconj;
1940 size_t i = 0;
1941
1942 /* get view of the interpolant matrix */
1943 gsl_matrix_complex_view Bview;
1944 XLAL_CALLGSL( Bview = gsl_matrix_complex_view_array((double *)B->data, B->dimLength->data[0], B->dimLength->data[1]) );
1945
1946 XLAL_CHECK_NULL( vars->length == 1 || vars->length == B->dimLength->data[1], XLAL_EFUNC, "Vector of variance values is the wrong size" );
1947
1948 XLAL_CALLGSL( conjdata = gsl_vector_complex_alloc(B->dimLength->data[1]) );
1949
1950 /* get conjugate of data and scale it */
1951 for ( i=0; i<conjdata->size; i++ ){
1952 gsl_complex cdata;
1953 GSL_SET_COMPLEX(&cdata, creal(data->data[i]), cimag(data->data[i]));
1954 XLAL_CALLGSL( cconj = gsl_complex_conjugate(cdata) );
1955 if ( vars->length == 1 ) { XLAL_CALLGSL( cconj = gsl_complex_div_real( cconj, vars->data[0] ) ); }
1956 else { XLAL_CALLGSL( cconj = gsl_complex_div_real( cconj, vars->data[i] ) ); }
1957 XLAL_CALLGSL( gsl_vector_complex_set(conjdata, i, cconj) );
1958 }
1959
1960 /* create weights */
1961 weights = XLALCreateCOMPLEX16Vector( B->dimLength->data[0] );
1962 gsl_vector_complex_view weightsview;
1963 XLAL_CALLGSL( weightsview = gsl_vector_complex_view_array((double *)weights->data, weights->length) );
1964 XLAL_CALLGSL( gsl_blas_zgemv(CblasNoTrans, GSL_COMPLEX_ONE, &Bview.matrix, conjdata, GSL_COMPLEX_ZERO, &weightsview.vector) );
1965 XLAL_CALLGSL( gsl_vector_complex_free(conjdata) );
1966
1967 return weights;
1968}
1969
1970
1971/** \brief Calculate the dot product of two vectors using the ROQ iterpolant
1972 *
1973 * This function calculates the dot product of two real vectors using the ROQ
1974 * interpolant. This required the interpolant weights computed with \c LALInferenceCreateREAL8DataModelWeights
1975 * and the waveform model defined at the interpolation node.
1976 *
1977 * @param[in] weights The ROQ interpolation weights
1978 * @param[in] model The waveform model (or quadratic model) defined at the interpolation points
1979 *
1980 * @return The dot product \c weights and \c model
1981 */
1983 XLAL_CHECK_REAL8( weights->length == model->length, XLAL_EFUNC, "Two vectors must have the same lengths." );
1984
1985 REAL8 d_dot_m = 0.;
1986 gsl_vector_view weightsview, modelview;
1987 XLAL_CALLGSL( weightsview = gsl_vector_view_array(weights->data, weights->length) );
1988 XLAL_CALLGSL( modelview = gsl_vector_view_array(model->data, model->length) );
1989 XLAL_CALLGSL( gsl_blas_ddot(&weightsview.vector, &modelview.vector, &d_dot_m) );
1990
1991 return d_dot_m;
1992}
1993
1994/** \brief Calculate the dot product of two complex vectors using the ROQ iterpolant
1995 *
1996 * This function calculates the dot product of two complex vectors using the ROQ
1997 * interpolant. This required the interpolant weights computed with \c LALInferenceCreateCOMPLEX16DataModelWeights
1998 * and the waveform model defined at the interolation node.
1999 *
2000 * @param[in] weights The ROQ interpolation weights
2001 * @param[in] model The waveform model defined at the interpolation points
2002 *
2003 * @return The dot product of the data and model
2004 */
2006 XLAL_CHECK_REAL8( weights->length == model->length, XLAL_EFUNC, "Two vectors must have the same lengths." );
2007
2008 gsl_complex d_dot_m;
2009 gsl_vector_complex_view weightsview, modelview;
2010 XLAL_CALLGSL( weightsview = gsl_vector_complex_view_array((double *)weights->data, weights->length) );
2011 XLAL_CALLGSL( modelview = gsl_vector_complex_view_array((double *)model->data, model->length) );
2012 XLAL_CALLGSL( gsl_blas_zdotu(&weightsview.vector, &modelview.vector, &d_dot_m) );
2013
2014 return GSL_REAL(d_dot_m) + I*GSL_IMAG(d_dot_m);
2015}
2016
2017
2018/** \brief Free memory for a \c LALInferenceREALROQInterpolant
2019 *
2020 * @param[in] a A pointer to a \c LALInferenceREALROQInterpolant
2021 */
2023 if ( a == NULL ) { return; }
2024
2025 if ( a->B != NULL ){ XLALDestroyREAL8Array( a->B ); }
2026 if ( a->nodes != NULL ){ XLALFree( a->nodes ); }
2027 XLALFree( a );
2028 a = NULL;
2029}
2030
2031
2032/** \brief Free memory for a \c LALInferenceCOMPLEXROQInterpolant
2033 *
2034 * @param[in] a A pointer to a \c LALInferenceCOMPLEXROQInterpolant
2035 */
2037 if ( a == NULL ) { return; }
2038
2039 if ( a->B != NULL ){ XLALDestroyCOMPLEX16Array( a->B ); }
2040 if ( a->nodes != NULL ){ XLALFree( a->nodes ); }
2041 XLALFree( a );
2042 a = NULL;
2043}
void project_onto_basis(gsl_vector *weight, gsl_matrix *RB, gsl_matrix *TS, gsl_matrix *projections, INT4 idx)
Function to project the training set onto a given basis vector.
void complex_normalise_training_set(gsl_vector *weight, gsl_matrix_complex *TS)
Normalise the set of complex training waveforms.
INT4 LALInferenceTestCOMPLEX16OrthonormalBasis(const REAL8Vector *delta, REAL8 tolerance, const COMPLEX16Array *RB, COMPLEX16Array **testmodels)
Test the reduced basis against another set of waveforms.
COMPLEX16 LALInferenceROQCOMPLEX16DotProduct(COMPLEX16Vector *weights, COMPLEX16Vector *model)
Calculate the dot product of two complex vectors using the ROQ iterpolant.
void modified_gs(gsl_vector *ru, gsl_vector *ortho_basis, const gsl_matrix *RB_space, const gsl_vector *wQuad, const int dim_RB)
Modified Gram-Schmidt algorithm for real data.
REAL8 LALInferenceGenerateCOMPLEX16OrthonormalBasis(COMPLEX16Array **RBin, const REAL8Vector *delta, REAL8 tolerance, COMPLEX16Array **TS, UINT4Vector **greedypoints)
Create a orthonormal basis set from a training set of complex waveforms.
INT4 LALInferenceTestREAL8OrthonormalBasis(const REAL8Vector *delta, REAL8 tolerance, const REAL8Array *RB, REAL8Array **testmodels)
Test the reduced basis against another set of waveforms.
void normalise_training_set(gsl_vector *weight, gsl_matrix *TS)
Normalise the set of training waveforms.
REAL8 weighted_dot_product(const gsl_vector *weight, gsl_vector *a, gsl_vector *b)
The dot product of two real vectors scaled by a given weight factor.
void LALInferenceRemoveCOMPLEXROQInterpolant(LALInferenceCOMPLEXROQInterpolant *a)
Free memory for a LALInferenceCOMPLEXROQInterpolant.
double normalisation(const gsl_vector *weight, gsl_vector *a)
Get normalisation constant for a real vector.
void iterated_modified_gm_complex(gsl_vector_complex *ru, gsl_vector_complex *ortho_basis, const gsl_matrix_complex *RB_space, const gsl_vector *wQuad, const int dim_RB)
Iterated modified Gram-Schmidt algorithm for complex data.
int complex_vector_maxabs_index(gsl_vector_complex *c)
Get the index of the maximum absolute value for a complex vector.
void complex_normalise(const gsl_vector *weight, gsl_vector_complex *a)
Normalise a complex vector with a given (real) weighting.
COMPLEX16Vector * LALInferenceGenerateCOMPLEX16LinearWeights(COMPLEX16Array *B, COMPLEX16Vector *data, REAL8Vector *vars)
Create the weights for the ROQ interpolant for the complex data and model dot product <d|h>
REAL8Vector * LALInferenceGenerateREAL8LinearWeights(REAL8Array *B, REAL8Vector *data, REAL8Vector *vars)
Create the weights for the ROQ interpolant for the linear data and model dot product <d|h>
gsl_complex complex_weighted_dot_product(const gsl_vector *weight, gsl_vector_complex *a, gsl_vector_complex *b)
The dot product of two complex vectors scaled by a given weight factor.
REAL8 LALInferenceROQREAL8DotProduct(REAL8Vector *weights, REAL8Vector *model)
Calculate the dot product of two vectors using the ROQ iterpolant.
REAL8 LALInferenceEnrichCOMPLEX16Basis(const REAL8Vector *delta, REAL8 tolerance, COMPLEX16Array **RB, UINT4Vector **greedypoints, const COMPLEX16Array *testmodels, COMPLEX16Array **testmodelsnew)
Expand the complex training waveforms with ones from a set of new training waveforms.
double complex_normalisation(const gsl_vector *weight, gsl_vector_complex *a)
Get normalisation constant for a complex vector.
void complex_project_onto_basis(gsl_vector *weight, gsl_matrix_complex *RB, gsl_matrix_complex *TS, gsl_matrix_complex *projections, INT4 idx)
Function to project the complex training set onto a given basis vector.
REAL8Vector * LALInferenceGenerateQuadraticWeights(REAL8Array *B, REAL8Vector *vars)
Create the weights for the ROQ interpolant for the model quadratic model term real(<h|h>).
REAL8Array * B_matrix(gsl_matrix *V, gsl_matrix *RB)
Get the interpolant of a reduced basis set.
LALInferenceCOMPLEXROQInterpolant * LALInferenceGenerateCOMPLEXROQInterpolant(COMPLEX16Array *RB)
Create a complex empirical interpolant from a set of orthonormal basis functions.
void LALInferenceValidateCOMPLEX16OrthonormalBasis(REAL8Vector **projerr, const REAL8Vector *delta, const COMPLEX16Array *RB, COMPLEX16Array **testmodels)
Validate the complex reduced basis against another set of waveforms.
REAL8 LALInferenceGenerateREAL8OrthonormalBasis(REAL8Array **RBin, const REAL8Vector *delta, REAL8 tolerance, REAL8Array **TS, UINT4Vector **greedypoints)
Create a orthonormal basis set from a training set of real waveforms.
COMPLEX16Array * complex_B_matrix(gsl_matrix_complex *V, gsl_matrix_complex *RB)
Get the interpolant of a complex reduced basis set.
void LALInferenceValidateREAL8OrthonormalBasis(REAL8Vector **projerr, const REAL8Vector *delta, const REAL8Array *RB, REAL8Array **testmodels)
Validate the real reduced basis against another set of waveforms.
void LALInferenceRemoveREALROQInterpolant(LALInferenceREALROQInterpolant *a)
Free memory for a LALInferenceREALROQInterpolant.
void modified_gs_complex(gsl_vector_complex *ru, gsl_vector_complex *ortho_basis, const gsl_matrix_complex *RB_space, const gsl_vector *wQuad, const int dim_RB)
Modified Gram-Schmidt algorithm for complex data.
REAL8 LALInferenceEnrichREAL8Basis(const REAL8Vector *delta, REAL8 tolerance, REAL8Array **RB, UINT4Vector **greedypoints, const REAL8Array *testmodels, REAL8Array **testmodelsnew)
Expand the real training waveforms with ones from a set of new training waveforms.
void normalise(const gsl_vector *weight, gsl_vector *a)
Normalise a real vector with a given weighting.
LALInferenceREALROQInterpolant * LALInferenceGenerateREALROQInterpolant(REAL8Array *RB)
Create a real empirical interpolant from a set of orthonormal basis functions.
void iterated_modified_gm(gsl_vector *ru, gsl_vector *ortho_basis, const gsl_matrix *RB_space, const gsl_vector *wQuad, const int dim_RB)
Iterated modified Gram-Schmidt algorithm for real data.
static REAL8 norm(const REAL8 x[3])
int j
int k
static double double delta
#define XLAL_CALLGSL(statement)
double e
sigmaKerr data[0]
const double B
REAL8Array * XLALResizeREAL8Array(REAL8Array *, UINT4Vector *)
void XLALDestroyREAL8Array(REAL8Array *)
COMPLEX16Array * XLALResizeCOMPLEX16Array(COMPLEX16Array *, UINT4Vector *)
COMPLEX16Array * XLALCreateCOMPLEX16Array(UINT4Vector *)
void XLALDestroyCOMPLEX16Array(COMPLEX16Array *)
REAL8Array * XLALCreateREAL8Array(UINT4Vector *)
double complex COMPLEX16
double REAL8
uint32_t UINT4
int32_t INT4
void * XLALMalloc(size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
static const INT4 a
void XLALDestroyUINT4Vector(UINT4Vector *vector)
UINT4Vector * XLALResizeUINT4Vector(UINT4Vector *vector, UINT4 length)
REAL8Vector * XLALCreateREAL8Vector(UINT4 length)
COMPLEX16Vector * XLALCreateCOMPLEX16Vector(UINT4 length)
void XLALDestroyREAL8Vector(REAL8Vector *vector)
UINT4Vector * XLALCreateUINT4Vector(UINT4 length)
#define XLAL_ERROR_VOID(...)
#define XLAL_ERROR_REAL8(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_VOID(assertion,...)
#define XLAL_CHECK_REAL8(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
#define XLAL_PRINT_ERROR(...)
XLAL_SUCCESS
XLAL_EFUNC
XLAL_FAILURE
c
ts
UINT4Vector * dimLength
COMPLEX16 * data
COMPLEX16 * data
A structure to hold a complex (double precision) interpolant matrix and interpolation node indices.
COMPLEX16Array * B
The interpolant matrix.
UINT4 * nodes
The nodes (indices) for the interpolation.
A structure to hold a real (double precision) interpolant matrix and interpolation node indices.
UINT4 * nodes
The nodes (indices) for the interpolation.
REAL8Array * B
The interpolant matrix.
UINT4Vector * dimLength
REAL8 * data
REAL8 * data
UINT4 * data
double V