I explain you my problem:
Imagine you have a bar, with say s positions. Each position can be counted as position 0, position 1, .. , position s-1.
Now what I want to do is simulate the following : At a certain point in time, a number of particles, say n particles, start in a state of the bar (assume a position in the middle).
At this point with random probabilities pr and pl (pr + pl =1) this particles go right or left respectively. So basically the probability reflects the proportion of particles swapping right or left.
I want to repeat this a number of times and see what is the final position of the particles and plot an histogram of it.
This is my function hop, which I made in order to simulate the hopping of the particles.
def hop(n):
'''
n is the number of particles starting in the middle position.
'''
s = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,n,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
global ls
ls = len(s)
i = 0
while i < 100:
for j in range(0,int(len(s))):
if s[j] != 0 :
pr = random.random()
pl = 1 - pr
if j - 1 < 0:
s[j+1] = s[j+1]+int(s[j]*pr)
s[j] = s[j] - int(s[j]*pr)
elif len(s) <= j+1:
s[j-1] = s[j-1] + int(s[j]*pl)
s[j] = s[j] - int(s[j]*pl)
else:
s[j-1] = s[j-1] + int(s[j]*pl)
s[j+1] = s[j+1] + int(s[j]*pr)
s[j] = s[j] - int(s[j]*pr) - int(s[j]*pl)
j+=1
elif s[j] == 0:
s[j] = 0
j+=1
i+=1
return s
And here is the rest, that I used to plot the histogram:
x = hop(100)
y = sum(x) #This is for debugging purposes, I want to check that I'm left
with the right number of particles
list1 = []
for k in range(0,ls):
list1.append(k)
plt.hist(x,list1)
plt.show()
Where I have imported mathplotlib and specifically I've imported
import matplotlib.pyplot as plt
import random
My problem is that from the histograms that I obtain this is doing something very wrong. Indeed the histograms are all skewed to the left, which wouldn't be possible If the probabilities are taken at random.
Furthermore the histogram doesn't show me the right amounts of particles.
Does anyone understand what is going wrong?
Thanks
I don't know if i got you right, but
do you want to see this instead of a histogram?
xs = np.arange(len(x))
width = 1/1.5
plt.bar(xs,x,width)
Related
Thanks to Veritasium great video about the topic, I was planning to do a quick replication of the animation he showed in the video where the number bouncing up and down until hit the number 1, depending on the initial number.
Below I figured out a version of code to implement the animation. But I have a question and confusion while constructing the code.
I found that if I don't initialize the y-data as y=np.empty(100) instead with a empty list, it will throw an error list assignment index out of range
So I'm very confused why I can't start with a empty list, because I know, depending on the value of y_start the len(y) varies. If I can collect those calculated y value into a list (converting them into array later) then I don't have to go the whole night-yard setting plt.xlim(1,100) (instead, I could just set plt.xlim(0,len(y)) also due to the potential remaining 0.0 value in the final y-data, I have to add additional condition (2nd after and) in the if statement -> if y[i] % 2 == 0 and y[i] != 0: Otherwise, it goes haywire even after y reached the value 1....
In addition, I want to add y-data's value displaying on top of the each individual point, but I have no clue how to implement that in the code...It would be greatly appreciate if anyone can help on this issue to make the animation looks more "complete"!
Here is the code that I've tested
import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt
def odd(num):
return (num*3)+1
def even(num):
return num // 2
y_start = 33
x = np.linspace(0, 100, 100)
# y = []
def collatz():
y = np.empty(100)
y[0] = y_start
for i in range(0,100):
if y[i] % 2 == 0 and y[i] != 0:
y[i+1] = even(y[i])
else:
y[i+1] = odd(y[i])
if y[i+1] == 1:
break
return y
y = collatz()
fig = plt.figure()
plt.xlim(1,100)
plt.ylim(1,max(y))
draw, = plt.plot([],[])
def update(idx):
draw.set_data(x[:idx], y[:idx])
return draw,
a = FuncAnimation(fig, update, frames=len(x), interval=90)
plt.show()
So again, my questions are,
why starting with an empty list to contain calculated y fails?
Also, in the early version, inside the collatz function definition, my code was like:
def collatz():
y = np.empty(100)
y[0] = y_start
for i in range(0,100):
while y[i] != 1:
if y[i] % 2 == 0 and y[i] != 0:
y[i+1] = even(y[i])
else:
y[i+1] = odd(y[i])
if y[i+1] == 1:
break
return y
The compilation freezes, the code seems undergoes an infinite cycle...I don't know, is it the usage of the while statement ? what should I do/add to correct it?
I have rewritten your code (works on my machine), and will try to answer your questions
You cannot start from an empty list for y because the collatz() function needs a starting point. Hence, if y is empty, there is nothing to start from and the function fails. In the new code below I have added a parameter start to your function (in the code: 49). This is now the new starting point of your function. Note that if you want a random starting point instead of one defined by you, you can delete start, and replace y = [start] with y = [int(np.random.randint(1, 100, 1))] or another code that draws a random integer.
Now collatz uses a while loop: it works as long as y is larger than 1 (hence for y = 0 or 1 it will stop). Note that the -1 operator means 'the last element added to y'. For each number it does the even() or odd() function, and then it adds the number to the list using append. This ensures that the list is only as long as it needs to be. Note that in this case a while loop is the best option since you don't know how long the loop will last. When you have a fixed amount of iterations, a for loop should be chosen.
Finally, x is determined based on the length of y.
from matplotlib.animation import FuncAnimation
from matplotlib import pyplot as plt
def odd(num):
return (num*3)+1
def even(num):
return num // 2
def collatz(start):
y = [start]
while y[-1] > 1:
if y[-1] % 2 == 0:
y.append(even(y[-1]))
else:
y.append(odd(y[-1]))
return y
y = collatz(49)
x = list(range(len(y)))
fig = plt.figure()
plt.xlim(1,len(y))
plt.ylim(1,max(y))
draw, = plt.plot([],[])
def update(idx):
draw.set_data(x[:idx], y[:idx])
return draw
a = FuncAnimation(fig, update, frames=len(x), interval=90)
plt.show()
I have code which simulates a Markov jump process.
I am trying to increase the number of realisations, Rr whilst reducing the computation time. The code is runs for some values and then will randomly get stuck and I don't know why exactly. I think it may be to do with my while loop, although I am unsure on how to get around this. If anyone could provide some insight that would be great.
import numpy as np
import random
import matplotlib.pyplot as plt
import csv
import time
t = time.time()
#Initial jump value
n0 = 1
#Constant
cbar = 1
#Constant
L = 1
#Constant
tau = 2*L/cbar
#Empty list to store N series
N_array = []
#Empty list to store z series
z_array = []
#Number of initial realisations
Rr = 2000
for r in range(0,Rr):
#Set initial z series values to be zero
z = [0]
#Set initial jump process values to be n0
N = [n0]
#Set iteration to be zero
j = 0
#While the value of N[j] series (realisation r) is greater than zero and j is less than jmax
while N[j] > 0:
#Form next value in z series according to exponential clock, parameter n^2, since Lloc = 2, cbar = 1, L=1
#In python the argument of this function is beta = 1/lambda, hence 1/n^2
z.append(z[j] + np.random.exponential(1/N[j]**2))
#Pick jump at position j+1 to be N[j] -1 or +1 with prob 1/2
N.append(N[j] + np.random.choice([-1,1]))
#Update iteration
j = j+1
#Store N,z realisation if sum dz < 10 say
if sum(np.diff(z)) < 10:
N_array.append(N)
z_array.append(z)
print(r/RR*100,'%)
elapsed = time.time() - t
print('Elapsed time =',elapsed,'seconds')
My goal is to find the probability density function for a certain distribution, using a given algorithm.
This algorithm requires that I search in which interval a float is placed in. Even though the code runs perfectly, it takes too long. I was looking for a way of optimizing my code, but none came to mind.
In each iteration I check if the float is in the interval: if that's the case, I'd like to had a unity to the position I'm considering, in array p.
This is my code:
import numpy as np
import pylab as plt
import random as rd
n = [10,100,1000]
N = [10**6]
dy = 0.005
k_max = int(1/dy-1)
y = np.array([(j+0.5)*dy for j in range(k_max+1)])
intervals = np.linspace(0,1,k_max+2)
def p(y,n,N):
p = np.zeros(len(y))
Y = np.array([sum(np.array([rd.random() for k in range(n)]))/n for j in range(N)])
z = np.array([sum(np.array([rd.random() for k in range(n)])) for l in range(N)])
for j in Y:
for i in range(len(y)-1):
if intervals[i] <= j < intervals[i+1]:
p[i] += 1
return(p/(dy*N))
for a in n:
pi = p(y,a,N[0])
plt.plot(y,pi,label = 'n = ' + str(a))
plt.title('Probability Density Function')
plt.xlabel('x')
plt.ylabel('p(x)')
plt.show()
Edit: I've added the full code, as requested.
Edit 2: Fixed an error intervals.
A quick and simple optimization can be made here:
for j in Y:
for i in range(len(y)-1):
if intervals[i] <= j < intervals[i+1]:
p[i] += 1
Since intervals consists of len(y) evenly spaced numbers over the interval [0, 1], which is also the range of Y values, we need not search the position of j in intervals, but rather we can compute it.
for j in Y: p[int(j*(len(y)-1))] += 1
Also we can remove the unused
z = np.array([sum(np.array([rd.random() for k in range(n)])) for l in range(N)])
The greatest part of the remaining execution time is taken by
Y = np.array([sum(np.array([rd.random() for k in range(n)]))/n for j in range(N)])
Here the inner conversions to np.array are very time consuming; better leave them all out:
Y = [sum([rd.random() for k in range(n)])/n for j in range(N)]
I am trying to simulate a random walk in 1D by graphing a Poisson process with a mean rate of 1 s^(-1), but in a randomly chosen direction (left or right). I am trying to plot the trajectories (x vs t) with a total duration of t = 400s, however, I can't seem to track the x direction with t (time) properly. How can I do this? I have this so far:
x = [0]
t = [0]
for j in range(100):
mean_rate = 1.0
d = 1.0
step_x = np.random.poisson(0, mean_rate)
bern_tri = np.random.binomial(0.5,step_x)
if bern_tri == 1:
x.append(x[j] + d)
t.append(t[j])
else:
x.append(x[j] - d)
t.append(t[j])
plt.plot(x,t)
plt.show()
I have been working on a project for my math class in which I am creating a Julia set generator. I had finally succeeded in generating it, but when I show the plot and save the image generated there are white lines all over it. They do not line up with x ticks or y ticks. When I view the saved image it had even more white lines. I have been searching to find what these might be, but I have found nothing.
import matplotlib.pyplot as plt
#Set up window with a name and size.
plt.figure("Julia Set Generator by Eric Kapilik", figsize=(7.0,7.0))
#Set Range of axes
plt.xlim([-2,2])
plt.ylim([-2,2])
#Add labels to axes
plt.xlabel("Real Numbers")
plt.ylabel("Imaginary Numbers")
plt.grid(b=False, which = "major", axis = "both")
plt.grid(b=False, which = "minor", axis = "both")
name = input("Save file as... \n")
#Ask for maximum amount of iterations to base colour
#selection off of with fractions.
max = int(input("What is the maximum amount of iterations you wish to run? "))
#Generate an array of colour names to be used to plot points.
#Set seed of array.
colourArray = ["r"]
for colourNum in range (1, max):
#if the place in array is between 0% and 25% then set the colour to red.
#Same method used for other three colours.
if colourNum >= 0 and colourNum <= (max/4):
colourArray.append("r") #red
elif colourNum > (max/4) and colourNum <= (max/2):
colourArray.append("y") #yellow
elif colourNum > (max/2) and colourNum <= ((3*max)/4):
colourArray.append("g") #green
elif colourNum > ((3*max)/4) and colourNum <= max:
colourArray.append("c") #cyan
#Get constant value of which the julia set is based off of.
#The real number component is plotted on the horizontal axis
#of a complex number grid so we will use x.
xConstant = float(input("Enter real number constant component: "))
#The imaginary nuber compenent of a complex number is plotted on the vertical axis,
#so we will use y in our real number grid (for simplicity's sake).
yConstant = float(input("Enter imaginary number constant component: "))
#Title the graph based on the constatn complex number entered.
plt.title(str(xConstant) + " + " + str(yConstant) + "i")
#See the starting coordinates to be tested and conditions
xTest = float(-2)
yTest = float(2)
stop = False
i = 0
xPrevious = xTest
yPrevious = yTest
#Using an escape time algorith, determine the amout of iterations of the recursion
#are needed for the coordinate to be attarcted to infinity.
#Continue doing this while the y value of the coordinate being tested is less
#than or equal to -2.
while yTest >= -2:
#We are following the recursive function of
#f(Z-1) = Z^2 + C
#Where Z is current coordinate, and C is the constant value.
#Reminder: Both Z and C are actually complex numbers but in our case we
#are using them both as real number coordinates on a real number grid.
xCurrent = ((xPrevious**2) - (yPrevious**2)) + xConstant
yCurrent = (2 * xPrevious * yPrevious) + yConstant
#Points that surpass a circle of radius 2 with a centre point at the origin
#are considered to indefinitely escape to infinity.
#So when the radius of the recursive coordinate based off of the tested coordinate
#becomes greater or equal to two we know it will be attaracted to infinity.
radius = xCurrent**2 + yCurrent**2
#"Is the point an escapee?"
if radius >= 2:
#Since the point has been defined as one that esacpes to infintity
#it is considered an escapee, so set that to true.
escapee = True
#"Is the point a prisoner?"
if i == max:
#The point is considered a prisoner if max iterations is reached and
#the point is still within the circle of radius 2.
#The testeed point will be considered a prisoner based off of the amount
#of iterations we selected, it is possible that with more iterations
#that we would find this to be an escapee.
prisoner = True
#If we have not defined what kind of point this is yet, then go to the next
#iteration of the recursion. i is the number of iterations completed for
#the test point.
if escapee == False and prisoner == False:
i = i + 1
#Out with the old, in with the new. Set the current points to the previous
#points for the next iteration.
xPrevious = xCurrent
yPrevious= yCurrent
#If, however, we have defined the point, then colour it based off of
#the amount of iterations using the array of colours generated at the
#beginning to select the colour.
if escapee == True or prisoner == True:
#This sets the black points that are prisoners, this is the body
#of the julia set.
if i == max:
colourPoint = "k,"
else:
#Colour the point and concatenate a ",", which means to plot this point
#as a pixel.
colourPoint = colourArray[i] + ","
#Plot the point! (Most satisfying part)
plt.plot(xTest, yTest, colourPoint)
#Determine the percentage finished, to give user an idea of how the
#renderig is going. (Not nessecary, but appreciable)
percent = int(((yTest-2)/4) * (-100))
print(str(percent) + "%")
#After setting a colour and plotting the point, jump to the next test coordinate.
#Once the end of the line is reached, jump down one.
if xTest >= 2:
xTest = -2
yTest = yTest - 0.01
else:
xTest= xTest + 0.01
#Reset the starting conditions.
i = 0
escapee = False
prisoner = False
xPrevious = xTest
yPrevious = yTest
#Show the beauty.
print("100%")
print("Wait for matplotlib to finish things up...\nWill take a minute...")
plt.show()
plt.savefig(name)
Plot that was generated:
Saved image, with even more white lines: