aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAiden Woodruff <woodra@rpi.edu>2025-12-12 23:48:39 -0500
committerAiden Woodruff <woodra@rpi.edu>2025-12-12 23:48:39 -0500
commitc0268db7865553ceece33d0ebc9a4b03bbbd0633 (patch)
treea45724fa743756de5b78396639a0d1212e8ff0d9 /src
parent275e94d023a7be698e9fc2f0d37dcf889e6a1b62 (diff)
downloadtipping-points-c0268db7865553ceece33d0ebc9a4b03bbbd0633.tar.gz
tipping-points-c0268db7865553ceece33d0ebc9a4b03bbbd0633.tar.bz2
tipping-points-c0268db7865553ceece33d0ebc9a4b03bbbd0633.zip
add confirmation bias and exp weights
- src/NameGame.cc: remove std::map best_move implementation. - add explicit confirmation bias macro. - add default random tie-breaker. - src/many-async.cc: reseed for each committed minority value because entropy may be exhausted. Signed-off-by: Aiden Woodruff <woodra@rpi.edu>
Diffstat (limited to 'src')
-rw-r--r--src/NameGame.cc50
-rw-r--r--src/NameGame.h3
-rw-r--r--src/many-async.cc9
3 files changed, 33 insertions, 29 deletions
diff --git a/src/NameGame.cc b/src/NameGame.cc
index 7561946..2a77db5 100644
--- a/src/NameGame.cc
+++ b/src/NameGame.cc
@@ -88,6 +88,10 @@ NameGame::NameGame(int group_size, int cm_size, int memory) :
88 initGraph(); 88 initGraph();
89} 89}
90 90
91void NameGame::seed(int s) {
92 rng.seed(s);
93}
94
91void NameGame::setCMsize(int cm_size) { 95void NameGame::setCMsize(int cm_size) {
92 if (cm_size <= 0 || cm_size > gsize) 96 if (cm_size <= 0 || cm_size > gsize)
93 throw std::invalid_argument("NameGame::setCMsize invalid cm_size"); 97 throw std::invalid_argument("NameGame::setCMsize invalid cm_size");
@@ -191,12 +195,12 @@ void NameGame::runRound(int r) {
191 strategy_record.push_back({r, speaker.GetId(), speaker().Val1, strategy}); 195 strategy_record.push_back({r, speaker.GetId(), speaker().Val1, strategy});
192} 196}
193 197
194#undef USE_EXP_WEIGHT 198#define USE_EXP_WEIGHT
195#ifdef USE_EXP_WEIGHT 199#ifdef USE_EXP_WEIGHT
196float weight(int i) { 200float weight(int i) {
197 static std::vector<float> weight_table; 201 static std::vector<float> weight_table;
198 if (i < 0) throw std::invalid_argument("bad weight input"); 202 if (i < 0) throw std::invalid_argument("bad weight input");
199 while (i < weight_table.size()) { 203 while (i >= weight_table.size()) {
200 float x = weight_table.size(); 204 float x = weight_table.size();
201 weight_table.push_back(std::exp(-x)); 205 weight_table.push_back(std::exp(-x));
202 } 206 }
@@ -204,37 +208,33 @@ float weight(int i) {
204} 208}
205#endif 209#endif
206 210
207int NameGame::best_move(int nId) const { 211#undef TP_BESTMOVE_CONFBIAS
212int NameGame::best_move(int nId) {
208 const auto& mem = graph.GetNDat(nId).Val2; 213 const auto& mem = graph.GetNDat(nId).Val2;
209#ifdef TP_BESTMOVE_STATIC 214#ifdef USE_EXP_WEIGHT
215 float votes[2] = {0.f, 0.f};
216 int i = 0;
217 for (const auto& strategy : mem) {
218 if (strategy == -1) votes[0] += weight(i);
219 else votes[1] += weight(i);
220 ++i;
221 }
222#else
210 int votes[2] = {0, 0}; 223 int votes[2] = {0, 0};
211 for (const auto& strategy : mem) { 224 for (const auto& strategy : mem) {
212 if (strategy == -1) votes[0]++; 225 if (strategy == -1) votes[0]++;
213 else votes[1]++; 226 else votes[1]++;
214 } 227 }
215 return votes[0] > votes[1] ? -1 : 1;
216#else
217#ifdef USE_EXP_WEIGHT
218 std::map<int, float> votes;
219 for (int i = 0; i < mem.Len(); ++i) {
220 int strategy = mem[i];
221 if (votes.count(strategy)) votes[strategy] += weight(i);
222 else votes[strategy] = weight(i);
223#else
224 std::map<int, int> votes;
225 for (const auto& strategy : mem) {
226 if (votes.count(strategy)) votes[strategy] += 1;
227 else votes[strategy] = 1;
228#endif 228#endif
229 } 229 if (votes[0] == votes[1]) {
230 if (votes.empty()) return 0; 230#ifdef TP_BESTMOVE_CONFBIAS
231 int best = std::max_element(votes.begin(), votes.end(), 231 return -1;
232 [](const auto& v1, const auto& v2) { 232#else
233 return v1.second < v2.second; 233 static std::bernoulli_distribution tie_dist;
234 } 234 return tie_dist(rng) ? -1 : 1;
235 )->first;
236 return best;
237#endif 235#endif
236 } else return votes[0] > votes[1] ? -1 : 1;
237 return votes[0] >= votes[1] ? -1 : 1;
238} 238}
239 239
240void NameGame::update_memory(int nId, int strategy) { 240void NameGame::update_memory(int nId, int strategy) {
diff --git a/src/NameGame.h b/src/NameGame.h
index 21a58b8..0c0552e 100644
--- a/src/NameGame.h
+++ b/src/NameGame.h
@@ -15,6 +15,7 @@ public:
15 15
16 void setCMsize(int cm_size); 16 void setCMsize(int cm_size);
17 17
18 void seed(int s);
18 void initGraph(); 19 void initGraph();
19 void initMemory(); 20 void initMemory();
20 void clearRecord(); 21 void clearRecord();
@@ -26,7 +27,7 @@ public:
26 void writeRecord(const char* fname, bool append = false); 27 void writeRecord(const char* fname, bool append = false);
27 28
28protected: 29protected:
29 int best_move(int nId) const; 30 int best_move(int nId);
30 void update_memory(int nId, int strategy); 31 void update_memory(int nId, int strategy);
31 32
32private: 33private:
diff --git a/src/many-async.cc b/src/many-async.cc
index 9df475b..557c8ae 100644
--- a/src/many-async.cc
+++ b/src/many-async.cc
@@ -5,14 +5,16 @@
5 5
6#include "NameGame.h" 6#include "NameGame.h"
7 7
8constexpr int group_size = 1000, T = 100; 8constexpr int group_size = 1000, T = 200;
9constexpr int cmsize_min = 200, cmsize_max = 600; 9constexpr int cmsize_min = 200, cmsize_max = 400;
10constexpr int trials = 100; 10constexpr int trials = 100;
11constexpr int workers = 6; 11constexpr int workers = 6;
12constexpr const char* csv_file = "many-async-T200-exp.csv";
12 13
13using RunVec = std::vector<std::pair<int, int>>; 14using RunVec = std::vector<std::pair<int, int>>;
14 15
15RunVec run_trials(int cmsize_start, int cmsize_end) { 16RunVec run_trials(int cmsize_start, int cmsize_end) {
17 std::random_device seeder;
16 tp::NameGame namegame(group_size, 0, 12); 18 tp::NameGame namegame(group_size, 0, 12);
17 RunVec runs; 19 RunVec runs;
18 for (int i = cmsize_start; i < cmsize_end; ++i) { 20 for (int i = cmsize_start; i < cmsize_end; ++i) {
@@ -23,6 +25,7 @@ RunVec run_trials(int cmsize_start, int cmsize_end) {
23 int a = namegame.run(group_size * T); 25 int a = namegame.run(group_size * T);
24 runs.push_back({i, a}); 26 runs.push_back({i, a});
25 } 27 }
28 namegame.seed(seeder());
26 std::cout << "finished cmsize " << i << std::endl; 29 std::cout << "finished cmsize " << i << std::endl;
27 } 30 }
28 return runs; 31 return runs;
@@ -47,7 +50,7 @@ int main(int argc, char* argv[]) {
47 RunVec v = futs[i].get(); 50 RunVec v = futs[i].get();
48 all_runs.insert(all_runs.end(), v.begin(), v.end()); 51 all_runs.insert(all_runs.end(), v.begin(), v.end());
49 } 52 }
50 std::ofstream f("many-async.csv"); 53 std::ofstream f(csv_file);
51 if (!f) { 54 if (!f) {
52 std::cerr << "ERROR: opening many-async.csv" << std::endl; 55 std::cerr << "ERROR: opening many-async.csv" << std::endl;
53 return 1; 56 return 1;