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.
Files changed (34) hide show
  1. {piegy-2.3.5/src/piegy.egg-info → piegy-2.3.6}/PKG-INFO +1 -1
  2. {piegy-2.3.5 → piegy-2.3.6}/pyproject.toml +1 -1
  3. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/Makefile +0 -1
  4. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/runner.c +1 -1
  5. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/sim_funcs.c +52 -45
  6. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/sim_funcs.h +8 -6
  7. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/__version__.py +2 -1
  8. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/simulation.py +9 -4
  9. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/test_var.py +4 -4
  10. {piegy-2.3.5 → piegy-2.3.6/src/piegy.egg-info}/PKG-INFO +1 -1
  11. {piegy-2.3.5 → piegy-2.3.6}/LICENSE.txt +0 -0
  12. {piegy-2.3.5 → piegy-2.3.6}/MANIFEST.in +0 -0
  13. {piegy-2.3.5 → piegy-2.3.6}/README.md +0 -0
  14. {piegy-2.3.5 → piegy-2.3.6}/setup.cfg +0 -0
  15. {piegy-2.3.5 → piegy-2.3.6}/setup.py +0 -0
  16. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/model.c +0 -0
  17. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/model.h +0 -0
  18. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/patch.c +0 -0
  19. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/C_core/patch.h +0 -0
  20. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/__init__.py +0 -0
  21. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/analysis.py +0 -0
  22. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/build_info.py +0 -0
  23. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/data_tools.py +0 -0
  24. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/figures.py +0 -0
  25. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/simulation_py.py +0 -0
  26. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/__init__.py +0 -0
  27. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/figure_tools.py +0 -0
  28. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/file_tools.py +0 -0
  29. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/tools/find_C.py +0 -0
  30. {piegy-2.3.5 → piegy-2.3.6}/src/piegy/videos.py +0 -0
  31. {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/SOURCES.txt +0 -0
  32. {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/dependency_links.txt +0 -0
  33. {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/requires.txt +0 -0
  34. {piegy-2.3.5 → piegy-2.3.6}/src/piegy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: piegy
3
- Version: 2.3.5
3
+ Version: 2.3.6
4
4
  Summary: Payoff-Driven Stochastic Spatial Model for Evolutionary Game Theory
5
5
  Author-email: Chenning Xu <cxu7@caltech.edu>
6
6
  License: BSD 3-Clause License
@@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'
4
4
 
5
5
  [project]
6
6
  name = 'piegy'
7
- version = '2.3.5'
7
+ version = '2.3.6'
8
8
  description = 'Payoff-Driven Stochastic Spatial Model for Evolutionary Game Theory'
9
9
  readme = 'README.md'
10
10
  requires-python = '>=3.7'
@@ -4,7 +4,6 @@ CC = gcc
4
4
  #### Common Flags ####
5
5
 
6
6
  ## Flags for Max Speed ##
7
- # standard
8
7
  CFLAGS_COMMON = -O3 -march=native -flto -std=c99 -DNDEBUG -ffp-contract=fast -funroll-loops -fomit-frame-pointer -MMD -MP
9
8
  LDFLAGS_COMMON = -flto
10
9
 
@@ -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, 100, 100, 0.001, 0.001};
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, signal_t* sig_p, patch_picked_t* picked_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 time to reduce numerical errors
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 update_sum_freq = UPDATE_SUM_FREQ_SM; // the frequency really using, change based on how large values are encountered
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 > update_sum_freq) {
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
- for (size_t i = 0; i < N; i++) {
273
- for (size_t j = 0; j < M; j++) {
274
- double sum_U_weight = 0;
275
- double sum_V_weight = 0;
276
- for (size_t k = 0; k < 4; k++) {
277
- sum_U_weight += world[ij].U_weight[k];
278
- sum_V_weight += world[ij].V_weight[k];
279
- }
280
- world[ij].sum_U_weight = sum_U_weight;
281
- world[ij].sum_V_weight = sum_V_weight;
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
- for (size_t i = 0; i < N; i++) {
429
- for (size_t j = 0; j < M; j++) {
430
- for (size_t k = record_index; k < upper; k++) {
431
- mod->U1d[ij * max_record + k] += world[ij].U;
432
- mod->V1d[ij * max_record + k] += world[ij].V;
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
- for (size_t i = 0; i < N; i++) {
446
- for (size_t j = 0; j < M; j++) {
447
- for (size_t k = record_index; k < max_record; k++) {
448
- mod->U1d[ij * max_record + k] += world[ij].U;
449
- mod->V1d[ij * max_record + k] += world[ij].V;
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) because the large numbers will be computed with close-to-0 ones (payoff rates), so higher accuracy is needed
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 UPDATE_SUM_FREQ_SM 100
46
- #define UPDATE_SUM_FREQ_LG 10000
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* sum_rates, signal_t* sig_p, patch_picked_t* picked_p) ;
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.4'
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 = 88 # where exp(x) reaches 1e34
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 encounter large values > 3e38 in simulation. \n\t w1, w2, or payoff matrix values too large")
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 OverflowError, skipped')
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 OverflowError, skipped')
142
+ except (OverflowError, RuntimeError):
143
+ print(current_var_str + ' raised error, skipped')
144
144
  continue
145
145
 
146
146
  return var_dirs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: piegy
3
- Version: 2.3.5
3
+ Version: 2.3.6
4
4
  Summary: Payoff-Driven Stochastic Spatial Model for Evolutionary Game Theory
5
5
  Author-email: Chenning Xu <cxu7@caltech.edu>
6
6
  License: BSD 3-Clause License
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