diff options
| author | Aiden Woodruff <woodra@rpi.edu> | 2025-12-12 23:48:39 -0500 |
|---|---|---|
| committer | Aiden Woodruff <woodra@rpi.edu> | 2025-12-12 23:48:39 -0500 |
| commit | c0268db7865553ceece33d0ebc9a4b03bbbd0633 (patch) | |
| tree | a45724fa743756de5b78396639a0d1212e8ff0d9 /src | |
| parent | 275e94d023a7be698e9fc2f0d37dcf889e6a1b62 (diff) | |
| download | tipping-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.cc | 50 | ||||
| -rw-r--r-- | src/NameGame.h | 3 | ||||
| -rw-r--r-- | src/many-async.cc | 9 |
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 | ||
| 91 | void NameGame::seed(int s) { | ||
| 92 | rng.seed(s); | ||
| 93 | } | ||
| 94 | |||
| 91 | void NameGame::setCMsize(int cm_size) { | 95 | void 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 |
| 196 | float weight(int i) { | 200 | float 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 | ||
| 207 | int NameGame::best_move(int nId) const { | 211 | #undef TP_BESTMOVE_CONFBIAS |
| 212 | int 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 | ||
| 240 | void NameGame::update_memory(int nId, int strategy) { | 240 | void 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 | ||
| 28 | protected: | 29 | protected: |
| 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 | ||
| 32 | private: | 33 | private: |
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 | ||
| 8 | constexpr int group_size = 1000, T = 100; | 8 | constexpr int group_size = 1000, T = 200; |
| 9 | constexpr int cmsize_min = 200, cmsize_max = 600; | 9 | constexpr int cmsize_min = 200, cmsize_max = 400; |
| 10 | constexpr int trials = 100; | 10 | constexpr int trials = 100; |
| 11 | constexpr int workers = 6; | 11 | constexpr int workers = 6; |
| 12 | constexpr const char* csv_file = "many-async-T200-exp.csv"; | ||
| 12 | 13 | ||
| 13 | using RunVec = std::vector<std::pair<int, int>>; | 14 | using RunVec = std::vector<std::pair<int, int>>; |
| 14 | 15 | ||
| 15 | RunVec run_trials(int cmsize_start, int cmsize_end) { | 16 | RunVec 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; |
