elpa_index.c 22.4 KB
Newer Older
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//    This file is part of ELPA.
//
//    The ELPA library was originally created by the ELPA consortium,
//    consisting of the following organizations:
//
//    - Max Planck Computing and Data Facility (MPCDF), formerly known as
//      Rechenzentrum Garching der Max-Planck-Gesellschaft (RZG),
//    - Bergische Universität Wuppertal, Lehrstuhl für angewandte
//      Informatik,
//    - Technische Universität München, Lehrstuhl für Informatik mit
//      Schwerpunkt Wissenschaftliches Rechnen ,
//    - Fritz-Haber-Institut, Berlin, Abt. Theorie,
//    - Max-Plack-Institut für Mathematik in den Naturwissenschaften,
//      Leipzig, Abt. Komplexe Strukutren in Biologie und Kognition,
//      and
//    - IBM Deutschland GmbH
//
//    This particular source code file contains additions, changes and
//    enhancements authored by Intel Corporation which is not part of
//    the ELPA consortium.
//
//    More information can be found here:
//    http://elpa.mpcdf.mpg.de/
//
//    ELPA is free software: you can redistribute it and/or modify
//    it under the terms of the version 3 of the license of the
//    GNU Lesser General Public License as published by the Free
//    Software Foundation.
//
//    ELPA is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public License
//    along with ELPA.  If not, see <http://www.gnu.org/licenses/>
//
//    ELPA reflects a substantial effort on the part of the original
//    ELPA consortium, and we ask you to respect the spirit of the
//    license that we chose: i.e., please contribute any changes you
//    may have back to the original ELPA library distribution, and keep
//    any derivatives of ELPA under the same license that we chose for
//    the original distribution, the GNU Lesser General Public License.
//
//    Authors: L. Huedepohl and A. Marek, MPCDF
46
#include <elpa/elpa.h>
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
47
#include "elpa_index.h"
48

49
50
51
52
53
54
#include <execinfo.h>

static int enumerate_identity(int i);
static int cardinality_bool(void);
static int valid_bool(elpa_index_t index, int n, int new_value);

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
55
56
57
static int number_of_solvers();
static int solver_enumerate(int i);
static int solver_is_valid(elpa_index_t index, int n, int new_value);
58
59
static const char* elpa_solver_name(int solver);

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
60
61
62
63
static int number_of_real_kernels();
static int real_kernel_enumerate(int i);
static int real_kernel_is_valid(elpa_index_t index, int n, int new_value);
static const char *real_kernel_name(int kernel);
64

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
65
66
67
68
static int number_of_complex_kernels();
static int complex_kernel_enumerate(int i);
static int complex_kernel_is_valid(elpa_index_t index, int n, int new_value);
static const char *complex_kernel_name(int kernel);
69

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
70
71
72
73
74
static int na_is_valid(elpa_index_t index, int n, int new_value);
static int bw_is_valid(elpa_index_t index, int n, int new_value);

static int elpa_double_string_to_value(char *name, char *string, double *value);
static int elpa_double_value_to_string(char *name, double value, const char **string);
75
76
77
78
79
80
81
82
83
84

#define BASE_ENTRY(option_name, option_description, once_value, readonly_value) \
                .base = { \
                        .name = option_name, \
                        .description = option_description, \
                        .once = once_value, \
                        .readonly = readonly_value, \
                        .env_default = "ELPA_DEFAULT_" option_name, \
                        .env_force = "ELPA_FORCE_" option_name, \
                }
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
85

86
#define INT_PARAMETER_ENTRY(option_name, option_description) \
87
        { \
88
89
                BASE_ENTRY(option_name, option_description, 1, 0), \
        }
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
90

91
#define BOOL_ENTRY(option_name, option_description, default) \
92
        { \
93
94
95
96
97
                BASE_ENTRY(option_name, option_description, 0, 0), \
                .default_value = default, \
                .cardinality = cardinality_bool, \
                .enumerate = enumerate_identity, \
                .valid = valid_bool, \
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
98
99
        }

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
100
#define INT_ENTRY(option_name, option_description, default, card_func, enumerate_func, valid_func, to_string_func) \
101
        { \
102
103
104
105
106
107
                BASE_ENTRY(option_name, option_description, 0, 0), \
                .default_value = default, \
                .cardinality = card_func, \
                .enumerate = enumerate_func, \
                .valid = valid_func, \
                .to_string = to_string_func, \
108
109
        }

110
#define INT_ANY_ENTRY(option_name, option_description) \
111
        { \
112
113
114
115
                BASE_ENTRY(option_name, option_description, 0, 0), \
        }

static const elpa_index_int_entry_t int_entries[] = {
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
116
117
        INT_ENTRY("na", "Global matrix has size (na * na)", 0,
                        NULL, NULL, na_is_valid, NULL),
118
119
120
121
122
123
        INT_PARAMETER_ENTRY("nev", "Number of eigenvectors to be computed, 0 <= nev <= na"),
        INT_PARAMETER_ENTRY("nblk", "Block size of scalapack block-cyclic distribution"),
        INT_PARAMETER_ENTRY("local_nrows", "Number of matrix rows stored on this process"),
        INT_PARAMETER_ENTRY("local_ncols", "Number of matrix columns stored on this process"),
        INT_PARAMETER_ENTRY("process_row", "Process row number in the 2D domain decomposition"),
        INT_PARAMETER_ENTRY("process_col", "Process column number in the 2D domain decomposition"),
Andreas Marek's avatar
Andreas Marek committed
124
        INT_ENTRY("bandwidth", "If specified, a band matrix with this bandwidth is expected as input; bandwidth must be multiply of nblk", -1,
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
125
                        NULL, NULL, bw_is_valid, NULL),
126
127
128
        INT_ANY_ENTRY("mpi_comm_rows", "Communicator for inter-row communication"),
        INT_ANY_ENTRY("mpi_comm_cols", "Communicator for inter-column communication"),
        INT_ANY_ENTRY("mpi_comm_parent", "Parent communicator"),
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
129
130
131
132
133
134
135
136
        INT_ENTRY("solver", "Solver to use", ELPA_SOLVER_1STAGE, \
                        number_of_solvers, solver_enumerate, solver_is_valid, elpa_solver_name),
        INT_ENTRY("real_kernel", "Real kernel to use if 'solver' is set to ELPA_SOLVER_2STAGE", ELPA_2STAGE_REAL_DEFAULT, \
                        number_of_real_kernels, real_kernel_enumerate, \
                        real_kernel_is_valid, real_kernel_name),
        INT_ENTRY("complex_kernel", "Complex kernel to use if 'solver' is set to ELPA_SOLVER_2STAGE", ELPA_2STAGE_COMPLEX_DEFAULT, \
                        number_of_complex_kernels, complex_kernel_enumerate, \
                        complex_kernel_is_valid, complex_kernel_name),
137
138
        BOOL_ENTRY("qr", "Use QR decomposition, only used for ELPA_SOLVER_2STAGE, real case", 0),
        BOOL_ENTRY("gpu", "Use GPU acceleration", 0),
139
        BOOL_ENTRY("timings", "Enable time measurement", 0),
140
        BOOL_ENTRY("debug", "Emit verbose debugging messages", 0),
141
        BOOL_ENTRY("print_flops", "Print FLOP rates on task 0", 0),
142
        BOOL_ENTRY("eigenvalues_only", "Only compute the eigenvalues and return", 0),
143
144
145
};

#define READONLY_DOUBLE_ENTRY(option_name, option_description) \
146
        { \
147
148
149
150
                BASE_ENTRY(option_name, option_description, 0, 1) \
        }

static const elpa_index_double_entry_t double_entries[] = {
151
        /* Empty for now */
152
};
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
153

154
void elpa_index_free(elpa_index_t index) {
155
156
157
158
159
160
161
#define FREE_OPTION(TYPE, ...) \
        free(index->TYPE##_options.values); \
        free(index->TYPE##_options.is_set); \
        free(index->TYPE##_options.notified);

        FOR_ALL_TYPES(FREE_OPTION);

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
162
163
164
165
166
        free(index);
}

static int compar(const void *key, const void *member) {
        const char *name = (const char *) key;
167
        elpa_index_int_entry_t *entry = (elpa_index_int_entry_t *) member;
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
168

169
        int l1 = strlen(entry->base.name);
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
170
171
172
173
        int l2 = strlen(name);
        if (l1 != l2) {
                return 1;
        }
174
        if (strncmp(name, entry->base.name, l1) == 0) {
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
175
176
177
178
179
180
                return 0;
        } else {
                return 1;
        }
}

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#define IMPLEMENT_FIND_ENTRY(TYPE, ...) \
        static int find_##TYPE##_entry(char *name) { \
                elpa_index_##TYPE##_entry_t *entry; \
                size_t nmembers = nelements(TYPE##_entries); \
                entry = lfind((const void*) name, (const void *) TYPE##_entries, &nmembers, sizeof(elpa_index_##TYPE##_entry_t), compar); \
                if (entry) { \
                        return (entry - &TYPE##_entries[0]); \
                } else { \
                        return -1; \
                } \
        }
FOR_ALL_TYPES(IMPLEMENT_FIND_ENTRY)


#define IMPLEMENT_GETENV(TYPE, PRINTF_SPEC, ...) \
        static int getenv_##TYPE(elpa_index_t index, const char *env_variable, enum NOTIFY_FLAGS notify_flag, int n, TYPE *value, const char *error_string) { \
                int err; \
                char *env_value = getenv(env_variable); \
                if (env_value) { \
200
                        err = elpa_##TYPE##_string_to_value(TYPE##_entries[n].base.name, env_value, value); \
201
202
203
204
205
                        if (err != ELPA_OK) { \
                                fprintf(stderr, "ELPA: Error interpreting environment variable %s with value '%s': %s\n", \
                                                TYPE##_entries[n].base.name, env_value, elpa_strerr(err)); \
                        } else {\
                                const char *value_string = NULL; \
206
                                if (elpa_##TYPE##_value_to_string(TYPE##_entries[n].base.name, *value, &value_string) == ELPA_OK) { \
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
                                        if (!(index->TYPE##_options.notified[n] & notify_flag)) { \
                                                fprintf(stderr, "ELPA: %s '%s' is set to %s due to environment variable %s\n", \
                                                                error_string, TYPE##_entries[n].base.name, value_string, env_variable); \
                                                index->TYPE##_options.notified[n] |= notify_flag; \
                                        } \
                                } else { \
                                        fprintf(stderr, "ELPA: %s '%s' is set to '" PRINTF_SPEC "' due to environment variable %s\n", \
                                                        error_string, TYPE##_entries[n].base.name, *value, env_variable);\
                                } \
                                return 1; \
                        } \
                } \
                return 0; \
        }
FOR_ALL_TYPES(IMPLEMENT_GETENV)


#define IMPLEMENT_GET_FUNCTION(TYPE, PRINTF_SPEC, ERROR_VALUE) \
        TYPE elpa_index_get_##TYPE##_value(elpa_index_t index, char *name, int *error) { \
                TYPE ret; \
227
228
229
                if (sizeof(TYPE##_entries) == 0) { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                } \
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
                int n = find_##TYPE##_entry(name); \
                if (n >= 0) { \
                        int from_env = 0; \
                        if (!TYPE##_entries[n].base.once && !TYPE##_entries[n].base.readonly) { \
                                from_env = getenv_##TYPE(index, TYPE##_entries[n].base.env_force, NOTIFY_ENV_FORCE, n, &ret, "Option"); \
                        } \
                        if (!from_env) { \
                                ret = index->TYPE##_options.values[n]; \
                        } \
                        if (error != NULL) { \
                                *error = ELPA_OK; \
                        } \
                        return ret; \
                } else { \
                        if (error != NULL) { \
                                *error = ELPA_ERROR_ENTRY_NOT_FOUND; \
                        } \
                        return ERROR_VALUE; \
                } \
        }
FOR_ALL_TYPES(IMPLEMENT_GET_FUNCTION)


#define IMPLEMENT_LOC_FUNCTION(TYPE, ...) \
        TYPE* elpa_index_get_##TYPE##_loc(elpa_index_t index, char *name) { \
255
256
257
                if (sizeof(TYPE##_entries) == 0) { \
                        return NULL; \
                } \
258
259
260
261
262
263
264
265
266
267
                int n = find_##TYPE##_entry(name); \
                if (n >= 0) { \
                        return &index->TYPE##_options.values[n]; \
                } else { \
                        return NULL; \
                } \
        }
FOR_ALL_TYPES(IMPLEMENT_LOC_FUNCTION)


268
269
#define IMPLEMENT_SET_FUNCTION(TYPE, PRINTF_SPEC, ...) \
        int elpa_index_set_##TYPE##_value(elpa_index_t index, char *name, TYPE value, int force_writable) { \
270
271
272
                if (sizeof(TYPE##_entries) == 0) { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                } \
273
274
275
276
277
278
                int n = find_##TYPE##_entry(name); \
                if (n < 0) { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                }; \
                if (TYPE##_entries[n].valid != NULL) { \
                        if(!TYPE##_entries[n].valid(index, n, value)) { \
279
                                return ELPA_ERROR_ENTRY_INVALID_VALUE; \
280
281
282
                        }; \
                } \
                if (TYPE##_entries[n].base.once & index->TYPE##_options.is_set[n]) { \
283
284
285
286
                        return ELPA_ERROR_ENTRY_ALREADY_SET; \
                } \
                if (TYPE##_entries[n].base.readonly & !force_writable) { \
                        return ELPA_ERROR_ENTRY_READONLY; \
287
288
289
290
291
292
293
294
295
296
                } \
                index->TYPE##_options.values[n] = value; \
                index->TYPE##_options.is_set[n] = 1; \
                return ELPA_OK; \
        }
FOR_ALL_TYPES(IMPLEMENT_SET_FUNCTION)


#define IMPLEMENT_IS_SET_FUNCTION(TYPE, ...) \
        int elpa_index_##TYPE##_value_is_set(elpa_index_t index, char *name) { \
297
298
299
                if (sizeof(TYPE##_entries) == 0) { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                } \
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
                int n = find_##TYPE##_entry(name); \
                if (n >= 0) { \
                        if (index->TYPE##_options.is_set[n]) { \
                                return 1; \
                        } else { \
                                return 0; \
                        } \
                } else { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                } \
        }
FOR_ALL_TYPES(IMPLEMENT_IS_SET_FUNCTION)


int elpa_index_value_is_set(elpa_index_t index, char *name) {
        int res = ELPA_ERROR;

#define RET_IF_SET(TYPE, ...) \
        res = elpa_index_##TYPE##_value_is_set(index, name); \
        if (res >= 0) { \
                return res; \
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
321
        }
322
323
324

        FOR_ALL_TYPES(RET_IF_SET)

325
        printf("ERROR: Could not find entry '%s'\n", name);
326
        return res;
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
327
328
}

329
330
331
332
333
334

int elpa_index_int_is_valid(elpa_index_t index, char *name, int new_value) {
        int n = find_int_entry(name); \
        if (n >= 0) { \
                if (int_entries[n].valid == NULL) {
                        return ELPA_OK;
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
335
                } else {
336
                        return int_entries[n].valid(index, n, new_value) ? ELPA_OK : ELPA_ERROR;
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
337
338
                }
        }
339
        return ELPA_ERROR_ENTRY_NOT_FOUND;
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
340
341
}

342
int elpa_int_value_to_string(char *name, int value, const char **string) {
343
344
345
        int n = find_int_entry(name);
        if (n < 0) {
                return ELPA_ERROR_ENTRY_NOT_FOUND;
346
        }
347
        if (int_entries[n].to_string == NULL) {
348
                return ELPA_ERROR_ENTRY_NO_STRING_REPRESENTATION;
349
350
351
        }
        *string = int_entries[n].to_string(value);
        return ELPA_OK;
352
353
}

354
355

int elpa_int_value_to_strlen(char *name, int value) {
356
        const char *string = NULL;
357
        elpa_int_value_to_string(name, value, &string);
358
        if (string == NULL) {
359
360
361
                return 0;
        } else {
                return strlen(string);
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
362
363
        }
}
364

365
366
367
368
369
370

int elpa_index_int_value_to_strlen(elpa_index_t index, char *name) {
        int n = find_int_entry(name);
        if (n < 0) {
                return 0;
        }
371
        return elpa_int_value_to_strlen(name, index->int_options.values[n]);
372
373
374
375
}


int elpa_int_string_to_value(char *name, char *string, int *value) {
376
377
378
379
380
381
382
383
384
385
        int n = find_int_entry(name);
        if (n < 0) {
                return ELPA_ERROR_ENTRY_NOT_FOUND;
        }

        if (int_entries[n].to_string == NULL) {
                int val, ret;
                ret = sscanf(string, "%d", &val);
                if (ret == strlen(string)) {
                        *value = val;
386
387
                        return ELPA_OK;
                } else {
388
                        return ELPA_ERROR_ENTRY_INVALID_VALUE;
389
390
391
392
393
394
395
396
                }
        }

        for (int i = 0; i < int_entries[n].cardinality(); i++) {
                int candidate = int_entries[n].enumerate(i);
                if (strcmp(string, int_entries[n].to_string(candidate)) == 0) {
                        *value = candidate;
                        return ELPA_OK;
397
                }
398
        }
399
        return ELPA_ERROR_ENTRY_INVALID_VALUE;
400
401
}

402
int elpa_double_string_to_value(char *name, char *string, double *value) {
403
404
405
406
407
        double val;
        int ret = sscanf(string, "%lf", &val);
        if (ret == strlen(string)) {
                *value = val;
                return ELPA_OK;
408
        } else {
409
410
                /* \todo: remove */
                fprintf(stderr, "ELPA: DEBUG: Could not parse double value '%s' for option '%s'\n", string, name);
411
                return ELPA_ERROR_ENTRY_INVALID_VALUE;
412
413
414
        }
}

415
int elpa_double_value_to_string(char *name, double value, const char **string) {
416
        return ELPA_ERROR_ENTRY_NO_STRING_REPRESENTATION;
417
}
418

419
int elpa_option_cardinality(char *name) {
420
421
422
423
424
425
        int n = find_int_entry(name);
        if (n < 0 || !int_entries[n].cardinality) {
                return ELPA_ERROR_ENTRY_NOT_FOUND;
        }
        return int_entries[n].cardinality();
}
426

427
int elpa_option_enumerate(char *name, int i) {
428
429
430
        int n = find_int_entry(name);
        if (n < 0 || !int_entries[n].enumerate) {
                return 0;
431
        }
432
        return int_entries[n].enumerate(i);
433
434
}

435

436
/* Helper functions for simple int entries */
437
438
439
static int cardinality_bool(void) {
        return 2;
}
440

441
442
static int valid_bool(elpa_index_t index, int n, int new_value) {
        return (0 <= new_value) && (new_value < 2);
443
444
}

445
static int enumerate_identity(int i) {
446
447
448
        return i;
}

449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
/* Helper functions for specific options */

#define NAME_CASE(name, value, ...) \
        case value: \
                return #name;

#define VALID_CASE(name, value) \
        case value: \
                return 1;

#define VALID_CASE_3(name, value, available) \
        case value: \
                return available;

static const char* elpa_solver_name(int solver) {
        switch(solver) {
                ELPA_FOR_ALL_SOLVERS(NAME_CASE)
                default:
                        return "(Invalid solver)";
468
469
470
        }
}

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
471
static int number_of_solvers() {
472
        return ELPA_NUMBER_OF_SOLVERS;
473
474
}

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
475
static int solver_enumerate(int i) {
476
#define OPTION_RANK(name, value, ...) \
477
        +(value >= sizeof(array_of_size_value)/sizeof(int) ? 0 : 1)
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494

#define EMPTY()
#define DEFER1(m) m EMPTY()
#define EVAL(...) __VA_ARGS__

#define ENUMERATE_CASE(name, value, ...) \
        { const int array_of_size_value[value]; \
        case 0 DEFER1(INNER_ITERATOR)()(OPTION_RANK): \
                return value; }

        switch(i) {
#define INNER_ITERATOR() ELPA_FOR_ALL_SOLVERS
                EVAL(ELPA_FOR_ALL_SOLVERS(ENUMERATE_CASE))
#undef INNER_ITERATOR
                default:
                        return 0;
        }
495
496
497
}


Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
498
static int solver_is_valid(elpa_index_t index, int n, int new_value) {
499
500
501
502
503
        switch(new_value) {
                ELPA_FOR_ALL_SOLVERS(VALID_CASE)
                default:
                        return 0;
        }
504
505
}

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
506
static int number_of_real_kernels() {
507
508
        return ELPA_2STAGE_NUMBER_OF_REAL_KERNELS;
}
509

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
510
static int real_kernel_enumerate(int i) {
511
512
513
514
515
516
517
518
        switch(i) {
#define INNER_ITERATOR() ELPA_FOR_ALL_2STAGE_REAL_KERNELS
                EVAL(ELPA_FOR_ALL_2STAGE_REAL_KERNELS(ENUMERATE_CASE))
#undef INNER_ITERATOR
                default:
                        return 0;
        }
}
519

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
520
static const char *real_kernel_name(int kernel) {
521
522
523
524
        switch(kernel) {
                ELPA_FOR_ALL_2STAGE_REAL_KERNELS(NAME_CASE)
                default:
                        return "(Invalid real kernel)";
525
        }
526
}
527

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
528
static int real_kernel_is_valid(elpa_index_t index, int n, int new_value) {
529
530
531
532
        switch(new_value) {
                ELPA_FOR_ALL_2STAGE_REAL_KERNELS(VALID_CASE_3)
                default:
                        return 0;
533
        }
534
}
535

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
536
static int number_of_complex_kernels() {
537
538
        return ELPA_2STAGE_NUMBER_OF_COMPLEX_KERNELS;
}
539

540

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
541
static int complex_kernel_enumerate(int i) {
542
543
544
545
546
547
548
549
550
        switch(i) {
#define INNER_ITERATOR() ELPA_FOR_ALL_2STAGE_COMPLEX_KERNELS
                EVAL(ELPA_FOR_ALL_2STAGE_COMPLEX_KERNELS(ENUMERATE_CASE))
#undef INNER_ITERATOR
                default:
                        return 0;
        }
}

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
551
static const char *complex_kernel_name(int kernel) {
552
553
554
555
        switch(kernel) {
                ELPA_FOR_ALL_2STAGE_COMPLEX_KERNELS(NAME_CASE)
                default:
                        return "(Invalid complex kernel)";
556
        }
557
}
558

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
559
static int complex_kernel_is_valid(elpa_index_t index, int n, int new_value) {
560
561
562
563
564
565
        switch(new_value) {
                ELPA_FOR_ALL_2STAGE_COMPLEX_KERNELS(VALID_CASE_3)
                default:
                        return 0;
        }
}
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
566
567
568
569
570
571
572
573
574
575
576
577
578
579

static int na_is_valid(elpa_index_t index, int n, int new_value) {
        return new_value > 0;
}

static int bw_is_valid(elpa_index_t index, int n, int new_value) {
        int na;
        if (elpa_index_int_value_is_set(index, "na") != 1) {
                return 0;
        }

        na = elpa_index_get_int_value(index, "na", NULL);
        return (0 <= new_value) && (new_value < na);
}
580
581

elpa_index_t elpa_index_instance() {
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
        elpa_index_t index = (elpa_index_t) calloc(1, sizeof(struct elpa_index_struct));

#define ALLOCATE(TYPE, PRINTF_SPEC, ...) \
        index->TYPE##_options.values = (TYPE*) calloc(nelements(TYPE##_entries), sizeof(TYPE)); \
        index->TYPE##_options.is_set = (int*) calloc(nelements(TYPE##_entries), sizeof(int)); \
        index->TYPE##_options.notified = (int*) calloc(nelements(TYPE##_entries), sizeof(int)); \
        for (int n = 0; n < nelements(TYPE##_entries); n++) { \
                TYPE default_value = TYPE##_entries[n].default_value; \
                if (!TYPE##_entries[n].base.once && !TYPE##_entries[n].base.readonly) { \
                        getenv_##TYPE(index, TYPE##_entries[n].base.env_default, NOTIFY_ENV_DEFAULT, n, &default_value, "Default for option"); \
                } \
                index->TYPE##_options.values[n] = default_value; \
        }

        FOR_ALL_TYPES(ALLOCATE)

        return index;
599
}
600