piegy 2.3.1__tar.gz → 2.3.3__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.1/src/piegy.egg-info → piegy-2.3.3}/PKG-INFO +1 -1
  2. {piegy-2.3.1 → piegy-2.3.3}/pyproject.toml +1 -1
  3. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/Makefile +1 -1
  4. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/runner.c +5 -5
  5. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/sim_funcs.c +30 -45
  6. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/sim_funcs.h +108 -81
  7. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/__version__.py +4 -1
  8. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/figures.py +6 -6
  9. {piegy-2.3.1 → piegy-2.3.3/src/piegy.egg-info}/PKG-INFO +1 -1
  10. {piegy-2.3.1 → piegy-2.3.3}/LICENSE.txt +0 -0
  11. {piegy-2.3.1 → piegy-2.3.3}/MANIFEST.in +0 -0
  12. {piegy-2.3.1 → piegy-2.3.3}/README.md +0 -0
  13. {piegy-2.3.1 → piegy-2.3.3}/setup.cfg +0 -0
  14. {piegy-2.3.1 → piegy-2.3.3}/setup.py +0 -0
  15. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/model.c +0 -0
  16. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/model.h +0 -0
  17. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/patch.c +0 -0
  18. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/C_core/patch.h +0 -0
  19. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/__init__.py +0 -0
  20. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/analysis.py +0 -0
  21. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/build_info.py +0 -0
  22. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/data_tools.py +0 -0
  23. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/simulation.py +0 -0
  24. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/simulation_py.py +0 -0
  25. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/test_var.py +0 -0
  26. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/tools/__init__.py +0 -0
  27. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/tools/figure_tools.py +0 -0
  28. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/tools/file_tools.py +0 -0
  29. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/tools/find_C.py +0 -0
  30. {piegy-2.3.1 → piegy-2.3.3}/src/piegy/videos.py +0 -0
  31. {piegy-2.3.1 → piegy-2.3.3}/src/piegy.egg-info/SOURCES.txt +0 -0
  32. {piegy-2.3.1 → piegy-2.3.3}/src/piegy.egg-info/dependency_links.txt +0 -0
  33. {piegy-2.3.1 → piegy-2.3.3}/src/piegy.egg-info/requires.txt +0 -0
  34. {piegy-2.3.1 → piegy-2.3.3}/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.1
3
+ Version: 2.3.3
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.1'
7
+ version = '2.3.3'
8
8
  description = 'Payoff-Driven Stochastic Spatial Model for Evolutionary Game Theory'
9
9
  readme = 'README.md'
10
10
  requires-python = '>=3.7'
@@ -5,7 +5,7 @@ CC = gcc
5
5
 
6
6
  ## Flags for Max Speed ##
7
7
  # standard
8
- CFLAGS_COMMON = -O3 -flto -std=c99 -DNDEBUG -ffp-contract=fast -MMD -MP
8
+ CFLAGS_COMMON = -O3 -march=native -flto -std=c99 -DNDEBUG -ffp-contract=fast -funroll-loops -fomit-frame-pointer -MMD -MP
9
9
  LDFLAGS_COMMON = -flto
10
10
 
11
11
  ## Flags for Debugging ##
@@ -11,14 +11,14 @@
11
11
  int main() {
12
12
  size_t N = 1;
13
13
  size_t M = 100;
14
- double maxtime = 200;
14
+ double maxtime = 600;
15
15
  double record_itv = 0.1;
16
- size_t sim_time = 200;
16
+ size_t sim_time = 1;
17
17
  bool boundary = true;
18
- uint32_t I_single[2] = {200, 100};
18
+ uint32_t I_single[2] = {440, 220};
19
19
  double X_single[4] = {-1, 4, 0, 2};
20
- double P_single[6] = {0.5, 0.5, 50, 294, 0.001, 0.001};
21
- int32_t print_pct = 25;
20
+ double P_single[6] = {0.5, 0.5, 100, 100, 0.001, 0.001};
21
+ int32_t print_pct = 1;
22
22
  int32_t seed = 36; // -1 for None
23
23
 
24
24
  uint32_t I[N * M * 2];
@@ -128,7 +128,7 @@ static double single_init(const model_t* mod, patch_t* world, size_t* nb_indices
128
128
  ij = 0;
129
129
  for (size_t i = 0; i < N; i++) {
130
130
  for (size_t j = 0; j < M; j++) {
131
- uint8_t mig_result = update_mig_all(&world[ij], &(mod->P[ij * 6])); // init mig rates for all 4 directions
131
+ uint8_t mig_result = init_mig(&world[ij], &(mod->P[ij * 6])); // init mig rates for all 4 directions
132
132
  if (mig_result == SIM_OVERFLOW) {
133
133
  return -1 * SIM_OVERFLOW;
134
134
  }
@@ -157,7 +157,7 @@ static double single_init(const model_t* mod, patch_t* world, size_t* nb_indices
157
157
 
158
158
  // update patch based on signal
159
159
  change_popu(&world[sig_p->ij1], sig_p->e1);
160
- if (!sig_p->only_first) {
160
+ if (sig_p->rela_loc != NO_MIG) {
161
161
  change_popu(&world[sig_p->ij2], sig_p->e2);
162
162
  }
163
163
 
@@ -300,71 +300,58 @@ static uint8_t single_test(model_t* restrict mod, uint32_t update_sum_freq, char
300
300
  size_t si2 = signal.i2;
301
301
  size_t sij1 = signal.ij1;
302
302
  size_t sij2 = signal.ij2;
303
- bool only_first = signal.only_first;
304
- if (only_first) {
303
+ uint8_t rela_loc = signal.rela_loc;
304
+ if (rela_loc == NO_MIG) {
305
305
  // if only one
306
- double picked_rate = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
307
- sum_rates_by_row[si1] -= picked_rate;
308
- sum_rates -= picked_rate;
306
+ sum_rates_by_row[si1] -= patch_rates[sij1];
307
+ sum_rates -= patch_rates[sij1];
309
308
 
310
309
  update_pi_k(&world[sij1], &(mod->X[sij1 * 4]), &(mod->P[sij1 * 6]));
311
- uint8_t mig_result = update_mig_all(&world[sij1], &(mod->P[sij1 * 6]));
312
- if (mig_result == SIM_OVERFLOW) {
313
- fprintf(stdout, "\nError: overflow at t = %f\n", time);
314
- fflush(stdout);
315
- single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
316
- return SIM_OVERFLOW;
317
- }
310
+ init_mig(&world[sij1], &(mod->P[sij1 * 6]));
318
311
 
319
- picked_rate = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
320
- patch_rates[sij1] = picked_rate;
321
- sum_rates_by_row[si1] += picked_rate;
322
- sum_rates += picked_rate;
312
+ patch_rates[sij1] = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
313
+ sum_rates_by_row[si1] += patch_rates[sij1];
314
+ sum_rates += patch_rates[sij1];
323
315
  } else {
324
316
  // two
325
- double picked_rate1 = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
326
- double picked_rate2 = world[sij2].sum_pi_death_rates + world[sij2].sum_mig_rates;
327
- sum_rates_by_row[si1] -= picked_rate1;
328
- sum_rates_by_row[si2] -= picked_rate2;
329
- sum_rates -= picked_rate1;
330
- sum_rates -= picked_rate2;
317
+ sum_rates_by_row[si1] -= patch_rates[sij1];
318
+ sum_rates_by_row[si2] -= patch_rates[sij2];
319
+ sum_rates -= patch_rates[sij1];
320
+ sum_rates -= patch_rates[sij2];
331
321
 
332
322
  update_pi_k(&world[sij1], &(mod->X[sij1 * 4]), &(mod->P[sij1 * 6])); // update both patches' payoffs first
333
323
  update_pi_k(&world[sij2], &(mod->X[sij2 * 4]), &(mod->P[sij2 * 6]));
334
- uint8_t mig_result1 = update_mig_all(&world[sij1], &(mod->P[sij1 * 6])); // and then mig rates
335
- uint8_t mig_result2 = update_mig_all(&world[sij2], &(mod->P[sij2 * 6]));
336
- if (mig_result1 == SIM_OVERFLOW || mig_result2 == SIM_OVERFLOW) {
324
+
325
+ if (update_mig_weight_rate(&world[sij1], &(mod->P[sij1 * 6]), rela_loc) == SIM_OVERFLOW ||
326
+ update_mig_weight_rate(&world[sij2], &(mod->P[sij2 * 6]), rela_loc ^ 1) == SIM_OVERFLOW) {
327
+
337
328
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
338
329
  fflush(stdout);
339
330
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
340
331
  return SIM_OVERFLOW;
341
332
  }
342
333
 
343
- picked_rate1 = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
344
- picked_rate2 = world[sij2].sum_pi_death_rates + world[sij2].sum_mig_rates;
345
-
346
- patch_rates[sij1] = picked_rate1;
347
- patch_rates[sij2] = picked_rate2;
348
- sum_rates_by_row[si1] += picked_rate1;
349
- sum_rates_by_row[si2] += picked_rate2;
350
- sum_rates += picked_rate1;
351
- sum_rates += picked_rate2;
334
+ patch_rates[sij1] = world[sij1].sum_pi_death_rates + world[sij1].sum_mig_rates;
335
+ patch_rates[sij2] = world[sij2].sum_pi_death_rates + world[sij2].sum_mig_rates;
336
+ sum_rates_by_row[si1] += patch_rates[sij1];
337
+ sum_rates_by_row[si2] += patch_rates[sij2];
338
+ sum_rates += patch_rates[sij1];
339
+ sum_rates += patch_rates[sij2];
352
340
  }
353
341
 
354
342
  // update neighbors of last-changed patches
355
- if (only_first) {
343
+ if (rela_loc == NO_MIG) {
356
344
  for (uint8_t k = 0; k < 4; k++) {
357
345
  size_t nb_idx = nb_indices[sij1 * 4 + k];
358
346
  if (nb_idx == NM) { continue; } // invalid neighbor
359
347
  // all neighbors, as long as exists, need to change
360
- uint8_t mig_result = update_mig_one(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1);
361
- if (mig_result == SIM_OVERFLOW) {
348
+ if (update_mig_weight_rate(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1) == SIM_OVERFLOW) {
362
349
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
363
350
  fflush(stdout);
364
351
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
365
352
  return SIM_OVERFLOW;
366
353
  }
367
- // sum_mig_rate is not changed
354
+ // patch_rates, and sums of rates is not changed
368
355
  }
369
356
  } else {
370
357
  // the first patch
@@ -372,8 +359,7 @@ static uint8_t single_test(model_t* restrict mod, uint32_t update_sum_freq, char
372
359
  size_t nb_idx = nb_indices[sij1 * 4 + k];
373
360
  if (nb_idx == NM) { continue; }
374
361
  if (nb_need_change(nb_idx, sij1, sij2)) {
375
- uint8_t mig_result = update_mig_one(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1);
376
- if (mig_result == SIM_OVERFLOW) {
362
+ if (update_mig_weight_rate(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1) == SIM_OVERFLOW) {
377
363
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
378
364
  fflush(stdout);
379
365
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
@@ -386,8 +372,7 @@ static uint8_t single_test(model_t* restrict mod, uint32_t update_sum_freq, char
386
372
  size_t nb_idx = nb_indices[sij2 * 4 + k];
387
373
  if (nb_idx == NM) { continue; }
388
374
  if (nb_need_change(nb_idx, sij1, sij2)) {
389
- uint8_t mig_result = update_mig_one(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1);
390
- if (mig_result == SIM_OVERFLOW) {
375
+ if (update_mig_weight_rate(&world[nb_idx], &(mod->P[nb_idx * 6]), k ^ 1) == SIM_OVERFLOW) {
391
376
  fprintf(stdout, "\nError: overflow at t = %f\n", time);
392
377
  fflush(stdout);
393
378
  single_test_free(&world, &nb_indices, &patch_rates, &sum_rates_by_row);
@@ -415,7 +400,7 @@ static uint8_t single_test(model_t* restrict mod, uint32_t update_sum_freq, char
415
400
 
416
401
  // let the event happenn
417
402
  change_popu(&world[signal.ij1], signal.e1);
418
- if (!signal.only_first) {
403
+ if (signal.rela_loc != NO_MIG) {
419
404
  change_popu(&world[signal.ij2], signal.e2);
420
405
  }
421
406
 
@@ -28,14 +28,15 @@
28
28
  #define MIG_DOWN 1
29
29
  #define MIG_LEFT 2
30
30
  #define MIG_RIGHT 3
31
+ #define NO_MIG 4
31
32
 
32
33
  // results of single_test
33
34
  #define SUCCESS 0
34
35
  #define DATA_NOT_EMPTY 1
35
- #define SMALL_MAXTIME 2 // must > 1 for signal control in single test
36
- #define SIM_OVERFLOW 3 // must > 1 for signal control in single test
36
+ #define SMALL_MAXTIME 2
37
+ #define SIM_OVERFLOW 3
37
38
 
38
- // where exp(x) is considered overflow
39
+ // where 1 + exp(x) is considered overflow
39
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
40
41
  #define EXP_OVERFLOW_BOUND 500
41
42
 
@@ -59,8 +60,10 @@ typedef struct patch_picked_t {
59
60
  * index & event number in make_signal_*
60
61
  */
61
62
  typedef struct signal_t {
62
- // does the signal only have the first patch?
63
- bool only_first;
63
+ // relative location of the second patch to the first
64
+ // set to NO_MIG if the event only affects one patch
65
+ // otherwise set to MIG_* constants as defined above
66
+ uint8_t rela_loc;
64
67
 
65
68
  // the first patch
66
69
  size_t i1;
@@ -113,19 +116,19 @@ static inline void update_pi_k(patch_t* restrict p, const double* restrict M_sta
113
116
 
114
117
  double U = (double) p->U;
115
118
  double V = (double) p->V;
116
- double sum_minus_1 = U + V - 1.0;
119
+ double sum = U + V - 1;
120
+ //double U_ratio = U / sum;
121
+ //double V_ratio = V / sum;
117
122
 
118
- if (sum_minus_1 > 0) {
119
- if (U != 0) {
120
- p->U_pi = ((U - 1) / sum_minus_1) * M_start[0] +
121
- (V / sum_minus_1) * M_start[1];
123
+ if (sum > 0) {
124
+ if (U > 0) {
125
+ p->U_pi = (U - 1) / sum * M_start[0] + V / sum * M_start[1];
122
126
  } else {
123
127
  p->U_pi = 0.0;
124
128
  }
125
129
 
126
- if (V != 0) {
127
- p->V_pi = (U / sum_minus_1) * M_start[2] +
128
- ((V - 1) / sum_minus_1) * M_start[3];
130
+ if (V > 0) {
131
+ p->V_pi = U / sum * M_start[2] + (V - 1) / sum * M_start[3];
129
132
  } else {
130
133
  p->V_pi = 0.0;
131
134
  }
@@ -138,8 +141,8 @@ static inline void update_pi_k(patch_t* restrict p, const double* restrict M_sta
138
141
  p->pi_death_rates[0] = fabs(U * p->U_pi);
139
142
  p->pi_death_rates[1] = fabs(V * p->V_pi);
140
143
 
141
- p->pi_death_rates[2] = P_start[4] * U * (sum_minus_1 + 1.0);
142
- p->pi_death_rates[3] = P_start[5] * V * (sum_minus_1 + 1.0);
144
+ p->pi_death_rates[2] = P_start[4] * U * (sum + 1);
145
+ p->pi_death_rates[3] = P_start[5] * V * (sum + 1);
143
146
 
144
147
  p->sum_pi_death_rates = 0.0;
145
148
  for (size_t i = 0; i < 4; i++) {
@@ -148,19 +151,38 @@ static inline void update_pi_k(patch_t* restrict p, const double* restrict M_sta
148
151
  }
149
152
 
150
153
 
151
- static inline uint8_t update_mig_one(patch_t* restrict p, const double* restrict P_start, uint8_t nb_loc) {
152
- // update mig rate for one direction
153
- // P_start: start index of p's patch variables, i.e., ij * 6
154
- // nb_loc: location of neighbor, up, down, left, right
154
+
155
+ static inline void update_mig_just_rate(patch_t* restrict p, const double* restrict P_start) {
156
+ // update migration weight for patch p, in location loc. Only rate is updated
157
+ // used by last-changed patch, when there is only one last-changed patch
158
+ double* p_U_weight = p->U_weight;
159
+ double* p_V_weight = p->V_weight;
155
160
 
156
161
  double mu1_U = P_start[0] * (double)p->U;
157
162
  double mu2_V = P_start[1] * (double)p->V;
163
+ p->sum_mig_rates = mu1_U + mu2_V;
164
+
165
+ double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
166
+ double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
167
+
168
+ for (uint8_t i = 0; i < 4; i++) {
169
+ p->mig_rates[i] = mu1_U_divide_sum * p_U_weight[i];
170
+ p->mig_rates[i + 4] = mu2_V_divide_sum * p_V_weight[i];
171
+ }
172
+ }
173
+
174
+
175
+ static inline uint8_t update_mig_weight_rate(patch_t* restrict p, const double* P_start, uint8_t loc) {
176
+ // update migration weight as well as rates, in one direction
177
+ // used by neighbors of last-changed patches
178
+ // also used by last-changed patches themselve, when there are two patch changed, to update mig rates of in each other's direction
179
+
158
180
  double* p_U_weight = p->U_weight;
159
181
  double* p_V_weight = p->V_weight;
160
182
 
161
- patch_t* nbi = p->nb[nb_loc];
162
- p->sum_U_weight -= p_U_weight[nb_loc];
163
- p->sum_V_weight -= p_V_weight[nb_loc];
183
+ patch_t* nbi = p->nb[loc];
184
+ p->sum_U_weight -= p_U_weight[loc];
185
+ p->sum_V_weight -= p_V_weight[loc];
164
186
 
165
187
  double w1_Upi = P_start[2] * nbi->U_pi;
166
188
  double w2_Vpi = P_start[3] * nbi->V_pi;
@@ -171,44 +193,45 @@ static inline uint8_t update_mig_one(patch_t* restrict p, const double* restrict
171
193
  return SIM_OVERFLOW;
172
194
  }
173
195
 
174
- switch(nb_loc) {
196
+ switch(loc) {
175
197
  case MIG_UP:
176
- p_U_weight[MIG_UP] = 1.0 + exp(w1_Upi);
177
- p_V_weight[MIG_UP] = 1.0 + exp(w2_Vpi);
198
+ p_U_weight[MIG_UP] = 1 + exp(w1_Upi);
199
+ p_V_weight[MIG_UP] = 1 + exp(w2_Vpi);
178
200
  break;
179
201
  case MIG_DOWN:
180
- p_U_weight[MIG_DOWN] = 1.0 + exp(w1_Upi);
181
- p_V_weight[MIG_DOWN] = 1.0 + exp(w2_Vpi);
202
+ p_U_weight[MIG_DOWN] = 1 + exp(w1_Upi);
203
+ p_V_weight[MIG_DOWN] = 1 + exp(w2_Vpi);
182
204
  break;
183
205
  case MIG_LEFT:
184
- p_U_weight[MIG_LEFT] = 1.0 + exp(w1_Upi);
185
- p_V_weight[MIG_LEFT] = 1.0 + exp(w2_Vpi);
206
+ p_U_weight[MIG_LEFT] = 1 + exp(w1_Upi);
207
+ p_V_weight[MIG_LEFT] = 1 + exp(w2_Vpi);
186
208
  break;
187
209
  default:
188
- p_U_weight[MIG_RIGHT] = 1.0 + exp(w1_Upi);
189
- p_V_weight[MIG_RIGHT] = 1.0 + exp(w2_Vpi);
210
+ p_U_weight[MIG_RIGHT] = 1 + exp(w1_Upi);
211
+ p_V_weight[MIG_RIGHT] = 1 + exp(w2_Vpi);
190
212
  break;
191
213
  }
192
- p->sum_U_weight += p_U_weight[nb_loc];
193
- p->sum_V_weight += p_V_weight[nb_loc];
214
+ p->sum_U_weight += p_U_weight[loc];
215
+ p->sum_V_weight += p_V_weight[loc];
194
216
 
217
+ double mu1_U = P_start[0] * (double)p->U;
218
+ double mu2_V = P_start[1] * (double)p->V;
195
219
  double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
196
220
  double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
197
221
 
198
- for (size_t i = 0; i < 4; i++) {
222
+ for (uint8_t i = 0; i < 4; i++) {
199
223
  p->mig_rates[i] = mu1_U_divide_sum * p_U_weight[i];
200
224
  p->mig_rates[i + 4] = mu2_V_divide_sum * p_V_weight[i];
201
225
  }
226
+ p->sum_mig_rates = mu1_U + mu2_V;
202
227
 
203
228
  return SUCCESS;
204
229
  }
205
230
 
206
231
 
207
232
 
208
- static inline uint8_t update_mig_all(patch_t* restrict p, const double* restrict P_start) {
233
+ static inline uint8_t init_mig(patch_t* restrict p, const double* restrict P_start) {
209
234
  // update migration rate for all directions
210
- double mu1_U = P_start[0] * (double)p->U;
211
- double mu2_V = P_start[1] * (double)p->V;
212
235
 
213
236
  double* p_U_weight = p->U_weight;
214
237
  double* p_V_weight = p->V_weight;
@@ -232,14 +255,17 @@ static inline uint8_t update_mig_all(patch_t* restrict p, const double* restrict
232
255
  if (w2_Vpi > EXP_OVERFLOW_BOUND) {
233
256
  return SIM_OVERFLOW;
234
257
  }
235
- p_U_weight[i] = 1.0 + exp(w1_Upi);
236
- p_V_weight[i] = 1.0 + exp(w2_Vpi);
258
+ p_U_weight[i] = 1 + exp(w1_Upi);
259
+ p_V_weight[i] = 1 + exp(w2_Vpi);
237
260
 
238
261
  p->sum_U_weight += p_U_weight[i];
239
262
  p->sum_V_weight += p_V_weight[i];
240
263
  }
241
264
  }
242
265
 
266
+
267
+ double mu1_U = P_start[0] * (double)p->U;
268
+ double mu2_V = P_start[1] * (double)p->V;
243
269
  double mu1_U_divide_sum = mu1_U / p->sum_U_weight;
244
270
  double mu2_V_divide_sum = mu2_V / p->sum_V_weight;
245
271
 
@@ -247,7 +273,6 @@ static inline uint8_t update_mig_all(patch_t* restrict p, const double* restrict
247
273
  p->mig_rates[i] = mu1_U_divide_sum * p_U_weight[i];
248
274
  p->mig_rates[i + 4] = mu2_V_divide_sum * p_V_weight[i];
249
275
  }
250
-
251
276
  p->sum_mig_rates = mu1_U + mu2_V;
252
277
 
253
278
  return SUCCESS;
@@ -297,7 +322,7 @@ static inline void change_popu(patch_t* restrict p, uint8_t s) {
297
322
  return;
298
323
  case 2:
299
324
  // Natural birth/death for U due to payoff
300
- if (p->U_pi > 0.0) {
325
+ if (p->U_pi > 0) {
301
326
  p->U += 1;
302
327
  } else if (p->U > 0) {
303
328
  p->U -= 1;
@@ -313,7 +338,7 @@ static inline void change_popu(patch_t* restrict p, uint8_t s) {
313
338
  return;
314
339
  default:
315
340
  // Natural birth/death for V due to payoff
316
- if (p->V_pi > 0.0) {
341
+ if (p->V_pi > 0) {
317
342
  p->V += 1;
318
343
  } else if (p->V > 0) {
319
344
  p->V -= 1;
@@ -337,23 +362,25 @@ static inline void find_patch(patch_picked_t* restrict picked, double expected_s
337
362
  size_t col = 0;
338
363
 
339
364
  // Find row
340
- if (expected_sum < sum_rates * 0.5) {
341
- current_sum = 0.0;
342
- row = 0;
343
- while (current_sum < expected_sum) {
344
- current_sum += sum_rates_by_row[row];
345
- row++;
346
- }
347
- row--;
348
- current_sum -= sum_rates_by_row[row];
349
- } else {
350
- current_sum = sum_rates;
351
- row = N - 1;
352
- while (current_sum > expected_sum) {
353
- current_sum -= sum_rates_by_row[row];
365
+ if (N != 1) {
366
+ if (expected_sum < sum_rates * 0.5) {
367
+ current_sum = 0.0;
368
+ row = 0;
369
+ while (current_sum < expected_sum) {
370
+ current_sum += sum_rates_by_row[row];
371
+ row++;
372
+ }
354
373
  row--;
374
+ current_sum -= sum_rates_by_row[row];
375
+ } else {
376
+ current_sum = sum_rates;
377
+ row = N - 1;
378
+ while (current_sum > expected_sum) {
379
+ current_sum -= sum_rates_by_row[row];
380
+ row--;
381
+ }
382
+ row++;
355
383
  }
356
- row++;
357
384
  }
358
385
 
359
386
  size_t row_M = row * M;
@@ -392,75 +419,75 @@ static inline void make_signal_zero_flux(size_t i, size_t j, uint8_t e, signal_t
392
419
  switch (e) {
393
420
  case 0:
394
421
  signal->e1 = 2;
395
- signal->only_first = true;
422
+ signal->rela_loc = NO_MIG;
396
423
  return;
397
424
  case 1:
398
425
  signal->e1 = 5;
399
- signal->only_first = true;
426
+ signal->rela_loc = NO_MIG;
400
427
  return;
401
428
  case 2:
402
429
  signal->e1 = 1;
403
- signal->only_first = true;
430
+ signal->rela_loc = NO_MIG;
404
431
  return;
405
432
  case 3:
406
433
  signal->e1 = 4;
407
- signal->only_first = true;
434
+ signal->rela_loc = NO_MIG;
408
435
  return;
409
436
  case 4:
410
437
  signal->e1 = 1;
411
438
  signal->i2 = i - 1;
412
439
  signal->j2 = j;
413
440
  signal->e2 = 0;
414
- signal->only_first = false;
441
+ signal->rela_loc = MIG_UP;
415
442
  return;
416
443
  case 5:
417
444
  signal->e1 = 1;
418
445
  signal->i2 = i + 1;
419
446
  signal->j2 = j;
420
447
  signal->e2 = 0;
421
- signal->only_first = false;
448
+ signal->rela_loc = MIG_DOWN;
422
449
  return;
423
450
  case 6:
424
451
  signal->e1 = 1;
425
452
  signal->i2 = i;
426
453
  signal->j2 = j - 1;
427
454
  signal->e2 = 0;
428
- signal->only_first = false;
455
+ signal->rela_loc = MIG_LEFT;
429
456
  return;
430
457
  case 7:
431
458
  signal->e1 = 1;
432
459
  signal->i2 = i;
433
460
  signal->j2 = j + 1;
434
461
  signal->e2 = 0;
435
- signal->only_first = false;
462
+ signal->rela_loc = MIG_RIGHT;
436
463
  return;
437
464
  case 8:
438
465
  signal->e1 = 4;
439
466
  signal->i2 = i - 1;
440
467
  signal->j2 = j;
441
468
  signal->e2 = 3;
442
- signal->only_first = false;
469
+ signal->rela_loc = MIG_UP;
443
470
  return;
444
471
  case 9:
445
472
  signal->e1 = 4;
446
473
  signal->i2 = i + 1;
447
474
  signal->j2 = j;
448
475
  signal->e2 = 3;
449
- signal->only_first = false;
476
+ signal->rela_loc = MIG_DOWN;
450
477
  return;
451
478
  case 10:
452
479
  signal->e1 = 4;
453
480
  signal->i2 = i;
454
481
  signal->j2 = j - 1;
455
482
  signal->e2 = 3;
456
- signal->only_first = false;
483
+ signal->rela_loc = MIG_LEFT;
457
484
  return;
458
485
  default:
459
486
  signal->e1 = 4;
460
487
  signal->i2 = i;
461
488
  signal->j2 = j + 1;
462
489
  signal->e2 = 3;
463
- signal->only_first = false;
490
+ signal->rela_loc = MIG_RIGHT;
464
491
  return;
465
492
  //default:
466
493
  // fprintf(stderr, "Bug: invalid case in make_signal_zf, i, j, e: %zu, %zu, %hhu\n", i, j, e);
@@ -478,75 +505,75 @@ static inline void make_signal_periodical(size_t N, size_t M, size_t i, size_t j
478
505
  switch (e) {
479
506
  case 0:
480
507
  signal->e1 = 2;
481
- signal->only_first = true;
508
+ signal->rela_loc = NO_MIG;
482
509
  return;
483
510
  case 1:
484
511
  signal->e1 = 5;
485
- signal->only_first = true;
512
+ signal->rela_loc = NO_MIG;
486
513
  return;
487
514
  case 2:
488
515
  signal->e1 = 1;
489
- signal->only_first = true;
516
+ signal->rela_loc = NO_MIG;
490
517
  return;
491
518
  case 3:
492
519
  signal->e1 = 4;
493
- signal->only_first = true;
520
+ signal->rela_loc = NO_MIG;
494
521
  return;
495
522
  case 4:
496
523
  signal->e1 = 1;
497
524
  signal->i2 = i != 0 ? i - 1 : N - 1;
498
525
  signal->j2 = j;
499
526
  signal->e2 = 0;
500
- signal->only_first = false;
527
+ signal->rela_loc = MIG_UP;
501
528
  return;
502
529
  case 5:
503
530
  signal->e1 = 1;
504
531
  signal->i2 = i != N - 1 ? i + 1 : 0;
505
532
  signal->j2 = j;
506
533
  signal->e2 = 0;
507
- signal->only_first = false;
534
+ signal->rela_loc = MIG_DOWN;
508
535
  return;
509
536
  case 6:
510
537
  signal->e1 = 1;
511
538
  signal->i2 = i;
512
539
  signal->j2 = j != 0 ? j - 1 : M - 1;
513
540
  signal->e2 = 0;
514
- signal->only_first = false;
541
+ signal->rela_loc = MIG_LEFT;
515
542
  return;
516
543
  case 7:
517
544
  signal->e1 = 1;
518
545
  signal->i2 = i;
519
546
  signal->j2 = j != M - 1 ? j + 1 : 0;
520
547
  signal->e2 = 0;
521
- signal->only_first = false;
548
+ signal->rela_loc = MIG_RIGHT;
522
549
  return;
523
550
  case 8:
524
551
  signal->e1 = 4;
525
552
  signal->i2 = i != 0 ? i - 1 : N - 1;
526
553
  signal->j2 = j;
527
554
  signal->e2 = 3;
528
- signal->only_first = false;
555
+ signal->rela_loc = MIG_UP;
529
556
  return;
530
557
  case 9:
531
558
  signal->e1 = 4;
532
559
  signal->i2 = i != N - 1 ? i + 1 : 0;
533
560
  signal->j2 = j;
534
561
  signal->e2 = 3;
535
- signal->only_first = false;
562
+ signal->rela_loc = MIG_DOWN;
536
563
  return;
537
564
  case 10:
538
565
  signal->e1 = 4;
539
566
  signal->i2 = i;
540
567
  signal->j2 = j != 0 ? j - 1 : M - 1;
541
568
  signal->e2 = 3;
542
- signal->only_first = false;
569
+ signal->rela_loc = MIG_LEFT;
543
570
  return;
544
571
  default:
545
572
  signal->e1 = 4;
546
573
  signal->i2 = i;
547
574
  signal->j2 = j != M - 1 ? j + 1 : 0;
548
575
  signal->e2 = 3;
549
- signal->only_first = false;
576
+ signal->rela_loc = MIG_RIGHT;
550
577
  return;
551
578
  //default:
552
579
  // fprintf(stderr, "Bug: invalid case in make_signal_pr, i, j, e: %zu, %zu, %hhu\n", i, j, e);
@@ -1,4 +1,4 @@
1
- __version__ = '2.3.1'
1
+ __version__ = '2.3.3'
2
2
 
3
3
  '''
4
4
  version history:
@@ -37,4 +37,7 @@ version history:
37
37
  2.2.3: raised rate calculation to higher accuracy (long double), and switched to 30-bit random number generator.
38
38
  2.3.1: roll back accuracy update. Decrease toleratable bound for exponent of exp() to 500.
39
39
  Add video_fig function to figures module, which plots change of patch popu/payoff overtime in a 2D figure. Add auto-sorting for values passed to test_var plot functions.
40
+ 2.3.2: allow play-with-self in payoff calculation. Changed migration function to e^(w*pi) (removed "1+" term).
41
+ Simplified update-migration functions, improve speed by ~10%. Add -march=native flag to Makefile.
42
+ 2.3.3: fix error in calculation of migration rates.
40
43
  '''
@@ -491,19 +491,19 @@ def UV_pi(mod, ax_U = None, ax_V = None, U_color = 'violet', V_color = 'yellowgr
491
491
 
492
492
 
493
493
 
494
- def video_fig(mod, ax_list = None, num_itv = 100, U_color = 'Purples', V_color = 'Greens'):
494
+ def video_fig(mod, ax_list = None, num_grid = 100, U_color = 'Purples', V_color = 'Greens'):
495
495
  '''
496
496
  Plot distribution dynamics over time, of U, V population and payoff.
497
497
 
498
498
  mod: simulation.model object
499
499
  ax_list: a 2*2 list of ax, or None (a new 2*2 ax_list will be created)
500
- num_itv: how many time intervals to plot
500
+ num_grid: how many grid for the time axis
501
501
  U_color & V_color: matplotlib color map, color for U, V population and payoff.
502
502
  '''
503
503
 
504
- if num_itv > mod.max_record:
505
- raise ValueError('num_itv too large, larger than mod.max_record')
506
- idx_step = int(mod.max_record / num_itv)
504
+ if num_grid > mod.max_record:
505
+ raise ValueError('num_grid too large, larger than mod.max_record')
506
+ idx_step = int(mod.max_record / num_grid)
507
507
  ave_U = []
508
508
  ave_V = []
509
509
  ave_Upi = []
@@ -525,7 +525,7 @@ def video_fig(mod, ax_list = None, num_itv = 100, U_color = 'Purples', V_color =
525
525
  ax_list[i, j].spines['right'].set_visible(False)
526
526
  ax_list[i, j].set_xlabel('Patches')
527
527
  ax_list[i, j].set_ylabel('Time')
528
- ax_list[i, j].set_xlim([0, mod.M - 1])
528
+ ax_list[i, j].set_xlim([0, mod.M])
529
529
  ax_list[i, j].set_ylim([0, mod.maxtime])
530
530
 
531
531
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: piegy
3
- Version: 2.3.1
3
+ Version: 2.3.3
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
File without changes