elpa_index.c 22.3 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
143
144
};

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

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

153
void elpa_index_free(elpa_index_t index) {
154
155
156
157
158
159
160
#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
161
162
163
164
165
        free(index);
}

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

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

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#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) { \
199
                        err = elpa_##TYPE##_string_to_value(TYPE##_entries[n].base.name, env_value, value); \
200
201
202
203
204
                        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; \
205
                                if (elpa_##TYPE##_value_to_string(TYPE##_entries[n].base.name, *value, &value_string) == ELPA_OK) { \
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
                                        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; \
226
227
228
                if (sizeof(TYPE##_entries) == 0) { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                } \
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
                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) { \
254
255
256
                if (sizeof(TYPE##_entries) == 0) { \
                        return NULL; \
                } \
257
258
259
260
261
262
263
264
265
266
                int n = find_##TYPE##_entry(name); \
                if (n >= 0) { \
                        return &index->TYPE##_options.values[n]; \
                } else { \
                        return NULL; \
                } \
        }
FOR_ALL_TYPES(IMPLEMENT_LOC_FUNCTION)


267
268
#define IMPLEMENT_SET_FUNCTION(TYPE, PRINTF_SPEC, ...) \
        int elpa_index_set_##TYPE##_value(elpa_index_t index, char *name, TYPE value, int force_writable) { \
269
270
271
                if (sizeof(TYPE##_entries) == 0) { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                } \
272
273
274
275
276
277
                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)) { \
278
                                return ELPA_ERROR_ENTRY_INVALID_VALUE; \
279
280
281
                        }; \
                } \
                if (TYPE##_entries[n].base.once & index->TYPE##_options.is_set[n]) { \
282
283
284
285
                        return ELPA_ERROR_ENTRY_ALREADY_SET; \
                } \
                if (TYPE##_entries[n].base.readonly & !force_writable) { \
                        return ELPA_ERROR_ENTRY_READONLY; \
286
287
288
289
290
291
292
293
294
295
                } \
                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) { \
296
297
298
                if (sizeof(TYPE##_entries) == 0) { \
                        return ELPA_ERROR_ENTRY_NOT_FOUND; \
                } \
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
                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
320
        }
321
322
323

        FOR_ALL_TYPES(RET_IF_SET)

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

328
329
330
331
332
333

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
334
                } else {
335
                        return int_entries[n].valid(index, n, new_value) ? ELPA_OK : ELPA_ERROR;
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
336
337
                }
        }
338
        return ELPA_ERROR_ENTRY_NOT_FOUND;
Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
339
340
}

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

353
354

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

364
365
366
367
368
369

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


int elpa_int_string_to_value(char *name, char *string, int *value) {
375
376
377
378
379
380
381
382
383
384
        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;
385
386
                        return ELPA_OK;
                } else {
387
                        return ELPA_ERROR_ENTRY_INVALID_VALUE;
388
389
390
391
392
393
394
395
                }
        }

        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;
396
                }
397
        }
398
        return ELPA_ERROR_ENTRY_INVALID_VALUE;
399
400
}

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

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

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

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

434

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

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

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

448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
/* 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)";
467
468
469
        }
}

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

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

#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;
        }
494
495
496
}


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

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

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
509
static int real_kernel_enumerate(int i) {
510
511
512
513
514
515
516
517
        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;
        }
}
518

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

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

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

539

Lorenz Huedepohl's avatar
Lorenz Huedepohl committed
540
static int complex_kernel_enumerate(int i) {
541
542
543
544
545
546
547
548
549
        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
550
static const char *complex_kernel_name(int kernel) {
551
552
553
554
        switch(kernel) {
                ELPA_FOR_ALL_2STAGE_COMPLEX_KERNELS(NAME_CASE)
                default:
                        return "(Invalid complex kernel)";
555
        }
556
}
557

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

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);
}
579
580

elpa_index_t elpa_index_instance() {
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
        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;
598
}
599