diff options
| author | Aiden Woodruff <woodra@rpi.edu> | 2025-11-27 00:45:06 -0500 |
|---|---|---|
| committer | Aiden Woodruff <woodra@rpi.edu> | 2025-11-27 00:45:06 -0500 |
| commit | 779ef216d71c12ba3f7ef6cfee67bcaccb3293e9 (patch) | |
| tree | 6c2abff0868f037c9cfc1f8c5f5d80c02e1f593f | |
| parent | f5015c2cd0eb4a2eedf21baa0921eeb90e8abf94 (diff) | |
| download | tipping-points-779ef216d71c12ba3f7ef6cfee67bcaccb3293e9.tar.gz tipping-points-779ef216d71c12ba3f7ef6cfee67bcaccb3293e9.tar.bz2 tipping-points-779ef216d71c12ba3f7ef6cfee67bcaccb3293e9.zip | |
optimizing many
- src/NameGame.h: update network to use linked list for memory (given
macro). seems to provide ~2x speedup.
- src/NameGame.cc: add iterator for TLst type.
- add copy constructor and copy assignment operator for TLst that are
not defined by the SNAP library.
- add TP_BESTMOVE_STATIC to use static array for voting to speed up
best_move by ~2x.
- add conditional logic in places to allow for A/B testing.
- based off testing I can get ~4x total improvement so I think I will
make both of these permanent (except maybe leaving in the old
unoptimized code in case I want to add multiple strategies).
- TASKS.md: update tasks.
Signed-off-by: Aiden Woodruff <woodra@rpi.edu>
| -rw-r--r-- | TASKS.md | 2 | ||||
| -rw-r--r-- | src/NameGame.cc | 76 | ||||
| -rw-r--r-- | src/NameGame.h | 9 |
3 files changed, 83 insertions, 4 deletions
| @@ -3,8 +3,6 @@ | |||
| 3 | ## To do | 3 | ## To do |
| 4 | 4 | ||
| 5 | - Profiling/optimizing `many`. | 5 | - Profiling/optimizing `many`. |
| 6 | - Use static array for best_move. | ||
| 7 | - Use SNAP list for memory. | ||
| 8 | - Divide and conquer multithreading. | 6 | - Divide and conquer multithreading. |
| 9 | - Vary strategy selection behavior. | 7 | - Vary strategy selection behavior. |
| 10 | - $exp(-i)$ weighting for memory? | 8 | - $exp(-i)$ weighting for memory? |
diff --git a/src/NameGame.cc b/src/NameGame.cc index 1454862..ed56f09 100644 --- a/src/NameGame.cc +++ b/src/NameGame.cc | |||
| @@ -2,12 +2,61 @@ | |||
| 2 | #include <fstream> | 2 | #include <fstream> |
| 3 | #include <iomanip> | 3 | #include <iomanip> |
| 4 | #include <iostream> | 4 | #include <iostream> |
| 5 | #define TP_BESTMOVE_STATIC | ||
| 6 | #ifndef TP_BESTMOVE_STATIC | ||
| 5 | #include <map> | 7 | #include <map> |
| 8 | #endif | ||
| 6 | #include <stdexcept> | 9 | #include <stdexcept> |
| 7 | #include <vector> | 10 | #include <vector> |
| 8 | 11 | ||
| 9 | #include "NameGame.h" | 12 | #include "NameGame.h" |
| 10 | 13 | ||
| 14 | #ifdef TP_MEMLIST | ||
| 15 | template<typename TVal> | ||
| 16 | class TLstIter { | ||
| 17 | public: | ||
| 18 | TLstIter(typename TLst<TVal>::PLstNd nd_) : nd(nd_) {} | ||
| 19 | const TVal& operator*() const { | ||
| 20 | return nd->GetVal(); | ||
| 21 | } | ||
| 22 | TVal& operator*() { | ||
| 23 | return nd->GetVal(); | ||
| 24 | } | ||
| 25 | TLstIter<TVal>& operator++() { | ||
| 26 | nd = nd->Next(); | ||
| 27 | return *this; | ||
| 28 | } | ||
| 29 | bool operator==(const TLstIter<TVal>& rhs) const { | ||
| 30 | return nd == rhs.nd; | ||
| 31 | } | ||
| 32 | private: | ||
| 33 | typename TLst<TVal>::PLstNd nd; | ||
| 34 | }; | ||
| 35 | |||
| 36 | template<typename TVal> | ||
| 37 | TLstIter<TVal> begin(const TLst<TVal>& l) { | ||
| 38 | return TLstIter<TVal>(l.First()); | ||
| 39 | } | ||
| 40 | |||
| 41 | template<typename TVal> | ||
| 42 | TLstIter<TVal> end(const TLst<TVal>& l) { | ||
| 43 | return TLstIter<TVal>(nullptr); | ||
| 44 | } | ||
| 45 | |||
| 46 | template<typename TVal> | ||
| 47 | TLst<TVal>::TLst(const TLst<TVal>& l) : TLst() { | ||
| 48 | for (const auto& val : l) AddBack(val); | ||
| 49 | } | ||
| 50 | |||
| 51 | template<typename TVal> | ||
| 52 | TLst<TVal>& TLst<TVal>::operator=(const TLst<TVal>& l) { | ||
| 53 | if (this != &l) { | ||
| 54 | Clr(); | ||
| 55 | for (const auto& val : l) AddBack(val); | ||
| 56 | } | ||
| 57 | return *this; | ||
| 58 | } | ||
| 59 | #else | ||
| 11 | template<typename TVal, typename TSizeTy> | 60 | template<typename TVal, typename TSizeTy> |
| 12 | auto begin(const TVec<TVal, TSizeTy>& v) -> decltype(v.BegI()) { | 61 | auto begin(const TVec<TVal, TSizeTy>& v) -> decltype(v.BegI()) { |
| 13 | return v.BegI(); | 62 | return v.BegI(); |
| @@ -17,6 +66,7 @@ template<typename TVal, typename TSizeTy> | |||
| 17 | auto end(const TVec<TVal, TSizeTy>& v) -> decltype(v.EndI()) { | 66 | auto end(const TVec<TVal, TSizeTy>& v) -> decltype(v.EndI()) { |
| 18 | return v.EndI(); | 67 | return v.EndI(); |
| 19 | } | 68 | } |
| 69 | #endif | ||
| 20 | 70 | ||
| 21 | namespace tp { | 71 | namespace tp { |
| 22 | 72 | ||
| @@ -61,7 +111,11 @@ void NameGame::initMemory() { | |||
| 61 | auto& rDat = graph.GetNDat(rId); | 111 | auto& rDat = graph.GetNDat(rId); |
| 62 | rDat.Val1 = true; | 112 | rDat.Val1 = true; |
| 63 | rDat.Val2.Clr(); | 113 | rDat.Val2.Clr(); |
| 114 | #ifdef TP_MEMLIST | ||
| 115 | rDat.Val2.AddFront(1); | ||
| 116 | #else | ||
| 64 | rDat.Val2.Add(1); | 117 | rDat.Val2.Add(1); |
| 118 | #endif | ||
| 65 | ids.erase(ids.begin() + r); | 119 | ids.erase(ids.begin() + r); |
| 66 | } | 120 | } |
| 67 | // Establish norm (fully memory of strategy 1) for remaining nodes. | 121 | // Establish norm (fully memory of strategy 1) for remaining nodes. |
| @@ -69,7 +123,13 @@ void NameGame::initMemory() { | |||
| 69 | auto& d = graph.GetNDat(id); | 123 | auto& d = graph.GetNDat(id); |
| 70 | d.Val1 = false; | 124 | d.Val1 = false; |
| 71 | d.Val2.Clr(); | 125 | d.Val2.Clr(); |
| 72 | while (d.Val2.Len() < memlen) d.Val2.Add(-1); | 126 | while (d.Val2.Len() < memlen) { |
| 127 | #ifdef TP_MEMLIST | ||
| 128 | d.Val2.AddFront(-1); | ||
| 129 | #else | ||
| 130 | d.Val2.Add(-1); | ||
| 131 | #endif | ||
| 132 | } | ||
| 73 | } | 133 | } |
| 74 | } | 134 | } |
| 75 | 135 | ||
| @@ -135,6 +195,14 @@ float weight(int i) { | |||
| 135 | 195 | ||
| 136 | int NameGame::best_move(int nId) const { | 196 | int NameGame::best_move(int nId) const { |
| 137 | const auto& mem = graph.GetNDat(nId).Val2; | 197 | const auto& mem = graph.GetNDat(nId).Val2; |
| 198 | #ifdef TP_BESTMOVE_STATIC | ||
| 199 | int votes[2] = {0, 0}; | ||
| 200 | for (const auto& strategy : mem) { | ||
| 201 | if (strategy == -1) votes[0]++; | ||
| 202 | else votes[1]++; | ||
| 203 | } | ||
| 204 | return votes[0] > votes[1] ? -1 : 1; | ||
| 205 | #else | ||
| 138 | #ifdef USE_EXP_WEIGHT | 206 | #ifdef USE_EXP_WEIGHT |
| 139 | std::map<int, float> votes; | 207 | std::map<int, float> votes; |
| 140 | for (int i = 0; i < mem.Len(); ++i) { | 208 | for (int i = 0; i < mem.Len(); ++i) { |
| @@ -155,13 +223,19 @@ int NameGame::best_move(int nId) const { | |||
| 155 | } | 223 | } |
| 156 | )->first; | 224 | )->first; |
| 157 | return best; | 225 | return best; |
| 226 | #endif | ||
| 158 | } | 227 | } |
| 159 | 228 | ||
| 160 | void NameGame::update_memory(int nId, int strategy) { | 229 | void NameGame::update_memory(int nId, int strategy) { |
| 161 | auto& d = graph.GetNDat(nId); | 230 | auto& d = graph.GetNDat(nId); |
| 162 | if (!d.Val1) { | 231 | if (!d.Val1) { |
| 232 | #ifdef TP_MEMLIST | ||
| 233 | d.Val2.AddFront(strategy); | ||
| 234 | d.Val2.DelLast(); | ||
| 235 | #else | ||
| 163 | d.Val2.Ins(0, strategy); | 236 | d.Val2.Ins(0, strategy); |
| 164 | d.Val2.Trunc(memlen); | 237 | d.Val2.Trunc(memlen); |
| 238 | #endif | ||
| 165 | } | 239 | } |
| 166 | } | 240 | } |
| 167 | 241 | ||
diff --git a/src/NameGame.h b/src/NameGame.h index 0b02a15..21a58b8 100644 --- a/src/NameGame.h +++ b/src/NameGame.h | |||
| @@ -34,7 +34,14 @@ private: | |||
| 34 | int gsize, cmsize, memlen; | 34 | int gsize, cmsize, memlen; |
| 35 | std::mt19937 rng; | 35 | std::mt19937 rng; |
| 36 | std::uniform_int_distribution<> dist; | 36 | std::uniform_int_distribution<> dist; |
| 37 | TNodeNet<TPair<TBool, TIntV>> graph; | 37 | TNodeNet<TPair< |
| 38 | TBool, | ||
| 39 | #ifdef TP_MEMLIST | ||
| 40 | TIntL | ||
| 41 | #else | ||
| 42 | TIntV | ||
| 43 | #endif | ||
| 44 | >> graph; | ||
| 38 | struct Record { | 45 | struct Record { |
| 39 | int round, speaker, committed, strategy; | 46 | int round, speaker, committed, strategy; |
| 40 | }; | 47 | }; |
