|
155 | 155 | "gbt.nash.lcp_solve(gbt_matrix_rps_game).equilibria[0]" |
156 | 156 | ] |
157 | 157 | }, |
| 158 | + { |
| 159 | + "cell_type": "markdown", |
| 160 | + "id": "966e7e3f", |
| 161 | + "metadata": {}, |
| 162 | + "source": [ |
| 163 | + "We can use OpenSpiel's dynamics module to demonstrate evolutionary game theory dynamics, or \"replicator dynamics\", which models how strategy population frequencies change over time based on relative fitness/payoffs.\n", |
| 164 | + "\n", |
| 165 | + "Let's start with an initial population that is not at equilibrium, but weighted quite heavily towards scissors with proportions: 20% Rock, 20% Paper, 60% Scissors:" |
| 166 | + ] |
| 167 | + }, |
158 | 168 | { |
159 | 169 | "cell_type": "code", |
160 | | - "execution_count": 40, |
| 170 | + "execution_count": 62, |
161 | 171 | "id": "cf1acdeb", |
162 | 172 | "metadata": {}, |
163 | 173 | "outputs": [ |
|
167 | 177 | "array([ 0.08, -0.08, 0. ])" |
168 | 178 | ] |
169 | 179 | }, |
170 | | - "execution_count": 40, |
| 180 | + "execution_count": 62, |
171 | 181 | "metadata": {}, |
172 | 182 | "output_type": "execute_result" |
173 | 183 | } |
174 | 184 | ], |
175 | 185 | "source": [ |
176 | 186 | "dyn = dynamics.SinglePopulationDynamics(matrix_rps_payoffs, dynamics.replicator)\n", |
177 | | - "x = np.array([0.2, 0.2, 0.6]) # population heavily-weighted toward scissors\n", |
| 187 | + "x = np.array([0.2, 0.2, 0.6])\n", |
178 | 188 | "dyn(x)" |
179 | 189 | ] |
180 | 190 | }, |
| 191 | + { |
| 192 | + "cell_type": "markdown", |
| 193 | + "id": "fa382753", |
| 194 | + "metadata": {}, |
| 195 | + "source": [ |
| 196 | + "`dyn(x)` calculates the rate of change (derivative) for each strategy in the current population state and returns how fast each strategy's frequency is changing.\n", |
| 197 | + "\n", |
| 198 | + "In replicator dynamics, strategies that perform better than average will increase in frequency, while strategies performing worse will decrease. Since Scissors beats Paper but loses to Rock, and this population has few Rock players, we'd expect:\n", |
| 199 | + "\n", |
| 200 | + "- Scissors frequency might decrease (vulnerable to Rock)\n", |
| 201 | + "- Rock frequency might increase (beats the abundant Scissors)\n", |
| 202 | + "- Paper frequency might decrease (loses to abundant Scissors)\n", |
| 203 | + "\n", |
| 204 | + "This is part of the evolutionary path toward the Nash equilibrium where all three strategies have equal frequency (1/3 each) in Rock-Paper-Scissors." |
| 205 | + ] |
| 206 | + }, |
| 207 | + { |
| 208 | + "cell_type": "code", |
| 209 | + "execution_count": 80, |
| 210 | + "id": "b9a352c5", |
| 211 | + "metadata": {}, |
| 212 | + "outputs": [ |
| 213 | + { |
| 214 | + "name": "stdout", |
| 215 | + "output_type": "stream", |
| 216 | + "text": [ |
| 217 | + "[0.17411743 0.45787641 0.36800616]\n" |
| 218 | + ] |
| 219 | + } |
| 220 | + ], |
| 221 | + "source": [ |
| 222 | + "x = np.array([0.25, 0.25, 0.5])\n", |
| 223 | + "alpha = 0.01\n", |
| 224 | + "for i in range(10000):\n", |
| 225 | + " x += alpha * dyn(x)\n", |
| 226 | + "print(x)" |
| 227 | + ] |
| 228 | + }, |
181 | 229 | { |
182 | 230 | "cell_type": "markdown", |
183 | 231 | "metadata": {}, |
|
0 commit comments