⚡️ Speed up function pure_nash_brute by 104%#106
Open
codeflash-ai[bot] wants to merge 1 commit intomainfrom
Open
⚡️ Speed up function pure_nash_brute by 104%#106codeflash-ai[bot] wants to merge 1 commit intomainfrom
pure_nash_brute by 104%#106codeflash-ai[bot] wants to merge 1 commit intomainfrom
Conversation
The optimized code achieves a **104% speedup** (9.67ms → 4.74ms) by **inlining the Nash equilibrium check** instead of calling `g.is_nash()` for every action profile. ## Key Optimizations **1. Direct payoff array access** - Original: Calls `g.is_nash(a, tol=tol)` which internally calls `player.is_best_response()` for each player - Optimized: Directly accesses `g.payoff_profile_array` and performs vectorized NumPy operations - **Impact**: Eliminates multiple method call overheads (~88% of original runtime was in `g.is_nash()`) **2. Pre-computed tolerances** - Moved tolerance lookup (`player.tol` attribute access) outside the main loop - For games with many action profiles to check (e.g., 1,438 iterations in the line profiler), this avoids thousands of repeated attribute accesses **3. Early termination with break** - When a player finds a better response, immediately sets `is_nash = False` and breaks out of the player loop - Avoids checking remaining players once we know it's not a Nash equilibrium ## Performance Analysis From the line profiler data: - Original: 33.4ms spent in `g.is_nash()` calls (88.2% of generator time) - Optimized: Direct array operations distributed across multiple lines, with the most expensive being `payoffs.max()` at 5.5ms (35% of generator time) - The optimization transforms O(N) method calls per action profile into direct array indexing ## Test Case Performance The optimization performs consistently well across all test cases: - **20-46% faster** on 2-player games (Prisoners' Dilemma, Coordination, Battle of Sexes) - **96.6% faster** on 3-player games where the method call overhead compounds with more players - Best gains on games with more actions (Rock-Paper-Scissors: 46.5% faster with 3×3 actions) ## Impact on Workloads Based on `function_references`, this function is used in: 1. **Unit tests for game generators** - checking that generated games have expected Nash equilibria properties 2. **Tolerance-based equilibrium detection** - finding epsilon-Nash equilibria with varying tolerance levels The optimization is particularly beneficial when: - Checking many games in test suites or Monte Carlo simulations - Games have larger action spaces (combinatorial explosion means more `is_nash` checks) - Multi-player games (N ≥ 3) where the overhead multiplies with each player check
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📄 104% (1.04x) speedup for
pure_nash_bruteinquantecon/game_theory/pure_nash.py⏱️ Runtime :
9.67 milliseconds→4.74 milliseconds(best of116runs)📝 Explanation and details
The optimized code achieves a 104% speedup (9.67ms → 4.74ms) by inlining the Nash equilibrium check instead of calling
g.is_nash()for every action profile.Key Optimizations
1. Direct payoff array access
g.is_nash(a, tol=tol)which internally callsplayer.is_best_response()for each playerg.payoff_profile_arrayand performs vectorized NumPy operationsg.is_nash())2. Pre-computed tolerances
player.tolattribute access) outside the main loop3. Early termination with break
is_nash = Falseand breaks out of the player loopPerformance Analysis
From the line profiler data:
g.is_nash()calls (88.2% of generator time)payoffs.max()at 5.5ms (35% of generator time)Test Case Performance
The optimization performs consistently well across all test cases:
Impact on Workloads
Based on
function_references, this function is used in:The optimization is particularly beneficial when:
is_nashchecks)✅ Correctness verification report:
🌀 Click to see Generated Regression Tests
To edit these changes
git checkout codeflash/optimize-pure_nash_brute-mkp2t49land push.