23 #include <gsl/gsl_math.h>
24 #include <gsl/gsl_blas.h>
25 #include <gsl/gsl_linalg.h>
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>
35 #define UNUSED __attribute__ ((unused))
41 #define LT_DATA_MAX_SIZE 65536
44 #define LT_CACHE_MAX_SIZE 6
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 ) )
53 typedef struct tagLT_Bound {
72 typedef struct tagLT_Callback {
82 typedef struct tagLT_FITSRecord {
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 );
171 for (
size_t i = 0;
i <
A->size1 / 2; ++
i ) {
172 gsl_matrix_swap_rows(
A,
i,
A->size1 -
i - 1 );
174 for (
size_t j = 0;
j <
A->size2 / 2; ++
j ) {
175 gsl_matrix_swap_columns(
A,
j,
A->size2 -
j - 1 );
183 const LatticeTiling *tiling,
185 const gsl_matrix *phys_point_cache,
186 const gsl_vector *phys_point,
193 const LT_Bound *bound = &tiling->bounds[dim];
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;
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;
204 *phys_lower = ( bound->
func )( (
const void * ) bound->
data_lower, dim, phys_point_cache_subm, phys_point_subv );
209 *phys_upper = ( bound->
func )( (
const void * ) bound->
data_upper, dim, phys_point_cache_subm, phys_point_subv );
212 if ( *phys_upper < *phys_lower ) {
213 *phys_upper = *phys_lower;
216 }
else if ( phys_upper != NULL ) {
219 *phys_upper = *phys_lower;
229 const LatticeTiling *tiling,
230 gsl_matrix *phys_point_cache,
231 gsl_vector *phys_point,
233 const double phys_point_dim
238 const LT_Bound *bound = &tiling->bounds[dim];
241 gsl_vector_set( phys_point, dim, phys_point_dim );
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;
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;
254 ( bound->
cache_func )( dim, phys_point_subv, phys_point_cache_subv );
264 const LatticeTiling *tiling,
267 gsl_matrix *phys_point_cache,
268 gsl_vector *phys_point,
269 double *phys_lower_minimum,
270 double *phys_upper_maximum
275 const LT_Bound *bound = &tiling->bounds[
i];
279 LT_CallBoundFunc( tiling, dim, phys_point_cache, phys_point, phys_lower_minimum, phys_upper_maximum );
284 const double phys_point_i = gsl_vector_get( phys_point,
i );
287 LT_FindBoundExtrema( tiling,
i + 1, dim, phys_point_cache, phys_point, phys_lower_minimum, phys_upper_maximum );
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,
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 );
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,
325 const size_t n = tiling->ndim;
329 for (
size_t i = 0;
i <
n; ++
i ) {
330 INT4 left = 0, right = 0;
332 const UINT4 num_points = right - left + 1;
343 for (
size_t i = changed_i;
i <
n; ++
i ) {
344 INT4 left = 0, right = 0;
346 const UINT4 num_points = right - left + 1;
349 }
else if (
i >= changed_i ) {
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 );
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 );
385 LT_IndexTrie *next = trie->next;
386 if ( next != NULL ) {
387 for (
INT4 i = trie->int_lower; i <= trie->int_upper; ++
i ) {
399 const LatticeTiling *tiling,
400 const LT_IndexTrie *trie,
402 const gsl_vector *point_int,
404 double *poll_min_distance,
409 const size_t n = tiling->ndim;
410 const size_t tn = tiling->tiled_ndim;
413 const INT4 int_lower = trie->int_lower;
414 const INT4 int_upper = trie->int_upper;
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 ) );
422 for ( poll_nearest[
i] = poll_lower; poll_nearest[
i] <= poll_upper; ++poll_nearest[
i] ) {
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 );
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;
445 if ( poll_distance < *poll_min_distance ) {
446 *poll_min_distance = poll_distance;
447 memcpy( nearest, poll_nearest,
n *
sizeof( nearest[0] ) );
458 const LatticeTiling *tiling,
459 const LT_IndexTrie *trie,
466 const size_t tn = tiling->tiled_ndim;
469 for (
size_t s = 0;
s <= ti; ++
s ) {
474 if ( trie == NULL ) {
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];
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 );
496 ti + 1, tn, trie->int_lower, trie->int_upper, phys_lower, phys_upper, trie->index );
499 LT_IndexTrie *next = trie->next;
500 if ( next != NULL ) {
501 for ( int32_t point = trie->int_lower; point <= trie->int_upper; ++point, ++next ) {
504 int_lower[ti] = point;
521 const LatticeTilingLocator *
loc,
522 const gsl_matrix *points,
523 gsl_matrix *nearest_points,
538 const size_t n =
loc->ndim;
539 const size_t tn =
loc->tiled_ndim;
540 const size_t num_points = points->size2;
543 gsl_matrix_memcpy( nearest_points, points );
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 );
551 gsl_blas_dtrmm( CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, 1.0,
loc->tiling->int_from_phys, nearest_points );
554 for (
size_t j = 0;
j < num_points; ++
j ) {
561 switch (
loc->tiling->lattice ) {
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 ) );
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];
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 );
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] );
622 z[ti - 1] =
y[ti - 1] -
k[ti - 1];
624 beta += z[ti - 1] * z[ti - 1];
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 ) {
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];
660 for (
size_t ti = 1; ti <= tn + 1; ++ti ) {
661 size_t tt = bucket[ti - 1];
664 beta = beta - 2 * z[tt - 1] + 1;
675 for (
size_t ti = 1; ti <= tm; ++ti ) {
676 size_t tt = bucket[ti - 1];
678 k[tt - 1] =
k[tt - 1] + 1;
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];
700 const LT_IndexTrie *trie =
loc->index_trie;
703 const size_t i =
loc->tiling->tiled_idx[ti];
706 if ( nearest[
i] < trie->int_lower || nearest[
i] > trie->int_upper ) {
708 __func__, trie->int_lower, nearest[
i], trie->int_upper,
i );
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 );
719 trie =
loc->index_trie;
727 trie = &trie->next[nearest[
i] - trie->int_lower];
739 const LT_IndexTrie *trie =
loc->index_trie;
740 UINT8 nearest_index = 0;
741 for (
size_t ti = 0,
i = 0;
i <
n; ++
i ) {
742 const bool is_tiled =
loc->tiling->bounds[
i].is_tiled;
746 gsl_matrix_set( nearest_points,
i,
j, nearest[
i] );
752 nearest_index = trie->index + nearest[
i] - trie->int_lower;
754 if ( nearest_indexes != NULL ) {
755 nearest_indexes->
data[
n *
j +
i] = nearest_index;
759 if ( nearest_lefts != NULL ) {
760 nearest_lefts->
data[
n *
j +
i] = is_tiled ? trie->int_lower - nearest[
i] : 0;
762 if ( nearest_rights != NULL ) {
763 nearest_rights->
data[
n *
j +
i] = is_tiled ? trie->int_upper - nearest[
i] : 0;
769 trie = &trie->next[nearest[
i] - trie->int_lower];
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 );
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 );
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 ) {
818 LatticeTiling *tiling =
XLALCalloc( 1,
sizeof( *tiling ) );
820 tiling->bounds =
XLALCalloc( ndim,
sizeof( *tiling->bounds ) );
822 tiling->ncallback_done =
XLALCalloc( 1,
sizeof( *tiling->ncallback_done ) );
830 for (
size_t i = 0;
i < ndim; ++
i ) {
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 );
848 LatticeTiling *tiling
851 if ( tiling != NULL ) {
854 for (
size_t m = 0;
m < tiling->ncallback; ++
m ) {
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 );
866 LatticeTiling *tiling,
869 const size_t data_len,
870 const void *data_lower,
871 const void *data_upper
886 XLAL_CHECK( tiling->bounds[dim].func == NULL,
XLAL_EINVAL,
"Lattice tiling dimension #%zu is already bounded", dim );
889 const BOOLEAN is_tiled = ( memcmp( data_lower, data_upper, data_len ) != 0 ) ? 1 : 0;
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 );
899 if ( !tiling->bounds[dim].name_set ) {
908 LatticeTiling *tiling,
922 XLAL_CHECK( !tiling->bounds[dim].name_set,
XLAL_EINVAL,
"Lattice tiling dimension #%zu is already named", dim );
927 const int retn = vsnprintf( tiling->bounds[dim].name,
sizeof( tiling->bounds[dim].name ),
fmt,
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;
937 LatticeTiling *tiling,
950 XLAL_CHECK( tiling->bounds[dim].func != NULL,
XLAL_EINVAL,
"Lattice tiling dimension #%zu is not bounded", dim );
953 tiling->bounds[dim].cache_func =
func;
961 const size_t dim UNUSED,
962 const gsl_matrix *
cache UNUSED,
963 const gsl_vector *point UNUSED
968 return *( (
const double * )
data );
973 LatticeTiling *tiling,
986 const double data_lower = GSL_MIN( bound1, bound2 );
987 const double data_upper = GSL_MAX( bound1, bound2 );
995 LatticeTiling *tiling,
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
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;
1017 tiling->bounds[dim].find_bound_extrema = find_bound_extrema < 0 ? true : ( find_bound_extrema ? true : false );
1024 LatticeTiling *tiling,
1037 gsl_vector_set( tiling->phys_origin, dim, origin );
1044 LatticeTiling *tiling,
1054 const size_t n = tiling->ndim;
1057 GAVEC( tiling->phys_origin_shift_frac,
n );
1061 for (
size_t i = 0;
i <
n; ++
i ) {
1070 LatticeTiling *tiling,
1071 const LatticeTiling *ref_tiling
1082 const size_t n = tiling->ndim;
1085 for (
size_t i = 0;
i <
n; ++
i ) {
1090 for (
size_t i = 0;
i <
n; ++
i ) {
1091 tiling->bounds[
i].is_tiled = ref_tiling->bounds[
i].is_tiled;
1099 LatticeTiling *tiling,
1101 const gsl_matrix *metric,
1102 const double max_mismatch
1114 const size_t n = tiling->ndim;
1117 for (
size_t i = 0;
i <
n; ++
i ) {
1122 for (
size_t i = 0;
i <
n; ++
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 );
1130 tiling->lattice = lattice;
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 );
1142 LT_SetPhysPoint( tiling, phys_origin_cache, tiling->phys_origin,
i, phys_origin_i );
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;
1156 if ( tiling->tiled_ndim == 0 ) {
1160 const size_t tn = tiling->tiled_ndim;
1163 tiling->tiled_idx =
XLALCalloc( tn,
sizeof( *tiling->tiled_idx ) );
1165 for (
size_t i = 0, ti = 0;
i <
n; ++
i ) {
1166 if ( tiling->bounds[
i].is_tiled ) {
1167 tiling->tiled_idx[ti++] =
i;
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 ) );
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 );
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 );
1203 gsl_matrix *GAMAT( t_basis, tn, tn );
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" );
1221 GAMAT( tiling->tiled_generator, tn, tn );
1225 double norm_thickness = 0.0;
1226 switch ( tiling->lattice ) {
1233 gsl_matrix_set_identity( tiling->tiled_generator );
1236 norm_thickness = pow( sqrt( tn ) / 2.0, tn );
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 ) );
1262 gsl_matrix_view Gp = gsl_matrix_submatrix( G, 0, 1, tn + 1, tn );
1264 gsl_vector *GAVEC( tau, tn );
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 );
1273 gsl_matrix_view L_view = gsl_matrix_submatrix(
L, 1, 0, tn, tn );
1274 gsl_matrix_memcpy( tiling->tiled_generator, &L_view.matrix );
1281 norm_thickness = sqrt( tn + 1.0 ) * pow( ( 1.0 * tn * ( tn + 2.0 ) ) / ( 12.0 * ( tn + 1.0 ) ), 0.5 * tn );
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 );
1304 gsl_matrix *GAMAT( LU_decomp, tn, tn );
1305 gsl_matrix_memcpy( LU_decomp, tiling->tiled_generator );
1306 gsl_permutation *GAPERM( LU_perm, tn );
1308 XLAL_CHECK( gsl_linalg_LU_decomp( LU_decomp, LU_perm, &LU_sign ) == 0,
XLAL_EFAILED,
"Generator matrix cannot be LU-decomposed" );
1315 const double generator_covering_radius = pow( norm_thickness * generator_determinant, 1.0 / tn );
1318 gsl_matrix_scale( tiling->tiled_generator, sqrt( max_mismatch ) / generator_covering_radius );
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 );
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 );
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 );
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;
1362 LT_SetPhysPoint( tiling, phys_origin_cache, tiling->phys_origin,
i, phys_origin_i );
1366 GFMAT( t_metric, t_basis, t_norm_from_int, t_int_from_norm, phys_origin_cache );
1367 GFVEC( t_norm, t_bbox );
1374 const LatticeTiling *tiling
1381 return tiling->ndim;
1386 const LatticeTiling *tiling
1394 return tiling->tiled_ndim;
1399 const LatticeTiling *tiling,
1400 const size_t tiled_dim
1409 return tiling->tiled_idx[tiled_dim];
1414 const LatticeTiling *tiling,
1422 XLAL_CHECK( tiling->bounds[dim].func != NULL,
XLAL_EINVAL,
"Lattice tiling dimension #%zu is not bounded", dim );
1424 return tiling->bounds[dim].is_tiled ? 1 : 0;
1429 const LatticeTiling *tiling,
1439 return tiling->bounds[dim].name;
1444 const LatticeTiling *tiling,
1445 const char *bound_name
1454 for (
int dim = 0; dim < (
int )tiling->ndim; ++dim ) {
1455 if ( strcmp( tiling->bounds[dim].name, bound_name ) == 0 ) {
1465 const LatticeTiling *tiling,
1476 if ( !tiling->bounds[dim].is_tiled ) {
1481 return gsl_matrix_get( tiling->phys_from_int, dim, dim );
1486 const LatticeTiling *tiling,
1497 if ( !tiling->bounds[dim].is_tiled ) {
1501 return gsl_vector_get( tiling->phys_bbox, dim );
1506 LatticeTiling *tiling,
1508 const size_t param_len,
1510 const size_t out_len
1524 ++tiling->ncallback;
1525 tiling->callbacks =
XLALRealloc( tiling->callbacks, tiling->ncallback *
sizeof( *tiling->callbacks ) );
1533 if ( param_len > 0 ) {
1534 memcpy( cb->
param, param, param_len );
1542 const LatticeTiling *tiling
1551 if ( *tiling->ncallback_done == tiling->ncallback ) {
1555 const size_t n = tiling->ndim;
1556 const size_t tn = tiling->tiled_ndim;
1563 double volume_pc_prev = 0;
1564 bool first_call =
true;
1566 double point_array[
n];
1567 gsl_vector_view point_view = gsl_vector_view_array( point_array,
n );
1569 const size_t changed_i = ( !first_call && tiling->tiled_ndim > 0 ) ? tiling->tiled_idx[changed_ti_p1 - 1] : 0;
1572 for (
size_t m = *tiling->ncallback_done; m < tiling->ncallback; ++
m ) {
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;
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;
1603 const UINT8 total_points = tiling->stats[
n - 1].total_points;
1608 *tiling->ncallback_done = tiling->ncallback;
1618 const LatticeTiling *tiling,
1633 return &tiling->stats[dim];
1638 const LatticeTiling *tiling,
1641 gsl_matrix *random_points
1653 const size_t n = tiling->ndim;
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 ) {
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 );
1670 LT_SetPhysPoint( tiling, phys_point_cache, &phys_point.vector,
i, phys_lower +
u * ( phys_upper - phys_lower ) );
1677 GFMAT( phys_point_cache );
1684 const LatticeTiling *tiling,
1686 const gsl_vector *point,
1701 const size_t n = tiling->ndim;
1704 const LT_Bound *bound = &tiling->bounds[dim];
1709 gsl_vector *GAVEC( phys_sampl,
n );
1712 gsl_vector_memcpy( phys_sampl, point );
1713 *lower = GSL_POSINF;
1714 *upper = GSL_NEGINF;
1715 if ( bound->
is_tiled && padding ) {
1717 LT_CallBoundFunc( tiling, dim, phys_point_cache, phys_sampl, lower, upper );
1721 const double phys_bbox_dim = gsl_vector_get( tiling->phys_bbox, dim );
1725 LT_CallBoundFunc( tiling, dim, phys_point_cache, phys_sampl, lower, upper );
1729 GFVEC( phys_sampl );
1730 GFMAT( phys_point_cache );
1731 GFMAT( phys_sampl_cache );
1738 const LatticeTiling *tiling,
1739 const size_t itr_ndim
1749 LatticeTilingIterator *itr =
XLALCalloc( 1,
sizeof( *itr ) );
1753 itr->tiling = tiling;
1756 itr->itr_ndim = itr_ndim;
1757 itr->alternating =
false;
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;
1769 const size_t n = itr->tiling->ndim;
1770 const size_t tn = itr->tiling->tiled_ndim;
1773 GAVEC_NULL( itr->phys_point,
n );
1775 gsl_matrix_set_all( itr->phys_point_cache, GSL_NAN );
1776 GAVEC_NULL( itr->phys_sampl,
n );
1778 gsl_matrix_set_all( itr->phys_sampl_cache, GSL_NAN );
1780 itr->int_lower =
XLALCalloc( tn,
sizeof( *itr->int_lower ) );
1782 itr->int_point =
XLALCalloc( tn,
sizeof( *itr->int_point ) );
1784 itr->int_upper =
XLALCalloc( tn,
sizeof( *itr->int_upper ) );
1786 itr->direction =
XLALCalloc( tn,
sizeof( *itr->direction ) );
1798 LatticeTilingIterator *itr
1802 GFVEC( itr->phys_point, itr->phys_sampl );
1803 GFMAT( itr->phys_point_cache, itr->phys_sampl_cache );
1813 LatticeTilingIterator *itr,
1814 const bool alternating
1823 itr->alternating = alternating;
1830 LatticeTilingIterator *itr
1845 LatticeTilingIterator *itr,
1854 const size_t n = itr->tiling->ndim;
1855 const size_t tn = itr->tiling->tiled_ndim;
1858 if ( itr->state > 1 ) {
1868 if ( itr->state == 0 ) {
1871 gsl_vector_set_zero( itr->phys_point );
1872 for (
size_t ti = 0; ti < tn; ++ti ) {
1873 itr->int_point[ti] = 0;
1877 for (
size_t ti = 0; ti < tn; ++ti ) {
1878 itr->direction[ti] = 1;
1893 size_t ti = itr->tiled_itr_ndim;
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;
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 );
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 ) ) {
1945 for (
size_t i = 0, ti = 0;
i <
n; ++
i ) {
1948 const LT_Bound *bound = &itr->tiling->bounds[
i];
1951 const double phys_origin_i = gsl_vector_get( itr->tiling->phys_origin,
i );
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 );
1961 if ( bound->
is_tiled && ti >= reset_ti ) {
1964 gsl_vector_memcpy( itr->phys_sampl, itr->phys_point );
1965 double phys_lower = GSL_POSINF, phys_upper = GSL_NEGINF;
1967 LT_CallBoundFunc( itr->tiling,
i, itr->phys_point_cache, itr->phys_sampl, &phys_lower, &phys_upper );
1969 LT_FindBoundExtrema( itr->tiling, 0,
i, itr->phys_sampl_cache, itr->phys_sampl, &phys_lower, &phys_upper );
1974 const double phys_bbox_i = gsl_vector_get( itr->tiling->phys_bbox,
i );
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 );
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 );
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 );
2001 itr->int_lower[ti] = int_lower_i;
2002 itr->int_upper[ti] = GSL_MAX( int_lower_i, int_upper_i );
2008 const INT4 int_lower_i = itr->int_lower[ti];
2009 const INT4 int_upper_i = itr->int_upper[ti];
2012 INT4 direction = itr->direction[ti];
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;
2027 if ( ti < itr->tiled_itr_ndim ) {
2028 itr->int_point[ti] = ( direction > 0 ) ? int_lower_i : int_upper_i;
2030 itr->int_point[ti] = ( int_lower_i + int_upper_i ) / 2;
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;
2044 LT_SetPhysPoint( itr->tiling, itr->phys_point_cache, itr->phys_point,
i, phys_point_i );
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 );
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;
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];
2072 LT_SetPhysPoint( itr->tiling, itr->phys_point_cache, itr->phys_point,
i, phys_point_i );
2087 if ( point != NULL ) {
2088 gsl_vector_memcpy( point, itr->phys_point );
2092 return 1 + changed_ti;
2097 LatticeTilingIterator *itr,
2109 for ( ;
j < ( *points )->size2; ++
j ) {
2110 gsl_vector_view point_j = gsl_matrix_column( *points,
j );
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 );
2124 *points = new_points;
2132 const LatticeTilingIterator *itr
2149 const LatticeTilingIterator *itr
2162 const LatticeTilingIterator *itr,
2178 for (
size_t ti = 0; ti < itr->tiling->tiled_ndim; ++ti ) {
2179 const size_t i = itr->tiling->tiled_idx[ti];
2181 *left = itr->int_lower[ti] - itr->int_point[ti];
2182 *right = itr->int_upper[ti] - itr->int_point[ti];
2192 const LatticeTilingIterator *itr,
2204 const size_t n = itr->tiling->ndim;
2211 for (
size_t i = 0, ti = 0;
i <
n; ++
i ) {
2225 record.checksum = checksum;
2227 record.phys_point = gsl_vector_get( itr->phys_point,
i );
2228 if ( itr->tiling->bounds[
i].is_tiled ) {
2229 record.int_point = itr->int_point[ti];
2230 record.int_lower = itr->int_lower[ti];
2231 record.int_upper = itr->int_upper[ti];
2232 record.direction = itr->direction[ti];
2243 UINT4 ndim = itr->tiling->ndim;
2246 UINT4 tiled_ndim = itr->tiling->tiled_ndim;
2249 UINT4 lattice = itr->tiling->lattice;
2255 UINT4 itr_ndim = itr->itr_ndim;
2258 UINT4 tiled_itr_ndim = itr->tiled_itr_ndim;
2261 BOOLEAN alternating = itr->alternating;
2264 UINT4 state = itr->state;
2270 UINT8 indx = itr->index;
2279 LatticeTilingIterator *itr,
2290 const size_t n = itr->tiling->ndim;
2306 XLAL_CHECK( tiled_ndim == itr->tiling->tiled_ndim,
XLAL_EIO,
"Could not restore iterator; invalid HDU '%s'",
name );
2310 XLAL_CHECK( lattice == itr->tiling->lattice,
XLAL_EIO,
"Could not restore iterator; invalid HDU '%s'",
name );
2319 UINT4 tiled_itr_ndim;
2321 XLAL_CHECK( tiled_itr_ndim == itr->tiled_itr_ndim,
XLAL_EIO,
"Could not restore iterator; invalid HDU '%s'",
name );
2325 XLAL_CHECK( !alternating == !itr->alternating,
XLAL_EIO,
"Could not restore iterator; invalid HDU '%s'",
name );
2344 for (
size_t i = 0, ti = 0;
i <
n; ++
i ) {
2359 XLAL_CHECK( record.checksum == checksum,
XLAL_EIO,
"Could not restore iterator; invalid HDU '%s'",
name );
2361 LT_SetPhysPoint( itr->tiling, itr->phys_point_cache, itr->phys_point,
i, record.phys_point );
2362 if ( itr->tiling->bounds[
i].is_tiled ) {
2363 itr->int_point[ti] = record.int_point;
2364 XLAL_CHECK( record.int_lower <= record.int_point,
XLAL_EIO,
"Could not restore iterator; invalid HDU '%s'",
name );
2365 itr->int_lower[ti] = record.int_lower;
2366 XLAL_CHECK( record.int_point <= record.int_upper,
XLAL_EIO,
"Could not restore iterator; invalid HDU '%s'",
name );
2367 itr->int_upper[ti] = record.int_upper;
2369 itr->direction[ti] = record.direction;
2380 const LatticeTiling *tiling
2393 loc->tiling = tiling;
2396 loc->ndim = tiling->ndim;
2397 loc->tiled_ndim = tiling->tiled_ndim;
2400 if (
loc->tiled_ndim > 0 ) {
2406 const size_t tn = itr->tiling->tiled_ndim;
2409 LT_IndexTrie *next[tn];
2410 memset( next, 0,
sizeof( next ) );
2414 memset( indx, 0,
sizeof( indx ) );
2421 const size_t changed_ti = changed_ti_p1 - 1;
2424 for (
size_t tj = changed_ti; tj < tn; ++tj ) {
2427 if ( next[tj] == NULL ) {
2432 LT_IndexTrie *trie = NULL;
2434 trie = next[tj - 1];
2441 trie->int_lower = itr->int_lower[tj];
2442 trie->int_upper = itr->int_upper[tj];
2445 trie->index = indx[tj];
2447 if ( tj + 1 < tn ) {
2451 const size_t next_length = trie->int_upper - trie->int_lower + 1;
2452 trie->next =
XLALCalloc( next_length,
sizeof( *trie->next ) );
2456 next[tj] = trie->next;
2469 if ( tj + 1 < tn ) {
2470 next[tj + 1] = NULL;
2476 for (
size_t tj = changed_ti; tj < tn; ++tj ) {
2479 indx[tn - 1] += itr->int_upper[tn - 1] - itr->int_lower[tn - 1];
2494 LatticeTilingLocator *
loc
2498 if (
loc->index_trie != NULL ) {
2507 const LatticeTilingLocator *
loc,
2508 const gsl_vector *point,
2509 gsl_vector *nearest_point,
2522 const size_t n =
loc->ndim;
2525 double local_point_array[
n];
2526 gsl_vector_view local_point_vector = gsl_vector_view_array( local_point_array,
n );
2527 gsl_matrix_view local_point_matrix = gsl_matrix_view_array( local_point_array,
n, 1 );
2528 gsl_vector *local_point = &local_point_vector.vector;
2529 gsl_matrix *local_points = &local_point_matrix.matrix;
2532 double local_nearest_point_array[
n];
2533 gsl_vector_view local_nearest_point_vector = gsl_vector_view_array( local_nearest_point_array,
n );
2534 gsl_matrix_view local_nearest_point_matrix = gsl_matrix_view_array( local_nearest_point_array,
n, 1 );
2535 gsl_vector *local_nearest_point = &local_nearest_point_vector.vector;
2536 gsl_matrix *local_nearest_points = &local_nearest_point_matrix.matrix;
2541 if ( nearest_index != NULL ) {
2543 nearest_indexes.
length = 1;
2544 nearest_indexes.
data = nearest_index->
data;
2545 nearest_indexes_ptr = &nearest_indexes;
2549 gsl_vector_memcpy( local_point, point );
2551 if ( nearest_point != NULL ) {
2552 gsl_vector_memcpy( nearest_point, local_nearest_point );
2560 const LatticeTilingLocator *
loc,
2561 const gsl_matrix *points,
2562 gsl_matrix **nearest_points,
2573 const size_t n =
loc->ndim;
2574 const size_t num_points = points->size2;
2577 if ( *nearest_points != NULL ) {
2578 if ( ( *nearest_points )->size1 !=
n || ( *nearest_points )->size2 < num_points ) {
2579 GFMAT( *nearest_points );
2580 *nearest_points = NULL;
2583 if ( *nearest_points == NULL ) {
2584 GAMAT( *nearest_points,
n, num_points );
2586 gsl_matrix_view nearest_points_view = gsl_matrix_submatrix( *nearest_points, 0, 0,
n, num_points );
2589 if ( nearest_indexes != NULL ) {
2590 if ( *nearest_indexes != NULL ) {
2591 if ( ( *nearest_indexes )->vectorLength !=
n || ( *nearest_indexes )->length < num_points ) {
2593 *nearest_indexes = NULL;
2596 if ( *nearest_indexes == NULL ) {
2601 UINT8VectorSequence *nearest_indexes_view = ( nearest_indexes != NULL ) ? *nearest_indexes : NULL;
2611 const LatticeTilingLocator *
loc,
2612 const gsl_vector *point,
2614 gsl_vector *nearest_point,
2615 UINT8 *nearest_index,
2632 const size_t n =
loc->ndim;
2635 double local_point_array[
n];
2636 gsl_vector_view local_point_vector = gsl_vector_view_array( local_point_array,
n );
2637 gsl_matrix_view local_point_matrix = gsl_matrix_view_array( local_point_array,
n, 1 );
2638 gsl_vector *local_point = &local_point_vector.vector;
2639 gsl_matrix *local_points = &local_point_matrix.matrix;
2642 double local_nearest_point_array[
n];
2643 gsl_vector_view local_nearest_point_vector = gsl_vector_view_array( local_nearest_point_array,
n );
2644 gsl_matrix_view local_nearest_point_matrix = gsl_matrix_view_array( local_nearest_point_array,
n, 1 );
2645 gsl_vector *local_nearest_point = &local_nearest_point_vector.vector;
2646 gsl_matrix *local_nearest_points = &local_nearest_point_matrix.matrix;
2649 UINT8 nearest_indexes_data[
n];
2651 INT4 nearest_lefts_data[
n];
2653 INT4 nearest_rights_data[
n];
2657 gsl_vector_memcpy( local_point, point );
2659 gsl_vector_memcpy( nearest_point, local_nearest_point );
2660 *nearest_index = ( dim > 0 ) ? nearest_indexes_data[dim - 1] : 0;
2661 *nearest_left = nearest_lefts_data[dim];
2662 *nearest_right = nearest_rights_data[dim];
2669 const LatticeTilingLocator *
loc,
2678 const size_t tn =
loc->tiled_ndim;
2681 if ( tn == 0 ||
loc->index_trie == NULL ) {
#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)
int XLALFITSTableWriteRow(FITSFile UNUSED *file, const void UNUSED *record)
int XLALFITSHeaderWriteBOOLEAN(FITSFile UNUSED *file, const CHAR UNUSED *key, const BOOLEAN UNUSED value, const CHAR UNUSED *comment)
int XLALFITSTableReadRow(FITSFile UNUSED *file, void UNUSED *record, UINT8 UNUSED *rem_nrows)
int XLALFITSHeaderReadBOOLEAN(FITSFile UNUSED *file, const CHAR UNUSED *key, BOOLEAN UNUSED *value)
int XLALFITSTableOpenWrite(FITSFile UNUSED *file, const CHAR UNUSED *name, const CHAR UNUSED *comment)
int XLALFITSHeaderWriteUINT8(FITSFile UNUSED *file, const CHAR UNUSED *key, const UINT8 UNUSED value, const CHAR UNUSED *comment)
int XLALFITSHeaderReadUINT8(FITSFile UNUSED *file, const CHAR UNUSED *key, UINT8 UNUSED *value)
int XLALFITSHeaderReadUINT4(FITSFile UNUSED *file, const CHAR UNUSED *key, UINT4 UNUSED *value)
int XLALFITSTableOpenRead(FITSFile UNUSED *file, const CHAR UNUSED *name, UINT8 UNUSED *nrows)
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
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.
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)
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.
const double scale
multiplicative scaling factor of the coordinate
UINT8VectorSequence * XLALCreateUINT8VectorSequence(UINT4 length, UINT4 veclen)
void XLALDestroyUINT8VectorSequence(UINT8VectorSequence *vecseq)
#define XLAL_FITS_TABLE_COLUMN_BEGIN(record_type)
#define XLAL_FITS_TABLE_COLUMN_ADD(file, type, field)
struct tagFITSFile FITSFile
Representation of a FITS file.
#define XLAL_INIT_DECL(var,...)
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)
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.
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.
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.
const LatticeTilingStats * XLALLatticeTilingStatistics(const LatticeTiling *tiling, const size_t dim)
Return statistics related to the number/value of lattice tiling points in a dimension.
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.
void(* LatticeTilingBoundCache)(const size_t dim, const gsl_vector *point, gsl_vector *cache)
Function which caches values required by a lattice tiling bound function.
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.
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.
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.
LatticeTilingIterator * XLALCreateLatticeTilingIterator(const LatticeTiling *tiling, const size_t itr_ndim)
Create a new lattice tiling iterator.
int XLALPerformLatticeTilingCallbacks(const LatticeTiling *tiling)
Perform all registered lattice tiling callbacks.
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.
LatticeTilingLocator * XLALCreateLatticeTilingLocator(const LatticeTiling *tiling)
Create a new lattice tiling locator.
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.
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...
LatticeTiling * XLALCreateLatticeTiling(const size_t ndim)
Create a new lattice tiling.
const UserChoices TilingLatticeChoices
Static array of all :tagTilingLattice choices, for use by the UserInput module parsing routines.
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 XLALPrintLatticeTilingIndexTrie(const LatticeTilingLocator *loc, FILE *file)
Print the internal index trie of a lattice tiling locator to the given file pointer.
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.
const char * XLALLatticeTilingBoundName(const LatticeTiling *tiling, const size_t dim)
Get the name of a lattice tiling parameter-space dimension.
TilingLattice
Type of lattice to generate tiling with.
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.
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...
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.
@ TILING_LATTICE_ANSTAR
An-star ( ) lattice.
@ TILING_LATTICE_CUBIC
Cubic ( ) lattice.
void LogPrintf(LogLevel_t, const char *format,...) _LAL_GCC_PRINTF_FORMAT_(2
double XLALMetricDeterminant(const gsl_matrix *g_ij)
Compute the determinant of a metric .
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 .
REAL4 XLALUniformDeviate(RandomParams *params)
int int int XLALPrintInfo(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
#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)
Lattice tiling parameter-space bound for one dimension.
LatticeTilingBoundCache cache_func
Parameter space bound cache function.
bool name_set
True if the name of the parameter-space dimension has been set.
double upper_bbox_pad
Upper padding as multiple of metric ellipse bounding box.
double lower_bbox_pad
Lower padding as multiple of metric ellipse bounding box.
char data_upper[LT_DATA_MAX_SIZE]
Arbitrary data describing upper parameter-space bound.
bool is_tiled
True if the dimension is tiled, false if it is a single point.
char data_lower[LT_DATA_MAX_SIZE]
Arbitrary data describing lower parameter-space bound.
LatticeTilingBound func
Parameter space bound function.
size_t data_len
Length of arbitrary data describing parameter-space bounds.
bool find_bound_extrema
Whether to find the extrema of the parameter-space bounds.
UINT4 lower_intp_pad
Lower padding as integer number of points.
UINT4 upper_intp_pad
Upper padding as integer number of points.
Lattice tiling callback function and associated data.
char out[LT_DATA_MAX_SIZE]
Output data to be filled by callback function.
LatticeTilingCallback func
Callback function.
char param[LT_DATA_MAX_SIZE]
Arbitrary input data for use by callback function.
size_t param_len
Length of arbitrary input data for use by callback function.
FITS record for for saving and restoring a lattice tiling iterator.
INT4 int_lower
Current lower parameter-space bound in generating integers.
REAL8 phys_point
Current lattice point in physical coordinates.
INT4 int_point
Current lattice point in generating integers.
INT4 int_upper
Current upper parameter-space bound in generating integers.
INT4 checksum
Checksum of various data describing parameter-space bounds.
INT4 direction
Direction of iteration in each tiled parameter-space dimension.
Statistics related to the number/value of lattice tiling points in a dimension.
UINT4 min_points
Minimum number of points in this dimension.
double min_value
Minimum value of points in this dimension.
UINT8 total_points
Total number of points up to this dimension.
double max_value
Maximum value of points in this dimension.
const char * name
Name of parameter-space dimension.
UINT4 max_points
Maximum number of points in this dimension.
Lattice tiling index trie for one dimension.
UINT8 index
Sequential lattice tiling index up to this dimension.
INT4 int_upper
Upper integer point bound in this dimension.
LT_IndexTrie * next
Pointer to array of index tries for the next-highest dimension.
INT4 int_lower
Lower integer point bound in this dimension.
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.