You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Could numba provide speed up? Isolated the core calcs, applied numba, and got roughly 7x speed compared to vanilla.
EVALUATING 1070190 scenarios with Numba...
WIN 38.40% | TIE 2.41% | LOS 59.19%
elapsed_numba: 589.950 ms
Numba: 1814037 evals per second
EVALUATING 1070190 scenarios with Vanilla...
WIN 38.40% | TIE 2.41% | LOS 59.19%
elapsed: 4185.983 ms
Vanilla: 255660 evals per second
Numba is 7.10x faster
Here is minimum reproducible example code. It is not as flexible for variety of input like original, but demonstrate the key speed.
import numpy as np
from numba import jit
from phevaluator.tables import (BINARIES_BY_ID, DP, FLUSH,
NO_FLUSH_5, NO_FLUSH_6, NO_FLUSH_7,
SUITBIT_BY_ID, SUITS,)
BINARIES_BY_ID_arr = np.array(BINARIES_BY_ID) #default int32
FLUSH_arr = np.array(FLUSH )
NO_FLUSH_5_arr = np.array(NO_FLUSH_5 )
NO_FLUSH_6_arr = np.array(NO_FLUSH_6 )
NO_FLUSH_7_arr = np.array(NO_FLUSH_7 )
SUITBIT_BY_ID_arr = np.array(SUITBIT_BY_ID )
SUITS_arr = np.array(SUITS )
DP_arr = np.array(DP )
@jit(nopython=True)
def numba_evaluate_cards(*cards):
hand_size = num_cards = len(cards)
if (hand_size == 7): #numba doesnt like dicts (make array?)
noflush = NO_FLUSH_7_arr
elif (hand_size == 5):
noflush = NO_FLUSH_5_arr
elif (hand_size == 6):
noflush = NO_FLUSH_6_arr
else:
raise ValueError #size not 567
#### DETERMINE FLUSH
suit_hash = 0
for card in cards:
suit_hash += SUITBIT_BY_ID_arr[card]
flush_suit = SUITS_arr[suit_hash] - 1
if flush_suit != -1:
hand_binary = 0
for card in cards:
if card % 4 == flush_suit:
hand_binary |= BINARIES_BY_ID_arr[card]
return FLUSH_arr[hand_binary]
#### DETERMINE NON-FLUSH
hand_quinary = [0,0,0,0,0,0,0,0,0,0,0,0,0] #hardcode [0]*13
for card in cards:
hand_quinary[card // 4] += 1
sum_numb = 0
for rank, cnt in enumerate(hand_quinary):
if cnt:
sum_numb += DP_arr[cnt][13 - rank - 1][num_cards] #hardcode 13
num_cards -= cnt
return noflush[sum_numb]
#### COMPILE IT BY RUNNING
# 2c, 5d, Ts, Js, Qs, Ks, As (ROYAL FLUSH, rank 1)
print(numba_evaluate_cards(0,13,35,39,43,47,51))
if "__main__" in __name__:
from phevaluator import evaluate_cards
from itertools import combinations
from collections import defaultdict
from math import comb
import random
import time
def print_win_tie_los(mine_them_D):
wtlD = {'WIN': 0, 'TIE': 0, 'LOS': 0,}
for mine_rank, thems in mine_them_D.items():
for them_rank in thems:
if mine_rank > them_rank:
wtlD['LOS'] += 1
elif mine_rank == them_rank:
wtlD['TIE'] += 1
else: #mine_rank < them_rank:
wtlD['WIN'] += 1
print(f"WIN {wtlD['WIN'] / sum(wtlD.values()):6.2%}",
f"TIE {wtlD['TIE'] / sum(wtlD.values()):6.2%}",
f"LOS {wtlD['LOS'] / sum(wtlD.values()):6.2%}",
sep=" | ")
def calc_post_flop(game_deck, unknown,
mine, flop, turn, rivr,
func=numba_evaluate_cards):
birth = time.perf_counter()
mine_them_D = defaultdict(list)
for comm_idxs in combinations(game_deck, unknown):
community = comm_idxs + flop + turn + rivr
mine_rank = func(*(mine + community))
for x in comm_idxs:
game_deck.remove(x)
for them in combinations(game_deck, 2):
them_rank = func(*(them + community))
mine_them_D[mine_rank].append(them_rank)
game_deck += comm_idxs
elapsed = time.perf_counter() - birth
return elapsed, mine_them_D
#### SETUP BASIC GAME
randcards = random.sample(range(52), k=5)
mine = tuple(randcards[0:2])
flop = tuple(randcards[2:5])
turn = tuple(randcards[5:6]) if randcards[5:6] else tuple()
rivr = tuple(randcards[6:7]) if randcards[6:7] else tuple()
game_deck = list(range(52))
for x in randcards:
game_deck.remove(x)
unknown = 7 - len(randcards) #7 for texas
n_scenarios = (comb(len(game_deck), unknown) *
comb(len(game_deck) - unknown, 2))
#### NUMBA EVAL FAST
print(f"EVALUATING {n_scenarios} scenarios with Numba...")
elapsed_numba, mine_them_D = calc_post_flop(game_deck, unknown,
mine, flop, turn, rivr,
func=numba_evaluate_cards)
print_win_tie_los(mine_them_D)
print(f"elapsed_numba: {1e3*elapsed_numba:.3f} ms")
print(f"Numba: {n_scenarios / elapsed_numba:.0f} evals per second")
#### VANILLA EVAL
print(f"\n\nEVALUATING {n_scenarios} scenarios with Vanilla...")
elapsed, mine_them_D = calc_post_flop(game_deck, unknown,
mine, flop, turn, rivr,
func=evaluate_cards)
print_win_tie_los(mine_them_D)
print(f"elapsed: {1e3*elapsed:.3f} ms")
print(f"Vanilla: {n_scenarios / elapsed:.0f} evals per second")
print(f"\n\n Numba is {elapsed / elapsed_numba:.2f}x faster")
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Could
numba
provide speed up? Isolated the core calcs, applied numba, and got roughly 7x speed compared to vanilla.Here is minimum reproducible example code. It is not as flexible for variety of input like original, but demonstrate the key speed.
Beta Was this translation helpful? Give feedback.
All reactions