Running trials in python - python

I'm a beginner when it comes to using Python and wants to do simulations where I estimate pi using trials. I first important random numbers for both the x and y values (between 0 and 1), then I check to see if those numbers are inside the circle. If they are then I estimate pi using the formula:
(4 * (number of points inside circle/number of trials)).
My code is attached below. With the seed I'm using I should get a number around 3.02 but instead, am getting 4.00. Could anyone point in the direction of where I've gone wrong?
import random
random.seed(1000)
x_value = random.random()
y_value = random.random()
print(x_value)
print(y_value)
pointsInCircle= 0
numberOfTrials = 1000
for trials in range(trials):
if 1 > ((x_value ** 2) + (y_value ** 2)):
pointsInCircle = pointsInCircle + 1
else:
print("No estimation possbile")
pi = 4 * (pointsInCircle/numberOfTrials)
print(pi)

The following 2 lines should go inside the for loop. At each trail it needs to have 2 random numbers which are different from the previous.
x_value = random.random()
y_value = random.random()
Hence the code should look like below.
import random
random.seed(1000)
# print(x_value)
# print(y_value)
pointsInCircle= 0
numberOfTrials = 1000
for trials in range(numberOfTrials):
x_value = random.random()
y_value = random.random()
if 1 > ((x_value ** 2) + (y_value ** 2)):
pointsInCircle = pointsInCircle + 1
else:
print("No estimation possbile")
pi = 4 * (pointsInCircle/numberOfTrials)
print(pi)
Which yields the answer 3.02.

I'm not sure I can provide a full solution without more information, but it seems like pointsInCircle/numberOfTrials == 1, therefore pointsInCircle == numberOfTrials.
Maybe use some print debugging to find the values of those two variables and see if that's the problem. If you get any more information, I'd be happy to help further!

Related

Mandelbrot set in Python

I have a problem. I'm doing a task for my lessons and I'm doing my best, but the teachers clues does not seem to help and I need to look for the problem myself facing the problem.
To begin with, I had to translate that task from my native language to english. So because of that there may be some misunderstandings as it was hard to explain it from mathematical point of view.
"There is a Mandelbrot set which is created by points defined on surface by complex numbers so as following recurrence equation does not go to infinity:
{ z0 = 0 // zn+1 = zn^2 + c
You have to make two-dimensional array T with a size of 600x600. Each element from that array T[k][l] will represent a complex number ckl = (−2 + k * 0.005, (−1.5 + l * 0.005)ˆi). Next for each of element from T[k][l] calculate first n_max = 100 numbers from series and save that value as n, for |zn| > 2."
Yea that was painful. I googled a lot about that but I could not use all other Python scripts to solve that task. I ended up using this: LINK, and made this:
import matplotlib.pyplot as plt
k = 600
l = 600
T = [0][0]
for i in range(k):
for j in range(k):
z = 0 + 0j
c = complex(-2 + i * 0.005, -1.5 + j * 0.005)
for g in range(100):
z = z * z + c
if abs(z) > 2.0:
T = i
break
plt.figure(dpi=200)
plt.imshow(T, cmap="hot")
plt.show()
And it is really bad, I really don't understand this. Plus I get an error: TypeError: Invalid shape () for image data. I found another solution couple of weeks ago, sent it but it has to be done the way described in script. Please help.. thanks for your time in advance. If you need any other screenshots of the task, I'll provide it.

Coupled map lattice in Python

I attempt to plot bifurcation diagram for following one-dimensional spatially extended system with boundary conditions
x[i,n+1] = (1-eps)*(r*x[i,n]*(1-x[i,n])) + 0.5*eps*( r*x[i-1,n]*(1-x[i-1,n]) + r*x[i+1,n]*(1-x[i+1,n])) + p
I am facing problem in getting desired output figure may be because of number of transients I am using. Can someone help me out by cross-checking my code, what values of nTransients should I choose or how many transients should I ignore ?
My Python code is as follows:
import numpy as np
from numpy import *
from pylab import *
L = 60 # no. of lattice sites
eps = 0.6 # diffusive coupling strength
r = 4.0 # control parameter r
np.random.seed(1010)
ic = np.random.uniform(0.1, 0.9, L) # random initial condition betn. (0,1)
nTransients = 900 # The iterates we'll throw away
nIterates = 1000 # This sets how much the attractor is filled in
nSteps = 400 # This sets how dense the bifurcation diagram will be
pLow = -0.4
pHigh = 0.0
pInc = (pHigh-pLow)/float(nSteps)
def LM(p, x):
x_new = []
for i in range(L):
if i==0:
x_new.append((1-eps)*(r*x[i]*(1-x[i])) + 0.5*eps*(r*x[L-1]*(1-x[L-1]) + r*x[i+1]*(1-x[i+1])) + p)
elif i==L-1:
x_new.append((1-eps)*(r*x[i]*(1-x[i])) + 0.5*eps*(r*x[i-1]*(1-x[i-1]) + r*x[0]*(1-x[0])) + p)
elif i>0 and i<L-1:
x_new.append((1-eps)*(r*x[i]*(1-x[i])) + 0.5*eps*(r*x[i-1]*(1-x[i-1]) + r*x[i+1]*(1-x[i+1])) + p)
return x_new
for p in arange(pLow, pHigh, pInc):
# set initial conditions
state = ic
# throw away the transient iterations
for i in range(nTransients):
state = LM(p, state)
# now stote the next batch of iterates
psweep = [] # store p values
x = [] # store iterates
for i in range(nIterates):
state = LM(p, state)
psweep.append(p)
x.append(state[L/2-1])
plot(psweep, x, 'k,') # Plot the list of (r,x) pairs as pixels
xlabel('Pinning Strength p')
ylabel('X(L/2)')
# Display plot in window
show()
Can someone also tell me figure displayed by pylab in the end has either dots or lines as a marker, if it is lines then how to get plot with dots.
This is my output image for reference, after using pixels:
It still isn't clear exactly what your desired output is, but I'm guessing you're aiming for something that looks like this image from Wikipedia:
Going with that assumption, I gave it my best shot, but I'm guessing your equations (with the boundary conditions and so on) give you something that simply doesn't look quite that pretty. Here's my result:
This plot by itself may not look like the best thing ever, however, if you zoom in, you can really see some beautiful detail (this is right from the center of the plot, where the two arms of the bifurcation come down, meet, and then branch away again):
Note that I have used horizontal lines, with alpha=0.1 (originally you were using solid, vertical lines, which was why the result didn't look good).
The code!
I essentially modified your program a little to make it vectorized: I removed the for loop over p, which made the whole thing run almost instantaneously. This enabled me to use a much denser sampling for p, and allowed me to plot horizontal lines.
from __future__ import print_function, division
import numpy as np
import matplotlib.pyplot as plt
L = 60 # no. of lattice sites
eps = 0.6 # diffusive coupling strength
r = 4.0 # control parameter r
np.random.seed(1010)
ic = np.random.uniform(0.1, 0.9, L) # random initial condition betn. (0,1)
nTransients = 100 # The iterates we'll throw away
nIterates = 100 # This sets how much the attractor is filled in
nSteps = 4000 # This sets how dense the bifurcation diagram will be
pLow = -0.4
pHigh = 0.0
pInc = (pHigh - pLow) / nSteps
def LM(p, x):
x_new = np.empty(x.shape)
for i in range(L):
if i == 0:
x_new[i] = ((1 - eps) * (r * x[i] * (1 - x[i])) + 0.5 * eps * (r * x[L - 1] * (1 - x[L - 1]) + r * x[i + 1] * (1 - x[i + 1])) + p)
elif i == L - 1:
x_new[i] = ((1 - eps) * (r * x[i] * (1 - x[i])) + 0.5 * eps * (r * x[i - 1] * (1 - x[i - 1]) + r * x[0] * (1 - x[0])) + p)
elif i > 0 and i < L - 1:
x_new[i] = ((1 - eps) * (r * x[i] * (1 - x[i])) + 0.5 * eps * (r * x[i - 1] * (1 - x[i - 1]) + r * x[i + 1] * (1 - x[i + 1])) + p)
return x_new
p = np.arange(pLow, pHigh, pInc)
state = np.tile(ic[:, np.newaxis], (1, p.size))
# set initial conditions
# throw away the transient iterations
for i in range(nTransients):
state = LM(p, state)
# now store the next batch of iterates
x = np.empty((p.size, nIterates)) # store iterates
for i in range(nIterates):
state = LM(p, state)
x[:, i] = state[L // 2 - 1]
# Plot the list of (r,x) pairs as pixels
plt.plot(p, x, c=(0, 0, 0, 0.1))
plt.xlabel('Pinning Strength p')
plt.ylabel('X(L/2)')
# Display plot in window
plt.show()
I don't want to try explaining the whole program to you: I've used a few standard numpy tricks, including broadcasting, but otherwise, I have not modified much. I've not modified your LM function at all.
Please don't hesitate to ask me in the comments if you have any questions! I'm happy to explain specifics that you want explained.
A note on transients and iterates: Hopefully, now that the program runs much faster, you can try playing with these elements yourself. To me, the number of transients seemed to decide for how long the plot remained "deterministic-looking". The number of iterates just increases the density of plot lines, so increasing this beyond a point didn't seem to make sense to me.
I tried increasing the number of transients all the way up till 10,000. Here's my result from that experiment, for your reference:

Modelize a spring Python

I need to model a spring in Python for one of my classes at the university and it doesn't really work. I've the second order differential equation and I translated it in 2 first order ones to have a system.
Can someone look my code and give me an idea about what could I do? For me, the equations are good, I just don't know how to draw it...
from math import pi
from time import sleep
from turtle import *
k=1
m=1
def main():
L = 5
total_time = 0
vo = 0 #Vitesse angulaire initial (rad/s)
time_step = 0.05
while total_time < 100:
total_time += time_step
vo += (-k/m) * L * time_step
L += vo * time_step
if draw(L): break
sleep(time_step)
def init():
setup()
mode('logo')
radians()
speed(0)
tracer(False)
hideturtle()
def draw(L):
if speed() != 0: return True
clear()
pendown()
setheading(L)
penup()
pensize(5)
pencolor('red')
dot(L * 10)
home
update()
if __name__ == '__main__':
init()
main()
Your equations are good, as far as I remember from my physic lessons, but the L variable is varying from -5 to +5, not from 0 to +5.
The dot(radius) function draws a circle. The radius needs to be positive.
Just replace :
dot(L * 10)
by :
dot(51 + L * 10)
(I put "51" instead of "50" to be sure to avoid errors due to crappy approximation of float numbers)
Some little tip : when you don't understand what happens, try to determine the current values of your variables.
You could have guessed that L varies from -5 to +5 by adding print("vo:", vo, "L:", L, "total_time:", total_time) in the loop of the main function.

Python gravity simulator behaving strangely

I'm making a gravity simulation in Python (in 3D with VPython, to be exact) and I'm sure there's nothing wrong with the code, but it behaves strangely when two objects get close to each other.
My inspiration is http://testtubegames.com/gravity.html. Note how you can place two planets with no velocity, they move towards each other, overtake, decelerate and turn back. In my program, they overtake, and decelerate, but only proportionately to the distance, so technically it should never turn back anyway.
I realize that the law f=G*(m1*m2)/r**2 wouldn't work if r (the distance) is or gets too close to 0, so I have included a max-out, so if it is less than 1 it is set to 1 (units not in pixels, by the way), but it still does not work.
Simple logic also suggests that the objects should not react in this way, so the next thing that follows is that I must be missing something.
Here is an extract of the code:
from visual import *
a = sphere(x=-10,mass=10, vel=vector())
b = sphere(x=10, mass=10, vel=vector())
while 1:
rate(20)
#distance between the two objects, a and b, where a.r.mag would be the magnitude of the vector
a.r = b.pos - a.pos
b.r = a.pos - b.pos
a.force = a.r
if a.r.mag > 1:
a.force.mag = (a.mass * b.mass) / a.r.mag**2
else:
a.force.mag = (a.mass * b.mass) / 1
a.vel = a.vel + a.force / a.mass
b.force = b.r
if b.r.mag > 1:
b.force.mag = (a.mass * b.mass) / b.r.mag**2
else:
b.force.mag = (a.mass * b.mass) / 1
b.vel = b.vel + b.force / b.mass
a.pos = a.pos + a.vel
b.pos = b.pos + b.vel
EDIT: Code re-written in response to shockburner:
from visual import *
import sys
limit2 = sys.float_info.min
limit = limit2**0.5
timestep = 0.0005
a = sphere(x=-5,mass=10, vel=vector())
b = sphere(x=5, mass=10, vel=vector())
def force(ob1, ob2):
ob1.r = ob2.pos - ob1.pos
ob1.force = ob1.r + vector()
if ob1.r.mag > limit:
ob1.force.mag = (ob1.mass * ob2.mass) / ob1.r.mag2
else:
ob1.force.mag = (ob1.mass * ob2.mass) / limit2
return ob1.force
while 1:
rt = int(1/timestep)
rate(rt)
a.acc = force(a, b) / a.mass
b.acc = force(b, a) / b.mass
a.pos = a.pos + timestep * (a.vel + timestep * a.acc / 2)
b.pos = b.pos + timestep * (b.vel + timestep * b.acc / 2)
a.acc1 = force(a,b) / a.mass
b.acc1 = force(b,a) / b.mass
a.vel = a.vel + timestep * (a.acc + a.acc1) / 2
b.vel = b.vel + timestep * (b.acc + b.acc1) / 2
Any help or pointer in the right direction would be greatly appreciated, and if the answer turns out to be idiotically simple (which with me is usually the case) remember I am quite an idiot anyway.
My guess is that your problem stems from numerical errors in your integration method. It seems you are using the Euler method which is prone to large numerical errors as it is a first-order integration method. I would recommend velocity verlet for numerically integrating orbits as it is a second-order method that also preserves total energy (kinetic + gravitational potential) to machine precision. This energy conservation generally makes velocity verlet more stable than 4th-order Runge–Kutta, because bound orbits stay bound.
Also you might want to consider having a dynamic time step as opposes to a static one. When your particles are closed together velocities and positions change faster. Thus in order to reduce your numerical errors you need to take a smaller time step.
Finally, I would make your limiter (if a.r.mag > 1:) as small as possible/practical. I'd try the following:
import sys
limit2 = sys.float_info.min
limit = limit2**.5
...
if a.r.mag > limit:
a.force.mag = (a.mass * b.mass) / a.r.mag**2
else:
a.force.mag = (a.mass * b.mass) / limit2
...
I've had this problem before too. If you just go directly to Runge-Kutta, everything will sort itself out. This pdf will explain how to incorporate the method: http://spiff.rit.edu/richmond/nbody/OrbitRungeKutta4.pdf. Good luck!

Python Beginner - How to equate a regression line from clicks and display graphically?

I am reading Python Programming by John Zelle and I am stuck on one the exercises shown in the picture below.
You can view my code below. I know the code is very ugly. (Any tips are appreciated)
Here's my code so far:
from graphics import *
def regression():
# creating the window for the regression line
win = GraphWin("Regression Line - Start Clicking!", 500, 500)
win.setCoords(0.0, 0.0, 10.0, 10.0)
rect = Rectangle(Point(0.5, 0.1), Point(2.5, 2.1))
rect.setFill("red")
rect.draw(win)
Text(rect.getCenter(), "Done").draw(win)
message = Text(Point(5, 0.5), "Click in this screen")
message.draw(win)
points = [] # list of points
n = 0 # count variable
sumX = 0
sumY = 0
while True:
p = win.getMouse()
p.draw(win)
# if user clicks in a red square it exits the loop and calculates the regression line
if (p.getX() >= 0.5 and p.getX() <= 2.5) and (p.getY() >= 0.1 and p.getY() <= 2.1):
break
n += 1 # count of the points
# get the sum of the X and Y points
sumX = sumX + p.getX()
sumY = sumY + p.getY()
# tuple of the X and Y points
dot = (p.getX(), p.getY())
points.append(dot)
avgX = sumX / n
avgY = sumY / n
top = 0
bottom = 0
# my ugly attempt at the regression equation shown in the book
for i in points:
gp = 0
numer = points[gp][0] * points[gp][1]
top = top + numer
denom = points[gp][0] ** 2
bottom = bottom + denom
gp += 1
m = (top - sumX * sumY) / (bottom - sumX ** 2)
y1 = avgY + m * (0.0 - avgX)
y2 = avgY + m * (10.0 - avgX)
regressionline = Line(Point(0, y1), Point(10.0, y2))
regressionline.draw(win)
raw_input("Press <Enter> to quit.")
win.close()
regression()
When I run the program the regression line never appears to be the real line of best fit. I believe I am interpreting the regression equation incorrectly in my code. What needs to be changed to get the correct regression line?
Issues:
from my_library import * should be avoided; better to specify exactly what you want from it. This helps keep your namespace uncluttered.
you've got one massive block of code; better to split it into separate functions. This makes it much easier to think about and debug, and may help you reuse code later. Sure, it's a toy problem, you're not going to reuse it - but the whole point of doing exercises is to develop good habits, and factoring your code this way is definitely a good habit! A general rule of thumb - if a function contains more than about a dozen lines of code, you should consider splitting it further.
the exercise asks you to keep track of x, y, xx, and xy running sums while getting input points. I think this is kind of a bad idea - or at least more C-ish than Python-ish - as it forces you to do two different tasks at once (get points and do math on them). My advice would be: if you are getting points, get points; if you are doing math, do math; don't try doing both at once.
similarly, I don't like the way you've got the regression calculation worrying about where the sides of the window are. Why should it know or care about windows? I hope you like my solution to this ;-)
Here's my refactored version of your code:
from graphics import GraphWin, Point, Line, Rectangle, Text
def draw_window()
# create canvas
win = GraphWin("Regression Line - Start Clicking!", 500, 500)
win.setCoords(0., 0., 10., 10.)
# exit button
rect = Rectangle(Point(0.5, 0.1), Point(2.5, 2.1))
rect.setFill("red")
rect.draw(win)
Text(rect.getCenter(), "Done").draw(win)
# instructions
Text(Point(5., 0.5), "Click in this screen").draw(win)
return win
def get_points(win):
points = []
while True:
p = win.getMouse()
p.draw(win)
# clicked the exit button?
px, py = p.getX(), p.getY()
if 0.5 <= px <= 2.5 and 0.1 <= py <= 2.1:
break
else:
points.append((px,py))
return points
def do_regression(points):
num = len(points)
x_sum, y_sum, xx_sum, xy_sum = 0., 0., 0., 0.
for x,y in points:
x_sum += x
y_sum += y
xx_sum += x*x
xy_sum += x*y
x_mean, y_mean = x_sum/num, y_sum/num
m = (xy_sum - num*x_mean*y_mean) / (xx_sum - num*x_mean*x_mean)
def lineFn(xval):
return y_mean + m*(xval - x_mean)
return lineFn
def main():
# set up
win = draw_window()
points = get_points(win)
# show regression line
lineFn = do_regression(points)
Line(
Point(0., lineFn(0. )),
Point(10., lineFn(10.))
).draw(win)
# wait to close
Text(Point(5., 5.), "Click to exit").draw(win)
win.getMouse()
win.close()
if __name__=="__main__":
main()
the for loop is all messed up! you have an i that changes in the loop, but then use gp which is always 0.
you want something more like:
for (X, Y) in points:
numer += X * Y
denom += X * X
...or move gp = 0 to before the for loop.
...or drop that part completely and add a sumXY and a sumXX to the sumX and sumY.
either way, once you fix that it should be ok (well, or maybe some other bug....).

Categories

Resources