piegy 2.3.8__tar.gz → 2.3.9__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.8/src/piegy.egg-info → piegy-2.3.9}/PKG-INFO +1 -1
  2. {piegy-2.3.8 → piegy-2.3.9}/pyproject.toml +1 -1
  3. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/C_core/model.c +8 -9
  4. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/C_core/patch.c +0 -3
  5. piegy-2.3.9/src/piegy/C_core/random.h +77 -0
  6. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/C_core/sim_funcs.c +14 -15
  7. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/C_core/sim_funcs.h +14 -26
  8. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/__version__.py +2 -1
  9. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/data_tools.py +18 -9
  10. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/simulation.py +5 -14
  11. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/simulation_py.py +17 -9
  12. {piegy-2.3.8 → piegy-2.3.9/src/piegy.egg-info}/PKG-INFO +1 -1
  13. {piegy-2.3.8 → piegy-2.3.9}/src/piegy.egg-info/SOURCES.txt +1 -0
  14. {piegy-2.3.8 → piegy-2.3.9}/LICENSE.txt +0 -0
  15. {piegy-2.3.8 → piegy-2.3.9}/MANIFEST.in +0 -0
  16. {piegy-2.3.8 → piegy-2.3.9}/README.md +0 -0
  17. {piegy-2.3.8 → piegy-2.3.9}/setup.cfg +0 -0
  18. {piegy-2.3.8 → piegy-2.3.9}/setup.py +0 -0
  19. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/C_core/Makefile +0 -0
  20. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/C_core/model.h +0 -0
  21. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/C_core/patch.h +0 -0
  22. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/__init__.py +0 -0
  23. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/analysis.py +0 -0
  24. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/build_info.py +0 -0
  25. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/figures.py +0 -0
  26. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/test_var.py +0 -0
  27. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/tools/__init__.py +0 -0
  28. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/tools/figure_tools.py +0 -0
  29. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/tools/file_tools.py +0 -0
  30. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/tools/find_C.py +0 -0
  31. {piegy-2.3.8 → piegy-2.3.9}/src/piegy/videos.py +0 -0
  32. {piegy-2.3.8 → piegy-2.3.9}/src/piegy.egg-info/dependency_links.txt +0 -0
  33. {piegy-2.3.8 → piegy-2.3.9}/src/piegy.egg-info/requires.txt +0 -0
  34. {piegy-2.3.8 → piegy-2.3.9}/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.8
3
+ Version: 2.3.9
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.8'
7
+ version = '2.3.9'
8
8
  description = 'Payoff-Driven Stochastic Spatial Model for Evolutionary Game Theory'
9
9
  readme = 'README.md'
10
10
  requires-python = '>=3.7'
@@ -79,17 +79,16 @@ void mod_free(model_t* mod) {
79
79
 
80
80
  void mod_free_py(model_t* mod) {
81
81
  // free function for python
82
-
82
+ // the same as mod_free except for not having free(mod)
83
83
  if (!mod) return;
84
- if (mod->I) { free(mod->I); }
85
- if (mod->X) { free(mod->X); }
86
- if (mod->P) { free(mod->P); }
87
- if (mod->U1d) { free(mod->U1d); }
88
- if (mod->V1d) { free(mod->V1d); }
89
- if (mod->Upi_1d) { free(mod->Upi_1d); }
90
- if (mod->Vpi_1d) { free(mod->Vpi_1d); }
91
- // if (mod) { free(mod); }
92
84
 
85
+ free(mod->I);
86
+ free(mod->X);
87
+ free(mod->P);
88
+ free(mod->U1d);
89
+ free(mod->V1d);
90
+ free(mod->Upi_1d);
91
+ free(mod->Vpi_1d);
93
92
  mod->I = NULL;
94
93
  mod->X = mod->P = mod->U1d = mod->V1d = mod->Upi_1d = mod->Vpi_1d = NULL;
95
94
  }
@@ -17,9 +17,6 @@ void patch_init(patch_t* p, uint32_t U, uint32_t V, size_t row, size_t col, doub
17
17
 
18
18
  memcpy(p->X, X_start, 4 * sizeof(double));
19
19
  memcpy(p->P, P_start, 6 * sizeof(double));
20
- for (size_t i = 0; i < 6; i++) {
21
- p->P[i] = P_start[i];
22
- }
23
20
 
24
21
  for (size_t i = 0; i < 4; i++) {
25
22
  p->U_weight[i] = 0;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * The Random Number Generation module
3
+ * Returns a random double in (0, 1) with 2^-53 resolution, 0 and 1 not included
4
+ *
5
+ * First initialize xoshiro256+ states with Splitmix64
6
+ * Then use xoshiro256+ for random number generation
7
+ *
8
+ * Referrence:
9
+ * xoshiro256++ code: https://prng.di.unimi.it
10
+ * Splitmix64 code: https://rosettacode.org/wiki/Pseudo-random_numbers/Splitmix64
11
+ *
12
+ */
13
+
14
+ #include <stdint.h>
15
+
16
+
17
+ // resolution of random01 is 2^-53
18
+ // which is (about) the IEEE 754 double precision
19
+ #define MAX_53BIT (uint64_t) ((1ULL << 53) - 1)
20
+ #define RAND_DENOM 1.0 / ((double) (1ULL << 53))
21
+ // xor_state
22
+ static uint64_t xor_state[4];
23
+ static uint64_t splitmix64_state;
24
+
25
+
26
+
27
+ static inline uint64_t Splitmix64_rand() {
28
+ // used to seed PCG initial states
29
+ splitmix64_state += 0x9e3779b97f4a7c15ULL;
30
+ uint64_t z = splitmix64_state;
31
+ z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
32
+ z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
33
+ return z ^ (z >> 31);
34
+ }
35
+
36
+
37
+ static inline uint64_t rot23(const uint64_t x) {
38
+ // 23 and 64 - 23
39
+ // Not used here, part of xoshiro256++
40
+ return (x << 23) | (x >> 41);
41
+ }
42
+
43
+
44
+ static inline uint64_t rot45(const uint64_t x) {
45
+ // 45 and 64 - 45
46
+ return (x << 45) | (x >> 19);
47
+ }
48
+
49
+
50
+ static inline double random01() {
51
+ // return a random number in (0, 1) with 2^-53 resolution. 0 and 1 not included.
52
+
53
+ const uint64_t result = xor_state[0] + xor_state[3];
54
+ const uint64_t t = xor_state[1] << 17;
55
+
56
+ xor_state[2] ^= xor_state[0];
57
+ xor_state[3] ^= xor_state[1];
58
+ xor_state[1] ^= xor_state[2];
59
+ xor_state[0] ^= xor_state[3];
60
+
61
+ xor_state[2] ^= t;
62
+ xor_state[3] = rot45(xor_state[3]);
63
+
64
+ return ((double) (result & MAX_53BIT) + 0.5) * RAND_DENOM;
65
+ }
66
+
67
+
68
+ static inline void rand_init(const uint64_t seed) {
69
+ // initialize PCG random
70
+ splitmix64_state = seed;
71
+ for (int i = 0; i < 4; i++) {
72
+ xor_state[i] = Splitmix64_rand();
73
+ }
74
+ (void) random01();
75
+ }
76
+
77
+
@@ -144,7 +144,7 @@ static double single_init(const model_t* restrict mod, patch_t* restrict world,
144
144
 
145
145
  // make signal
146
146
  if (mod->boundary) {
147
- make_signal_zero_flux(picked_p->i, picked_p->j, e0, sig_p);
147
+ make_signal_zero_flux(N, M, picked_p->i, picked_p->j, e0, sig_p);
148
148
  } else {
149
149
  make_signal_periodical(N, M, picked_p->i, picked_p->j, e0, sig_p);
150
150
  }
@@ -205,6 +205,14 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
205
205
  size_t curr_update_sum_round = 0; // current round
206
206
  size_t update_sum_freq = UPDATE_SUM_ROUNDS_SM; // recalculate sum every this many rounds
207
207
 
208
+ // set make_signal function based on boundary conditions
209
+ void (*make_signal)(size_t, size_t, size_t, size_t, uint8_t, signal_t*);
210
+ if (mod->boundary) {
211
+ make_signal = &make_signal_zero_flux;
212
+ } else {
213
+ make_signal = &make_signal_periodical;
214
+ }
215
+
208
216
  // core containers
209
217
  patch_t* world = (patch_t*) calloc(NM, sizeof(patch_t));
210
218
  size_t* nb_indices = (size_t*) calloc(NM * 4, sizeof(size_t));
@@ -261,10 +269,11 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
261
269
  uint8_t curr_prog = (uint8_t)(time * 100 / maxtime);
262
270
  if (curr_prog < 10) {
263
271
  fprintf(stdout, "\r%s: %d %%", message, (int)(time * 100 / maxtime));
272
+ fflush(stdout);
264
273
  } else {
265
274
  fprintf(stdout, "\r%s: %d%%", message, (int)(time * 100 / maxtime));
275
+ fflush(stdout);
266
276
  }
267
- fflush(stdout);
268
277
  //fprintf(stdout, "\n99: %d, %d, %f, %f\n100: %d, %d, %f, %f\n",
269
278
  //world[98].U, world[98].V, world[98].mig_rates[3], world[98].mig_rates[7], world[99].U, world[99].V, world[99].mig_rates[2], world[99].mig_rates[6]);
270
279
  //fflush(stdout);
@@ -405,11 +414,7 @@ static uint8_t single_test(model_t* restrict mod, char* message) {
405
414
  }
406
415
 
407
416
  // make signal
408
- if (boundary) {
409
- make_signal_zero_flux(picked.i, picked.j, e0, &signal);
410
- } else {
411
- make_signal_periodical(N, M, picked.i, picked.j, e0, &signal);
412
- }
417
+ (*make_signal)(N, M, picked.i, picked.j, e0, &signal);
413
418
  signal.ij1 = signal.i1 * M + signal.j1;
414
419
  signal.ij2 = signal.i2 * M + signal.j2;
415
420
 
@@ -498,15 +503,9 @@ uint8_t run(model_t* restrict mod, char* message, size_t msg_len) {
498
503
 
499
504
  // initialize random
500
505
  if (mod->seed != -1) {
501
- srand((uint32_t) mod->seed);
502
- } else {
503
- srand(time(NULL));
504
- }
505
-
506
- if (mod->seed == -1){
507
- srand(time(NULL));
506
+ rand_init((uint64_t) mod->seed);
508
507
  } else {
509
- srand(mod->seed);
508
+ rand_init((uint64_t) time(NULL));
510
509
  }
511
510
 
512
511
  if (mod->print_pct == 0) {
@@ -15,11 +15,11 @@
15
15
 
16
16
  #include "patch.h"
17
17
  #include "model.h"
18
+ #include "random.h"
19
+
18
20
 
19
21
 
20
22
 
21
- // upper bound for RNG is 2^30 + 1
22
- #define RAND_UPPER_PLUS_2 (double) ((1LL << 30) + 1)
23
23
 
24
24
  // directions of migration
25
25
  // so that 3 - mig_dir = reflection of it. Used to track neighbors
@@ -55,8 +55,6 @@
55
55
  #define UPDATE_SUM_ROUNDS_SM 100 // small, more frequent if some rate is larger than ACCURATE_BOUND
56
56
  #define UPDATE_SUM_ROUNDS_LG 10000
57
57
 
58
-
59
-
60
58
 
61
59
  /**
62
60
  * index of patch in find_patch
@@ -105,19 +103,6 @@ uint8_t run(model_t* restrict mod, char* message, size_t msg_len);
105
103
 
106
104
 
107
105
 
108
- /**
109
- * Inline Functions
110
- */
111
-
112
- static inline double random01() {
113
- // generate a 24 bit random int, then convert to a (0, 1) ranged double
114
- uint32_t r1 = rand() & 0x7fff; // RAND_MAX is different across machines, ensure 15 bits
115
- uint32_t r2 = rand() & 0x7fff;
116
-
117
- double r_combined = (r1 << 15) + r2;
118
- return (r_combined + 1) / RAND_UPPER_PLUS_2;
119
- }
120
-
121
106
  /**
122
107
  * patch functions
123
108
  */
@@ -127,10 +112,10 @@ static inline void update_pi_k(patch_t* restrict p) {
127
112
  uint32_t U = p->U;
128
113
  uint32_t V = p->V;
129
114
  double sum = U + V;
130
- double U_ratio = U / sum;
131
- double V_ratio = V / sum;
132
115
 
133
116
  if (sum > 0) {
117
+ double U_ratio = U / sum;
118
+ double V_ratio = V / sum;
134
119
  if (U > 0) {
135
120
  p->U_pi = U_ratio * p->X[0] + V_ratio * p->X[1];
136
121
  } else {
@@ -182,7 +167,7 @@ static inline void update_mig_just_rate(patch_t* restrict p) {
182
167
  }
183
168
 
184
169
 
185
- static inline uint8_t update_mig_weight_rate(patch_t* restrict p, uint8_t loc) {
170
+ static inline uint8_t update_mig_weight_rate(patch_t* restrict p, const uint8_t loc) {
186
171
  // update migration weight as well as rates, in one direction
187
172
  // used by neighbors of last-changed patches
188
173
  // also used by last-changed patches themselve, when there are two patch changed, to update mig rates of in each other's direction
@@ -288,7 +273,7 @@ static inline uint8_t init_mig(patch_t* restrict p) {
288
273
 
289
274
 
290
275
 
291
- static inline uint8_t find_event(const patch_t* restrict p, double expected_sum) {
276
+ static inline uint8_t find_event(const patch_t* restrict p, const double expected_sum) {
292
277
  size_t event = 0;
293
278
  double current_sum;
294
279
 
@@ -318,7 +303,7 @@ static inline uint8_t find_event(const patch_t* restrict p, double expected_sum)
318
303
  }
319
304
 
320
305
 
321
- static inline void change_popu(patch_t* restrict p, uint8_t s) {
306
+ static inline void change_popu(patch_t* restrict p, const uint8_t s) {
322
307
  switch (s) {
323
308
  case 0:
324
309
  // Migration IN for U
@@ -360,8 +345,8 @@ static inline void change_popu(patch_t* restrict p, uint8_t s) {
360
345
  * Main Simulation Functions
361
346
  */
362
347
 
363
- static inline void find_patch(patch_picked_t* restrict picked, double expected_sum,
364
- const double* restrict patch_rates, const double* restrict sum_rates_by_row, double sum_rates, size_t N, size_t M) {
348
+ static inline void find_patch(patch_picked_t* restrict picked, const double expected_sum,
349
+ const double* restrict patch_rates, const double* restrict sum_rates_by_row, const double sum_rates, const size_t N, const size_t M) {
365
350
  double current_sum = 0;
366
351
  size_t row = 0;
367
352
  size_t col = 0;
@@ -416,7 +401,10 @@ static inline void find_patch(patch_picked_t* restrict picked, double expected_s
416
401
 
417
402
 
418
403
 
419
- static inline void make_signal_zero_flux(size_t i, size_t j, uint8_t e, signal_t* restrict signal) {
404
+ static inline void make_signal_zero_flux(const size_t N, const size_t M, const size_t i, const size_t j, const uint8_t e, signal_t* restrict signal) {
405
+ // pass in N & M as well to match the param set of make_signal_periodical
406
+ (void) N;
407
+ (void) M;
420
408
  // this is always the case for the first one
421
409
  signal->i1 = i;
422
410
  signal->j1 = j;
@@ -499,7 +487,7 @@ static inline void make_signal_zero_flux(size_t i, size_t j, uint8_t e, signal_t
499
487
 
500
488
 
501
489
 
502
- static inline void make_signal_periodical(size_t N, size_t M, size_t i, size_t j, uint8_t e, signal_t* restrict signal) {
490
+ static inline void make_signal_periodical(const size_t N, const size_t M, const size_t i, const size_t j, const uint8_t e, signal_t* restrict signal) {
503
491
  // this is always the case for the first one
504
492
  signal->i1 = i;
505
493
  signal->j1 = j;
@@ -1,4 +1,4 @@
1
- __version__ = '2.3.8'
1
+ __version__ = '2.3.9'
2
2
 
3
3
  '''
4
4
  version history:
@@ -45,4 +45,5 @@ version history:
45
45
  2.3.6: index error due to reduced accuracy is now explicitly handled.
46
46
  2.3.7: update migration rules on the boundary. mu values are scaled based on how many neighbors a patch has. Minor debugging in several modules.
47
47
  2.3.8: bug fix for 2.3.7 update.
48
+ 2.3.9: now use xoshiro256+ as RNG.
48
49
  '''
@@ -12,6 +12,7 @@ from . import simulation
12
12
  import json
13
13
  import gzip
14
14
  import os
15
+ import numpy as np
15
16
 
16
17
 
17
18
  def save(mod, dirs = '', print_msg = True):
@@ -46,7 +47,6 @@ def save(mod, dirs = '', print_msg = True):
46
47
  inputs.append(mod.P.tolist())
47
48
  inputs.append(mod.print_pct)
48
49
  inputs.append(mod.seed)
49
- inputs.append(mod.check_overflow)
50
50
  data.append(inputs)
51
51
 
52
52
  # skipped rng
@@ -54,11 +54,17 @@ def save(mod, dirs = '', print_msg = True):
54
54
  outputs = []
55
55
  outputs.append(mod.max_record)
56
56
  outputs.append(mod.compress_itv)
57
- outputs.append(mod.U.tolist())
58
- outputs.append(mod.V.tolist())
59
- outputs.append(mod.Upi.tolist())
60
- outputs.append(mod.Vpi.tolist())
61
- # H&Vpi_total are not saved, will be calculated when reading the data
57
+ if not mod.data_empty:
58
+ outputs.append(mod.U.tolist())
59
+ outputs.append(mod.V.tolist())
60
+ outputs.append(mod.Upi.tolist())
61
+ outputs.append(mod.Vpi.tolist())
62
+ else:
63
+ outputs.append(None)
64
+ outputs.append(None)
65
+ outputs.append(None)
66
+ outputs.append(None)
67
+
62
68
  data.append(outputs)
63
69
 
64
70
  data_dirs = os.path.join(dirs, 'data.json.gz')
@@ -96,16 +102,19 @@ def load(dirs):
96
102
  try:
97
103
  mod = simulation.model(N = data[0][0], M = data[0][1], maxtime = data[0][2], record_itv = data[0][3],
98
104
  sim_time = data[0][4], boundary = data[0][5], I = data[0][6], X = data[0][7], P = data[0][8],
99
- print_pct = data[0][9], seed = data[0][10], check_overflow = data[0][11])
105
+ print_pct = data[0][9], seed = data[0][10], check_overflow = False)
100
106
  except:
101
- raise ValueError('Invalid input parameters saved in data')
107
+ raise ValueError('Invalid input parameters stored in data')
102
108
 
103
109
  # outputs
104
110
  try:
105
111
  mod.set_data(data_empty = False, max_record = data[1][0], compress_itv = data[1][1],
106
112
  U = data[1][2], V = data[1][3], Upi = data[1][4], Vpi = data[1][5])
113
+ if (mod.U is None) or (isinstance(mod.U, np.ndarray) and mod.U.shape == () and mod.U.item() is None):
114
+ # if data is None
115
+ mod.data_empty = True
107
116
  except:
108
- raise ValueError('Invalid model results saved in data')
117
+ raise ValueError('Invalid simulation results stored in data')
109
118
 
110
119
  return mod
111
120
 
@@ -164,22 +164,11 @@ class model:
164
164
  if check_overflow:
165
165
  check_overflow_func(self)
166
166
 
167
- self.init_storage() # initialize storage bins. Put in a separate function because might want to change maxtime
168
- # and that doesn't need to initialze the whole object again
167
+ # initialize storage bins.
168
+ self.set_data(data_empty = True, max_record = int(maxtime / record_itv), compress_itv = 1,
169
+ U = None, V = None, Upi = None, Vpi = None)
169
170
 
170
171
 
171
- def init_storage(self):
172
- # initialize storage bins
173
- self.data_empty = True # whether data storage bins are empty. model.run will refuse to run (raise error) if not empty.
174
- self.max_record = int(self.maxtime / self.record_itv) # int, how many data points to store sin total
175
- self.compress_itv = 1 # int, intended to reduce size of data (if not 1). Updated by compress_data function
176
- # if set to an int, say 20, mod will take average over every 20 data points and save them as new data.
177
- # May be used over and over again to recursively reduce data size.
178
- # Default is 1, not to take average.
179
- self.U = None # initialized by simulation.run or data_tools.load
180
- self.V = None
181
- self.Upi = None
182
- self.Vpi = None
183
172
 
184
173
 
185
174
  def check_valid_input(self, N, M, maxtime, record_itv, sim_time, boundary, I, X, P, print_pct, seed, check_overflow):
@@ -319,6 +308,8 @@ class model:
319
308
 
320
309
  if copy_data:
321
310
  # copy data as well
311
+ if self.data_empty:
312
+ print("Warning: model has empty data")
322
313
  sim2.set_data(self.data_empty, self.max_record, self.compress_itv, self.U, self.V, self.Upi, self.Vpi)
323
314
 
324
315
  return sim2
@@ -93,7 +93,13 @@ class patch:
93
93
  def set_nb_pointers(self, nb):
94
94
  # nb is a list of pointers (point to patches)
95
95
  # nb is passed from the model class
96
+ nb_count = 0
97
+ for nb_i in nb:
98
+ if nb_i != None:
99
+ nb_count += 1
96
100
  self.nb = nb
101
+ self.mu1 *= (0.25 * nb_count)
102
+ self.mu2 *= (0.25 * nb_count)
97
103
 
98
104
 
99
105
  def update_pi_k(self):
@@ -101,19 +107,21 @@ class patch:
101
107
 
102
108
  U = self.U # bring the values to front
103
109
  V = self.V
104
- sum_minus_1 = U + V - 1 # this value is used several times
110
+ sum_UV = U + V # this value is used several times
105
111
 
106
- if sum_minus_1 > 0:
112
+ if sum_UV > 0:
107
113
  # interaction happens only if there is more than 1 individual
114
+ U_ratio = U / sum_UV
115
+ V_ratio = V / sum_UV
108
116
 
109
117
  if U != 0:
110
118
  # no payoff if U == 0
111
- self.Upi = (U - 1) / sum_minus_1 * self.matrix[0] + V / sum_minus_1 * self.matrix[1]
119
+ self.Upi = U_ratio * self.matrix[0] + V_ratio * self.matrix[1]
112
120
  else:
113
121
  self.Upi = 0
114
122
 
115
123
  if V != 0:
116
- self.Vpi = U / sum_minus_1 * self.matrix[2] + (V - 1) / sum_minus_1 * self.matrix[3]
124
+ self.Vpi = U_ratio * self.matrix[2] + V_ratio * self.matrix[3]
117
125
  else:
118
126
  self.Vpi = 0
119
127
 
@@ -127,8 +135,8 @@ class patch:
127
135
  self.pi_death_rates[1] = abs(V * self.Vpi)
128
136
 
129
137
  # update natural death rates
130
- self.pi_death_rates[2] = self.kappa1 * U * (sum_minus_1 + 1)
131
- self.pi_death_rates[3] = self.kappa2 * V * (sum_minus_1 + 1)
138
+ self.pi_death_rates[2] = self.kappa1 * U * sum_UV
139
+ self.pi_death_rates[3] = self.kappa2 * V * sum_UV
132
140
 
133
141
  # update sum of rates
134
142
  self.sum_pi_death_rates = sum(self.pi_death_rates)
@@ -143,8 +151,8 @@ class patch:
143
151
 
144
152
  for i in range(4):
145
153
  if self.nb[i] != None:
146
- U_weight[i] = 1 + pow(math.e, self.w1 * self.nb[i].Upi)
147
- V_weight[i] = 1 + pow(math.e, self.w2 * self.nb[i].Vpi)
154
+ U_weight[i] = pow(math.e, self.w1 * self.nb[i].Upi)
155
+ V_weight[i] = pow(math.e, self.w2 * self.nb[i].Vpi)
148
156
 
149
157
  mu1_U = self.mu1 * self.U
150
158
  mu2_V = self.mu2 * self.V
@@ -746,7 +754,7 @@ def single_test(mod, front_info, end_info, update_sum_frequency, rng):
746
754
 
747
755
 
748
756
 
749
- def run_py(mod, predict_runtime = False, message = ''):
757
+ def run(mod, predict_runtime = False, message = ''):
750
758
  '''
751
759
  Main function. Recursively calls single_test to run many models and then takes the average.
752
760
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: piegy
3
- Version: 2.3.8
3
+ Version: 2.3.9
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
@@ -23,6 +23,7 @@ src/piegy/C_core/model.c
23
23
  src/piegy/C_core/model.h
24
24
  src/piegy/C_core/patch.c
25
25
  src/piegy/C_core/patch.h
26
+ src/piegy/C_core/random.h
26
27
  src/piegy/C_core/sim_funcs.c
27
28
  src/piegy/C_core/sim_funcs.h
28
29
  src/piegy/tools/__init__.py
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