Firstly lets get your code to be a little cleaner:
You can use statistics.mean rather than make my_mean.
You should use a for loop rather than a while loop in monte_carlo.
You don't need to do assign n_emperer at all in the function.
Exp and D should be lower_snake_case. This is as they are functions and variables.
You should put spaces around all operators.
There should be a space after commas.
You should have some better names day_list could just be days, D could also be something like days, summ can be total, iters could be amounts.
You can just use all(day_list) rather than all((d == 1 for d in day_list)).
Do not use == to compare to singletons like False. It would be better if you instead use not.
This doesn't check if both of the values are 1 it checks if the first is truthy and the second is one. This means if you set day_list[index - 1] to two it'd still be true.
day_list[ind - 1] and day_list[ind + 1] == 1
To check they are both equal to one you shoud use:
day_list[ind - 1] == 1 and day_list[ind + 1] == 1
Here I would instead just check if they are truthy.
You don't need if ind == 0: as if ind is 0 then ind - 1 will be -1.
You can just use (ind + 1) % len(days) to remove the need for elif index == len(days)-1:.
import random
import statistics
def simulate(days_in_year):
days = [0] * days_in_year
emperors = 0
while not all(days):
days[random.randint(0, len(days))] = 1
emperors += 1
for index, value in enumerate(days):
if value:
continue
if days[index - 1] and days[(index + 1) % len(days)]:
days[index] = 1
return emperors
def monte_carlo(amount, days):
for _ in range(amount):
yield simulate(days)
print(statistics.mean(monte_carlo(amount, days)))
Now that the code is nice and small we can focus on what is causing performance issues.
The following runs in \$O(n)\$ time, where \$n\$ is the length of days. This means worst case it will run however long days is each time you call it.
while not all(days):
We can do better than that by adding a variable in that increments each time we change a 0 to a 1. We can then compare that to days_in_year to see if the list is full. This will run in \$O(1)\$ time causing a significant saving.
If a new emperor is born on an already existing holiday then no extra holidays will be made.
When a new emperor is born you don't need to check whether each zero can be changed, you instead only need to check two. This will cut another \$O(n)\$ operation to \$O(1)\$.
Say we have the following as days:
0123456
1000010
If the new birthday is:
6 - Because both 5 and 0 are already 1s no additional holidays can be made.
3 - Because 4 is a 0 and 5 is a 1, 4 can become a 1. Because 2 is a 0 but 1 is a 0 then 3 cannot become a 1.
This cannot propagate outwards.