Please help to optimize my python code, I wrote this JS code and tried to convert it to python that I need the execution time comparable to the original code.
The original code follows for-loop in JS, I transferred the code literally by using pure python and numpy but I didn’t optimize it well resulting in poor execution time and memory usage.
This code calculates a preset enemy vs player power with +-10% difference and do a random roll then get the player winrate. The target is to set the HERO_POWER or ENEMY_POWER atleast in 100000-300000 range.
''' ##winchance.js## Original code var h = 0 var g = 0 var i = char_power var l = i*.9 var u = enemy_power * 1.1 var d = enemy_power * .9 for (let e = Math.floor(l); e <= i; e++) for (let t = Math.floor(d); t <= u; t++) e >= t ? h++ : g++ var z = h / (h + g)*100; return z } var out = combat_simulate(parseInt(arguments[2]),parseInt(arguments[3])) console.log(out) ''' import subprocess,itertools,math import numpy as np def calc_iter(array): w=0 l=0 for x,y in array: if x >= y: w +=1 else: l +=1 return w,l ###inputs### HERO_POWER=120000 ENEMY_POWER=110000 w=0 l=0 h_l = HERO_POWER * .9 e_h = ENEMY_POWER * 1.1 e_l = ENEMY_POWER * .9 hp = np.arange(math.floor(h_l),math.floor(HERO_POWER)) ep = np.arange(math.floor(e_l),math.floor(e_h)) print('process using itertools') start_time = time.time() array = itertools.product(hp,ep) w,l = calc_iter(array) print('win rate:{}%'.format(round((w/(w+l))*100,2))) end_time = time.time() print('time elapsed',end_time-start_time) print() print('process using numpy') start_time = time.time() x,y = np.meshgrid(hp,ep) n = x>y w,l = (np.count_nonzero(n),np.count_nonzero(n==0)) print('win rate:{}%'.format(round((w/(w+l))*100,2))) end_time = time.time() print('time elapsed',end_time-start_time) print() print('process using nodejs') start_time = time.time() result = subprocess.run('node winchance.js {} {}'.format(HERO_POWER,ENEMY_POWER),capture_output=True,text=True) print('win rate:{}%'.format(round(float(result.stdout),2))) end_time = time.time() print('time elapsed',end_time-start_time) ######################################## process using itertools win rate:68.18% time elapsed 30.484147787094116 process using numpy win rate:68.18% time elapsed 2.0294463634490967 process using nodejs win rate:68.18% time elapsed 0.799668550491333
Advertisement
Answer
upon searching the web, I tried to translate the python function code using ‘numba’ and it shows faster execution with no additional thing to do on my end in this context.
import math import numpy as np import time import subprocess import os from numba import njit hero_power_list = [120000,130000,140000] enemy_power_list = [110000,121000,131000] @njit def calc_iter_1(array1,array2): w=0 l=0 for x in array1: for y in array2: if x >= y: w +=1 else: l +=1 return w,l print('process using numba') for x in range(len(hero_power_list)): h_l = hero_power_list[x] * .9 e_h = enemy_power_list[x] * 1.1 e_l = enemy_power_list[x] * .9 hp = np.arange(math.floor(h_l),math.floor(hero_power_list[x])) ep = np.arange(math.floor(e_l),math.floor(e_h)) start_time = time.perf_counter() w,l = calc_iter_1(hp,ep) # print('win rate:{}%'.format(round((w/(w+l))*100,2))) end_time = time.perf_counter() print('time elapsed:',round(end_time-start_time,2),'sec(s)') print() print('process using nodejs') for x in range(len(hero_power_list)): HERO_POWER = hero_power_list[x] ENEMY_POWER = enemy_power_list[x] start_time = time.perf_counter() result = subprocess.run('node winchance.js {} {}'.format(HERO_POWER,ENEMY_POWER),capture_output=True,text=True) # print('win rate:{}%'.format(round(float(result.stdout),2))) end_time = time.perf_counter() print('time elapsed:',round(end_time-start_time,2),'sec(s)') ######################################## process using numba time elapsed: 0.87 sec(s) time elapsed: 0.43 sec(s) time elapsed: 0.52 sec(s) process using nodejs time elapsed: 0.81 sec(s) time elapsed: 1.07 sec(s) time elapsed: 1.1 sec(s)