0

I am trying to run a simulation where ı have n balls and wants to put them in n boxes. I want to run the simulation 10.000 times and see how many boxes stayed empty in each time. For example in first simulation (1,1,1,1,0,3,0,2,1,0) I have 3 zeros. and at the and ı want to see how many times how many boxes stayed empty. Thats what I tried so far. Anyhelp would be appreciated. My code runs but it doesn't print the results. Also it doesn't loop either. I am using spyder IDE.

import itertools, operator
def combinations_with_replacement_counts(n, r):  
    size = n + r - 1
    for indices in itertools.combinations(range(size), n): 
        starts = [0] + [index+1 for index in indices]
        stops = indices + (size,)
        yield tuple(map(operator.sub, stops, starts))
        list(combinations_with_replacement_counts(10, 10))
 


a=combinations_with_replacement_counts(10, 10) 
print (a)
  • 2
    you are using yield. Result will be generated on the fly when you request them. So far you have not iterated the generator. Maybe you want to use return instead of yield? Also you have a line after yield that will be unreachable. –  Oct 05 '22 at 07:45
  • @SembeiNorimaki, if they use `return` the function will end after the first iteration. Being inside generator, the line after yield is executed, but it doesn't make much sense either. Maybe it was intended to be outside, just a wrong indentation. At the moment the list is just thrown away and Maximum Recursion error will raise – buran Oct 05 '22 at 07:59
  • @SembeiNorimaki What do you mean with unreachable? – Kelly Bundy Oct 05 '22 at 07:59
  • True, changing yield for return is not as easy as changing the keyword, but appending the results and moving the return outside the loop. Yield makes more sense, but then it needs to be called appropiately. –  Oct 05 '22 at 08:00

3 Answers3

0

If you want to use loops you can do the following. The function still takes 2 arguments and returns a tuple of format (number_of_empty_boxes:number_of_occurrence)

import random
import numpy as np

def combinations_with_replacement_counts(n, m):
    empty_boxes = []

    # run the simulation m times
    for i in range(m):
        boxes = [0] * n

        # put n balls in n boxes
        for j in range(n):

            # put a ball in a random box
            boxes[random.randint(0, n-1)] += 1

        # count the number of empty boxes
        empty_boxe = boxes.count(0)

        # save how often how many boxes are empty
        empty_boxes.append(empty_boxe)

    # count the different unique integers in empty_boxes
    unique, counts = np.unique(empty_boxes, return_counts=True)

    # return the results as a tuple
    return dict(zip(unique, counts))

print(combinations_with_replacement_counts(10, 10000))

I hope this helps.

Greetings

0

You could try smtg like this, super simple

def ball_in_boxes(nball,nboxes):
    box = np.array(nboxes*[0])
    for i in range(nball):
         radn = np.random.randint(0,nboxes)
         box[radn] += 1
    return box.tolist().count(0)


output = ball_in_boxes(10,10)
imburningbabe
  • 742
  • 1
  • 2
  • 13
0

I am not well versed with itertools, but I think if you want to simulate the experiment randomly anyway, I would suggest np.random.randint, since it is usually very straightforward and intuitive. In the code you provided, your function did not return a value at the end.

I wrote a code that simulates the desired distribution. I added a matplotlib plot at the end to visualize how many boxes will stay empty on average.

Please let my know, if this is helpful and if this answers your question.

import numpy as np
import matplotlib.pyplot as plt

def Fill_boxes_randomly(N_boxes,N_balls):
    
    Filling = np.zeros(N_boxes,dtype = int) #start with N_boxes empty boxes. We choose datatype int, since each box
                                            #can only contain an integer number of balls
    
    for i in range(N_balls): #Now we put each ball in a random box
        Box_index = np.random.randint(N_boxes) #here we decide for a box to place the ball in
        Filling[Box_index] += 1
        
    Number_of_empty_boxes = N_boxes - np.count_nonzero(Filling)
    
    return Number_of_empty_boxes
    
Array_of_how_many_boxes_stayed_empty = []

N_boxes = 10 #Here you can decide how many boxes you intend to fill up.
N_balls = 10 #Here you can decide the number of balls to fill the boxes with.

for i in range(10000):
    #10000 times we fill up the boxes randomly and count how many stayed empty
    Array_of_how_many_boxes_stayed_empty.append(Fill_boxes_randomly(N_boxes,N_balls))

#We visualize how maany boxes stayed empty
plt.hist(Array_of_how_many_boxes_stayed_empty,bins = np.linspace(-0.5,N_boxes+0.5,N_boxes+2))
plt.show()

The final plot

Ritteraxt
  • 82
  • 8