-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathQuorumOrg.h
318 lines (258 loc) · 9.35 KB
/
QuorumOrg.h
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
// This file is part of Empirical, https://github.com/devosoft/Empirical
// Copyright (C) Michigan State University, 2016.
// Released under the MIT Software license; see doc/LICENSE
//
// This file contains the general configuration for a quorum-sensing organism
#ifndef EMP_EVO_QUORUM_ORGANISM
#define EMP_EVO_QUORUM_ORGANISM
// Empirical library includes
#include "config/config.h"
#include "tools/Random.h"
#include <iostream>
/* Simple class to contain the genome for a QuorumOrg
* Shoved in here in case we decide to use the fancy liniage tracker I saw
* in this directory.
*
* Also because it'll be easy to make specific types of orgs.
*/
namespace emp {
namespace evo {
struct QuorumOrgGenome {
private:
bool can_make_HiAI;
bool can_make_LoAI;
public:
int lineage = -1;
double co_op_prob;
double control_prob;
double ai_radius;
double quorum_threshold;
QuorumOrgGenome () {
co_op_prob = 0;
control_prob = 0;
ai_radius = 10;
quorum_threshold = 1;
can_make_HiAI = false;
can_make_LoAI = false;
}
QuorumOrgGenome(double cprob, double ctlprob, double airad, double qthresh, int lin, bool cmha, bool cmla) :
co_op_prob(cprob),control_prob(ctlprob), ai_radius(airad), quorum_threshold(qthresh), lineage(lin),
can_make_HiAI(cmha), can_make_LoAI(cmla) {};
// prints co-op prob, ai_gen_prob, quorum_thresh
void print (std::ostream & out) {
out << co_op_prob << ", " << ai_radius << ", " << quorum_threshold;
}
std::ostream & operator << (std::ostream & out) {
print(out);
return out;
}
int get_lineage() const {return lineage;}
bool get_hi_ai() const {return can_make_HiAI;}
bool get_lo_ai() const {return can_make_LoAI;}
friend bool operator== (QuorumOrgGenome const & lhs, QuorumOrgGenome const & rhs);
friend struct QuorumOrgState;
friend class QuorumOrganism;
};
bool operator== (QuorumOrgGenome const & lhs, QuorumOrgGenome const & rhs) {
return (lhs.co_op_prob == rhs.co_op_prob &&
lhs.ai_radius == rhs.ai_radius &&
lhs.quorum_threshold == rhs.quorum_threshold &&
lhs.can_make_HiAI == rhs.can_make_HiAI &&
lhs.can_make_LoAI == rhs.can_make_LoAI);
}
std::ostream & operator<< (std::ostream & out, QuorumOrgGenome & genome) {
genome.print(out);
return out;
}
/* Simple class to contain the current state of the organism
*/
struct QuorumOrgState {
protected:
unsigned int age;
int points;
int out, in;
public:
QuorumOrgGenome genome;
bool hi_density;
bool mutate; // dunno if we'll want to do this by-org, but eh
unsigned int loc;
unsigned int num_offspring; // gonna use this as/in a basic fitness function
unsigned int get_age() const {return age;}
unsigned int get_points() const {return points;}
unsigned int add_points(unsigned int add) {
in += add;
return points += add;
}
void reset_points() {points = 0;}
unsigned int remove_points(unsigned int remove) {
if (remove <= points) {
out += points;
return points -= remove;
}
else return points;
}
unsigned int bump_age() {return ++age;}
void reset_age() {age = 0;}
void reset_accounting() {out = 0; in = 0;}
QuorumOrgState() {
hi_density = false;
mutate = false;
};
QuorumOrgState (double cprob,double ctlprob, double aprob, double qthresh, bool mut,
unsigned int pts, int lin=-1, bool cmha = false, bool cmla = false) :
genome(cprob,ctlprob, aprob, qthresh, lin, cmha, cmla), mutate(mut), points(pts) {
age = 0;
loc = 0;
num_offspring = 0;
hi_density = false;
};
// Copy constructor!
QuorumOrgState (const QuorumOrgState & other) : genome(other.genome.co_op_prob,
other.genome.control_prob,
other.genome.ai_radius,
other.genome.quorum_threshold,
other.genome.get_lineage(),
other.genome.can_make_HiAI,
other.genome.can_make_LoAI),
hi_density(false), mutate(other.mutate),
points(0), age(0), loc(0), num_offspring(0) {
}
QuorumOrgState operator= (const QuorumOrgState & rhs) {
age = rhs.age;
loc = rhs.loc;
num_offspring = rhs.num_offspring;
hi_density = rhs.hi_density;
genome = rhs.genome;
points = rhs.points;
mutate = rhs.mutate;
return *this;
}
// prints out loc, age, points, if_producing_ai, if_mutation_on, {genome}
void print (std::ostream & out) {
out << loc << ", " << age << ", " << points << ", " << num_offspring;
out << ", " << hi_density << ", " << mutate << ", (";
//genome.print(out); // dunno why streaming doesn't work here
out << genome;
out << ")";
}
};
// for some reason these have to be outside of the class to work properly
std::ostream & operator<< (std::ostream & out, QuorumOrgState & state) {
state.print(out);
return out;
}
/* Here we see the QuorumOrganism in its natural habitat....
*/
class QuorumOrganism {
public:
static emp::Random * random;
static unsigned int num_to_donate, needed_to_reproduce, cost_to_donate;
static double mutation_amount;
static const QuorumOrgGenome initial_configurations[6];
static int classify (QuorumOrganism const * org) {
if (org == nullptr) { return -1;}
return (int) (org->state.genome.co_op_prob * 100);
}
// access specifiers are really annoying.
QuorumOrgState state;
QuorumOrganism () {};
// Config constructor
QuorumOrganism (double cprob,double ctlprob, double airad, double qthresh, bool mut,
unsigned int pts, int lin, bool cmha, bool cmla) {
this->QuorumOrganism::state = QuorumOrgState(cprob,ctlprob, airad, qthresh, mut, pts, lin, cmha, cmla);
}
QuorumOrganism (const QuorumOrganism & other) {
this->state = QuorumOrgState(other.state);
this->random = other.random;
}
QuorumOrganism & operator=(const QuorumOrganism & other) {
if (&other == this) {return *this;}
this->state = *(new QuorumOrgState(other.state));
this->random = other.random;
return *this;
}
// the aforementioned mutate function
bool mutate (Random & random) {
if (state.mutate && mutation_amount > random.GetDouble(0, 1)) {
//state.genome.co_op_prob += random.GetRandNormal(0, mutation_amount);
state.genome.co_op_prob = random.GetDouble(0, 1);
state.genome.control_prob = random.GetDouble(0, 1);
state.genome.can_make_HiAI = random.P(state.genome.co_op_prob);
state.genome.can_make_LoAI = state.genome.can_make_LoAI && random.P(state.genome.co_op_prob);
return true;
}
else {return false;}
}
bool mutate() {
return mutate(*(this->random));
}
// utility/accessor methods
void set_state (QuorumOrgState new_state) {state = new_state;}
unsigned int set_id (unsigned int new_id) {return state.loc = new_id;}
unsigned int get_loc() {return state.loc;}
unsigned int get_age() {return state.get_age();}
unsigned int add_points(unsigned int points) {return state.add_points(points);}
unsigned int get_points() {return state.get_points();}
void set_density(bool hd) {state.hi_density = hd && state.genome.can_make_HiAI;}
bool set_density(double q) {
state.hi_density = (q > state.genome.quorum_threshold);
return state.hi_density = state.hi_density && state.genome.can_make_HiAI;
}
bool hi_density () const {
return state.hi_density && state.genome.can_make_HiAI;
}
bool lo_density () const {
return state.genome.can_make_LoAI;
}
unsigned int get_fitness() {return state.get_points();}
// methods for interacting with the world / neighbors
int get_contribution (bool current_quorum) {
set_density(current_quorum);
if (random->P(state.genome.co_op_prob) && current_quorum && state.hi_density) {
if (state.get_points() >= cost_to_donate) {
state.remove_points(cost_to_donate);
return num_to_donate;
}
}
return 0;
}
void print (std::ostream & out) {
out << state;
}
bool operator<(const QuorumOrganism & other) const {
return this->state.loc < other.state.loc;
}
bool operator>(const QuorumOrganism & other) const {
return this->state.loc > other.state.loc;
}
bool operator==(const QuorumOrganism & other) const {
return this->state.genome == other.state.genome;
}
};
std::ostream & operator << (std::ostream & out, QuorumOrganism & org) {
org.print(out);
return out;
}
const QuorumOrgGenome standard_genome = QuorumOrgGenome(0.0,0.0, 10, 40, 0, true, true);
const QuorumOrgGenome lying_defector_genome = QuorumOrgGenome(0,0, 10, 40, 1, false, true);
const QuorumOrgGenome cooperator_genome = QuorumOrgGenome(1,1, 10, 40, 2, true, true);
const QuorumOrgGenome scrooge_genome = QuorumOrgGenome(0.015,0.015, 10, 40, 3, true, true);
const QuorumOrgGenome truthful_defector_genome = QuorumOrgGenome(0,0, 10, 40, 4, false, false);
const QuorumOrgGenome intermediate_genome = QuorumOrgGenome(0.5,0.5, 10, 40, 5, true, true);
/// selection of standardized starting configurations for QOrgs
const QuorumOrgGenome QuorumOrganism::initial_configurations[6] = {
standard_genome,
lying_defector_genome,
cooperator_genome,
scrooge_genome,
truthful_defector_genome,
intermediate_genome
};
unsigned int QuorumOrganism::num_to_donate;
unsigned int QuorumOrganism::cost_to_donate;
unsigned int QuorumOrganism::needed_to_reproduce;
double QuorumOrganism::mutation_amount;
emp::Random * QuorumOrganism::random;
} // close evo::
} // close emp::
#endif