-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
⚡️ Speed up method PolymatrixGame.range_of_payoffs by 1,749%
#812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
⚡️ Speed up method PolymatrixGame.range_of_payoffs by 1,749%
#812
Conversation
The optimization replaces the inefficient double-pass approach in `range_of_payoffs()` with a single-pass vectorized operation using NumPy. **Key changes:** - **Original approach**: Two separate list comprehensions calling `min([np.min(M) for M in ...])` and `max([np.max(M) for M in ...])`, which iterate through all matrices twice and involve Python's built-in `min`/`max` functions on a list of scalar values. - **Optimized approach**: Single concatenation of all flattened matrices using `np.concatenate([M.ravel() for M in ...])`, then applying `np.min()` and `np.max()` directly on the combined array. **Why this is faster:** - **Eliminates redundant iterations**: Instead of scanning all matrices twice (once for min, once for max), we flatten and concatenate once, then perform both min/max operations on the same contiguous array. - **Vectorized operations**: NumPy's `min` and `max` functions are highly optimized C implementations that operate on contiguous memory, compared to Python's built-in functions working on lists. - **Reduces function call overhead**: The original code calls `np.min()` once per matrix, while the optimized version calls it once total. **Performance characteristics:** The optimization shows dramatic speedup especially for larger games - achieving **651% to 2010% improvements** on large-scale test cases with many players/matchups, while maintaining **9-30% improvements** on smaller cases. The single-pass approach scales much better as the number of matrices increases.
|
@misrasaurabh1 Thanks for your contribution. For this PR, the line An alternative approach is to use Numba with explicit loops (even for obtaining the max and the min) over the Dict (which has to be converted to a Numba typed Dict). |
|
I agree the concatenation will use more memory, even though ravel helps here reduce it. We currently don't measure memory unfortunately. Although the speedup achieved is a lot. I'll leave it to your judgement |
|
Hi @oyamad, can i ask you for a resolution on this PR? I would recommend accepting the changes since the performance gains are so large. |
|
@misrasaurabh1 Here's an "alternative approach" that uses Numba: 66c4037 Sample timing on my machine: import quantecon.game_theory as gt
seed = 123
N = 100
M = 2
pmg = gt.random_polymatrix_game((M,)*N, random_state=seed)
%timeit pmg.range_of_payoffs()
|
|
awesome! these gains look great. I will look into how I can make codeflash automatically convert code to use numba. |
📄 1,749% (17.49x) speedup for
PolymatrixGame.range_of_payoffsinquantecon/game_theory/polymatrix_game.py⏱️ Runtime :
3.83 seconds→207 milliseconds(best of5runs)📝 Explanation and details
The optimization replaces the inefficient double-pass approach in
range_of_payoffs()with a single-pass vectorized operation using NumPy.Key changes:
min([np.min(M) for M in ...])andmax([np.max(M) for M in ...]), which iterate through all matrices twice and involve Python's built-inmin/maxfunctions on a list of scalar values.np.concatenate([M.ravel() for M in ...]), then applyingnp.min()andnp.max()directly on the combined array.Why this is faster:
minandmaxfunctions are highly optimized C implementations that operate on contiguous memory, compared to Python's built-in functions working on lists.np.min()once per matrix, while the optimized version calls it once total.Performance characteristics:
The optimization shows dramatic speedup especially for larger games - achieving 651% to 2010% improvements on large-scale test cases with many players/matchups, while maintaining 9-30% improvements on smaller cases. The single-pass approach scales much better as the number of matrices increases.
✅ Correctness verification report:
🌀 Generated Regression Tests and Runtime
To edit these changes
git checkout codeflash/optimize-PolymatrixGame.range_of_payoffs-mgh46ignand push.