piegy 2.3.5__tar.gz → 2.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {piegy-2.3.5/src/piegy.egg-info → piegy-2.3.6}/PKG-INFO +1 -1
- {piegy-2.3.5 → piegy-2.3.6}/pyproject.toml +1 -1
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/Makefile +0 -1
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/runner.c +1 -1
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/sim_funcs.c +52 -45
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/sim_funcs.h +8 -6
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/__version__.py +2 -1
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/simulation.py +9 -4
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/test_var.py +4 -4
- {piegy-2.3.5 → piegy-2.3.6/src/piegy.egg-info}/PKG-INFO +1 -1
- {piegy-2.3.5 → piegy-2.3.6}/LICENSE.txt +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/MANIFEST.in +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/README.md +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/setup.cfg +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/setup.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/model.c +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/model.h +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/patch.c +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/patch.h +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/__init__.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/analysis.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/build_info.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/data_tools.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/figures.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/simulation_py.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/__init__.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/figure_tools.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/file_tools.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/find_C.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy/videos.py +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/SOURCES.txt +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/dependency_links.txt +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/requires.txt +0 -0
- {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/top_level.txt +0 -0
@@ -17,7 +17,7 @@ int main() {
|
|
17
17
|
bool boundary = true;
|
18
18
|
uint32_t I_single[2] = {3, 3};
|
19
19
|
double X_single[4] = {-1, 4, 0, 2};
|
20
|
-
double P_single[6] = {0.5, 0.5,
|
20
|
+
double P_single[6] = {0.5, 0.5, 80, 80, 0.001, 0.001};
|
21
21
|
int32_t print_pct = 1;
|
22
22
|
int32_t seed = 36; // -1 for None
|
23
23
|
|
@@ -68,8 +68,9 @@ static void find_nb_periodical(size_t* restrict nb, size_t i, size_t j, size_t N
|
|
68
68
|
|
69
69
|
|
70
70
|
// single_init function: initializes world, runs 1 event, returns updated variables
|
71
|
-
static double single_init(const model_t* mod, patch_t* world, size_t* nb_indices,
|
72
|
-
double* patch_rates, double* sum_rates_by_row, double* sum_rates_p,
|
71
|
+
static double single_init(const model_t* restrict mod, patch_t* restrict world, size_t* restrict nb_indices,
|
72
|
+
double* restrict patch_rates, double* restrict sum_rates_by_row, double* restrict sum_rates_p,
|
73
|
+
signal_t* restrict sig_p, patch_picked_t* restrict picked_p) {
|
73
74
|
|
74
75
|
size_t N = mod->N;
|
75
76
|
size_t M = mod->M;
|
@@ -145,6 +146,9 @@ static double single_init(const model_t* mod, patch_t* world, size_t* nb_indices
|
|
145
146
|
find_patch(picked_p, expected_sum, patch_rates, sum_rates_by_row, *sum_rates_p, N, M);
|
146
147
|
size_t picked_idx = picked_p->i * M + picked_p->j;
|
147
148
|
size_t e0 = find_event(&world[picked_idx], expected_sum - picked_p->current_sum);
|
149
|
+
if (picked_idx >= NM || e0 >= 12) {
|
150
|
+
return -1 * ACCURACY_ERROR;
|
151
|
+
}
|
148
152
|
|
149
153
|
// make signal
|
150
154
|
if (mod->boundary) {
|
@@ -215,9 +219,9 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
215
219
|
|
216
220
|
// update sum of rates every 1e5 rounds
|
217
221
|
// many rates are updated each time, rather than re-calculated.
|
218
|
-
// So need to re-calculate from scratch every some
|
222
|
+
// So need to re-calculate from scratch every some rounds to reduce numerical errors
|
219
223
|
size_t curr_update_sum_round = 0; // current round
|
220
|
-
size_t
|
224
|
+
size_t update_sum_rounds = UPDATE_SUM_ROUNDS_SM; // recalculate sum every this many rounds
|
221
225
|
|
222
226
|
// Initialize simulation
|
223
227
|
patch_t* world = (patch_t*) calloc(NM, sizeof(patch_t));
|
@@ -242,7 +246,12 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
242
246
|
fflush(stdout);
|
243
247
|
single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
|
244
248
|
return SIM_OVERFLOW;
|
245
|
-
}
|
249
|
+
} else if (time == -1 * ACCURACY_ERROR) {
|
250
|
+
fprintf(stdout, "\nError: accuracy too low at t = 0, simulation stopped\n");
|
251
|
+
fflush(stdout);
|
252
|
+
single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
|
253
|
+
return ACCURACY_ERROR;
|
254
|
+
}
|
246
255
|
size_t record_index = time / mod->record_itv;
|
247
256
|
double record_time = time - record_index * record_itv;
|
248
257
|
|
@@ -264,29 +273,25 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
264
273
|
|
265
274
|
// update sums
|
266
275
|
curr_update_sum_round++;
|
267
|
-
if (curr_update_sum_round >
|
276
|
+
if (curr_update_sum_round > update_sum_rounds) {
|
268
277
|
curr_update_sum_round = 0;
|
269
|
-
update_sum_freq = UPDATE_SUM_FREQ_LG; // assume can make it larger
|
270
|
-
size_t ij = 0;
|
271
278
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
// patch_rates are updated every time a patch is changed
|
283
|
-
if (sum_U_weight > ACCURATE_BOUND) {
|
284
|
-
update_sum_freq = UPDATE_SUM_FREQ_SM; // values too large, put back the small update frequency
|
285
|
-
}
|
286
|
-
ij++;
|
279
|
+
update_sum_rounds = UPDATE_SUM_ROUNDS_LG; // assume can make it larger
|
280
|
+
for (size_t ij = 0; ij < NM; ij++) {
|
281
|
+
double sum_U_weight = 0;
|
282
|
+
double sum_V_weight = 0;
|
283
|
+
for (size_t k = 0; k < 4; k++) {
|
284
|
+
sum_U_weight += world[ij].U_weight[k];
|
285
|
+
sum_V_weight += world[ij].V_weight[k];
|
286
|
+
}
|
287
|
+
if (sum_U_weight > ACCURATE_BOUND || sum_V_weight > ACCURATE_BOUND) {
|
288
|
+
update_sum_rounds = UPDATE_SUM_ROUNDS_SM; // values too large, put back the small update frequency
|
287
289
|
}
|
290
|
+
world[ij].sum_U_weight = sum_U_weight;
|
291
|
+
world[ij].sum_V_weight = sum_V_weight;
|
292
|
+
// patch_rates are updated every time a patch is changed
|
288
293
|
}
|
289
|
-
ij = 0;
|
294
|
+
size_t ij = 0;
|
290
295
|
sum_rates = 0;
|
291
296
|
for (size_t i = 0; i < N; i++) {
|
292
297
|
double sum_rates_by_row_i = 0;
|
@@ -307,6 +312,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
307
312
|
size_t sij1 = signal.ij1;
|
308
313
|
size_t sij2 = signal.ij2;
|
309
314
|
uint8_t rela_loc = signal.rela_loc;
|
315
|
+
|
310
316
|
if (rela_loc == NO_MIG) {
|
311
317
|
// if only one
|
312
318
|
sum_rates_by_row[si1] -= patch_rates[sij1];
|
@@ -396,6 +402,12 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
396
402
|
find_patch(&picked, expected_sum, patch_rates, sum_rates_by_row, sum_rates, N, M);
|
397
403
|
size_t picked_idx = picked.i * M + picked.j;
|
398
404
|
uint8_t e0 = find_event(&world[picked_idx], expected_sum - picked.current_sum);
|
405
|
+
if (picked_idx >= NM || e0 >= 12) {
|
406
|
+
fprintf(stdout, "\nError: accuracy too low at t = %f, simulation stopped\n", time);
|
407
|
+
fflush(stdout);
|
408
|
+
single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
|
409
|
+
return ACCURACY_ERROR;
|
410
|
+
}
|
399
411
|
|
400
412
|
// make signal
|
401
413
|
if (boundary) {
|
@@ -424,16 +436,12 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
424
436
|
record_time -= multi_records * record_itv;
|
425
437
|
size_t upper = record_index + multi_records;
|
426
438
|
|
427
|
-
size_t ij = 0;
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
|
434
|
-
mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
|
435
|
-
}
|
436
|
-
ij++;
|
439
|
+
for (size_t ij = 0; ij < NM; ij++) {
|
440
|
+
for (size_t k = record_index; k < upper; k++) {
|
441
|
+
mod->U1d[ij * max_record + k] += world[ij].U;
|
442
|
+
mod->V1d[ij * max_record + k] += world[ij].V;
|
443
|
+
mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
|
444
|
+
mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
|
437
445
|
}
|
438
446
|
}
|
439
447
|
record_index += multi_records;
|
@@ -441,16 +449,12 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
|
|
441
449
|
|
442
450
|
} else {
|
443
451
|
// if already exceeds maxtime
|
444
|
-
size_t ij = 0;
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
|
451
|
-
mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
|
452
|
-
}
|
453
|
-
ij++;
|
452
|
+
for (size_t ij = 0; ij < NM; ij++) {
|
453
|
+
for (size_t k = record_index; k < max_record; k++) {
|
454
|
+
mod->U1d[ij * max_record + k] += world[ij].U;
|
455
|
+
mod->V1d[ij * max_record + k] += world[ij].V;
|
456
|
+
mod->Upi_1d[ij * max_record + k] += world[ij].U_pi;
|
457
|
+
mod->Vpi_1d[ij * max_record + k] += world[ij].V_pi;
|
454
458
|
}
|
455
459
|
}
|
456
460
|
}
|
@@ -483,7 +487,7 @@ static void single_test_free(patch_t** world, size_t** nb_indices, double** patc
|
|
483
487
|
|
484
488
|
|
485
489
|
|
486
|
-
uint8_t run(model_t* mod, char* message, size_t msg_len) {
|
490
|
+
uint8_t run(model_t* restrict mod, char* message, size_t msg_len) {
|
487
491
|
if (!mod->data_empty) {
|
488
492
|
// this won't happen if called from python, the ``simulation.run`` caller has checked it.
|
489
493
|
fprintf(stdout, "Error: mod has non-empty data\n");
|
@@ -538,6 +542,9 @@ uint8_t run(model_t* mod, char* message, size_t msg_len) {
|
|
538
542
|
case SIM_OVERFLOW:
|
539
543
|
// error message is handled by single_test
|
540
544
|
return SIM_OVERFLOW;
|
545
|
+
case ACCURACY_ERROR:
|
546
|
+
// error message is handled by single_test
|
547
|
+
return ACCURACY_ERROR;
|
541
548
|
}
|
542
549
|
}
|
543
550
|
|
@@ -35,15 +35,16 @@
|
|
35
35
|
#define DATA_NOT_EMPTY 1
|
36
36
|
#define SMALL_MAXTIME 2
|
37
37
|
#define SIM_OVERFLOW 3
|
38
|
+
#define ACCURACY_ERROR 4
|
38
39
|
|
39
40
|
// where exp(x) is considered overflow
|
40
|
-
// below the actual bound (709)
|
41
|
+
// below the actual bound (709) to preserve accuracy
|
41
42
|
#define EXP_OVERFLOW_BOUND 500
|
42
43
|
#define ACCURATE_BOUND 10000000000LL
|
43
44
|
|
44
45
|
// how frequent to update rates & sum of rates in single test (recalculate)
|
45
|
-
#define
|
46
|
-
#define
|
46
|
+
#define UPDATE_SUM_ROUNDS_SM 100
|
47
|
+
#define UPDATE_SUM_ROUNDS_LG 10000
|
47
48
|
|
48
49
|
|
49
50
|
static uint64_t pcg_state = 0;
|
@@ -90,11 +91,12 @@ typedef struct signal_t {
|
|
90
91
|
*/
|
91
92
|
static void find_nb_zero_flux(size_t* restrict nb, size_t i, size_t j, size_t N, size_t M, size_t NM);
|
92
93
|
static void find_nb_periodical(size_t* restrict nb, size_t i, size_t j, size_t N, size_t M, size_t NM);
|
93
|
-
static double single_init(const model_t* mod, patch_t* world, size_t* nb_indices,
|
94
|
-
double* patch_rates, double* sum_rates_by_row, double*
|
94
|
+
static double single_init(const model_t* restrict mod, patch_t* restrict world, size_t* restrict nb_indices,
|
95
|
+
double* restrict patch_rates, double* restrict sum_rates_by_row, double* restrict sum_rates_p,
|
96
|
+
signal_t* restrict sig_p, patch_picked_t* restrict picked_p);
|
95
97
|
static uint8_t single_test(model_t* restrict mod, char* message);
|
96
98
|
static void single_test_free(patch_t** world, size_t** nb_indices, double** patch_rates, double** sum_rates_by_row);
|
97
|
-
uint8_t run(model_t* mod, char* message, size_t msg_len);
|
99
|
+
uint8_t run(model_t* restrict mod, char* message, size_t msg_len);
|
98
100
|
|
99
101
|
|
100
102
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
__version__ = '2.3.
|
1
|
+
__version__ = '2.3.6'
|
2
2
|
|
3
3
|
'''
|
4
4
|
version history:
|
@@ -42,4 +42,5 @@ version history:
|
|
42
42
|
2.3.3: fix error in calculation of migration rates.
|
43
43
|
2.3.4: change back to the mig & payoff rules in version 2.3.2
|
44
44
|
2.3.5: improved accuracy for simulation, now can better handle large mig rates. Numerical errors are now being checked and reduced automatically based on how large the values are.
|
45
|
+
2.3.6: index error due to reduced accuracy is now explicitly handled.
|
45
46
|
'''
|
@@ -25,7 +25,7 @@ from numpy.ctypeslib import ndpointer
|
|
25
25
|
# check whether overflow / too large values might be encountered
|
26
26
|
# these values are considered as exponents in exp()
|
27
27
|
EXP_OVERFLOW_BOUND = 709 # where exp(x) almost reaches overflow bound
|
28
|
-
EXP_TOO_LARGE_BOUND =
|
28
|
+
EXP_TOO_LARGE_BOUND = 30 # where exp(x) reaches ~10e13 and accuracy goes below 10^-3 (10^-3 isn't accurate any more)
|
29
29
|
|
30
30
|
|
31
31
|
# read the C core into LIB
|
@@ -36,6 +36,7 @@ SIM_SUCCESS = 0
|
|
36
36
|
SIM_DATA_EMPTY = 1
|
37
37
|
SIM_SMALL_MAXTIME = 2
|
38
38
|
SIM_OVERFLOW = 3
|
39
|
+
ACCURACY_ERROR = 4
|
39
40
|
|
40
41
|
|
41
42
|
'''
|
@@ -449,7 +450,11 @@ def run(mod, message = ""):
|
|
449
450
|
elif result == SIM_OVERFLOW:
|
450
451
|
LIB.mod_free_py(ctypes.byref(mod_c))
|
451
452
|
del mod_c
|
452
|
-
raise OverflowError('Overflow in simulation')
|
453
|
+
raise OverflowError('Overflow in simulation. Possibly due to too large w1, w2, or payoff matrix values.')
|
454
|
+
elif result == ACCURACY_ERROR:
|
455
|
+
LIB.mod_free_py(ctypes.byref(mod_c))
|
456
|
+
del mod_c
|
457
|
+
raise RuntimeError('Accuracy dropped catastrophically during simulation. Possibly due to too large w1, w2, or payoff matrix values.')
|
453
458
|
else:
|
454
459
|
LIB.mod_free_py(ctypes.byref(mod_c))
|
455
460
|
del mod_c
|
@@ -524,9 +529,9 @@ def check_overflow_func(mod):
|
|
524
529
|
w1_pi = pi_expected[i][j] * mod.P[i][j][2] # w1 * U_pi
|
525
530
|
w2_pi = pi_expected[i][j] * mod.P[i][j][3] # w2 * V_pi
|
526
531
|
if ((w1_pi > EXP_OVERFLOW_BOUND) or (w2_pi > EXP_OVERFLOW_BOUND)):
|
527
|
-
print("Warning: might cause overflow. \n\t w1, w2, or payoff matrix values too large")
|
532
|
+
print("Warning: might cause overflow in simulation. \n\t w1, w2, or payoff matrix values too large")
|
528
533
|
return
|
529
534
|
if ((w1_pi > EXP_TOO_LARGE_BOUND) or (w2_pi > EXP_TOO_LARGE_BOUND)):
|
530
|
-
print("Warning: might
|
535
|
+
print("Warning: might have low accuracy in simulation. \n\t w1, w2, or payoff matrix values too large")
|
531
536
|
return
|
532
537
|
|
@@ -92,8 +92,8 @@ def test_var1(mod, var, values, dirs, compress_itv = None):
|
|
92
92
|
if compress_itv != None:
|
93
93
|
sim2.compress_data(compress_itv)
|
94
94
|
data_t.save_data(sim2, var_dirs[k], print_msg = False)
|
95
|
-
except OverflowError:
|
96
|
-
print(current_var_str + ' raised
|
95
|
+
except (OverflowError, RuntimeError):
|
96
|
+
print(current_var_str + ' raised error, skipped')
|
97
97
|
continue
|
98
98
|
|
99
99
|
return var_dirs
|
@@ -139,8 +139,8 @@ def test_var2(mod, var1, var2, values1, values2, dirs, compress_itv = None):
|
|
139
139
|
if compress_itv != None:
|
140
140
|
sim2.compress_data(compress_itv)
|
141
141
|
data_t.save_data(sim2, var_dirs[k1][k2], print_msg = False)
|
142
|
-
except OverflowError:
|
143
|
-
print(current_var_str + ' raised
|
142
|
+
except (OverflowError, RuntimeError):
|
143
|
+
print(current_var_str + ' raised error, skipped')
|
144
144
|
continue
|
145
145
|
|
146
146
|
return var_dirs
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|