Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALPulsar 7.1.1.1-5e288d3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
LatticeTiling.c
Go to the documentation of this file.
1//
2// Copyright (C) 2007, 2008, 2012, 2014, 2015, 2016, 2017 Karl Wette
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with with program; see the file COPYING. If not, write to the
16// Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17// MA 02110-1301 USA
18//
19
20#include <config.h>
21#include <fenv.h>
22
23#include <gsl/gsl_math.h>
24#include <gsl/gsl_blas.h>
25#include <gsl/gsl_linalg.h>
26
27#include <lal/LatticeTiling.h>
28#include <lal/LALStdio.h>
29#include <lal/LogPrintf.h>
30#include <lal/LALHashFunc.h>
31#include <lal/MetricUtils.h>
32#include <lal/GSLHelpers.h>
33
34#ifdef __GNUC__
35#define UNUSED __attribute__ ((unused))
36#else
37#define UNUSED
38#endif
39
40// Maximum length of arbitrary data
41#define LT_DATA_MAX_SIZE 65536
42
43// Number of cached values which can be stored per dimension
44#define LT_CACHE_MAX_SIZE 6
45
46// Determine if parameter-space bound has strict padding
47#define STRICT_BOUND_PADDING( b ) \
48 ( ( (b)->lower_bbox_pad == 0 ) && ( (b)->upper_bbox_pad == 0 ) && ( (b)->lower_intp_pad == 0 ) && ( (b)->upper_intp_pad == 0 ) )
49
50///
51/// Lattice tiling parameter-space bound for one dimension.
52///
53typedef struct tagLT_Bound {
54 char name[32]; ///< Name of the parameter-space dimension
55 bool name_set; ///< True if the name of the parameter-space dimension has been set
56 bool is_tiled; ///< True if the dimension is tiled, false if it is a single point
57 LatticeTilingBound func; ///< Parameter space bound function
58 size_t data_len; ///< Length of arbitrary data describing parameter-space bounds
59 char data_lower[LT_DATA_MAX_SIZE]; ///< Arbitrary data describing lower parameter-space bound
60 char data_upper[LT_DATA_MAX_SIZE]; ///< Arbitrary data describing upper parameter-space bound
61 LatticeTilingBoundCache cache_func; ///< Parameter space bound cache function
62 double lower_bbox_pad; ///< Lower padding as multiple of metric ellipse bounding box
63 double upper_bbox_pad; ///< Upper padding as multiple of metric ellipse bounding box
64 UINT4 lower_intp_pad; ///< Lower padding as integer number of points
65 UINT4 upper_intp_pad; ///< Upper padding as integer number of points
66 bool find_bound_extrema; ///< Whether to find the extrema of the parameter-space bounds
67} LT_Bound;
68
69///
70/// Lattice tiling callback function and associated data
71///
72typedef struct tagLT_Callback {
73 LatticeTilingCallback func; ///< Callback function
74 size_t param_len; ///< Length of arbitrary input data for use by callback function
75 char param[LT_DATA_MAX_SIZE]; ///< Arbitrary input data for use by callback function
76 char out[LT_DATA_MAX_SIZE]; ///< Output data to be filled by callback function
78
79///
80/// FITS record for for saving and restoring a lattice tiling iterator.
81///
82typedef struct tagLT_FITSRecord {
83 INT4 checksum; ///< Checksum of various data describing parameter-space bounds
84 REAL8 phys_point; ///< Current lattice point in physical coordinates
85 INT4 int_point; ///< Current lattice point in generating integers
86 INT4 int_lower; ///< Current lower parameter-space bound in generating integers
87 INT4 int_upper; ///< Current upper parameter-space bound in generating integers
88 INT4 direction; ///< Direction of iteration in each tiled parameter-space dimension
90
91///
92/// Lattice tiling index trie for one dimension.
93///
94typedef struct tagLT_IndexTrie LT_IndexTrie;
96 INT4 int_lower; ///< Lower integer point bound in this dimension
97 INT4 int_upper; ///< Upper integer point bound in this dimension
98 UINT8 index; ///< Sequential lattice tiling index up to this dimension
99 LT_IndexTrie *next; ///< Pointer to array of index tries for the next-highest dimension
100};
101
103 size_t ndim; ///< Number of parameter-space dimensions
104 LT_Bound *bounds; ///< Array of parameter-space bound info for each dimension
105 size_t tiled_ndim; ///< Number of tiled parameter-space dimensions
106 size_t *tiled_idx; ///< Index to tiled parameter-space dimensions
107 TilingLattice lattice; ///< Type of lattice to generate tiling with
108 gsl_vector *phys_bbox; ///< Metric ellipse bounding box
109 gsl_vector *phys_origin; ///< Parameter-space origin in physical coordinates
110 gsl_vector *phys_origin_shift_frac; ///< Fraction of step size to shift physical parameter-space origin
111 gsl_matrix *int_from_phys; ///< Transform to generating integers from physical coordinates
112 gsl_matrix *phys_from_int; ///< Transform to physical coordinates from generating integers
113 gsl_matrix *tiled_generator; ///< Lattice generator matrix in tiled dimensions
114 size_t ncallback; ///< Number of registered callbacks
115 LT_Callback **callbacks; ///< Registered callbacks
116 size_t *ncallback_done; ///< Pointer to number of successfully performed callbacks (mutable)
117 const LatticeTilingStats *stats; ///< Lattice tiling statistics computed by default callback
118};
119
121 const LatticeTiling *tiling; ///< Lattice tiling
122 size_t itr_ndim; ///< Number of parameter-space dimensions to iterate over
123 size_t tiled_itr_ndim; ///< Number of tiled parameter-space dimensions to iterate over
124 bool alternating; ///< If true, alternate iterator direction after every crossing
125 UINT4 state; ///< Iterator state: 0=initialised, 1=in progress, 2=finished
126 gsl_vector *phys_point; ///< Current lattice point in physical coordinates
127 gsl_matrix *phys_point_cache; ///< Cached values for computing physical bounds on current point
128 gsl_vector *phys_sampl; ///< Copy of physical point for sampling bounds with LT_FindBoundExtrema()
129 gsl_matrix *phys_sampl_cache; ///< Cached values for sampling bounds with LT_FindBoundExtrema()
130 INT4 *int_point; ///< Current lattice point in generating integers
131 INT4 *int_lower; ///< Current lower parameter-space bound in generating integers
132 INT4 *int_upper; ///< Current upper parameter-space bound in generating integers
133 INT4 *direction; ///< Direction of iteration in each tiled parameter-space dimension
134 UINT8 index; ///< Index of current lattice tiling point
135};
136
138 const LatticeTiling *tiling; ///< Lattice tiling
139 size_t ndim; ///< Number of parameter-space dimensions
140 size_t tiled_ndim; ///< Number of tiled parameter-space dimensions
141 LT_IndexTrie *index_trie; ///< Trie for locating unique index of nearest point
142};
143
145 { TILING_LATTICE_CUBIC, "Zn" },
146 { TILING_LATTICE_CUBIC, "cubic" },
147 { TILING_LATTICE_ANSTAR, "Ans" },
148 { TILING_LATTICE_ANSTAR, "An-star" },
149 { TILING_LATTICE_ANSTAR, "optimal" },
150};
151
153
154///
155/// Zero out the strictly upper triangular part of the matrix \c A.
156///
157static void LT_ZeroStrictUpperTriangle( gsl_matrix *A )
158{
159 for ( size_t i = 0; i < A->size1; ++i ) {
160 for ( size_t j = i + 1; j < A->size2; ++j ) {
161 gsl_matrix_set( A, i, j, 0.0 );
162 }
163 }
164}
165
166///
167/// Reverse the order of both the rows and columns of the matrix \c A.
168///
169static void LT_ReverseOrderRowsCols( gsl_matrix *A )
170{
171 for ( size_t i = 0; i < A->size1 / 2; ++i ) {
172 gsl_matrix_swap_rows( A, i, A->size1 - i - 1 );
173 }
174 for ( size_t j = 0; j < A->size2 / 2; ++j ) {
175 gsl_matrix_swap_columns( A, j, A->size2 - j - 1 );
176 }
177}
178
179///
180/// Call the parameter-space bound function of a given dimension.
181///
182static inline void LT_CallBoundFunc(
183 const LatticeTiling *tiling, ///< [in] Lattice tiling
184 const size_t dim, ///< [in] Dimension on which bound applies
185 const gsl_matrix *phys_point_cache, ///< [in] Cached values for computing physical point bounds
186 const gsl_vector *phys_point, ///< [in] Physical point at which to find bounds
187 double *phys_lower, ///< [out] Lower parameter-space bound
188 double *phys_upper ///< [out] Upper parameter-space bound
189)
190{
191
192 // Get bound information for this dimension
193 const LT_Bound *bound = &tiling->bounds[dim];
194
195 // Get view of first 'dim' rows of cache
196 gsl_matrix_const_view phys_point_cache_subm_view = gsl_matrix_const_submatrix( phys_point_cache, 0, 0, GSL_MAX( 1, dim ), phys_point_cache->size2 );
197 const gsl_matrix *phys_point_cache_subm = ( dim == 0 ) ? NULL : &phys_point_cache_subm_view.matrix;
198
199 // Get view of first 'dim' dimensions of physical point
200 gsl_vector_const_view phys_point_subv_view = gsl_vector_const_subvector( phys_point, 0, GSL_MAX( 1, dim ) );
201 const gsl_vector *phys_point_subv = ( dim == 0 ) ? NULL : &phys_point_subv_view.vector;
202
203 // Get lower parameter-space bound
204 *phys_lower = ( bound->func )( ( const void * ) bound->data_lower, dim, phys_point_cache_subm, phys_point_subv );
205
206 if ( bound->is_tiled ) {
207
208 // Get upper parameter-space bound
209 *phys_upper = ( bound->func )( ( const void * ) bound->data_upper, dim, phys_point_cache_subm, phys_point_subv );
210
211 // Do not allow upper parameter-space bound to be less than lower parameter-space bound
212 if ( *phys_upper < *phys_lower ) {
213 *phys_upper = *phys_lower;
214 }
215
216 } else if ( phys_upper != NULL ) {
217
218 // Set upper bound to lower bound
219 *phys_upper = *phys_lower;
220
221 }
222
223}
224
225///
226/// Set value of physical point in a given dimension, and update cache
227///
228static inline void LT_SetPhysPoint(
229 const LatticeTiling *tiling, ///< [in] Lattice tiling
230 gsl_matrix *phys_point_cache, ///< [out] Cached values for computing physical point bounds
231 gsl_vector *phys_point, ///< [out] Physical point
232 const size_t dim, ///< [in] Dimension on which to set point
233 const double phys_point_dim ///< [in] Value of physical point in this dimension
234)
235{
236
237 // Get bound information for this dimension
238 const LT_Bound *bound = &tiling->bounds[dim];
239
240 // Set physical point
241 gsl_vector_set( phys_point, dim, phys_point_dim );
242
243 if ( bound->cache_func != NULL ) {
244
245 // Get view of 'dim'th row of cache
246 gsl_vector_view phys_point_cache_subv_view = gsl_matrix_row( phys_point_cache, dim );
247 gsl_vector *phys_point_cache_subv = &phys_point_cache_subv_view.vector;
248
249 // Get view of first 'dim+1' dimensions of physical point
250 gsl_vector_const_view phys_point_subv_view = gsl_vector_const_subvector( phys_point, 0, dim + 1 );
251 const gsl_vector *phys_point_subv = &phys_point_subv_view.vector;
252
253 // Update cache values required by bound functions
254 ( bound->cache_func )( dim, phys_point_subv, phys_point_cache_subv );
255
256 }
257
258}
259
260///
261/// Find the extrema of the parameter-space bounds, by sampling the bounds around the current point.
262///
264 const LatticeTiling *tiling, ///< [in] Lattice tiling
265 const size_t i, ///< [in] Current dimension in LT_FindBoundExtrema() iteration
266 const size_t dim, ///< [in] Dimension on which bound applies
267 gsl_matrix *phys_point_cache, ///< [in] Cached values for computing physical point bounds
268 gsl_vector *phys_point, ///< [in] Physical point at which to find bounds
269 double *phys_lower_minimum, ///< [out] Minimum lower parameter-space bound
270 double *phys_upper_maximum ///< [out] Maximum upper parameter-space bound
271)
272{
273
274 // Get bound information for this dimension
275 const LT_Bound *bound = &tiling->bounds[i];
276
277 // If 'i' equals target dimension 'dim', get parameter-space bounds in this dimension
278 if ( i == dim ) {
279 LT_CallBoundFunc( tiling, dim, phys_point_cache, phys_point, phys_lower_minimum, phys_upper_maximum );
280 return;
281 }
282
283 // Move to higher dimensions if this dimension is not tiled
284 const double phys_point_i = gsl_vector_get( phys_point, i );
285 if ( !bound->is_tiled ) {
286 LT_SetPhysPoint( tiling, phys_point_cache, phys_point, i, phys_point_i );
287 LT_FindBoundExtrema( tiling, i + 1, dim, phys_point_cache, phys_point, phys_lower_minimum, phys_upper_maximum );
288 return;
289 }
290
291 // Sample parameter-space bounds at +/0/- half the lattice tiling step size
292 const double phys_hstep_i = 0.5 * gsl_matrix_get( tiling->phys_from_int, i, i );
293 const double phys_point_sample_i[] = {
294 phys_point_i - phys_hstep_i,
295 phys_point_i + phys_hstep_i,
296 phys_point_i // Must be last to reset physical point to original value
297 };
298 for ( size_t j = 0; j < XLAL_NUM_ELEM( phys_point_sample_i ); ++j ) {
299 LT_SetPhysPoint( tiling, phys_point_cache, phys_point, i, phys_point_sample_i[j] );
300 double phys_lower = *phys_lower_minimum;
301 double phys_upper = *phys_upper_maximum;
302 LT_FindBoundExtrema( tiling, i + 1, dim, phys_point_cache, phys_point, &phys_lower, &phys_upper );
303 *phys_lower_minimum = GSL_MIN( *phys_lower_minimum, phys_lower );
304 *phys_upper_maximum = GSL_MAX( *phys_upper_maximum, phys_upper );
305 }
306
307}
308
309///
310/// Callback function for computing lattice tiling statistics
311///
313 const bool first_call,
314 const LatticeTiling *tiling,
315 const LatticeTilingIterator *itr,
316 const gsl_vector *point,
317 const size_t changed_i,
318 const void *param UNUSED,
319 void *out
320)
321{
322
324
325 const size_t n = tiling->ndim;
326
327 // Initialise statistics
328 if ( first_call ) {
329 for ( size_t i = 0; i < n; ++i ) {
330 INT4 left = 0, right = 0;
332 const UINT4 num_points = right - left + 1;
334 stats[i].total_points = 0;
335 stats[i].min_points = num_points;
336 stats[i].max_points = num_points;
337 stats[i].min_value = gsl_vector_get( point, i );
338 stats[i].max_value = gsl_vector_get( point, i );
339 }
340 }
341
342 // Update statistics
343 for ( size_t i = changed_i; i < n; ++i ) {
344 INT4 left = 0, right = 0;
346 const UINT4 num_points = right - left + 1;
347 if ( i + 1 == n ) {
348 stats[i].total_points += num_points;
349 } else if ( i >= changed_i ) {
350 stats[i].total_points += 1;
351 }
352 stats[i].min_points = GSL_MIN( stats[i].min_points, num_points );
353 stats[i].max_points = GSL_MAX( stats[i].max_points, num_points );
354 const double step = XLALLatticeTilingStepSize( tiling, i );
355 stats[i].min_value = GSL_MIN( stats[i].min_value, gsl_vector_get( point, i ) + left * step );
356 stats[i].max_value = GSL_MAX( stats[i].max_value, gsl_vector_get( point, i ) + right * step );
357 }
358
359 return XLAL_SUCCESS;
360
361}
362
363///
364/// Initialise FITS table for saving and restoring a lattice tiling iterator
365///
367{
375 return XLAL_SUCCESS;
376}
377
378///
379/// Free memory pointed to by an index trie. The trie itself should be freed by the caller.
380///
382 LT_IndexTrie *trie ///< [in] Pointer to array of index tries
383)
384{
385 LT_IndexTrie *next = trie->next;
386 if ( next != NULL ) {
387 for ( INT4 i = trie->int_lower; i <= trie->int_upper; ++i ) {
388 LT_FreeIndexTrie( next++ );
389 }
390 XLALFree( trie->next );
391 }
392}
393
394///
395/// Find the nearest point within the parameter-space bounds of the lattice tiling, by polling
396/// the neighbours of an 'original' nearest point found by LT_FindNearestPoints().
397///
399 const LatticeTiling *tiling, ///< [in] Lattice tiling
400 const LT_IndexTrie *trie, ///< [in] Lattice tiling index trie
401 const size_t ti, ///< [in] Current depth of the trie
402 const gsl_vector *point_int, ///< [in] Original point in generating integers
403 INT4 *poll_nearest, ///< [in] Neighbouring point currently being polled
404 double *poll_min_distance, ///< [in] Minimum distance to neighbouring point found so far
405 INT4 *nearest ///< [in] New nearest point found by polling
406)
407{
408
409 const size_t n = tiling->ndim;
410 const size_t tn = tiling->tiled_ndim;
411
412 // Get integer lower and upper bounds
413 const INT4 int_lower = trie->int_lower;
414 const INT4 int_upper = trie->int_upper;
415
416 // Poll points within 1 of original nearest point, but within bounds
417 const size_t i = tiling->tiled_idx[ti];
418 const double point_int_i = gsl_vector_get( point_int, i );
419 const INT4 poll_lower = GSL_MAX( int_lower, GSL_MIN( floor( point_int_i ) - 1, int_upper ) );
420 const INT4 poll_upper = GSL_MAX( int_lower, GSL_MIN( ceil( point_int_i ) + 1, int_upper ) );
421
422 for ( poll_nearest[i] = poll_lower; poll_nearest[i] <= poll_upper; ++poll_nearest[i] ) {
423
424 // Continue polling in higher dimensions
425 if ( ti + 1 < tn ) {
426 const LT_IndexTrie *next = &trie->next[poll_nearest[i] - trie->int_lower];
427 LT_PollIndexTrie( tiling, next, ti + 1, point_int, poll_nearest, poll_min_distance, nearest );
428 continue;
429 }
430
431 // Compute distance between original and poll point with respect to lattice generator
432 double poll_distance = 0;
433 for ( size_t tj = 0; tj < tn; ++tj ) {
434 const size_t j = tiling->tiled_idx[tj];
435 const double diff_j = gsl_vector_get( point_int, j ) - poll_nearest[j];
436 for ( size_t tk = 0; tk < tn; ++tk ) {
437 const size_t k = tiling->tiled_idx[tk];
438 const double diff_k = gsl_vector_get( point_int, k ) - poll_nearest[k];
439 const double generator_j_k = gsl_matrix_get( tiling->tiled_generator, tj, tk );
440 poll_distance += generator_j_k * diff_j * diff_k;
441 }
442 }
443
444 // If distance is smaller than minimum distance, record current poll point as nearest
445 if ( poll_distance < *poll_min_distance ) {
446 *poll_min_distance = poll_distance;
447 memcpy( nearest, poll_nearest, n * sizeof( nearest[0] ) );
448 }
449
450 }
451
452}
453
454///
455/// Print one level of a lattice tiling index trie.
456///
458 const LatticeTiling *tiling, ///< [in] Lattice tiling
459 const LT_IndexTrie *trie, ///< [in] Lattice tiling index trie
460 const size_t ti, ///< [in] Current depth of the trie
461 FILE *file, ///< [in] File pointer to print trie to
462 INT4 int_lower[] ///< [in] Current integer lower bound
463)
464{
465
466 const size_t tn = tiling->tiled_ndim;
467
468 // Print indentation
469 for ( size_t s = 0; s <= ti; ++s ) {
470 fprintf( file, " " );
471 }
472
473 // Return if 'trie' is NULL (which should never happen)
474 if ( trie == NULL ) {
475 fprintf( file, "ERROR: 'trie' is NULL\n" );
476 return;
477 }
478
479 // Set 'i'th integer lower bound to 'trie' lower bound, then
480 // transform to physical coordinates from generating integers
481 int_lower[ti] = trie->int_lower;
482 const size_t i = tiling->tiled_idx[ti];
483 double phys_lower = gsl_vector_get( tiling->phys_origin, i );
484 for ( size_t tj = 0; tj < tn; ++tj ) {
485 const size_t j = tiling->tiled_idx[tj];
486 const double phys_from_int_i_j = gsl_matrix_get( tiling->phys_from_int, i, j );
487 phys_lower += phys_from_int_i_j * int_lower[tj];
488 }
489
490 // Calculate physical upper bound from physical lower_bound
491 const double phys_from_int_i_i = gsl_matrix_get( tiling->phys_from_int, i, i );
492 double phys_upper = phys_lower + phys_from_int_i_i * ( trie->int_upper - trie->int_lower );
493
494 // Print information on the current trie trie dimension
495 fprintf( file, "dim: #%zu/%zu int: [%+5" LAL_INT4_FORMAT ",%+5" LAL_INT4_FORMAT "] phys: [%+10g,%+10g] index:%" LAL_UINT8_FORMAT "\n",
496 ti + 1, tn, trie->int_lower, trie->int_upper, phys_lower, phys_upper, trie->index );
497
498 // If this is not the highest dimension, loop over this dimension
499 LT_IndexTrie *next = trie->next;
500 if ( next != NULL ) {
501 for ( int32_t point = trie->int_lower; point <= trie->int_upper; ++point, ++next ) {
502
503 // Set 'i'th integer lower bound to this point
504 int_lower[ti] = point;
505
506 // Print higher dimensions
507 LT_PrintIndexTrie( tiling, next, ti + 1, file, int_lower );
508
509 }
510 }
511
512}
513
514///
515/// Locate the nearest points in a lattice tiling to a given set of points. Return the nearest
516/// points in 'nearest_points', and optionally: unique sequential indexes to the nearest points in
517/// 'nearest_indexes', and indexes of the left/right-most points in the blocks of the nearest points
518/// relative to the nearest points in 'nearest_left' and 'nearest_right' respectively.
519///
521 const LatticeTilingLocator *loc, ///< [in] Lattice tiling locator
522 const gsl_matrix *points, ///< [in] Columns are set of points for which to find nearest points
523 gsl_matrix *nearest_points, ///< [out] Columns are the corresponding nearest points
524 UINT8VectorSequence *nearest_indexes, ///< [out] Vectors are unique sequential indexes of the nearest points
525 INT4VectorSequence *nearest_lefts, ///< [out] Vectors are indexes of left-most points of blocks relative to nearest points
526 INT4VectorSequence *nearest_rights ///< [out] Vectors are indexes of right-most points of blocks relative to nearest points
527)
528{
529
530 // Check input
531 XLAL_CHECK( loc != NULL, XLAL_EFAULT );
532 XLAL_CHECK( points != NULL, XLAL_EFAULT );
533 XLAL_CHECK( points->size1 == loc->ndim, XLAL_EINVAL );
534 XLAL_CHECK( nearest_points != NULL, XLAL_EFAULT );
535 XLAL_CHECK( nearest_points->size1 == loc->ndim, XLAL_EINVAL );
536 XLAL_CHECK( nearest_points->size2 == points->size2, XLAL_EINVAL );
537
538 const size_t n = loc->ndim;
539 const size_t tn = loc->tiled_ndim;
540 const size_t num_points = points->size2;
541
542 // Copy 'points' to 'nearest_points'
543 gsl_matrix_memcpy( nearest_points, points );
544
545 // Transform 'nearest_points' from physical coordinates to generating integers
546 for ( size_t i = 0; i < n; ++i ) {
547 const double phys_origin = gsl_vector_get( loc->tiling->phys_origin, i );
548 gsl_vector_view nearest_points_row = gsl_matrix_row( nearest_points, i );
549 gsl_vector_add_constant( &nearest_points_row.vector, -phys_origin );
550 }
551 gsl_blas_dtrmm( CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, 1.0, loc->tiling->int_from_phys, nearest_points );
552
553 // Find the nearest points in the lattice tiling to the points in 'nearest_points'
554 for ( size_t j = 0; j < num_points; ++j ) {
555
556 // If there are tiled dimensions:
557 INT4 nearest[n];
558 if ( tn > 0 ) {
559
560 // Find the nearest point to 'nearest_points[:,j]', the tiled dimensions of which are generating integers
561 switch ( loc->tiling->lattice ) {
562
563 case TILING_LATTICE_CUBIC: // Cubic ( \f$ Z_n \f$ ) lattice
564
565 {
566
567 // Round each dimension of 'nearest_points[:,j]' to nearest integer to find the nearest point in Zn
568 feclearexcept( FE_ALL_EXCEPT );
569 for ( size_t ti = 0; ti < tn; ++ti ) {
570 const size_t i = loc->tiling->tiled_idx[ti];
571 nearest[i] = lround( gsl_matrix_get( nearest_points, i, j ) );
572 }
573 if ( fetestexcept( FE_INVALID ) != 0 ) {
574 XLALPrintError( "Rounding failed while finding nearest point #%zu:", j );
575 for ( size_t ti = 0; ti < tn; ++ti ) {
576 const size_t i = loc->tiling->tiled_idx[ti];
577 XLALPrintError( " %0.2e", gsl_matrix_get( nearest_points, i, j ) );
578 }
579 XLALPrintError( "\n" );
581 }
582
583 }
584 break;
585
586 case TILING_LATTICE_ANSTAR: // An-star ( \f$ A_n^* \f$ ) lattice
587
588 {
589
590 // The nearest point algorithm used below embeds the An* lattice in tn+1 dimensions,
591 // however 'nearest_points[:,j]' has only 'tn' tiled dimensional. The algorithm is only
592 // sensitive to the differences between the 'ti'th and 'ti+1'th dimension, so we can
593 // freely set one of the dimensions to a constant value. We choose to set the 0th
594 // dimension to zero, i.e. the (tn+1)-dimensional lattice point is
595 // y = (0, tiled dimensions of 'nearest_points[:,j]').
596 double y[tn + 1];
597 y[0] = 0;
598 for ( size_t ti = 0; ti < tn; ++ti ) {
599 const size_t i = loc->tiling->tiled_idx[ti];
600 y[ti + 1] = gsl_matrix_get( nearest_points, i, j );
601 }
602
603 // Find the nearest point in An* to the point 'y', using the O(tn) Algorithm 2 given in:
604 // McKilliam et.al., "A linear-time nearest point algorithm for the lattice An*"
605 // in "International Symposium on Information Theory and Its Applications", ISITA2008,
606 // Auckland, New Zealand, 7-10 Dec. 2008. DOI: 10.1109/ISITA.2008.4895596
607 // Notes:
608 // * Since Algorithm 2 uses 1-based arrays, we have to translate, e.g.:
609 // z_t in paper <---> z[tn-1] in C code
610 // * Line 6 in Algorithm 2 as written in the paper is in error, see correction below.
611 // * We are only interested in 'k', the generating integers of the nearest point
612 // 'x = Q * k', therefore line 26 in Algorithm 2 is not included.
613 INT4 k[tn + 1];
614 {
615
616 // Lines 1--4, 20
617 double z[tn + 1], alpha = 0, beta = 0;
618 size_t bucket[tn + 1], link[tn + 1];
619 feclearexcept( FE_ALL_EXCEPT );
620 for ( size_t ti = 1; ti <= tn + 1; ++ti ) {
621 k[ti - 1] = lround( y[ti - 1] ); // Line 20, moved here to avoid duplicate round
622 z[ti - 1] = y[ti - 1] - k[ti - 1];
623 alpha += z[ti - 1];
624 beta += z[ti - 1] * z[ti - 1];
625 bucket[ti - 1] = 0;
626 }
627 if ( fetestexcept( FE_INVALID ) != 0 ) {
628 XLALPrintError( "Rounding failed while finding nearest point #%zu:", j );
629 for ( size_t ti = 1; ti <= tn + 1; ++ti ) {
630 XLALPrintError( " %0.2e", y[ti - 1] );
631 }
632 XLALPrintError( "\n" );
634 }
635
636 // Lines 5--8
637 // Notes:
638 // * Correction to line 6, as as written in McKilliam et.al.:
639 // ti = tn + 1 - (tn + 1)*floor(z_t + 0.5)
640 // should instead read
641 // ti = tn + 1 - floor((tn + 1)*(z_t + 0.5))
642 // * We also convert the floor() operation into an lround():
643 // ti = tn + 1 - lround((tn + 1)*(z_t + 0.5) - 0.5)
644 // to avoid a casting operation. Rewriting the line as:
645 // ti = lround((tn + 1)*(0.5 - z_t) + 0.5)
646 // appears to improve numerical robustness in some cases.
647 // * No floating-point exception checking needed for lround()
648 // here since its argument will be of order 'tn'.
649 for ( size_t tt = 1; tt <= tn + 1; ++tt ) {
650 const INT4 ti = lround( ( tn + 1 ) * ( 0.5 - z[tt - 1] ) + 0.5 );
651 link[tt - 1] = bucket[ti - 1];
652 bucket[ti - 1] = tt;
653 }
654
655 // Lines 9--10
656 double D = beta - alpha * alpha / ( tn + 1 );
657 size_t tm = 0;
658
659 // Lines 11--19
660 for ( size_t ti = 1; ti <= tn + 1; ++ti ) {
661 size_t tt = bucket[ti - 1];
662 while ( tt != 0 ) {
663 alpha = alpha - 1;
664 beta = beta - 2 * z[tt - 1] + 1;
665 tt = link[tt - 1];
666 }
667 double d = beta - alpha * alpha / ( tn + 1 );
668 if ( d < D ) {
669 D = d;
670 tm = ti;
671 }
672 }
673
674 // Lines 21--25
675 for ( size_t ti = 1; ti <= tm; ++ti ) {
676 size_t tt = bucket[ti - 1];
677 while ( tt != 0 ) {
678 k[tt - 1] = k[tt - 1] + 1;
679 tt = link[tt - 1];
680 }
681 }
682
683 }
684
685 // The nearest point in An* is the tn differences between k[1]...k[tn] and k[0]
686 for ( size_t ti = 0; ti < tn; ++ti ) {
687 const size_t i = loc->tiling->tiled_idx[ti];
688 nearest[i] = k[ti + 1] - k[0];
689 }
690
691 }
692 break;
693
694 default:
695 XLAL_ERROR( XLAL_EFAILED, "Invalid lattice" );
696 }
697
698 // Bound generating integers
699 {
700 const LT_IndexTrie *trie = loc->index_trie;
701 size_t ti = 0;
702 while ( ti < tn ) {
703 const size_t i = loc->tiling->tiled_idx[ti];
704
705 // If 'nearest[i]' is outside parameter-space bounds:
706 if ( nearest[i] < trie->int_lower || nearest[i] > trie->int_upper ) {
707 XLALPrintInfo( "%s: failed %" LAL_INT4_FORMAT " <= %" LAL_INT4_FORMAT " <= %" LAL_INT4_FORMAT " in dimension #%zu\n",
708 __func__, trie->int_lower, nearest[i], trie->int_upper, i );
709
710 // Find the nearest point within the parameter-space bounds of the lattice tiling
711 gsl_vector_view point_int_view = gsl_matrix_column( nearest_points, j );
712 INT4 poll_nearest[n];
713 double poll_min_distance = GSL_POSINF;
714 feclearexcept( FE_ALL_EXCEPT );
715 LT_PollIndexTrie( loc->tiling, loc->index_trie, 0, &point_int_view.vector, poll_nearest, &poll_min_distance, nearest );
716 XLAL_CHECK( fetestexcept( FE_INVALID ) == 0, XLAL_EFAILED, "Rounding failed while calling LT_PollIndexTrie() for nearest point #%zu", j );
717
718 // Reset 'trie', given that 'nearest' may have changed in any dimension
719 trie = loc->index_trie;
720 ti = 0;
721 continue;
722
723 }
724
725 // If we are below the highest dimension, jump to the next dimension based on 'nearest[i]'
726 if ( ti + 1 < tn ) {
727 trie = &trie->next[nearest[i] - trie->int_lower];
728 }
729
730 ++ti;
731
732 }
733 }
734
735 }
736
737 // Return various outputs
738 {
739 const LT_IndexTrie *trie = loc->index_trie;
741 for ( size_t ti = 0, i = 0; i < n; ++i ) {
742 const bool is_tiled = loc->tiling->bounds[i].is_tiled;
743
744 // Return nearest point
745 if ( is_tiled ) {
746 gsl_matrix_set( nearest_points, i, j, nearest[i] );
747 }
748
749 // Return sequential indexes of nearest point
750 // - Non-tiled dimensions inherit value of next-lowest dimension
751 if ( is_tiled ) {
752 nearest_index = trie->index + nearest[i] - trie->int_lower;
753 }
754 if ( nearest_indexes != NULL ) {
755 nearest_indexes->data[n * j + i] = nearest_index;
756 }
757
758 // Return indexes of left/right-most points in block relative to nearest point
759 if ( nearest_lefts != NULL ) {
760 nearest_lefts->data[n * j + i] = is_tiled ? trie->int_lower - nearest[i] : 0;
761 }
762 if ( nearest_rights != NULL ) {
763 nearest_rights->data[n * j + i] = is_tiled ? trie->int_upper - nearest[i] : 0;
764 }
765
766 // If we are below the highest dimension, jump to the next dimension based on 'nearest[i]'
767 if ( is_tiled ) {
768 if ( ti + 1 < tn ) {
769 trie = &trie->next[nearest[i] - trie->int_lower];
770 }
771 ++ti;
772 }
773
774 }
775 }
776
777 }
778
779 // Transform 'nearest_points' from generating integers to physical coordinates
780 gsl_blas_dtrmm( CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, 1.0, loc->tiling->phys_from_int, nearest_points );
781 for ( size_t i = 0; i < n; ++i ) {
782 const double phys_origin = gsl_vector_get( loc->tiling->phys_origin, i );
783 gsl_vector_view nearest_points_row = gsl_matrix_row( nearest_points, i );
784 gsl_vector_add_constant( &nearest_points_row.vector, phys_origin );
785 }
786
787 // Create local cache for computing physical bounds
788 double local_cache_array[n * LT_CACHE_MAX_SIZE];
789 gsl_matrix_view local_cache_view = gsl_matrix_view_array( local_cache_array, n, LT_CACHE_MAX_SIZE );
790 gsl_matrix *local_cache = &local_cache_view.matrix;
791 gsl_matrix_set_all( local_cache, GSL_NAN );
792
793 // Set any non-tiled dimensions in 'nearest_points'
794 for ( size_t j = 0; j < num_points; ++j ) {
795 gsl_vector_view nearest_points_col = gsl_matrix_column( nearest_points, j );
796 for ( size_t i = 0; i < n; ++i ) {
797 double phys_point = gsl_vector_get( &nearest_points_col.vector, i );
798 if ( !loc->tiling->bounds[i].is_tiled ) {
799 LT_CallBoundFunc( loc->tiling, i, local_cache, &nearest_points_col.vector, &phys_point, NULL );
800 }
801 LT_SetPhysPoint( loc->tiling, local_cache, &nearest_points_col.vector, i, phys_point );
802 }
803 }
804
805 return XLAL_SUCCESS;
806
807}
808
810 const size_t ndim
811)
812{
813
814 // Check input
815 XLAL_CHECK_NULL( ndim > 0, XLAL_EINVAL );
816
817 // Allocate memory
818 LatticeTiling *tiling = XLALCalloc( 1, sizeof( *tiling ) );
820 tiling->bounds = XLALCalloc( ndim, sizeof( *tiling->bounds ) );
821 XLAL_CHECK_NULL( tiling->bounds != NULL, XLAL_ENOMEM );
822 tiling->ncallback_done = XLALCalloc( 1, sizeof( *tiling->ncallback_done ) );
823 XLAL_CHECK_NULL( tiling->ncallback_done != NULL, XLAL_ENOMEM );
824
825 // Initialise fields
826 tiling->ndim = ndim;
827 tiling->lattice = TILING_LATTICE_MAX;
828
829 // Initialise default padding
830 for ( size_t i = 0; i < ndim; ++i ) {
832 }
833
834 // Allocate and initialise vectors and matrices
835 GAVEC_NULL( tiling->phys_bbox, ndim );
836 GAVEC_NULL( tiling->phys_origin, ndim );
837 gsl_vector_set_all( tiling->phys_origin, GSL_NAN );
838 GAMAT_NULL( tiling->int_from_phys, ndim, ndim );
839 gsl_matrix_set_identity( tiling->int_from_phys );
840 GAMAT_NULL( tiling->phys_from_int, ndim, ndim );
841 gsl_matrix_set_identity( tiling->phys_from_int );
842
843 return tiling;
844
845}
846
848 LatticeTiling *tiling
849)
850{
851 if ( tiling != NULL ) {
852 XLALFree( tiling->bounds );
853 XLALFree( tiling->tiled_idx );
854 for ( size_t m = 0; m < tiling->ncallback; ++m ) {
855 XLALFree( tiling->callbacks[m] );
856 }
857 XLALFree( tiling->callbacks );
858 XLALFree( tiling->ncallback_done );
859 GFMAT( tiling->int_from_phys, tiling->phys_from_int, tiling->tiled_generator );
860 GFVEC( tiling->phys_bbox, tiling->phys_origin, tiling->phys_origin_shift_frac );
861 XLALFree( tiling );
862 }
863}
864
866 LatticeTiling *tiling,
867 const size_t dim,
868 const LatticeTilingBound func,
869 const size_t data_len,
870 const void *data_lower,
871 const void *data_upper
872)
873{
874
875 // Check input
876 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
878 XLAL_CHECK( dim < tiling->ndim, XLAL_ESIZE );
879 XLAL_CHECK( func != NULL, XLAL_EFAULT );
880 XLAL_CHECK( data_len > 0, XLAL_EFAULT );
881 XLAL_CHECK( data_len < LT_DATA_MAX_SIZE, XLAL_EFAULT, "Arbitrary data is too long" );
882 XLAL_CHECK( data_lower != NULL, XLAL_EFAULT );
883 XLAL_CHECK( data_upper != NULL, XLAL_EFAULT );
884
885 // Check that bound has not already been set
886 XLAL_CHECK( tiling->bounds[dim].func == NULL, XLAL_EINVAL, "Lattice tiling dimension #%zu is already bounded", dim );
887
888 // Determine if this dimension is tiled
889 const BOOLEAN is_tiled = ( memcmp( data_lower, data_upper, data_len ) != 0 ) ? 1 : 0;
890
891 // Set the parameter-space bound
892 tiling->bounds[dim].is_tiled = is_tiled;
893 tiling->bounds[dim].func = func;
894 tiling->bounds[dim].data_len = data_len;
895 memcpy( tiling->bounds[dim].data_lower, data_lower, data_len );
896 memcpy( tiling->bounds[dim].data_upper, data_upper, data_len );
897
898 // Set a default parameter-space bound name, if none has yet been set
899 if ( !tiling->bounds[dim].name_set ) {
900 XLAL_CHECK( XLALSetLatticeTilingBoundName( tiling, dim, "dimension #%zu", dim ) == XLAL_SUCCESS, XLAL_EFUNC );
901 }
902
903 return XLAL_SUCCESS;
904
905}
906
908 LatticeTiling *tiling,
909 const size_t dim,
910 const char *fmt,
911 ...
912)
913{
914
915 // Check input
916 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
918 XLAL_CHECK( dim < tiling->ndim, XLAL_ESIZE );
919 XLAL_CHECK( fmt != NULL, XLAL_EFAULT );
920
921 // Check that bound has not already been named
922 XLAL_CHECK( !tiling->bounds[dim].name_set, XLAL_EINVAL, "Lattice tiling dimension #%zu is already named", dim );
923
924 // Set the parameter-space bound name
925 va_list ap;
926 va_start( ap, fmt );
927 const int retn = vsnprintf( tiling->bounds[dim].name, sizeof( tiling->bounds[dim].name ), fmt, ap );
928 va_end( ap );
929 XLAL_CHECK( retn < ( int ) sizeof( tiling->bounds[dim].name ), XLAL_EINVAL, "Name '%s' for lattice tiling dimension #%zu was truncated", tiling->bounds[dim].name, dim );
930 tiling->bounds[dim].name_set = true;
931
932 return XLAL_SUCCESS;
933
934}
935
937 LatticeTiling *tiling,
938 const size_t dim,
939 const LatticeTilingBoundCache func
940)
941{
942
943 // Check input
944 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
946 XLAL_CHECK( dim < tiling->ndim, XLAL_ESIZE );
947 XLAL_CHECK( func != NULL, XLAL_EFAULT );
948
949 // Check that bound has been set
950 XLAL_CHECK( tiling->bounds[dim].func != NULL, XLAL_EINVAL, "Lattice tiling dimension #%zu is not bounded", dim );
951
952 // Set the parameter-space bound cache function
953 tiling->bounds[dim].cache_func = func;
954
955 return XLAL_SUCCESS;
956
957}
958
959static double ConstantBound(
960 const void *data,
961 const size_t dim UNUSED,
962 const gsl_matrix *cache UNUSED,
963 const gsl_vector *point UNUSED
964)
965{
966
967 // Return bound
968 return *( ( const double * ) data );
969
970}
971
973 LatticeTiling *tiling,
974 const size_t dim,
975 const double bound1,
976 const double bound2
977)
978{
979
980 // Check input
981 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
982 XLAL_CHECK( isfinite( bound1 ), XLAL_EINVAL );
983 XLAL_CHECK( isfinite( bound2 ), XLAL_EINVAL );
984
985 // Set the parameter-space bound
986 const double data_lower = GSL_MIN( bound1, bound2 );
987 const double data_upper = GSL_MAX( bound1, bound2 );
988 XLAL_CHECK( XLALSetLatticeTilingBound( tiling, dim, ConstantBound, sizeof( data_lower ), &data_lower, &data_upper ) == XLAL_SUCCESS, XLAL_EFUNC );
989
990 return XLAL_SUCCESS;
991
992}
993
995 LatticeTiling *tiling,
996 const size_t dim,
997 const double lower_bbox_pad,
998 const double upper_bbox_pad,
999 const int lower_intp_pad,
1000 const int upper_intp_pad,
1001 const int find_bound_extrema
1002)
1003{
1004
1005 // Check input
1006 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1008 XLAL_CHECK( dim < tiling->ndim, XLAL_ESIZE );
1009
1010 // Set parameter-space padding
1011 tiling->bounds[dim].lower_bbox_pad = lower_bbox_pad < 0 ? 0.5 : lower_bbox_pad;
1012 tiling->bounds[dim].upper_bbox_pad = upper_bbox_pad < 0 ? 0.5 : upper_bbox_pad;
1013 tiling->bounds[dim].lower_intp_pad = lower_intp_pad < 0 ? 0 : lower_intp_pad;
1014 tiling->bounds[dim].upper_intp_pad = upper_intp_pad < 0 ? 0 : upper_intp_pad;
1015
1016 // Set whether to find the extrema of the parameter-space bounds
1017 tiling->bounds[dim].find_bound_extrema = find_bound_extrema < 0 ? true : ( find_bound_extrema ? true : false );
1018
1019 return XLAL_SUCCESS;
1020
1021}
1022
1024 LatticeTiling *tiling,
1025 const size_t dim,
1026 const double origin
1027)
1028{
1029
1030 // Check input
1031 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1033 XLAL_CHECK( dim < tiling->ndim, XLAL_ESIZE );
1034 XLAL_CHECK( isfinite( origin ), XLAL_EINVAL );
1035
1036 // Set physical parameter-space origin
1037 gsl_vector_set( tiling->phys_origin, dim, origin );
1038
1039 return XLAL_SUCCESS;
1040
1041}
1042
1044 LatticeTiling *tiling,
1045 RandomParams *rng
1046)
1047{
1048
1049 // Check input
1050 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1052 XLAL_CHECK( rng != NULL, XLAL_EFAULT );
1053
1054 const size_t n = tiling->ndim;
1055
1056 // Allocate memory
1057 GAVEC( tiling->phys_origin_shift_frac, n );
1058
1059 // Generate random uniform offsets for later use in XLALSetTilingLatticeAndMetric()
1060 // - Only values in tiled dimensions of 'phys_origin_shift_frac' will actually be used
1061 for ( size_t i = 0; i < n; ++i ) {
1062 gsl_vector_set( tiling->phys_origin_shift_frac, i, XLALUniformDeviate( rng ) );
1063 }
1064
1065 return XLAL_SUCCESS;
1066
1067}
1068
1070 LatticeTiling *tiling,
1071 const LatticeTiling *ref_tiling
1072)
1073{
1074
1075 // Check input
1076 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1078 XLAL_CHECK( ref_tiling != NULL, XLAL_EFAULT );
1079 XLAL_CHECK( ref_tiling->lattice < TILING_LATTICE_MAX, XLAL_EINVAL );
1080 XLAL_CHECK( tiling->ndim == ref_tiling->ndim, XLAL_EINVAL );
1081
1082 const size_t n = tiling->ndim;
1083
1084 // Check that all parameter-space dimensions are bounded
1085 for ( size_t i = 0; i < n; ++i ) {
1086 XLAL_CHECK( tiling->bounds[i].func != NULL, XLAL_EFAILED, "Lattice tiling dimension #%zu is unbounded", i );
1087 }
1088
1089 // Set the tiled dimensions of 'tiling' to match 'ref_tiling'
1090 for ( size_t i = 0; i < n; ++i ) {
1091 tiling->bounds[i].is_tiled = ref_tiling->bounds[i].is_tiled;
1092 }
1093
1094 return XLAL_SUCCESS;
1095
1096}
1097
1099 LatticeTiling *tiling,
1100 const TilingLattice lattice,
1101 const gsl_matrix *metric,
1102 const double max_mismatch
1103)
1104{
1105
1106 // Check input
1107 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1110 XLAL_CHECK( metric != NULL, XLAL_EFAULT );
1111 XLAL_CHECK( metric->size1 == tiling->ndim && metric->size2 == tiling->ndim, XLAL_EINVAL );
1112 XLAL_CHECK( max_mismatch > 0, XLAL_EINVAL );
1113
1114 const size_t n = tiling->ndim;
1115
1116 // Check that all parameter-space dimensions are bounded
1117 for ( size_t i = 0; i < n; ++i ) {
1118 XLAL_CHECK( tiling->bounds[i].func != NULL, XLAL_EFAILED, "Lattice tiling dimension #%zu is unbounded", i );
1119 }
1120
1121 // Check metric is symmetric and has positive diagonal elements
1122 for ( size_t i = 0; i < n; ++i ) {
1123 XLAL_CHECK( gsl_matrix_get( metric, i, i ) > 0, XLAL_EINVAL, "Parameter-space metric(%zu,%zu) <= 0", i, i );
1124 for ( size_t j = i + 1; j < n; ++j ) {
1125 XLAL_CHECK( gsl_matrix_get( metric, i, j ) == gsl_matrix_get( metric, j, i ), XLAL_EINVAL, "Parameter-space metric(%zu,%zu) != metric(%zu,%zu)", i, j, j, i );
1126 }
1127 }
1128
1129 // Set type of lattice to generate tiling with
1130 tiling->lattice = lattice;
1131
1132 // Set physical parameter-space origin to mid-point of parameter-space bounds
1133 gsl_matrix *GAMAT( phys_origin_cache, n, LT_CACHE_MAX_SIZE );
1134 gsl_matrix_set_all( phys_origin_cache, GSL_NAN );
1135 for ( size_t i = 0; i < n; ++i ) {
1136 double phys_origin_i = gsl_vector_get( tiling->phys_origin, i );
1137 if ( !isfinite( phys_origin_i ) ) {
1138 double phys_lower = 0.0, phys_upper = 0.0;
1139 LT_CallBoundFunc( tiling, i, phys_origin_cache, tiling->phys_origin, &phys_lower, &phys_upper );
1140 phys_origin_i = 0.5 * ( phys_lower + phys_upper );
1141 }
1142 LT_SetPhysPoint( tiling, phys_origin_cache, tiling->phys_origin, i, phys_origin_i );
1143 }
1144
1145 // Register default statistics callback function
1146 tiling->stats = XLALRegisterLatticeTilingCallback( tiling, LT_StatsCallback, 0, NULL, tiling->ndim * sizeof( *tiling->stats ) );
1147 XLAL_CHECK( tiling->stats != NULL, XLAL_EFUNC );
1148
1149 // Count number of tiled dimensions; if no parameter-space dimensions are tiled, we're done
1150 tiling->tiled_ndim = 0;
1151 for ( size_t i = 0; i < n; ++i ) {
1152 if ( tiling->bounds[i].is_tiled ) {
1153 ++tiling->tiled_ndim;
1154 }
1155 }
1156 if ( tiling->tiled_ndim == 0 ) {
1157 return XLAL_SUCCESS;
1158 }
1159
1160 const size_t tn = tiling->tiled_ndim;
1161
1162 // Build index to tiled parameter-space dimensions
1163 tiling->tiled_idx = XLALCalloc( tn, sizeof( *tiling->tiled_idx ) );
1164 XLAL_CHECK( tiling->tiled_idx != NULL, XLAL_ENOMEM );
1165 for ( size_t i = 0, ti = 0; i < n; ++i ) {
1166 if ( tiling->bounds[i].is_tiled ) {
1167 tiling->tiled_idx[ti++] = i;
1168 }
1169 }
1170
1171 // Calculate normalisation scale from metric diagonal elements
1172 gsl_vector *GAVEC( t_norm, tn );
1173 for ( size_t ti = 0; ti < tn; ++ti ) {
1174 const size_t i = tiling->tiled_idx[ti];
1175 const double metric_i_i = gsl_matrix_get( metric, i, i );
1176 gsl_vector_set( t_norm, ti, sqrt( metric_i_i ) );
1177 }
1178
1179 // Copy and normalise tiled dimensions of metric
1180 gsl_matrix *GAMAT( t_metric, tn, tn );
1181 for ( size_t ti = 0; ti < tn; ++ti ) {
1182 const size_t i = tiling->tiled_idx[ti];
1183 const double t_norm_ti = gsl_vector_get( t_norm, ti );
1184 for ( size_t tj = 0; tj < tn; ++tj ) {
1185 const size_t j = tiling->tiled_idx[tj];
1186 const double t_norm_tj = gsl_vector_get( t_norm, tj );
1187 gsl_matrix_set( t_metric, ti, tj, gsl_matrix_get( metric, i, j ) / t_norm_ti / t_norm_tj );
1188 }
1189 }
1190
1191 // Compute metric ellipse bounding box
1192 gsl_vector *t_bbox = XLALMetricEllipseBoundingBox( t_metric, max_mismatch );
1193 XLAL_CHECK( t_bbox != NULL, XLAL_EFUNC );
1194
1195 // Copy bounding box in physical coordinates to tiled dimensions
1196 for ( size_t ti = 0; ti < tn; ++ti ) {
1197 const size_t i = tiling->tiled_idx[ti];
1198 const double t_norm_ti = gsl_vector_get( t_norm, ti );
1199 gsl_vector_set( tiling->phys_bbox, i, gsl_vector_get( t_bbox, ti ) / t_norm_ti );
1200 }
1201
1202 // Compute a lower-triangular basis matrix whose columns are orthonormal with respect to the tiled metric
1203 gsl_matrix *GAMAT( t_basis, tn, tn );
1204 {
1205 // We want to find a lower-triangular basis such that:
1206 // basis^T * metric * basis = I
1207 // This is rearranged to give:
1208 // metric^-1 = basis * basis^T
1209 // Hence basis is the Cholesky decomposition of metric^-1
1210 gsl_matrix_memcpy( t_basis, t_metric );
1211 XLAL_CHECK( gsl_linalg_cholesky_decomp( t_basis ) == 0, XLAL_EFAILED, "Parameter-space metric is not positive definite" );
1212 XLAL_CHECK( gsl_linalg_cholesky_invert( t_basis ) == 0, XLAL_EFAILED, "Parameter-space metric cannot be inverted" );
1213 XLAL_CHECK( gsl_linalg_cholesky_decomp( t_basis ) == 0, XLAL_EFAILED, "Inverse of parameter-space metric is not positive definite" );
1214
1215 // gsl_linalg_cholesky_decomp() stores both basis and basis^T
1216 // in the same matrix; zero out upper triangle to get basis
1217 LT_ZeroStrictUpperTriangle( t_basis );
1218 }
1219
1220 // Compute a lower-triangular generator matrix for a given lattice type and mismatch
1221 GAMAT( tiling->tiled_generator, tn, tn );
1222 {
1223
1224 // Compute lattice generator and normalised thickness
1225 double norm_thickness = 0.0;
1226 switch ( tiling->lattice ) {
1227
1228 case TILING_LATTICE_CUBIC: // Cubic ( \f$ Z_n \f$ ) lattice
1229
1230 {
1231
1232 // Zn lattice generator is the identity
1233 gsl_matrix_set_identity( tiling->tiled_generator );
1234
1235 // Zn normalised thickness
1236 norm_thickness = pow( sqrt( tn ) / 2.0, tn );
1237
1238 }
1239 break;
1240
1241 case TILING_LATTICE_ANSTAR: // An-star ( \f$ A_n^* \f$ ) lattice
1242
1243 {
1244
1245 // An* lattice generator in tn+1 dimensions, given in:
1246 // McKilliam et.al., "A linear-time nearest point algorithm for the lattice An*"
1247 // in "International Symposium on Information Theory and Its Applications", ISITA2008,
1248 // Auckland, New Zealand, 7-10 Dec. 2008. DOI: 10.1109/ISITA.2008.4895596
1249 gsl_matrix *GAMAT( G, tn + 1, tn + 1 );
1250 gsl_matrix_set_identity( G );
1251 gsl_matrix_add_constant( G, -1.0 / ( tn + 1 ) );
1252
1253 // Find the QL decomposition of the generator matrix G, excluding 1st column,
1254 // which is linearly dependent on the remaining columns:
1255 // G(:, 2:end) = Gp = Q * L
1256 // where Q is an orthogonal matrix and L an lower-triangular matrix.
1257 // This is found using the more commonly implemented QR decomposition by:
1258 // - reversing the order of the rows/columns of Gp
1259 // - decomposing Gp = Qp * Lp, where Lp is upper triangular
1260 // - reversing the order of the rows/columns of Qp to give Q
1261 // - reversing the order of the rows/columns of Lp to give L
1262 gsl_matrix_view Gp = gsl_matrix_submatrix( G, 0, 1, tn + 1, tn );
1263 LT_ReverseOrderRowsCols( &Gp.matrix );
1264 gsl_vector *GAVEC( tau, tn );
1265 XLAL_CHECK( gsl_linalg_QR_decomp( &Gp.matrix, tau ) == 0, XLAL_EFAILED, "'G' cannot be QR-decomposed" );
1266 gsl_matrix *GAMAT( Q, tn + 1, tn + 1 );
1267 gsl_matrix *GAMAT( L, tn + 1, tn );
1268 gsl_linalg_QR_unpack( &Gp.matrix, tau, Q, L );
1271
1272 // Discard the first row of L, which is zero, to get the generator in tn dimensions
1273 gsl_matrix_view L_view = gsl_matrix_submatrix( L, 1, 0, tn, tn );
1274 gsl_matrix_memcpy( tiling->tiled_generator, &L_view.matrix );
1275
1276 // Cleanup
1277 GFMAT( G, L, Q );
1278 GFVEC( tau );
1279
1280 // An* normalised thickness
1281 norm_thickness = sqrt( tn + 1.0 ) * pow( ( 1.0 * tn * ( tn + 2.0 ) ) / ( 12.0 * ( tn + 1.0 ) ), 0.5 * tn );
1282
1283 }
1284 break;
1285
1286 default:
1287 XLAL_ERROR( XLAL_EFAILED, "Invalid lattice" );
1288 }
1289
1290 // Generator will be lower-triangular, so zero out upper triangle
1291 LT_ZeroStrictUpperTriangle( tiling->tiled_generator );
1292
1293 // Ensure that the generator has positive diagonal elements, by
1294 // changing the sign of the columns of the matrix, if necessary
1295 for ( size_t tj = 0; tj < tn; ++tj ) {
1296 gsl_vector_view generator_col = gsl_matrix_column( tiling->tiled_generator, tj );
1297 XLAL_CHECK( gsl_vector_get( &generator_col.vector, tj ) != 0, XLAL_ERANGE, "Generator matrix(%zu,%zu) == 0", tj, tj );
1298 if ( gsl_vector_get( &generator_col.vector, tj ) < 0 ) {
1299 gsl_vector_scale( &generator_col.vector, -1 );
1300 }
1301 }
1302
1303 // Compute generator LU decomposition
1304 gsl_matrix *GAMAT( LU_decomp, tn, tn );
1305 gsl_matrix_memcpy( LU_decomp, tiling->tiled_generator );
1306 gsl_permutation *GAPERM( LU_perm, tn );
1307 int LU_sign = 0;
1308 XLAL_CHECK( gsl_linalg_LU_decomp( LU_decomp, LU_perm, &LU_sign ) == 0, XLAL_EFAILED, "Generator matrix cannot be LU-decomposed" );
1309
1310 // Compute generator determinant
1311 const double generator_determinant = XLALMetricDeterminant( tiling->tiled_generator );
1312 XLAL_CHECK( !XLAL_IS_REAL8_FAIL_NAN( generator_determinant ), XLAL_EFUNC );
1313
1314 // Compute generator covering radius
1315 const double generator_covering_radius = pow( norm_thickness * generator_determinant, 1.0 / tn );
1316
1317 // Normalise so covering spheres have sqrt(max_mismatch) covering radii
1318 gsl_matrix_scale( tiling->tiled_generator, sqrt( max_mismatch ) / generator_covering_radius );
1319
1320 // Cleanup
1321 GFMAT( LU_decomp );
1322 GFPERM( LU_perm );
1323
1324 }
1325
1326 // Compute transform to normalised physical coordinates from generating integers
1327 gsl_matrix *GAMAT( t_norm_from_int, tn, tn );
1328 gsl_blas_dgemm( CblasNoTrans, CblasNoTrans, 1.0, t_basis, tiling->tiled_generator, 0.0, t_norm_from_int );
1329 LT_ZeroStrictUpperTriangle( t_norm_from_int );
1330
1331 // Compute transform to generating integers from normalised physical coordinates
1332 gsl_matrix *GAMAT( t_int_from_norm, tn, tn );
1333 gsl_matrix_set_identity( t_int_from_norm );
1334 gsl_blas_dtrsm( CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, 1.0, t_norm_from_int, t_int_from_norm );
1335 LT_ZeroStrictUpperTriangle( t_int_from_norm );
1336
1337 // Set tiled dimensions of transforms, and convert to unnormalised physical coordinates
1338 for ( size_t ti = 0; ti < tn; ++ti ) {
1339 const size_t i = tiling->tiled_idx[ti];
1340 const double t_norm_ti = gsl_vector_get( t_norm, ti );
1341 for ( size_t tj = 0; tj < tn; ++tj ) {
1342 const size_t j = tiling->tiled_idx[tj];
1343 const double t_norm_tj = gsl_vector_get( t_norm, tj );
1344 gsl_matrix_set( tiling->int_from_phys, i, j, gsl_matrix_get( t_int_from_norm, ti, tj ) * t_norm_tj );
1345 gsl_matrix_set( tiling->phys_from_int, i, j, gsl_matrix_get( t_norm_from_int, ti, tj ) / t_norm_ti );
1346 }
1347 }
1348
1349 // Round tiled dimensions of physical parameter-space origin to nearest lattice step size, then
1350 // shift by the fraction of a step size 'phys_origin_shift_frac_i', if given, or 0.5 otherwise.
1351 // - The default of 0.5 was to ensure that the tiling will never place a lattice point at zero
1352 // in physical coordinates, since the physical coordinates may not be well-defined at zero.
1353 // This could potentially not be the case if 'phys_origin_shift_frac_i' happens to be zero.
1354 for ( size_t i = 0; i < n; ++i ) {
1355 double phys_origin_i = gsl_vector_get( tiling->phys_origin, i );
1356 if ( tiling->bounds[i].is_tiled ) {
1357 const double int_from_phys_i_i = gsl_matrix_get( tiling->int_from_phys, i, i );
1358 const double phys_from_int_i_i = gsl_matrix_get( tiling->phys_from_int, i, i );
1359 const double phys_origin_shift_frac_i = ( tiling->phys_origin_shift_frac != NULL ) ? gsl_vector_get( tiling->phys_origin_shift_frac, i ) : 0.5;
1360 phys_origin_i = ( round( phys_origin_i * int_from_phys_i_i ) + phys_origin_shift_frac_i ) * phys_from_int_i_i;
1361 }
1362 LT_SetPhysPoint( tiling, phys_origin_cache, tiling->phys_origin, i, phys_origin_i );
1363 }
1364
1365 // Cleanup
1366 GFMAT( t_metric, t_basis, t_norm_from_int, t_int_from_norm, phys_origin_cache );
1367 GFVEC( t_norm, t_bbox );
1368
1369 return XLAL_SUCCESS;
1370
1371}
1372
1374 const LatticeTiling *tiling
1375)
1376{
1377
1378 // Check input
1379 XLAL_CHECK_VAL( 0, tiling != NULL, XLAL_EFAULT );
1380
1381 return tiling->ndim;
1382
1383}
1384
1386 const LatticeTiling *tiling
1387)
1388{
1389
1390 // Check input
1391 XLAL_CHECK_VAL( 0, tiling != NULL, XLAL_EFAULT );
1393
1394 return tiling->tiled_ndim;
1395
1396}
1397
1399 const LatticeTiling *tiling,
1400 const size_t tiled_dim
1401)
1402{
1403
1404 // Check input
1405 XLAL_CHECK_VAL( 0, tiling != NULL, XLAL_EFAULT );
1407 XLAL_CHECK_VAL( 0, tiled_dim < tiling->tiled_ndim, XLAL_ESIZE );
1408
1409 return tiling->tiled_idx[tiled_dim];
1410
1411}
1412
1414 const LatticeTiling *tiling,
1415 const size_t dim
1416)
1417{
1418
1419 // Check input
1420 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1421 XLAL_CHECK( dim < tiling->ndim, XLAL_ESIZE );
1422 XLAL_CHECK( tiling->bounds[dim].func != NULL, XLAL_EINVAL, "Lattice tiling dimension #%zu is not bounded", dim );
1423
1424 return tiling->bounds[dim].is_tiled ? 1 : 0;
1425
1426}
1427
1429 const LatticeTiling *tiling,
1430 const size_t dim
1431)
1432{
1433
1434 // Check input
1437 XLAL_CHECK_NULL( dim < tiling->ndim, XLAL_ESIZE );
1438
1439 return tiling->bounds[dim].name;
1440
1441}
1442
1444 const LatticeTiling *tiling,
1445 const char *bound_name
1446)
1447{
1448
1449 // Check input
1450 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1451 XLAL_CHECK( bound_name != NULL, XLAL_EFAULT );
1452
1453 // Find and return index of dimension with matching bound name
1454 for ( int dim = 0; dim < ( int )tiling->ndim; ++dim ) {
1455 if ( strcmp( tiling->bounds[dim].name, bound_name ) == 0 ) {
1456 return dim;
1457 }
1458 }
1459
1460 return XLAL_FAILURE;
1461
1462}
1463
1465 const LatticeTiling *tiling,
1466 const size_t dim
1467)
1468{
1469
1470 // Check input
1473 XLAL_CHECK_REAL8( dim < tiling->ndim, XLAL_ESIZE );
1474
1475 // Return 0 for non-tiled dimensions
1476 if ( !tiling->bounds[dim].is_tiled ) {
1477 return 0.0;
1478 }
1479
1480 // Step size is the (dim)th diagonal element of 'phys_from_int'
1481 return gsl_matrix_get( tiling->phys_from_int, dim, dim );
1482
1483}
1484
1486 const LatticeTiling *tiling,
1487 const size_t dim
1488)
1489{
1490
1491 // Check input
1494 XLAL_CHECK_REAL8( dim < tiling->ndim, XLAL_ESIZE );
1495
1496 // Return 0 for non-tiled dimensions
1497 if ( !tiling->bounds[dim].is_tiled ) {
1498 return 0.0;
1499 }
1500
1501 return gsl_vector_get( tiling->phys_bbox, dim );
1502
1503}
1504
1506 LatticeTiling *tiling,
1507 const LatticeTilingCallback func,
1508 const size_t param_len,
1509 const void *param,
1510 const size_t out_len
1511)
1512{
1513
1514 // Check input
1517 XLAL_CHECK_NULL( func != NULL, XLAL_EFAULT );
1518 XLAL_CHECK_NULL( ( param_len > 0 ) == ( param != NULL ), XLAL_EINVAL );
1520 XLAL_CHECK_NULL( out_len > 0, XLAL_EINVAL );
1522
1523 // Allocate memory for new callback
1524 ++tiling->ncallback;
1525 tiling->callbacks = XLALRealloc( tiling->callbacks, tiling->ncallback * sizeof( *tiling->callbacks ) );
1526 XLAL_CHECK_NULL( tiling->callbacks != NULL, XLAL_ENOMEM );
1527 LT_Callback *cb = tiling->callbacks[tiling->ncallback - 1] = XLALCalloc( 1, sizeof( *cb ) );
1528 XLAL_CHECK_NULL( cb != NULL, XLAL_ENOMEM );
1529
1530 // Set fields
1531 cb->func = func;
1532 cb->param_len = param_len;
1533 if ( param_len > 0 ) {
1534 memcpy( cb->param, param, param_len );
1535 }
1536
1537 return cb->out;
1538
1539}
1540
1542 const LatticeTiling *tiling
1543)
1544{
1545
1546 // Check input
1547 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1549
1550 // Return immediately if there are no callbacks to perform
1551 if ( *tiling->ncallback_done == tiling->ncallback ) {
1552 return XLAL_SUCCESS;
1553 }
1554
1555 const size_t n = tiling->ndim;
1556 const size_t tn = tiling->tiled_ndim;
1557
1558 // Create iterator over tiling (except highest dimension)
1559 LatticeTilingIterator *itr = XLALCreateLatticeTilingIterator( tiling, n - 1 );
1560 XLAL_CHECK( itr != NULL, XLAL_EFUNC );
1561
1562 // Iterate over all points
1563 double volume_pc_prev = 0;
1564 bool first_call = true;
1565 int changed_ti_p1;
1566 double point_array[n];
1567 gsl_vector_view point_view = gsl_vector_view_array( point_array, n );
1568 while ( ( changed_ti_p1 = XLALNextLatticeTilingPoint( itr, &point_view.vector ) ) > 0 ) {
1569 const size_t changed_i = ( !first_call && tiling->tiled_ndim > 0 ) ? tiling->tiled_idx[changed_ti_p1 - 1] : 0;
1570
1571 // Call callback functions
1572 for ( size_t m = *tiling->ncallback_done; m < tiling->ncallback; ++m ) {
1573 LT_Callback *cb = tiling->callbacks[m];
1574 XLAL_CHECK( ( cb->func )( first_call, tiling, itr, &point_view.vector, changed_i, cb->param, cb->out ) == XLAL_SUCCESS, XLAL_EFUNC );
1575 }
1576
1577 // Estimate volume of parameter space covered
1578 double volume_pc = 0.0;
1579 double volume_pc_norm = 1.0;
1580 for ( size_t tj = 0; tj < tn; ++tj ) {
1581 const size_t j = itr->tiling->tiled_idx[tj];
1582 const INT8 count_j = itr->int_point[j] - itr->int_lower[j];
1583 const INT8 total_j = itr->int_upper[j] - itr->int_lower[j] + 1;
1584 volume_pc += 100.0 * ( ( double ) count_j ) / ( ( double ) total_j ) / volume_pc_norm;
1585 volume_pc_norm *= ( double ) total_j;
1586 }
1587
1588 // Log progress if:
1589 // - at least 1000 points have been counted
1590 // - parameter space covered has increased by ( EITHER a factor of 3 OR 5 percentage points ) since last log
1591 const UINT8 total_points = tiling->stats[n - 1].total_points;
1592 if ( total_points >= 1000 && ( volume_pc >= 3.0 * volume_pc_prev || volume_pc - volume_pc_prev >= 5.0 ) ) {
1593 volume_pc_prev = volume_pc;
1594 LogPrintf( LatticeTilingProgressLogLevel, "LatticeTiling: counted %" LAL_UINT8_FORMAT " templates; estimated %0.2g%% done\n", total_points, volume_pc );
1595 }
1596
1597 first_call = false;
1598 }
1600
1601 // Log final progress
1602 {
1603 const UINT8 total_points = tiling->stats[n - 1].total_points;
1604 LogPrintf( LatticeTilingProgressLogLevel, "LatticeTiling: counted %" LAL_UINT8_FORMAT " templates; done\n", total_points );
1605 }
1606
1607 // Mark callbacks as have been successfully performed
1608 *tiling->ncallback_done = tiling->ncallback;
1609
1610 // Cleanup
1612
1613 return XLAL_SUCCESS;
1614
1615}
1616
1618 const LatticeTiling *tiling,
1619 const size_t dim
1620)
1621{
1622
1623 // Check input
1626 XLAL_CHECK_NULL( tiling->stats != NULL, XLAL_EFUNC );
1627 XLAL_CHECK_NULL( dim < tiling->ndim, XLAL_ESIZE );
1628
1629 // Ensure statistics have been computed
1631 XLAL_CHECK_NULL( tiling->stats[dim].total_points > 0, XLAL_EFAILED );
1632
1633 return &tiling->stats[dim];
1634
1635}
1636
1638 const LatticeTiling *tiling,
1639 const double scale,
1640 RandomParams *rng,
1641 gsl_matrix *random_points
1642)
1643{
1644
1645 // Check input
1646 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1648 XLAL_CHECK( scale > -1.0, XLAL_EINVAL );
1649 XLAL_CHECK( rng != NULL, XLAL_EFAULT );
1650 XLAL_CHECK( random_points != NULL, XLAL_EFAULT );
1651 XLAL_CHECK( random_points->size1 == tiling->ndim, XLAL_ESIZE );
1652
1653 const size_t n = tiling->ndim;
1654
1655 // Generate random points in parameter space
1656 gsl_matrix *GAMAT( phys_point_cache, n, LT_CACHE_MAX_SIZE );
1657 gsl_matrix_set_all( phys_point_cache, GSL_NAN );
1658 for ( size_t k = 0; k < random_points->size2; ++k ) {
1659 gsl_vector_view phys_point = gsl_matrix_column( random_points, k );
1660 for ( size_t i = 0; i < n; ++i ) {
1661
1662 // Get the physical bounds on the current dimension
1663 double phys_lower = 0.0, phys_upper = 0.0;
1664 LT_CallBoundFunc( tiling, i, phys_point_cache, &phys_point.vector, &phys_lower, &phys_upper );
1665
1666 // Generate random number
1667 const double u = ( 1.0 + scale ) * ( XLALUniformDeviate( rng ) - 0.5 ) + 0.5;
1668
1669 // Set parameter-space point
1670 LT_SetPhysPoint( tiling, phys_point_cache, &phys_point.vector, i, phys_lower + u * ( phys_upper - phys_lower ) );
1671
1672 }
1673
1674 }
1675
1676 // Cleanup
1677 GFMAT( phys_point_cache );
1678
1679 return XLAL_SUCCESS;
1680
1681}
1682
1684 const LatticeTiling *tiling,
1685 const size_t dim,
1686 const gsl_vector *point,
1687 const bool padding,
1688 double *lower,
1689 double *upper
1690)
1691{
1692
1693 // Check input
1694 XLAL_CHECK( tiling != NULL, XLAL_EFAULT );
1696 XLAL_CHECK( dim < tiling->ndim, XLAL_ESIZE );
1697 XLAL_CHECK( point != NULL, XLAL_EFAULT );
1698 XLAL_CHECK( lower != NULL, XLAL_EFAULT );
1699 XLAL_CHECK( upper != NULL, XLAL_EFAULT );
1700
1701 const size_t n = tiling->ndim;
1702
1703 // Get bound information for this dimension
1704 const LT_Bound *bound = &tiling->bounds[dim];
1705
1706 // Get the parameter-space bounds on the current dimension:
1707 // - If tiled, or padding requested, get bounds respecting strict/extrema settings, and add padding
1708 // - Otherwise, get bounds without extrema/padding
1709 gsl_vector *GAVEC( phys_sampl, n );
1710 gsl_matrix *GAMAT( phys_point_cache, n, LT_CACHE_MAX_SIZE );
1711 gsl_matrix *GAMAT( phys_sampl_cache, n, LT_CACHE_MAX_SIZE );
1712 gsl_vector_memcpy( phys_sampl, point );
1713 *lower = GSL_POSINF;
1714 *upper = GSL_NEGINF;
1715 if ( bound->is_tiled && padding ) {
1716 if ( STRICT_BOUND_PADDING( bound ) || !bound->find_bound_extrema ) {
1717 LT_CallBoundFunc( tiling, dim, phys_point_cache, phys_sampl, lower, upper );
1718 } else {
1719 LT_FindBoundExtrema( tiling, 0, dim, phys_sampl_cache, phys_sampl, lower, upper );
1720 }
1721 const double phys_bbox_dim = gsl_vector_get( tiling->phys_bbox, dim );
1722 *lower -= bound->lower_bbox_pad * phys_bbox_dim;
1723 *upper += bound->upper_bbox_pad * phys_bbox_dim;
1724 } else {
1725 LT_CallBoundFunc( tiling, dim, phys_point_cache, phys_sampl, lower, upper );
1726 }
1727
1728 // Cleanup
1729 GFVEC( phys_sampl );
1730 GFMAT( phys_point_cache );
1731 GFMAT( phys_sampl_cache );
1732
1733 return XLAL_SUCCESS;
1734
1735}
1736
1737LatticeTilingIterator *XLALCreateLatticeTilingIterator(
1738 const LatticeTiling *tiling,
1739 const size_t itr_ndim
1740)
1741{
1742
1743 // Check input
1746 XLAL_CHECK_NULL( itr_ndim <= tiling->ndim, XLAL_EINVAL );
1747
1748 // Allocate memory
1749 LatticeTilingIterator *itr = XLALCalloc( 1, sizeof( *itr ) );
1750 XLAL_CHECK_NULL( itr != NULL, XLAL_ENOMEM );
1751
1752 // Store reference to lattice tiling
1753 itr->tiling = tiling;
1754
1755 // Set fields
1756 itr->itr_ndim = itr_ndim;
1757 itr->alternating = false;
1758 itr->state = 0;
1759 itr->index = 0;
1760
1761 // Determine the maximum tiled dimension to iterate over
1762 itr->tiled_itr_ndim = 0;
1763 for ( size_t i = 0; i < itr_ndim; ++i ) {
1764 if ( itr->tiling->bounds[i].is_tiled ) {
1765 ++itr->tiled_itr_ndim;
1766 }
1767 }
1768
1769 const size_t n = itr->tiling->ndim;
1770 const size_t tn = itr->tiling->tiled_ndim;
1771
1772 // Allocate and initialise vectors and matrices
1773 GAVEC_NULL( itr->phys_point, n );
1774 GAMAT_NULL( itr->phys_point_cache, n, LT_CACHE_MAX_SIZE );
1775 gsl_matrix_set_all( itr->phys_point_cache, GSL_NAN );
1776 GAVEC_NULL( itr->phys_sampl, n );
1777 GAMAT_NULL( itr->phys_sampl_cache, n, LT_CACHE_MAX_SIZE );
1778 gsl_matrix_set_all( itr->phys_sampl_cache, GSL_NAN );
1779 if ( tn > 0 ) {
1780 itr->int_lower = XLALCalloc( tn, sizeof( *itr->int_lower ) );
1781 XLAL_CHECK_NULL( itr->int_lower != NULL, XLAL_EINVAL );
1782 itr->int_point = XLALCalloc( tn, sizeof( *itr->int_point ) );
1783 XLAL_CHECK_NULL( itr->int_point != NULL, XLAL_EINVAL );
1784 itr->int_upper = XLALCalloc( tn, sizeof( *itr->int_upper ) );
1785 XLAL_CHECK_NULL( itr->int_upper != NULL, XLAL_EINVAL );
1786 itr->direction = XLALCalloc( tn, sizeof( *itr->direction ) );
1787 XLAL_CHECK_NULL( itr->direction != NULL, XLAL_EINVAL );
1788 }
1789
1790 // Set iterator to beginning of lattice tiling
1792
1793 return itr;
1794
1795}
1796
1798 LatticeTilingIterator *itr
1799)
1800{
1801 if ( itr ) {
1802 GFVEC( itr->phys_point, itr->phys_sampl );
1803 GFMAT( itr->phys_point_cache, itr->phys_sampl_cache );
1804 XLALFree( itr->int_lower );
1805 XLALFree( itr->int_point );
1806 XLALFree( itr->int_upper );
1807 XLALFree( itr->direction );
1808 XLALFree( itr );
1809 }
1810}
1811
1813 LatticeTilingIterator *itr,
1814 const bool alternating
1815)
1816{
1817
1818 // Check input
1819 XLAL_CHECK( itr != NULL, XLAL_EFAULT );
1820 XLAL_CHECK( itr->state == 0, XLAL_EINVAL );
1821
1822 // Set alternating iterator
1823 itr->alternating = alternating;
1824
1825 return XLAL_SUCCESS;
1826
1827}
1828
1830 LatticeTilingIterator *itr
1831)
1832{
1833
1834 // Check input
1835 XLAL_CHECK( itr != NULL, XLAL_EFAULT );
1836
1837 // Return iterator to initialised state
1838 itr->state = 0;
1839
1840 return XLAL_SUCCESS;
1841
1842}
1843
1845 LatticeTilingIterator *itr,
1846 gsl_vector *point
1847)
1848{
1849
1850 // Check input
1851 XLAL_CHECK( itr != NULL, XLAL_EFAULT );
1852 XLAL_CHECK( point == NULL || point->size == itr->tiling->ndim, XLAL_EINVAL );
1853
1854 const size_t n = itr->tiling->ndim;
1855 const size_t tn = itr->tiling->tiled_ndim;
1856
1857 // If iterator is finished, we're done
1858 if ( itr->state > 1 ) {
1859 return 0;
1860 }
1861
1862 // Which dimensions have changed?
1863 size_t changed_ti;
1864
1865 // Which dimensions need to be reset?
1866 size_t reset_ti;
1867
1868 if ( itr->state == 0 ) { // Iterator has been initialised
1869
1870 // Initialise lattice point
1871 gsl_vector_set_zero( itr->phys_point );
1872 for ( size_t ti = 0; ti < tn; ++ti ) {
1873 itr->int_point[ti] = 0;
1874 }
1875
1876 // Initialise iteration direction to 1, i.e. lower to upper bound
1877 for ( size_t ti = 0; ti < tn; ++ti ) {
1878 itr->direction[ti] = 1;
1879 }
1880
1881 // Initialise index
1882 itr->index = 0;
1883
1884 // All dimensions have changed
1885 changed_ti = 0;
1886
1887 // All dimensions need to be reset
1888 reset_ti = 0;
1889
1890 } else { // Iterator is in progress
1891
1892 // Start iterating from the maximum tiled dimension specified at iterator creation
1893 size_t ti = itr->tiled_itr_ndim;
1894
1895 // Find the next lattice point
1896 while ( true ) {
1897
1898 // If dimension index is now zero, we're done
1899 if ( ti == 0 ) {
1900
1901 // Iterator is now finished
1902 itr->state = 2;
1903
1904 return 0;
1905
1906 }
1907
1908 // Decrement current dimension index
1909 --ti;
1910
1911 // Increment integer point in this dimension, in current direction
1912 const INT4 direction = itr->direction[ti];
1913 const INT4 int_point_ti = itr->int_point[ti] + direction;
1914 itr->int_point[ti] = int_point_ti;
1915
1916 // Increment physical point in this dimension, in current direction
1917 const size_t i = itr->tiling->tiled_idx[ti];
1918 gsl_vector_const_view phys_from_int_i = gsl_matrix_const_column( itr->tiling->phys_from_int, i );
1919 gsl_blas_daxpy( direction, &phys_from_int_i.vector, itr->phys_point );
1920
1921 // If point is not out of bounds, we have found the next lattice point
1922 const INT4 int_lower_ti = itr->int_lower[ti];
1923 const INT4 int_upper_ti = itr->int_upper[ti];
1924 if ( ( direction > 0 && int_point_ti <= int_upper_ti ) || ( direction < 0 && int_point_ti >= int_lower_ti ) ) {
1925 break;
1926 }
1927
1928 // Move on to lower dimensions
1929 continue;
1930
1931 }
1932
1933 // Point was found, so increase index
1934 ++itr->index;
1935
1936 // This dimension and higher have changed
1937 changed_ti = ti;
1938
1939 // Higher dimensions need to be reset
1940 reset_ti = ti + 1;
1941
1942 }
1943
1944 // Reset parameter-space bounds and recompute physical point
1945 for ( size_t i = 0, ti = 0; i < n; ++i ) {
1946
1947 // Get bound information for this dimension
1948 const LT_Bound *bound = &itr->tiling->bounds[i];
1949
1950 // Get physical parameter-space origin in the current dimension
1951 const double phys_origin_i = gsl_vector_get( itr->tiling->phys_origin, i );
1952
1953 // If not tiled, set current physical point to non-tiled parameter-space bound
1954 if ( !bound->is_tiled && ti >= reset_ti ) {
1955 double phys_lower = 0, phys_upper = 0;
1956 LT_CallBoundFunc( itr->tiling, i, itr->phys_point_cache, itr->phys_point, &phys_lower, &phys_upper );
1957 LT_SetPhysPoint( itr->tiling, itr->phys_point_cache, itr->phys_point, i, phys_lower );
1958 }
1959
1960 // If tiled, reset parameter-space bounds
1961 if ( bound->is_tiled && ti >= reset_ti ) {
1962
1963 // Find the parameter-space bounds on the current dimension
1964 gsl_vector_memcpy( itr->phys_sampl, itr->phys_point );
1965 double phys_lower = GSL_POSINF, phys_upper = GSL_NEGINF;
1966 if ( STRICT_BOUND_PADDING( bound ) || !bound->find_bound_extrema ) {
1967 LT_CallBoundFunc( itr->tiling, i, itr->phys_point_cache, itr->phys_sampl, &phys_lower, &phys_upper );
1968 } else {
1969 LT_FindBoundExtrema( itr->tiling, 0, i, itr->phys_sampl_cache, itr->phys_sampl, &phys_lower, &phys_upper );
1970 }
1971
1972 // Add padding of a multiple of the extext of the metric ellipse bounding box, if requested
1973 {
1974 const double phys_bbox_i = gsl_vector_get( itr->tiling->phys_bbox, i );
1975 phys_lower -= bound->lower_bbox_pad * phys_bbox_i;
1976 phys_upper += bound->upper_bbox_pad * phys_bbox_i;
1977 }
1978
1979 // Transform physical point in lower dimensions to generating integer offset
1980 double int_from_phys_point_i = 0;
1981 for ( size_t j = 0; j < i; ++j ) {
1982 const double int_from_phys_i_j = gsl_matrix_get( itr->tiling->int_from_phys, i, j );
1983 const double phys_point_j = gsl_vector_get( itr->phys_point, j );
1984 const double phys_origin_j = gsl_vector_get( itr->tiling->phys_origin, j );
1985 int_from_phys_point_i += int_from_phys_i_j * ( phys_point_j - phys_origin_j );
1986 }
1987
1988 {
1989 // Transform physical bounds to generating integers
1990 const double int_from_phys_i_i = gsl_matrix_get( itr->tiling->int_from_phys, i, i );
1991 const double dbl_int_lower_i = int_from_phys_point_i + int_from_phys_i_i * ( phys_lower - phys_origin_i );
1992 const double dbl_int_upper_i = int_from_phys_point_i + int_from_phys_i_i * ( phys_upper - phys_origin_i );
1993
1994 // Compute integer lower/upper bounds, rounded up/down to avoid extra boundary points
1995 feclearexcept( FE_ALL_EXCEPT );
1996 const INT4 int_lower_i = lround( ceil( dbl_int_lower_i ) );
1997 const INT4 int_upper_i = lround( floor( dbl_int_upper_i ) );
1998 XLAL_CHECK( fetestexcept( FE_INVALID ) == 0, XLAL_EFAILED, "Integer bounds on dimension #%zu are too large: %0.2e to %0.2e", i, dbl_int_lower_i, dbl_int_upper_i );
1999
2000 // Set integer lower/upper bounds
2001 itr->int_lower[ti] = int_lower_i;
2002 itr->int_upper[ti] = GSL_MAX( int_lower_i, int_upper_i );
2003
2004 // Add padding as a multiple of integer points, if requested
2005 itr->int_lower[ti] -= bound->lower_intp_pad;
2006 itr->int_upper[ti] += bound->upper_intp_pad;
2007 }
2008 const INT4 int_lower_i = itr->int_lower[ti];
2009 const INT4 int_upper_i = itr->int_upper[ti];
2010
2011 // Get iteration direction
2012 INT4 direction = itr->direction[ti];
2013
2014 // Only switch iteration direction:
2015 // - if this is an alternating iterator
2016 // - if iterator is in progress
2017 // - for iterated-over dimensions
2018 // - if there is more than one point in this dimension
2019 if ( itr->alternating && ( itr->state > 0 ) && ( ti < itr->tiled_itr_ndim ) && ( int_lower_i < int_upper_i ) ) {
2020 direction = -direction;
2021 itr->direction[ti] = direction;
2022 }
2023
2024 // Set integer point to:
2025 // - lower or upper bound (depending on current direction) for iterated-over dimensions
2026 // - mid-point of integer bounds for non-iterated dimensions
2027 if ( ti < itr->tiled_itr_ndim ) {
2028 itr->int_point[ti] = ( direction > 0 ) ? int_lower_i : int_upper_i;
2029 } else {
2030 itr->int_point[ti] = ( int_lower_i + int_upper_i ) / 2;
2031 }
2032
2033 }
2034
2035 // If tiled, recompute current physical point from integer point
2036 if ( bound->is_tiled && ti >= changed_ti ) {
2037 double phys_point_i = phys_origin_i;
2038 for ( size_t tj = 0; tj < tn; ++tj ) {
2039 const size_t j = itr->tiling->tiled_idx[tj];
2040 const double phys_from_int_i_j = gsl_matrix_get( itr->tiling->phys_from_int, i, j );
2041 const INT4 int_point_tj = itr->int_point[tj];
2042 phys_point_i += phys_from_int_i_j * int_point_tj;
2043 }
2044 LT_SetPhysPoint( itr->tiling, itr->phys_point_cache, itr->phys_point, i, phys_point_i );
2045 }
2046
2047 // Handle strict parameter space boundaries
2048 if ( STRICT_BOUND_PADDING( bound ) && ti >= changed_ti ) {
2049
2050 // Get current physical point and bounds
2051 double phys_point_i = gsl_vector_get( itr->phys_point, i );
2052 double phys_lower = 0, phys_upper = 0;
2053 LT_CallBoundFunc( itr->tiling, i, itr->phys_point_cache, itr->phys_point, &phys_lower, &phys_upper );
2054
2055 // If physical point outside lower bound, try to move just inside
2056 if ( phys_point_i < phys_lower ) {
2057 const double phys_from_int_i_i = gsl_matrix_get( itr->tiling->phys_from_int, i, i );
2058 const INT4 di = lround( ceil( ( phys_lower - phys_point_i ) / phys_from_int_i_i ) );
2059 itr->int_point[ti] += di;
2060 phys_point_i += phys_from_int_i_i * di;
2061 }
2062
2063 // If physical point now outside upper bound, parameter space is narrower than step size:
2064 // - Set physical point to mid-point of parameter space bounds
2065 // - Set integer point to upper bound, so that next iteration will reset
2066 if ( phys_point_i > phys_upper ) {
2067 phys_point_i = 0.5 * ( phys_lower + phys_upper );
2068 itr->int_point[ti] = itr->int_upper[ti];
2069 }
2070
2071 // Set physical point
2072 LT_SetPhysPoint( itr->tiling, itr->phys_point_cache, itr->phys_point, i, phys_point_i );
2073
2074 }
2075
2076 // Increment tiled dimension index
2077 if ( bound->is_tiled ) {
2078 ++ti;
2079 }
2080
2081 }
2082
2083 // Iterator is in progress
2084 itr->state = 1;
2085
2086 // Optionally, copy current physical point
2087 if ( point != NULL ) {
2088 gsl_vector_memcpy( point, itr->phys_point );
2089 }
2090
2091 // Return index of changed dimensions (offset from 1, since 0 is used to indicate no more points)
2092 return 1 + changed_ti;
2093
2094}
2095
2097 LatticeTilingIterator *itr,
2098 gsl_matrix **points
2099)
2100{
2101
2102 // Check input
2103 XLAL_CHECK( itr != NULL, XLAL_EFAULT );
2104 XLAL_CHECK( points != NULL && *points != NULL, XLAL_EFAULT );
2105 XLAL_CHECK( ( *points )->size1 == itr->tiling->ndim, XLAL_EINVAL );
2106
2107 // Fill 'points' with points from XLALNextLatticeTilingPoint(), but stop if there are none left
2108 size_t j = 0;
2109 for ( ; j < ( *points )->size2; ++j ) {
2110 gsl_vector_view point_j = gsl_matrix_column( *points, j );
2111 int retn = XLALNextLatticeTilingPoint( itr, &point_j.vector );
2112 XLAL_CHECK( retn >= 0, XLAL_EFUNC, "XLALNextLatticeTilingPoint() failed at j=%zu", j );
2113 if ( retn == 0 ) {
2114 break;
2115 }
2116 }
2117
2118 // If there are fewer points than the size of 'points', resize 'points' to fit
2119 if ( 0 < j && j < ( *points )->size2 ) {
2120 gsl_matrix *GAMAT( new_points, ( *points )->size1, j );
2121 gsl_matrix_view points_view = gsl_matrix_submatrix( *points, 0, 0, ( *points )->size1, j );
2122 gsl_matrix_memcpy( new_points, &points_view.matrix );
2123 GFMAT( *points );
2124 *points = new_points;
2125 }
2126
2127 return j;
2128
2129}
2130
2132 const LatticeTilingIterator *itr
2133)
2134{
2135
2136 // Check input
2137 XLAL_CHECK_VAL( 0, itr != NULL, XLAL_EFAULT );
2138
2139 // Get lattice tiling statistics
2140 const LatticeTilingStats *stats = XLALLatticeTilingStatistics( itr->tiling, itr->itr_ndim - 1 );
2141 XLAL_CHECK_VAL( 0, stats != NULL, XLAL_EFUNC );
2142 XLAL_CHECK_VAL( 0, stats->total_points > 0, XLAL_EFUNC );
2143
2144 return stats->total_points;
2145
2146}
2147
2149 const LatticeTilingIterator *itr,
2150 const size_t dim
2151)
2152{
2153
2154 // Check input
2155 XLAL_CHECK_VAL( 0, itr != NULL, XLAL_EFAULT );
2156
2157 // Get lattice tiling statistics
2158 const LatticeTilingStats *stats = XLALLatticeTilingStatistics( itr->tiling, dim );
2159 XLAL_CHECK_VAL( 0, stats != NULL, XLAL_EFUNC );
2160 XLAL_CHECK_VAL( 0, stats->total_points > 0, XLAL_EFUNC );
2161
2162 return stats->total_points;
2163
2164}
2165
2167 const LatticeTilingIterator *itr
2168)
2169{
2170
2171 // Check input
2172 XLAL_CHECK_VAL( 0, itr != NULL, XLAL_EFAULT );
2173 XLAL_CHECK_VAL( 0, itr->state > 0, XLAL_EINVAL );
2174
2175 return itr->index;
2176
2177}
2178
2180 const LatticeTilingIterator *itr,
2181 const size_t dim,
2182 INT4 *left,
2183 INT4 *right
2184)
2185{
2186
2187 // Check input
2188 XLAL_CHECK( itr != NULL, XLAL_EFAULT );
2189 XLAL_CHECK( itr->state > 0, XLAL_EINVAL );
2190 XLAL_CHECK( dim < itr->tiling->ndim, XLAL_EINVAL );
2191 XLAL_CHECK( left != NULL, XLAL_EFAULT );
2192 XLAL_CHECK( right != NULL, XLAL_EFAULT );
2193
2194 // Return indexes of left/right-most points in block relative to current point
2195 *left = *right = 0;
2196 for ( size_t ti = 0; ti < itr->tiling->tiled_ndim; ++ti ) {
2197 const size_t i = itr->tiling->tiled_idx[ti];
2198 if ( i == dim ) {
2199 *left = itr->int_lower[ti] - itr->int_point[ti];
2200 *right = itr->int_upper[ti] - itr->int_point[ti];
2201 break;
2202 }
2203 }
2204
2205 return XLAL_SUCCESS;
2206
2207}
2208
2210 const LatticeTilingIterator *itr,
2211 FITSFile *file,
2212 const char *name
2213)
2214{
2215
2216 // Check input
2217 XLAL_CHECK( itr != NULL, XLAL_EFAULT );
2218 XLAL_CHECK( itr->state > 0, XLAL_EINVAL );
2219 XLAL_CHECK( file != NULL, XLAL_EFAULT );
2220 XLAL_CHECK( name != NULL, XLAL_EFAULT );
2221
2222 const size_t n = itr->tiling->ndim;
2223
2224 // Open FITS table for writing
2225 XLAL_CHECK( XLALFITSTableOpenWrite( file, name, "serialised lattice tiling iterator" ) == XLAL_SUCCESS, XLAL_EFUNC );
2227
2228 // Write FITS records to table
2229 for ( size_t i = 0, ti = 0; i < n; ++i ) {
2230
2231 // Fill record
2232 LT_FITSRecord XLAL_INIT_DECL( record );
2233 {
2234 INT4 checksum = 0;
2235 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].is_tiled, sizeof( itr->tiling->bounds[i].is_tiled ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2236 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].data_len, sizeof( itr->tiling->bounds[i].data_len ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2237 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), itr->tiling->bounds[i].data_lower, itr->tiling->bounds[i].data_len ) == XLAL_SUCCESS, XLAL_EFUNC );
2238 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), itr->tiling->bounds[i].data_upper, itr->tiling->bounds[i].data_len ) == XLAL_SUCCESS, XLAL_EFUNC );
2239 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].lower_bbox_pad, sizeof( itr->tiling->bounds[i].lower_bbox_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2240 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].upper_bbox_pad, sizeof( itr->tiling->bounds[i].upper_bbox_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2241 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].lower_intp_pad, sizeof( itr->tiling->bounds[i].lower_intp_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2242 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].upper_intp_pad, sizeof( itr->tiling->bounds[i].upper_intp_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2243 record.checksum = checksum;
2244 }
2245 record.phys_point = gsl_vector_get( itr->phys_point, i );
2246 if ( itr->tiling->bounds[i].is_tiled ) {
2247 record.int_point = itr->int_point[ti];
2248 record.int_lower = itr->int_lower[ti];
2249 record.int_upper = itr->int_upper[ti];
2250 record.direction = itr->direction[ti];
2251 ++ti;
2252 }
2253
2254 // Write record
2256
2257 }
2258
2259 // Write tiling properties
2260 {
2261 UINT4 ndim = itr->tiling->ndim;
2262 XLAL_CHECK( XLALFITSHeaderWriteUINT4( file, "ndim", ndim, "number of parameter-space dimensions" ) == XLAL_SUCCESS, XLAL_EFUNC );
2263 } {
2264 UINT4 tiled_ndim = itr->tiling->tiled_ndim;
2265 XLAL_CHECK( XLALFITSHeaderWriteUINT4( file, "tiled_ndim", tiled_ndim, "number of tiled parameter-space dimensions" ) == XLAL_SUCCESS, XLAL_EFUNC );
2266 } {
2267 UINT4 lattice = itr->tiling->lattice;
2268 XLAL_CHECK( XLALFITSHeaderWriteUINT4( file, "lattice", lattice, "type of lattice to generate tiling with" ) == XLAL_SUCCESS, XLAL_EFUNC );
2269 }
2270
2271 // Write iterator properties
2272 {
2273 UINT4 itr_ndim = itr->itr_ndim;
2274 XLAL_CHECK( XLALFITSHeaderWriteUINT4( file, "itr_ndim", itr_ndim, "number of parameter-space dimensions to iterate over" ) == XLAL_SUCCESS, XLAL_EFUNC );
2275 } {
2276 UINT4 tiled_itr_ndim = itr->tiled_itr_ndim;
2277 XLAL_CHECK( XLALFITSHeaderWriteUINT4( file, "tiled_itr_ndim", tiled_itr_ndim, "number of tiled parameter-space dimensions to iterate over" ) == XLAL_SUCCESS, XLAL_EFUNC );
2278 } {
2279 BOOLEAN alternating = itr->alternating;
2280 XLAL_CHECK( XLALFITSHeaderWriteBOOLEAN( file, "alternating", alternating, "if true, alternate iterator direction after every crossing" ) == XLAL_SUCCESS, XLAL_EFUNC );
2281 } {
2282 UINT4 state = itr->state;
2283 XLAL_CHECK( XLALFITSHeaderWriteUINT4( file, "state", state, "iterator state" ) == XLAL_SUCCESS, XLAL_EFUNC );
2284 } {
2286 XLAL_CHECK( count > 0, XLAL_EFUNC );
2287 XLAL_CHECK( XLALFITSHeaderWriteUINT8( file, "count", count, "total number of lattice tiling points" ) == XLAL_SUCCESS, XLAL_EFUNC );
2288 UINT8 indx = itr->index;
2289 XLAL_CHECK( XLALFITSHeaderWriteUINT8( file, "index", indx, "index of current lattice tiling point" ) == XLAL_SUCCESS, XLAL_EFUNC );
2290 }
2291
2292 return XLAL_SUCCESS;
2293
2294}
2295
2297 LatticeTilingIterator *itr,
2298 FITSFile *file,
2299 const char *name
2300)
2301{
2302
2303 // Check input
2304 XLAL_CHECK( itr != NULL, XLAL_EFAULT );
2305 XLAL_CHECK( file != NULL, XLAL_EFAULT );
2306 XLAL_CHECK( name != NULL, XLAL_EFAULT );
2307
2308 const size_t n = itr->tiling->ndim;
2309
2310 // Open FITS table for reading
2311 UINT8 nrows = 0;
2313 XLAL_CHECK( nrows == ( UINT8 ) n, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2315
2316 // Read and check tiling properties
2317 {
2318 UINT4 ndim;
2320 XLAL_CHECK( ndim == itr->tiling->ndim, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2321 } {
2322 UINT4 tiled_ndim;
2323 XLAL_CHECK( XLALFITSHeaderReadUINT4( file, "tiled_ndim", &tiled_ndim ) == XLAL_SUCCESS, XLAL_EFUNC );
2324 XLAL_CHECK( tiled_ndim == itr->tiling->tiled_ndim, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2325 } {
2326 UINT4 lattice;
2327 XLAL_CHECK( XLALFITSHeaderReadUINT4( file, "lattice", &lattice ) == XLAL_SUCCESS, XLAL_EFUNC );
2328 XLAL_CHECK( lattice == itr->tiling->lattice, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2329 }
2330
2331 // Read and check iterator properties
2332 {
2333 UINT4 itr_ndim;
2334 XLAL_CHECK( XLALFITSHeaderReadUINT4( file, "itr_ndim", &itr_ndim ) == XLAL_SUCCESS, XLAL_EFUNC );
2335 XLAL_CHECK( itr_ndim == itr->itr_ndim, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2336 } {
2337 UINT4 tiled_itr_ndim;
2338 XLAL_CHECK( XLALFITSHeaderReadUINT4( file, "tiled_itr_ndim", &tiled_itr_ndim ) == XLAL_SUCCESS, XLAL_EFUNC );
2339 XLAL_CHECK( tiled_itr_ndim == itr->tiled_itr_ndim, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2340 } {
2341 BOOLEAN alternating;
2342 XLAL_CHECK( XLALFITSHeaderReadBOOLEAN( file, "alternating", &alternating ) == XLAL_SUCCESS, XLAL_EFUNC );
2343 XLAL_CHECK( !alternating == !itr->alternating, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2344 } {
2345 UINT4 state;
2347 itr->state = state;
2348 } {
2349 UINT8 count;
2351 XLAL_CHECK( count > 0, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2352 UINT8 count_ref = XLALTotalLatticeTilingPoints( itr );
2353 XLAL_CHECK( count_ref > 0, XLAL_EFUNC );
2354 XLAL_CHECK( count == count_ref, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2355 UINT8 indx;
2357 XLAL_CHECK( indx < count_ref, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2358 itr->index = indx;
2359 }
2360
2361 // Read FITS records from table
2362 for ( size_t i = 0, ti = 0; i < n; ++i ) {
2363
2364 // Read and check record
2365 LT_FITSRecord XLAL_INIT_DECL( record );
2366 XLAL_CHECK( XLALFITSTableReadRow( file, &record, &nrows ) == XLAL_SUCCESS, XLAL_EFUNC );
2367 {
2368 INT4 checksum = 0;
2369 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].is_tiled, sizeof( itr->tiling->bounds[i].is_tiled ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2370 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].data_len, sizeof( itr->tiling->bounds[i].data_len ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2371 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), itr->tiling->bounds[i].data_lower, itr->tiling->bounds[i].data_len ) == XLAL_SUCCESS, XLAL_EFUNC );
2372 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), itr->tiling->bounds[i].data_upper, itr->tiling->bounds[i].data_len ) == XLAL_SUCCESS, XLAL_EFUNC );
2373 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].lower_bbox_pad, sizeof( itr->tiling->bounds[i].lower_bbox_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2374 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].upper_bbox_pad, sizeof( itr->tiling->bounds[i].upper_bbox_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2375 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].lower_intp_pad, sizeof( itr->tiling->bounds[i].lower_intp_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2376 XLAL_CHECK( XLALPearsonHash( &checksum, sizeof( checksum ), &itr->tiling->bounds[i].upper_intp_pad, sizeof( itr->tiling->bounds[i].upper_intp_pad ) ) == XLAL_SUCCESS, XLAL_EFUNC );
2377 XLAL_CHECK( record.checksum == checksum, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2378 }
2379 LT_SetPhysPoint( itr->tiling, itr->phys_point_cache, itr->phys_point, i, record.phys_point );
2380 if ( itr->tiling->bounds[i].is_tiled ) {
2381 itr->int_point[ti] = record.int_point;
2382 XLAL_CHECK( record.int_lower <= record.int_point, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2383 itr->int_lower[ti] = record.int_lower;
2384 XLAL_CHECK( record.int_point <= record.int_upper, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2385 itr->int_upper[ti] = record.int_upper;
2386 XLAL_CHECK( record.direction != 0, XLAL_EIO, "Could not restore iterator; invalid HDU '%s'", name );
2387 itr->direction[ti] = record.direction;
2388 ++ti;
2389 }
2390
2391 }
2392
2393 return XLAL_SUCCESS;
2394
2395}
2396
2398 const LatticeTiling *tiling
2399)
2400{
2401
2402 // Check input
2405
2406 // Allocate memory
2407 LatticeTilingLocator *loc = XLALCalloc( 1, sizeof( *loc ) );
2408 XLAL_CHECK_NULL( loc != NULL, XLAL_ENOMEM );
2409
2410 // Store reference to lattice tiling
2411 loc->tiling = tiling;
2412
2413 // Set fields
2414 loc->ndim = tiling->ndim;
2415 loc->tiled_ndim = tiling->tiled_ndim;
2416
2417 // Build index trie to enforce parameter-space bounds
2418 if ( loc->tiled_ndim > 0 ) {
2419
2420 // Create iterator over the bounded dimensions (except for the highest dimension)
2421 LatticeTilingIterator *itr = XLALCreateLatticeTilingIterator( tiling, tiling->tiled_idx[tiling->tiled_ndim - 1] );
2422 XLAL_CHECK_NULL( itr != NULL, XLAL_EFUNC );
2423
2424 const size_t tn = itr->tiling->tiled_ndim;
2425
2426 // Allocate array of pointers to the next index trie in each dimension
2427 LT_IndexTrie *next[tn];
2428 memset( next, 0, sizeof( next ) );
2429
2430 // Allocate array containing sequential indices for every dimension
2431 UINT8 indx[tn];
2432 memset( indx, 0, sizeof( indx ) );
2433
2434 // Iterate over all points; XLALNextLatticeTilingPoint() returns the index
2435 // (offset from 1) of the lowest dimension where the current point has changed
2436 xlalErrno = 0;
2437 int changed_ti_p1;
2438 while ( ( changed_ti_p1 = XLALNextLatticeTilingPoint( itr, NULL ) ) > 0 ) {
2439 const size_t changed_ti = changed_ti_p1 - 1;
2440
2441 // Iterate over all dimensions where the current point has changed
2442 for ( size_t tj = changed_ti; tj < tn; ++tj ) {
2443
2444 // If next index trie pointer is NULL, it needs to be initialised
2445 if ( next[tj] == NULL ) {
2446
2447 // Get a pointer to the index trie which needs to be built:
2448 // - if 'tj' is non-zero, we should use the struct pointed to by 'next' in the lower dimension
2449 // - otherwise, this is the first point of the tiling, so initialise the base index trie
2450 LT_IndexTrie *trie = NULL;
2451 if ( tj > 0 ) {
2452 trie = next[tj - 1];
2453 } else {
2454 trie = loc->index_trie = XLALCalloc( 1, sizeof( *trie ) );
2455 XLAL_CHECK_NULL( loc->index_trie != NULL, XLAL_ENOMEM );
2456 }
2457
2458 // Save the lower and upper integer point bounds
2459 trie->int_lower = itr->int_lower[tj];
2460 trie->int_upper = itr->int_upper[tj];
2461
2462 // Save the sequential index of the current point up to this dimension
2463 trie->index = indx[tj];
2464
2465 if ( tj + 1 < tn ) {
2466
2467 // If we are below the highest dimension, allocate a new
2468 // array of index tries for the next highest dimension
2469 const size_t next_length = trie->int_upper - trie->int_lower + 1;
2470 trie->next = XLALCalloc( next_length, sizeof( *trie->next ) );
2471 XLAL_CHECK_NULL( trie->next != NULL, XLAL_ENOMEM );
2472
2473 // Point 'next[tj]' to this array, for higher dimensions to use
2474 next[tj] = trie->next;
2475
2476 }
2477
2478 } else {
2479
2480 // Otherwise, advance to the next index trie in the array
2481 ++next[tj];
2482
2483 }
2484
2485 // If we are below the highest dimension, set 'next' in the next highest
2486 // dimension to NULL, so that on the next loop a new array will be created
2487 if ( tj + 1 < tn ) {
2488 next[tj + 1] = NULL;
2489 }
2490
2491 }
2492
2493 // Increment sequential index in every higher dimension
2494 for ( size_t tj = changed_ti; tj < tn; ++tj ) {
2495 ++indx[tj];
2496 }
2497 indx[tn - 1] += itr->int_upper[tn - 1] - itr->int_lower[tn - 1];
2498
2499 }
2501
2502 // Cleanup
2504
2505 }
2506
2507 return loc;
2508
2509}
2510
2512 LatticeTilingLocator *loc
2513)
2514{
2515 if ( loc ) {
2516 if ( loc->index_trie != NULL ) {
2517 LT_FreeIndexTrie( loc->index_trie );
2518 XLALFree( loc->index_trie );
2519 }
2520 XLALFree( loc );
2521 }
2522}
2523
2525 const LatticeTilingLocator *loc,
2526 const gsl_vector *point,
2527 gsl_vector *nearest_point,
2529)
2530{
2531
2532 // Check input
2533 XLAL_CHECK( loc != NULL, XLAL_EFAULT );
2534 XLAL_CHECK( point != NULL, XLAL_EFAULT );
2535 XLAL_CHECK( point->size == loc->ndim, XLAL_EINVAL );
2536 XLAL_CHECK( nearest_point == NULL || nearest_point->size == loc->ndim, XLAL_EINVAL );
2537 XLAL_CHECK( nearest_index == NULL || nearest_index->data != NULL, XLAL_EFAULT );
2538 XLAL_CHECK( nearest_index == NULL || nearest_index->length == loc->ndim, XLAL_EINVAL );
2539
2540 const size_t n = loc->ndim;
2541
2542 // Create local vector/matrix view for 'point'
2543 double local_point_array[n];
2544 gsl_vector_view local_point_vector = gsl_vector_view_array( local_point_array, n );
2545 gsl_matrix_view local_point_matrix = gsl_matrix_view_array( local_point_array, n, 1 );
2546 gsl_vector *local_point = &local_point_vector.vector;
2547 gsl_matrix *local_points = &local_point_matrix.matrix;
2548
2549 // Create local vector/matrix view for 'nearest_point'
2550 double local_nearest_point_array[n];
2551 gsl_vector_view local_nearest_point_vector = gsl_vector_view_array( local_nearest_point_array, n );
2552 gsl_matrix_view local_nearest_point_matrix = gsl_matrix_view_array( local_nearest_point_array, n, 1 );
2553 gsl_vector *local_nearest_point = &local_nearest_point_vector.vector;
2554 gsl_matrix *local_nearest_points = &local_nearest_point_matrix.matrix;
2555
2556 // Create local vector sequence view of 'nearest_index', if required
2557 UINT8VectorSequence nearest_indexes;
2558 UINT8VectorSequence *nearest_indexes_ptr = NULL;
2559 if ( nearest_index != NULL ) {
2560 nearest_indexes.vectorLength = n;
2561 nearest_indexes.length = 1;
2562 nearest_indexes.data = nearest_index->data;
2563 nearest_indexes_ptr = &nearest_indexes;
2564 }
2565
2566 // Call LT_FindNearestPoints()
2567 gsl_vector_memcpy( local_point, point );
2568 XLAL_CHECK( LT_FindNearestPoints( loc, local_points, local_nearest_points, nearest_indexes_ptr, NULL, NULL ) == XLAL_SUCCESS, XLAL_EFUNC );
2569 if ( nearest_point != NULL ) {
2570 gsl_vector_memcpy( nearest_point, local_nearest_point );
2571 }
2572
2573 return XLAL_SUCCESS;
2574
2575}
2576
2578 const LatticeTilingLocator *loc,
2579 const gsl_matrix *points,
2580 gsl_matrix **nearest_points,
2581 UINT8VectorSequence **nearest_indexes
2582)
2583{
2584
2585 // Check input
2586 XLAL_CHECK( loc != NULL, XLAL_EFAULT );
2587 XLAL_CHECK( points != NULL, XLAL_EFAULT );
2588 XLAL_CHECK( points->size1 == loc->ndim, XLAL_EINVAL );
2589 XLAL_CHECK( nearest_points != NULL, XLAL_EFAULT );
2590
2591 const size_t n = loc->ndim;
2592 const size_t num_points = points->size2;
2593
2594 // Resize or allocate nearest points matrix, if required, and create view of correct size
2595 if ( *nearest_points != NULL ) {
2596 if ( ( *nearest_points )->size1 != n || ( *nearest_points )->size2 < num_points ) {
2597 GFMAT( *nearest_points );
2598 *nearest_points = NULL;
2599 }
2600 }
2601 if ( *nearest_points == NULL ) {
2602 GAMAT( *nearest_points, n, num_points );
2603 }
2604 gsl_matrix_view nearest_points_view = gsl_matrix_submatrix( *nearest_points, 0, 0, n, num_points );
2605
2606 // Resize or allocate nearest sequential index vector sequence, if required
2607 if ( nearest_indexes != NULL ) {
2608 if ( *nearest_indexes != NULL ) {
2609 if ( ( *nearest_indexes )->vectorLength != n || ( *nearest_indexes )->length < num_points ) {
2610 XLALDestroyUINT8VectorSequence( *nearest_indexes );
2611 *nearest_indexes = NULL;
2612 }
2613 }
2614 if ( *nearest_indexes == NULL ) {
2615 *nearest_indexes = XLALCreateUINT8VectorSequence( n, num_points );
2616 XLAL_CHECK( *nearest_indexes != NULL, XLAL_ENOMEM );
2617 }
2618 }
2619 UINT8VectorSequence *nearest_indexes_view = ( nearest_indexes != NULL ) ? *nearest_indexes : NULL;
2620
2621 // Call LT_FindNearestPoints()
2622 XLAL_CHECK( LT_FindNearestPoints( loc, points, &nearest_points_view.matrix, nearest_indexes_view, NULL, NULL ) == XLAL_SUCCESS, XLAL_EFUNC );
2623
2624 return XLAL_SUCCESS;
2625
2626}
2627
2629 const LatticeTilingLocator *loc,
2630 const gsl_vector *point,
2631 const size_t dim,
2632 gsl_vector *nearest_point,
2634 INT4 *nearest_left,
2635 INT4 *nearest_right
2636)
2637{
2638
2639 // Check input
2640 XLAL_CHECK( loc != NULL, XLAL_EFAULT );
2641 XLAL_CHECK( point != NULL, XLAL_EFAULT );
2642 XLAL_CHECK( point->size == loc->ndim, XLAL_EINVAL );
2643 XLAL_CHECK( dim < loc->ndim, XLAL_EINVAL );
2645 XLAL_CHECK( nearest_point->size == loc->ndim, XLAL_EINVAL );
2647 XLAL_CHECK( nearest_left != NULL, XLAL_EFAULT );
2648 XLAL_CHECK( nearest_right != NULL, XLAL_EFAULT );
2649
2650 const size_t n = loc->ndim;
2651
2652 // Create local vector/matrix view for 'point'
2653 double local_point_array[n];
2654 gsl_vector_view local_point_vector = gsl_vector_view_array( local_point_array, n );
2655 gsl_matrix_view local_point_matrix = gsl_matrix_view_array( local_point_array, n, 1 );
2656 gsl_vector *local_point = &local_point_vector.vector;
2657 gsl_matrix *local_points = &local_point_matrix.matrix;
2658
2659 // Create local vector/matrix view for 'nearest_point'
2660 double local_nearest_point_array[n];
2661 gsl_vector_view local_nearest_point_vector = gsl_vector_view_array( local_nearest_point_array, n );
2662 gsl_matrix_view local_nearest_point_matrix = gsl_matrix_view_array( local_nearest_point_array, n, 1 );
2663 gsl_vector *local_nearest_point = &local_nearest_point_vector.vector;
2664 gsl_matrix *local_nearest_points = &local_nearest_point_matrix.matrix;
2665
2666 // Create local vectors for sequential indexes and number of left/right points
2667 UINT8 nearest_indexes_data[n];
2668 UINT8VectorSequence nearest_indexes = { .length = 1, .vectorLength = n, .data = &nearest_indexes_data[0] };
2669 INT4 nearest_lefts_data[n];
2670 INT4VectorSequence nearest_lefts = { .length = 1, .vectorLength = n, .data = &nearest_lefts_data[0] };
2671 INT4 nearest_rights_data[n];
2672 INT4VectorSequence nearest_rights = { .length = 1, .vectorLength = n, .data = &nearest_rights_data[0] };
2673
2674 // Call LT_FindNearestPoints()
2675 gsl_vector_memcpy( local_point, point );
2676 XLAL_CHECK( LT_FindNearestPoints( loc, local_points, local_nearest_points, &nearest_indexes, &nearest_lefts, &nearest_rights ) == XLAL_SUCCESS, XLAL_EFUNC );
2677 gsl_vector_memcpy( nearest_point, local_nearest_point );
2678 *nearest_index = ( dim > 0 ) ? nearest_indexes_data[dim - 1] : 0;
2679 *nearest_left = nearest_lefts_data[dim];
2680 *nearest_right = nearest_rights_data[dim];
2681
2682 return XLAL_SUCCESS;
2683
2684}
2685
2687 const LatticeTilingLocator *loc,
2688 FILE *file
2689)
2690{
2691
2692 // Check input
2693 XLAL_CHECK( loc != NULL, XLAL_EFAULT );
2694 XLAL_CHECK( file != NULL, XLAL_EFAULT );
2695
2696 const size_t tn = loc->tiled_ndim;
2697
2698 // Return if index trie is NULL
2699 if ( tn == 0 || loc->index_trie == NULL ) {
2700 fprintf( file, "WARNING: index trie is NULL\n" );
2701 return XLAL_SUCCESS;
2702 }
2703
2704 // Print index trie
2705 INT4 int_lower[tn];
2706 LT_PrintIndexTrie( loc->tiling, loc->index_trie, 0, file, int_lower );
2707
2708 return XLAL_SUCCESS;
2709
2710}
2711
2712// Local Variables:
2713// c-file-style: "linux"
2714// c-basic-offset: 2
2715// End:
#define __func__
log an I/O error, i.e.
int XLALFITSHeaderWriteUINT4(FITSFile UNUSED *file, const CHAR UNUSED *key, const UINT4 UNUSED value, const CHAR UNUSED *comment)
Definition: FITSFileIO.c:762
int XLALFITSTableWriteRow(FITSFile UNUSED *file, const void UNUSED *record)
Definition: FITSFileIO.c:2550
int XLALFITSHeaderWriteBOOLEAN(FITSFile UNUSED *file, const CHAR UNUSED *key, const BOOLEAN UNUSED value, const CHAR UNUSED *comment)
Definition: FITSFileIO.c:635
int XLALFITSTableReadRow(FITSFile UNUSED *file, void UNUSED *record, UINT8 UNUSED *rem_nrows)
Definition: FITSFileIO.c:2621
int XLALFITSHeaderReadBOOLEAN(FITSFile UNUSED *file, const CHAR UNUSED *key, BOOLEAN UNUSED *value)
Definition: FITSFileIO.c:668
int XLALFITSTableOpenWrite(FITSFile UNUSED *file, const CHAR UNUSED *name, const CHAR UNUSED *comment)
Definition: FITSFileIO.c:2162
int XLALFITSHeaderWriteUINT8(FITSFile UNUSED *file, const CHAR UNUSED *key, const UINT8 UNUSED value, const CHAR UNUSED *comment)
Definition: FITSFileIO.c:827
int XLALFITSHeaderReadUINT8(FITSFile UNUSED *file, const CHAR UNUSED *key, UINT8 UNUSED *value)
Definition: FITSFileIO.c:863
int XLALFITSHeaderReadUINT4(FITSFile UNUSED *file, const CHAR UNUSED *key, UINT4 UNUSED *value)
Definition: FITSFileIO.c:797
int XLALFITSTableOpenRead(FITSFile UNUSED *file, const CHAR UNUSED *name, UINT8 UNUSED *nrows)
Definition: FITSFileIO.c:2198
int j
int k
static void LT_SetPhysPoint(const LatticeTiling *tiling, gsl_matrix *phys_point_cache, gsl_vector *phys_point, const size_t dim, const double phys_point_dim)
Set value of physical point in a given dimension, and update cache.
static void LT_PrintIndexTrie(const LatticeTiling *tiling, const LT_IndexTrie *trie, const size_t ti, FILE *file, INT4 int_lower[])
Print one level of a lattice tiling index trie.
static void LT_FindBoundExtrema(const LatticeTiling *tiling, const size_t i, const size_t dim, gsl_matrix *phys_point_cache, gsl_vector *phys_point, double *phys_lower_minimum, double *phys_upper_maximum)
Find the extrema of the parameter-space bounds, by sampling the bounds around the current point.
static void LT_ReverseOrderRowsCols(gsl_matrix *A)
Reverse the order of both the rows and columns of the matrix A.
#define LT_CACHE_MAX_SIZE
Definition: LatticeTiling.c:44
static int LT_FindNearestPoints(const LatticeTilingLocator *loc, const gsl_matrix *points, gsl_matrix *nearest_points, UINT8VectorSequence *nearest_indexes, INT4VectorSequence *nearest_lefts, INT4VectorSequence *nearest_rights)
Locate the nearest points in a lattice tiling to a given set of points.
#define LT_DATA_MAX_SIZE
Definition: LatticeTiling.c:41
int XLALSetLatticeTilingBoundName(LatticeTiling *tiling, const size_t dim, const char *fmt,...)
static void LT_PollIndexTrie(const LatticeTiling *tiling, const LT_IndexTrie *trie, const size_t ti, const gsl_vector *point_int, INT4 *poll_nearest, double *poll_min_distance, INT4 *nearest)
Find the nearest point within the parameter-space bounds of the lattice tiling, by polling the neighb...
static void LT_CallBoundFunc(const LatticeTiling *tiling, const size_t dim, const gsl_matrix *phys_point_cache, const gsl_vector *phys_point, double *phys_lower, double *phys_upper)
Call the parameter-space bound function of a given dimension.
static void LT_ZeroStrictUpperTriangle(gsl_matrix *A)
Zero out the strictly upper triangular part of the matrix A.
static double ConstantBound(const void *data, const size_t dim UNUSED, const gsl_matrix *cache UNUSED, const gsl_vector *point UNUSED)
#define STRICT_BOUND_PADDING(b)
Definition: LatticeTiling.c:47
static void LT_FreeIndexTrie(LT_IndexTrie *trie)
Free memory pointed to by an index trie.
static int LT_InitFITSRecordTable(FITSFile *file)
Initialise FITS table for saving and restoring a lattice tiling iterator.
static int LT_StatsCallback(const bool first_call, const LatticeTiling *tiling, const LatticeTilingIterator *itr, const gsl_vector *point, const size_t changed_i, const void *param UNUSED, void *out)
Callback function for computing lattice tiling statistics.
#define D(j)
#define L(i, j)
UINT2 A
Definition: SFTnaming.c:46
const char * name
Definition: SearchTiming.c:93
#define fprintf
const double scale
multiplicative scaling factor of the coordinate
const double Q
const double u
UINT8VectorSequence * XLALCreateUINT8VectorSequence(UINT4 length, UINT4 veclen)
void XLALDestroyUINT8VectorSequence(UINT8VectorSequence *vecseq)
#define XLAL_FITS_TABLE_COLUMN_BEGIN(record_type)
Definition: FITSFileIO.h:239
#define XLAL_FITS_TABLE_COLUMN_ADD(file, type, field)
Definition: FITSFileIO.h:243
struct tagFITSFile FITSFile
Representation of a FITS file.
Definition: FITSFileIO.h:54
unsigned char BOOLEAN
#define XLAL_NUM_ELEM(x)
uint64_t UINT8
double REAL8
#define XLAL_INIT_DECL(var,...)
int64_t INT8
uint32_t UINT4
int32_t INT4
int XLALPearsonHash(void *hval, const size_t hval_len, const void *data, const size_t data_len)
void * XLALCalloc(size_t m, size_t n)
void * XLALRealloc(void *p, size_t n)
void XLALFree(void *p)
#define LAL_INT4_FORMAT
#define LAL_UINT8_FORMAT
double(* LatticeTilingBound)(const void *data, const size_t dim, const gsl_matrix *cache, const gsl_vector *point)
Function which returns a bound on a dimension of the lattice tiling.
Definition: LatticeTiling.h:82
int XLALIsTiledLatticeTilingDimension(const LatticeTiling *tiling, const size_t dim)
Return >0 if a lattice tiling dimension is tiled (i.e.
int XLALSetLatticeTilingBound(LatticeTiling *tiling, const size_t dim, const LatticeTilingBound func, const size_t data_len, const void *data_lower, const void *data_upper)
Set a parameter-space bound on a dimension of the lattice tiling.
size_t XLALTotalLatticeTilingDimensions(const LatticeTiling *tiling)
Return the total number of dimensions of the lattice tiling.
const char * XLALLatticeTilingBoundName(const LatticeTiling *tiling, const size_t dim)
Get the name of a lattice tiling parameter-space dimension.
int XLALNearestLatticeTilingPoint(const LatticeTilingLocator *loc, const gsl_vector *point, gsl_vector *nearest_point, UINT8Vector *nearest_index)
Locate the nearest point in a lattice tiling to a given point.
UINT8 XLALTotalLatticeTilingPoints(const LatticeTilingIterator *itr)
Return the total number of points covered by the lattice tiling iterator.
UINT8 XLALLatticeTilingPointsAtDimension(const LatticeTilingIterator *itr, const size_t dim)
Return the total number of points along a certain dimension covered by the lattice tiling iterator.
int XLALSetLatticeTilingConstantBound(LatticeTiling *tiling, const size_t dim, const double bound1, const double bound2)
Set a constant lattice tiling parameter-space bound, given by the minimum and maximum of the two supp...
int XLALSetTiledLatticeDimensionsFromTiling(LatticeTiling *tiling, const LatticeTiling *ref_tiling)
Set the tiled (i.e.
int XLALSaveLatticeTilingIterator(const LatticeTilingIterator *itr, FITSFile *file, const char *name)
Save the state of a lattice tiling iterator to a FITS file.
REAL8 XLALLatticeTilingStepSize(const LatticeTiling *tiling, const size_t dim)
Return the step size of the lattice tiling in a given dimension, or 0 for non-tiled dimensions.
int XLALGetLatticeTilingBound(const LatticeTiling *tiling, const size_t dim, const gsl_vector *point, const bool padding, double *lower, double *upper)
Get a parameter-space bound on a dimension of the lattice tiling.
int XLALLatticeTilingDimensionByName(const LatticeTiling *tiling, const char *bound_name)
Return the index of the lattice tiling dimension which has the given name.
int XLALSetTilingLatticeAndMetric(LatticeTiling *tiling, const TilingLattice lattice, const gsl_matrix *metric, const double max_mismatch)
Set the tiling lattice, parameter-space metric, and maximum prescribed mismatch.
int XLALNearestLatticeTilingBlock(const LatticeTilingLocator *loc, const gsl_vector *point, const size_t dim, gsl_vector *nearest_point, UINT8 *nearest_index, INT4 *nearest_left, INT4 *nearest_right)
Locate the nearest block in a lattice tiling to a given point.
void XLALDestroyLatticeTilingLocator(LatticeTilingLocator *loc)
Destroy a lattice tiling locator.
UINT8 XLALCurrentLatticeTilingIndex(const LatticeTilingIterator *itr)
Return the index of the current point in the lattice tiling iterator.
size_t XLALTiledLatticeTilingDimensions(const LatticeTiling *tiling)
Return the number of tiled dimensions of the lattice tiling.
void(* LatticeTilingBoundCache)(const size_t dim, const gsl_vector *point, gsl_vector *cache)
Function which caches values required by a lattice tiling bound function.
Definition: LatticeTiling.h:92
size_t XLALLatticeTilingTiledDimension(const LatticeTiling *tiling, const size_t tiled_dim)
Return the dimension of the tiled lattice tiling dimension indexed by 'tiled_dim'.
int XLALRestoreLatticeTilingIterator(LatticeTilingIterator *itr, FITSFile *file, const char *name)
Restore the state of a lattice tiling iterator from a FITS file.
int XLALPerformLatticeTilingCallbacks(const LatticeTiling *tiling)
Perform all registered lattice tiling callbacks.
LatticeTilingIterator * XLALCreateLatticeTilingIterator(const LatticeTiling *tiling, const size_t itr_ndim)
Create a new lattice tiling iterator.
void XLALDestroyLatticeTilingIterator(LatticeTilingIterator *itr)
Destroy a lattice tiling iterator.
void XLALDestroyLatticeTiling(LatticeTiling *tiling)
Destroy a lattice tiling.
int XLALNextLatticeTilingPoint(LatticeTilingIterator *itr, gsl_vector *point)
Advance lattice tiling iterator, and optionally return the next point in point.
int XLALSetLatticeTilingAlternatingIterator(LatticeTilingIterator *itr, const bool alternating)
Set whether the lattice tiling iterator should alternate its iteration direction (i....
int XLALNearestLatticeTilingPoints(const LatticeTilingLocator *loc, const gsl_matrix *points, gsl_matrix **nearest_points, UINT8VectorSequence **nearest_indexes)
Locate the nearest points in a lattice tiling to a given set of points.
int LatticeTilingProgressLogLevel
Log level at which to print progress messages when counting templates and performing callbacks.
LatticeTiling * XLALCreateLatticeTiling(const size_t ndim)
Create a new lattice tiling.
int XLALSetLatticeTilingBoundCacheFunction(LatticeTiling *tiling, const size_t dim, const LatticeTilingBoundCache func)
Set bound cache function for a lattice tiling parameter-space dimension.
int XLALCurrentLatticeTilingBlock(const LatticeTilingIterator *itr, const size_t dim, INT4 *left, INT4 *right)
Return indexes of the left-most and right-most points in the current block of points in the given dim...
const LatticeTilingStats * XLALLatticeTilingStatistics(const LatticeTiling *tiling, const size_t dim)
Return statistics related to the number/value of lattice tiling points in a dimension.
const UserChoices TilingLatticeChoices
Static array of all :tagTilingLattice choices, for use by the UserInput module parsing routines.
int XLALPrintLatticeTilingIndexTrie(const LatticeTilingLocator *loc, FILE *file)
Print the internal index trie of a lattice tiling locator to the given file pointer.
LatticeTilingLocator * XLALCreateLatticeTilingLocator(const LatticeTiling *tiling)
Create a new lattice tiling locator.
int XLALSetLatticeTilingOrigin(LatticeTiling *tiling, const size_t dim, const double origin)
Set the physical parameter-space origin of the lattice tiling in the given dimension.
int XLALSetLatticeTilingRandomOriginOffsets(LatticeTiling *tiling, RandomParams *rng)
Offset the physical parameter-space origin of the lattice tiling by a random fraction of the lattice ...
int XLALResetLatticeTilingIterator(LatticeTilingIterator *itr)
Reset an iterator to the beginning of a lattice tiling.
TilingLattice
Type of lattice to generate tiling with.
Definition: LatticeTiling.h:63
int(* LatticeTilingCallback)(const bool first_call, const LatticeTiling *tiling, const LatticeTilingIterator *itr, const gsl_vector *point, const size_t changed_i, const void *param, void *out)
Callback function which can be used to compute properties of a lattice tiling.
int XLALSetLatticeTilingPadding(LatticeTiling *tiling, const size_t dim, const double lower_bbox_pad, const double upper_bbox_pad, const int lower_intp_pad, const int upper_intp_pad, const int find_bound_extrema)
Control the padding of lattice tiling parameter-space bounds in the given dimension.
int XLALNextLatticeTilingPoints(LatticeTilingIterator *itr, gsl_matrix **points)
Advance lattice tiling iterator, and optionally return the next set of points in points.
const void * XLALRegisterLatticeTilingCallback(LatticeTiling *tiling, const LatticeTilingCallback func, const size_t param_len, const void *param, const size_t out_len)
Register a callback function which can be used to compute properties of a lattice tiling.
int XLALRandomLatticeTilingPoints(const LatticeTiling *tiling, const double scale, RandomParams *rng, gsl_matrix *random_points)
Generate random points within the parameter space of the lattice tiling.
REAL8 XLALLatticeTilingBoundingBox(const LatticeTiling *tiling, const size_t dim)
Return the bounding box extent of the lattice tiling in a given dimension, or 0 for non-tiled dimensi...
@ TILING_LATTICE_ANSTAR
An-star ( ) lattice.
Definition: LatticeTiling.h:65
@ TILING_LATTICE_MAX
Definition: LatticeTiling.h:66
@ TILING_LATTICE_CUBIC
Cubic ( ) lattice.
Definition: LatticeTiling.h:64
void LogPrintf(LogLevel_t, const char *format,...) _LAL_GCC_PRINTF_FORMAT_(2
LOG_DEBUG
double XLALMetricDeterminant(const gsl_matrix *g_ij)
Compute the determinant of a metric .
Definition: MetricUtils.c:98
gsl_vector * XLALMetricEllipseBoundingBox(const gsl_matrix *g_ij, const double max_mismatch)
Compute the extent of the bounding box of the mismatch ellipse of a metric .
Definition: MetricUtils.c:131
static const INT4 m
REAL4 XLALUniformDeviate(RandomParams *params)
#define xlalErrno
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_ERROR(...)
#define XLAL_CHECK(assertion,...)
#define XLAL_CHECK_VAL(val, assertion,...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#define XLAL_CHECK_REAL8(assertion,...)
#define XLAL_CHECK_NULL(assertion,...)
#define XLAL_IS_REAL8_FAIL_NAN(val)
XLAL_ENOMEM
XLAL_SUCCESS
XLAL_EFAULT
XLAL_ERANGE
XLAL_EFUNC
XLAL_ESIZE
XLAL_EIO
XLAL_EINVAL
XLAL_EFAILED
XLAL_FAILURE
long long count
Definition: hwinject.c:371
float data[BLOCKSIZE]
Definition: hwinject.c:360
list y
def func(x)
n
out
double alpha
Lattice tiling parameter-space bound for one dimension.
Definition: LatticeTiling.c:53
LatticeTilingBoundCache cache_func
Parameter space bound cache function.
Definition: LatticeTiling.c:61
bool name_set
True if the name of the parameter-space dimension has been set.
Definition: LatticeTiling.c:55
double upper_bbox_pad
Upper padding as multiple of metric ellipse bounding box.
Definition: LatticeTiling.c:63
double lower_bbox_pad
Lower padding as multiple of metric ellipse bounding box.
Definition: LatticeTiling.c:62
char data_upper[LT_DATA_MAX_SIZE]
Arbitrary data describing upper parameter-space bound.
Definition: LatticeTiling.c:60
bool is_tiled
True if the dimension is tiled, false if it is a single point.
Definition: LatticeTiling.c:56
char data_lower[LT_DATA_MAX_SIZE]
Arbitrary data describing lower parameter-space bound.
Definition: LatticeTiling.c:59
LatticeTilingBound func
Parameter space bound function.
Definition: LatticeTiling.c:57
size_t data_len
Length of arbitrary data describing parameter-space bounds.
Definition: LatticeTiling.c:58
bool find_bound_extrema
Whether to find the extrema of the parameter-space bounds.
Definition: LatticeTiling.c:66
UINT4 lower_intp_pad
Lower padding as integer number of points.
Definition: LatticeTiling.c:64
UINT4 upper_intp_pad
Upper padding as integer number of points.
Definition: LatticeTiling.c:65
Lattice tiling callback function and associated data.
Definition: LatticeTiling.c:72
char out[LT_DATA_MAX_SIZE]
Output data to be filled by callback function.
Definition: LatticeTiling.c:76
LatticeTilingCallback func
Callback function.
Definition: LatticeTiling.c:73
char param[LT_DATA_MAX_SIZE]
Arbitrary input data for use by callback function.
Definition: LatticeTiling.c:75
size_t param_len
Length of arbitrary input data for use by callback function.
Definition: LatticeTiling.c:74
FITS record for for saving and restoring a lattice tiling iterator.
Definition: LatticeTiling.c:82
INT4 int_lower
Current lower parameter-space bound in generating integers.
Definition: LatticeTiling.c:86
REAL8 phys_point
Current lattice point in physical coordinates.
Definition: LatticeTiling.c:84
INT4 int_point
Current lattice point in generating integers.
Definition: LatticeTiling.c:85
INT4 int_upper
Current upper parameter-space bound in generating integers.
Definition: LatticeTiling.c:87
INT4 checksum
Checksum of various data describing parameter-space bounds.
Definition: LatticeTiling.c:83
INT4 direction
Direction of iteration in each tiled parameter-space dimension.
Definition: LatticeTiling.c:88
Statistics related to the number/value of lattice tiling points in a dimension.
Lattice tiling index trie for one dimension.
Definition: LatticeTiling.c:95
UINT8 index
Sequential lattice tiling index up to this dimension.
Definition: LatticeTiling.c:98
INT4 int_upper
Upper integer point bound in this dimension.
Definition: LatticeTiling.c:97
LT_IndexTrie * next
Pointer to array of index tries for the next-highest dimension.
Definition: LatticeTiling.c:99
INT4 int_lower
Lower integer point bound in this dimension.
Definition: LatticeTiling.c:96
Describes a lattice tiling parameter-space bounds and metric.
gsl_matrix * int_from_phys
Transform to generating integers from physical coordinates.
gsl_matrix * phys_from_int
Transform to physical coordinates from generating integers.
size_t * tiled_idx
Index to tiled parameter-space dimensions.
gsl_vector * phys_bbox
Metric ellipse bounding box.
LT_Callback ** callbacks
Registered callbacks.
const LatticeTilingStats * stats
Lattice tiling statistics computed by default callback.
size_t ncallback
Number of registered callbacks.
TilingLattice lattice
Type of lattice to generate tiling with.
size_t * ncallback_done
Pointer to number of successfully performed callbacks (mutable)
LT_Bound * bounds
Array of parameter-space bound info for each dimension.
size_t ndim
Number of parameter-space dimensions.
size_t tiled_ndim
Number of tiled parameter-space dimensions.
gsl_vector * phys_origin
Parameter-space origin in physical coordinates.
gsl_vector * phys_origin_shift_frac
Fraction of step size to shift physical parameter-space origin.
gsl_matrix * tiled_generator
Lattice generator matrix in tiled dimensions.
Iterates over all points in a lattice tiling.
const LatticeTiling * tiling
Lattice tiling.
size_t itr_ndim
Number of parameter-space dimensions to iterate over.
bool alternating
If true, alternate iterator direction after every crossing.
UINT8 index
Index of current lattice tiling point.
gsl_vector * phys_point
Current lattice point in physical coordinates.
INT4 * int_upper
Current upper parameter-space bound in generating integers.
INT4 * int_lower
Current lower parameter-space bound in generating integers.
gsl_matrix * phys_sampl_cache
Cached values for sampling bounds with LT_FindBoundExtrema()
size_t tiled_itr_ndim
Number of tiled parameter-space dimensions to iterate over.
INT4 * int_point
Current lattice point in generating integers.
gsl_matrix * phys_point_cache
Cached values for computing physical bounds on current point.
gsl_vector * phys_sampl
Copy of physical point for sampling bounds with LT_FindBoundExtrema()
INT4 * direction
Direction of iteration in each tiled parameter-space dimension.
UINT4 state
Iterator state: 0=initialised, 1=in progress, 2=finished.
Locates the nearest point in a lattice tiling.
size_t ndim
Number of parameter-space dimensions.
LT_IndexTrie * index_trie
Trie for locating unique index of nearest point.
const LatticeTiling * tiling
Lattice tiling.
size_t tiled_ndim
Number of tiled parameter-space dimensions.