This is a python program that does some sort of simulation,, I am looking for any type of optimization while keeping the same p[i] form, I have tried Pypy and I got an around 3x performance gain over python. Any suggestions are welcomed
import random
from time import perf_counter
infected, non_infected = 1, 99999
infectation_chance, infection_days, death_chance = 1/100, 2/1000, 2/100
population, population_list = infected non_infected, non_infected * [0] infected * [1]
place = 10
p = {i: [] for i in range(1,place 1)}
day = 1
simulation_duration = 3
while 0 < simulation_duration:
print(f"Working on day {day}..")
time1 = perf_counter()
for person in population_list:
p[random.randint(1, place)].append(person)
time2 = perf_counter()
i = 0
while i < place:
tl = []
i = 1
for crowd in p[i]:
if crowd == 0:
if (random.random() < infectation_chance * str(p[i]).count("1")) - (infectation_chance/100 * str(p[i]).count("0")):
tl.append(1)
else:
tl.append(0)
if crowd == 1:
tl.append(1)
p[i] = tl
i = 0
population_list = []
while i < place:
i = 1
population_list.append(p[i])
simulation_duration -= 1
day = 1
print(f"Total time: {perf_counter() - time1} \nInfection time: {perf_counter() - time2} \nPlacing time: {time2-time1}")
print(str(population_list).count("1"), str(population_list).count("0"))
CodePudding user response:
here is a corrected version in pure python, commented because there were some bugs. your major time loss was counting infected/non-infected inside the for loop, though the result is always the same. it could be optimized again with numpy if you wanna use a bigger population
import random
from time import perf_counter
infected, non_infected = 1, 99999
infectation_chance, infection_days, death_chance = 1/100, 2/1000, 2/100
population, population_list = infected non_infected, non_infected * [0] infected * [1]
place = 10
day = 1
simulation_duration = 3
while 0 < simulation_duration:
# p must be reset here or it will grow indefinitely
p = {i: [] for i in range(1,place 1)}
print(f"Working on day {day}..")
time1 = perf_counter()
for person in population_list:
p[random.randint(1, place)].append(person)
time2 = perf_counter()
i = 0
while i < place:
i = 1
# if you need to, count infected/non-infected here
# not in your for loop where it has always the same value
# and don't cast to str, what's the point?
# pi_infected = p[i].count(1)
# pi_sane = p[i].count(0)
for j, crowd in enumerate(p[i]):
if crowd == 0:
# your formula was broken (a-b is always true)
# i used a generic one
if random.random()>(1-infectation_chance):
# change your list in place:
# no need for temp list, save lots of cycles
p[i][j] = 1
i = 0
population_list = []
while i < place:
i = 1
# it's extend, not append here or your population list
# will have a length of #place
population_list.extend(p[i])
simulation_duration -= 1
day = 1
print(f"Total time: {perf_counter() - time1} \nInfection time: {perf_counter() - time2} \nPlacing time: {time2-time1}")
print(population_list.count(1), population_list.count(0))