I need to plot the position of a particle at time t, given the following formulae: s(t) = -0.5*g(s)*t^2+v0*t, where g(s) = G*M/(R+s(t))^2 (G, M, and R are constants, s being a value, not the function s(t)). The particle is being shot up vertically, and I want to print its current position every second until it hits the ground. But I can't figure out how to define one function without using the other before it's defined. This is my code so far:
G = 6.6742*10^(-11)
M = 5.9736*10^24
R = 6371000
s0 = 0
v0 = 300
t = 0
dt = 0.005
def g(s):
def s(t):
s(t) = -0.5*g(s)*t^2+v0*t
g(s) = G*M/(R+s(t))^2
def v(t):
v(t) = v(t-dt)-g(s(t-dt))*dt
while s(t) >= 0:
s(t) = s(t-dt)+v(t)*dt
t = t+dt
if t == int(t):
print s(t)
When I run the function, it says that it can't assign the function call.
The error means that you can't write s(t) = x, because s(t) is a function, and assignment on functions is performed with def .... Instead, you'll want to return the value, so you'd rewrite it like this:
def g(s):
def s(t):
return -0.5*g(s)*t^2+v0*t
return G*M/(R+s(t))^2
However, there are other issues with that as well. From a computational standpoint, this calculation would never terminate. Python is not an algebra system and can't solve for certain values. If you try to call s(t) within g(s), and g(s) within s(t), you'd never terminate, unless you define a termination condition. Otherwise they'll keep calling each other, until the recursion stack is filled up and then throws an error.
Also, since you defined s(t) within g(s), you can't call it from the outside, as you do several times further down in your code.
You seem to be confused about several syntax and semantic specifics of Python. If you ask us for what exactly you'd like to do and provide us with the mathematical formulae for it, it might be easier to formulate an answer that may help you better.
Edit:
To determine the position of a particle at time t, you'll want the following code (reformatted your code to Python syntax, use ** instead of ^ and return statements):
G = 6.6742*10**(-11)
M = 5.9736*10**24
R = 6371000
s0 = 0
v0 = 300
t = 0
dt = 0.005
sc = s0 # Current position of the particle, initially at s0
def g(s):
return -G*M/(R+s)**2
def s(t):
return 0.5*g(sc)*t**2 + v0*t + s0
count = 0
while s(t) >= 0:
if count % 200 == 0:
print(sc)
sc = s(t)
count += 1
t = dt*count
Python functions can call each other, but that's not how a function returns a value. To make a function return a particular value, use return, e.g.,
def v(t):
return v(t - dt) - g(s(t - dt)) * dt
Furthermore, I don't really understand what you're trying to do with this, but you'll probably need to express yourself differently:
while s(t) >= 0:
s(t) = s(t-dt)+v(t)*dt
t = t+dt
Related
def f(x):
f='exp(x)-x-2'
y=eval(f)
print(y)
return y
def bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2):
x=a
result_a=f(a)
x=b
result_b=f(b)
if (f.evalf(a)*f.evalf(b)>=0):
print("Interval [a,b] does not contain a zero ")
exit()
zeta=min(epsilon1,epsilon2)/10
x=a
while(f_line(x)>0):
if(x<b or x>-b):
x=x+zeta
else:
stop
ak=a
bk=b
xk=(ak+bk)/2
k=0
if (f(xk)*f(ak)<0):
ak=ak
bk=xk
if (f(xk)*f(bk)<0):
ak=xk
bk=bk
k=k+1
from sympy import *
import math
x=Symbol('x')
f=exp(x)-x-2
f_line=f.diff(x)
f_2lines=f_line.diff(x)
print("Derivative of f:", f_line)
print("2nd Derivative of f:", f_2lines)
a=int(input('Beginning of interval: '))
b=int(input('End of interval: '))
epsilon1=input('1st tolerance: ')
epsilon2=input('2nd tolerance: ')
bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2)
This program is an attempt to implement the Bissection Method. I've tried writing two functions:
The first one, f, is supposed to receive the extremes of the interval that may or may not contain a root (a and b) and return the value of the function evaluated in this point.
The second one, bissection, should receive the function, the function's first and second derivatives, the extremes of the interval (a,b) and two tolerances (epsilon1,epsilon2).
What I want to do is pass each value a and b, one at a time, as arguments to the function f, that is supposed to return f(a) and f(b); that is, the values of the function in each of the points a and b.
Then, it should test two conditions:
1) If the function values in the extremes of the intervals have opposite signs. If they don't, the method won't converge for this interval, then the program should terminate.
if(f.evalf(a)*f.evalf(b)>=0)
exit()
2)
while(f_line(x)>0): #while the first derivative of the function evaluated in x is positive
if(x<b or x>-b): #This should test whether x belongs to the interval [a,b]
x=x+zeta #If it does, x should receive x plus zeta
else:
stop
At the end of this loop, my objective was to determine whether the first derivative was strictly positive (I didn't do the negative case yet).
The problem: I'm getting the error
Traceback (most recent call last):
File "bissec.py", line 96, in <module>
bissection(f,f_line,f_2lines,a,b,epsilon1,epsilon2)
File "bissec.py", line 41, in bissection
result_a=f(a)
TypeError: 'Add' object is not callable
How can I properly call the function so that it returns the value of the function (in this case, f(x)=exp(x)-x-2), for every x needed? That is, how can I evaluate f(a) and f(b)?
Ok, so I've figured it out where your program was failing and I've got 4 reasons why.
First of all, and the main topic of your question, if you want to evaluate a function f for a determined x value, let's say a, you need to use f.subs(x, a).evalf(), as it is described in SymPy documentation. You used in 2 different ways: f.evalf(2) and f_line(a); both were wrong and need to be substituted by the correct syntax.
Second, if you want to stop a while loop you should use the keyword break, not "stop", as written in your code.
Third, avoid using the same name for variables and functions. In your f function, you also used f as the name of a variable. In bissection function, you passed f as a parameter and tried to call the f function. That'll fail too. Instead, I've changed the f function to f_calc, and applied the correct syntax of my first point in it.
Fourth, your epsilon1 and epsilon2 inputs were missing a float() conversion. I've added that.
Now, I've also edited your code to use good practices and applied PEP8.
This code should fix this error that you're getting and a few others:
from sympy import *
def func_calc(func, x, val):
"""Evaluate a given function func, whose varible is x, with value val"""
return func.subs(x, val).evalf()
def bissection(x, f, f_line, f_2lines, a, b, epsilon1, epsilon2):
"""Applies the Bissection Method"""
result_a = func_calc(f, x, a)
result_b = func_calc(f, x, b)
if (result_a * result_b >= 0):
print("Interval [a,b] does not contain a zero")
exit()
zeta = min(epsilon1, epsilon2) / 10
x_val = a
while(func_calc(f_line, x, a) > 0):
if(-b < x_val or x_val < b):
x_val = x_val + zeta
else:
break # the keyword you're looking for is break, instead of "stop"
print(x_val)
ak = a
bk = b
xk = (ak + bk) / 2
k = 0
if (func_calc(f, x, xk) * func_calc(f, x, ak) < 0):
ak = ak
bk = xk
if (func_calc(f, x, xk) * func_calc(f, x, bk) < 0):
ak = xk
bk = bk
k = k + 1
def main():
x = Symbol('x')
f = exp(x) - x - 2
f_line = f.diff(x)
f_2lines = f_line.diff(x)
print("Derivative of f:", f_line)
print("2nd Derivative of f:", f_2lines)
a = int(input('Beginning of interval: '))
b = int(input('End of interval: '))
epsilon1 = float(input('1st tolerance: '))
epsilon2 = float(input('2nd tolerance: '))
bissection(x, f, f_line, f_2lines, a, b, epsilon1, epsilon2)
if __name__ == '__main__':
main()
I cannot seem to get an output when I pass numbers to the function. I need to get the computed value and subtract it from the exact. Is there something I am not getting right?
def f1(x):
f1 = np.exp(x)
return f1;
def trapezoid(f,a,b,n):
'''Computes the integral of functions using the trapezoid rule
f = function of x
a = upper limit of the function
b = lower limit of the function
N = number of divisions'''
h = (b-a)/N
xi = np.linspace(a,b,N+1)
fi = f(xi)
s = 0.0
for i in range(1,N):
s = s + fi[i]
s = np.array((h/2)*(fi[0] + fi[N]) + h*s)
print(s)
return s
exactValue = np.full((20),math.exp(1)-1)
a = 0.0;b = 1.0 # integration interval [a,b]
computed = np.empty(20)
E=np.zeros(20)
exact=np.zeros(20)
N=20
def convergence_tests(f, a, b, N):
n = np.zeros(N, 1);
E = np.zeros(N, 1);
Exact = math.exp(1)-1
for i in range(N):
n[i] = 2^i
computed[i] = trapezoid(f, a, b, n[i])
E = abs(Exact - computed)
print(E, computed)
return E, computed
You have defined several functions, but your main program never calls any of them. In fact, your "parent" function convergence_test cannot be called, because it's defined at the bottom of the program.
I suggest that you use incremental programming: write a few lines; test those before you proceed to the next mini-task in your code. In the posting, you've written about 30 lines of active code, without realizing that virtually none of it actually executes. There may well be several other errors in this; you'll likely have a difficult time fixing all of them to get the expected output.
Start small and grow incrementally.
Programming in python with numpy and sympy, and my attempts to use derivatives in my code are falling flat. I frequently get either
"TypeError: 'Add' object is not callable"
and,
"ValueError: First variable cannot be a number: 1".
This is for a program meant to define Newton's Method for solving a root-finding problem. The sample equation I've used is 1/x+log(x)-2. I mention this because I've had a few issues with numpy's log function, as well. I think my problem has to do with the diff I'm using, as I'm not entirely certain how to use it to return an actual value, and the literature I've read on it isn't incredibly helpful.
def newton(p0, f, n, t):
global p
p = 0
for i in range(1, n+1):
p = p0 - f(p0)/diff(f(x),p0)
if abs(p-p0) < t:
return p
p0 = p
i = i + 1
return f"The method failed after {n} iterations. The procedure was unsuccessful."
print(newton(p0=1, f=1/x+log(x)-2, n=10, t=5e-324))
I'm at least expecting a number, but I'm getting the errors I describe above.
there are two problems in your code,
the first is the parameter f in your function should have a 'function' input, which means f=lambda x: 1/x+log(x)-2,
the second is p = p0 - f(p0)/diff(f(x),p0). If I understand correctly, you are expecting the diff function to perform as a derivation function, however, it's not. Maybe you can define your own derivation function:
def df(f, x):
h = 1e-5
return (f(x+h)-f(x))/h
then you can write p = p0 - f(p0)/df(f, p0)
so the whole code can be written as below:
def newton(p0, f, n, t):
global p
p = 0
for i in range(1, n+1):
def df(f, x):
h = 1e-5
return (f(x+h)-f(x))/h
p = p0 - f(p0)/df(f, p0)
if abs(p-p0) < t:
return p
p0 = p
i = i + 1
return f"The method failed after {n} iterations. The procedure was unsuccessful."
print(newton(p0=1, f=lambda x: 1/x+log(x)-2, n=10, t=5e-324))
I am trying to revamp a function that uses the Pollard Rho method to factor an integer but my attempt at using memoize has had no improvement in being able to factor a specific number (N=7331117) that this function should be able to facotr.
Before attempt:
import fractions
def pollard_Rho(n):
def f(xn):
if xn == 0:
return 2
return f(xn - 1) ** 2 + 1
i = 0
x = f(i)
y = f(f(i))
d = fractions.gcd(abs(x - y), n)
while d == 1:
i = i + 1
d = fractions.gcd(abs(x - y), n)
root1 = d
root2 = n / d
print i + 1
return (root1, root2)
memoize attempt:
def pollard_Rho(n):
class memoize:
def __init__(self, function):
self.function = function
self.memoized = {}
def __call__(self, *args):
try:
return self.memoized[args]
except KeyError:
self.memoized[args] = self.function(*args)
return self.memoized[args]
#memoize
def f(xn):
if xn == 0:
return 2
return f(xn - 1) ** 2 + 1
i = 0
x = f(i)
y = f(f(i))
d = fractions.gcd(abs(x - y), n)
while d == 1:
i = i + 1
d = fractions.gcd(abs(x - y), n)
root1 = d
root2 = n / d
print i + 1
return (root1, root2)
Now neither code produces any errors but both codes also do produce any results.
The output of
print pollard_Rho(7331117)
should be (641, 11437) (I know this because of another factorization function I have written) but what actually happens is the code runs through 3 iterations of the while loop and nothing happens afterwards. Does anyone have any suggestions?
Sorry for the vague question, does anyone have any suggestions on improving the the codes ability to factor in general? Maybe by a method more efficient than a recursive function? 7331116 and 7331118 factor perfectly fine and only 7331117 seems to be a tough nut to crack so far using this method.
Its possible I didn't use memoize right because even with looking at at on of stackoverflow examples I don't really understand how to use it. It seems every single instance of it I came across was drastically different.
It seems like your algorithm does not work for some reason. In order to see what is going on I went to wikipedia site of the algorithm and implemented regular version from there and it worked without a problem. Than I replaced my g function with your recursive version and I got following error
File "rho.py", line 25, in f_fun
return 2 if xn == 0 else f_fun(xn - 1) ** 2 + 1
RecursionError: maximum recursion depth exceeded
It seems like you cannot implement this with a regular recursion. I would suggest to convert your recursion to a fold or a generator.
Here is the code I tried:
https://gist.github.com/huseyinyilmaz/73c1ac42b2a20d24d3b5
UPDATE:
Here is your version with cache, it still have maximum depth problem. (python 2 implementation)
https://gist.github.com/huseyinyilmaz/bb26ac172fbec4c655d3
Program calculates the shortest route from point, to line, then to second point. Also I need to say how long is from the start of the line, to where point crosses. My code so far:
from math import sqrt
numbers_total = []
numbers_canal = []
first_triangle_longest_side_length = 300 #defining the variable
def first_triangle(first_triangle_longest_side_length):
calculation_one = sqrt(first_triangle_longest_side_length)
first_triangle_bottom_side_length = calculation_one - sqrt(300)
def second_triangle(canal_length_left):
canal_length_left = canal_length_left ** 2
calculation_two = canal_length_left + 500 ** 2
second_triangle_longest_side_length = sqrt(calculation_two)
while True:
first_triangle_longest_side_length = first_triangle_longest_side_length + 0.01
first_triangle(first_triangle_longest_side_length)
canal_length_left = 1000 - first_triangle_bottom_side_length
second_triangle(canal_length_left)
if first_triangle_longest_side_length == 1044.03:
break
total_distance = first_triangle_longest_side_length + second_triangle_longest_side_length
numbers_total.append(total_distance)
numbers_canal.append(first_trangle_bottom_side_length)
minimal_total_distance = min(numbers_total)
number_on_the_list = numbers_total.index(minimal_total_distance)
print "The distance of the shortest route is: " + "%.1f" % minimal_total_distance
print "The distance of the canal from point A is: " + "%.1f" % numbers_canal[number_on_the_list]
However, it gives the error:
line 19, in <module>
canal_length_left = 1000 - first_triangle_bottom_side_length
NameError: name 'first_triangle_bottom_side_length' is not defined
Any ideas?
For those interested, here is the problem: Cambridge February Computing Competition
You are taking a very brute-force approach; it works, but could be much more efficient Edit: I take it back; your math is incorrect too. I will correct it in a new post.
Here is a more analytic way to do it:
TOWER_DIST = 300
CANAL_LEN = 1000
FIRE_DIST = 500
#
# express the problem as a function
#
def path_length(dist_a):
"""
Given distance in meters from A along the canal,
return total path length
"""
leg_a = (TOWER_DIST**2 + dist_a**2) ** 0.5
leg_b = ((CANAL_LEN - dist_a)**2 + FIRE_DIST**2) ** 0.5
return leg_a + leg_b
#
# find x such that path_length(x) is minimized
#
# (the easy way:
# import scipy.optimize
# result = scipy.optimize.minimize(path_length, CANAL_LEN * 0.5)
# best_dist = result.x[0] # => 375.00092001
# best_length = path_length(best_dist) # => 1280.6248
#
# but because this is a competition we will avoid add-on modules)
def deriv(f, delta=0.01):
"""
Return a function which is a numerical first derivative of f
"""
def df(x):
a, b = f(x - delta), f(x + delta)
return (b - a) / (2. * delta)
return df
def newton_root(f, initial_x, tolerance=0.01, max_tries=1000):
"""
Use Newton-Raphson method to find x such that abs(f(x)) <= tolerance
"""
df = deriv(f)
x = initial_x
for try_ in range(max_tries):
err = f(x)
if abs(err) <= tolerance:
# found a solution
return x
else:
# find next value for x
x -= err / df(x)
else:
raise ValueError(
"newton_root fails to converge for initial_guess = {}"
.format(initial_x)
)
# By inspection, path_length is a smooth upward curve (ie a U-shape)
# on 0 .. CANAL_LEN; minimum occurs where first derivative is 0
best_dist = newton_root(deriv(path_length), CANAL_LEN * 0.5, 0.00001) # => 374.9999
best_length = path_length(best_dist) # => 1280.62484
# return results to nearest 0.1 meter
print("{:0.1f} {:0.1f}".format(best_dist, best_length))
If you play with this and think about it a while, you should realize that the shortest path is always such that the angles between leg_a and the canal and between the canal and leg_b are identical; if you think of the canal as a mirror, the shortest path is to run straight to the fire's reflection in the mirror.
This allows us to reduce the problem to a simple pair of similar triangles,
# TOWER_DIST / best_dist == (TOWER_DIST + FIRE_DIST) / CANAL_LEN
best_dist = TOWER_DIST * CANAL_LEN / (TOWER_DIST + FIRE_DIST)
best_length = ((TOWER_DIST + FIRE_DIST)**2 + CANAL_LEN**2) ** 0.5
After taking another look at your answer I realized your math is also wrong. I will point out your syntax and math errors and add a bit of free advice along the way ;-)
Stepping through your original code:
from math import sqrt
numbers_total = []
numbers_canal = []
first_triangle_longest_side_length = 300 #defining the variable
Really? where_on_earth_did_you_learn_variable_naming? Try tower_dist = 300.
def first_triangle(tower_hypot):
calculation_one = sqrt(tower_hypot)
first_triangle_bottom_side_length = calculation_one - sqrt(300)
First mistake: assigning a value to first_triangle_bottom_side_length doesn't accomplish anything. The variable is of local scope (ie it only exists inside this function) so as soon as the function ends it disappears.
You could be completely evil and make it a global variable, or you could just return calculation_one - sqrt(300) instead.
Second mistake: the math is just wrong. I'll come back to that in a moment.
def second_triangle(canal_length_left):
canal_length_left = canal_length_left ** 2
calculation_two = canal_length_left + 500 ** 2
second_triangle_longest_side_length = sqrt(calculation_two)
Same error again; do return sqrt(calculation_two) instead.
Important note: naming conventions! first_triangle returns a base length, second_triangle returns a hypotenuse. This is more than a bit confusing. Also, both functions have constants hard-wired in, meaning the functions cannot be reused for anything else.
If you instead did:
def side(adjacent, hypotenuse):
"""
Given the side and hypotenuse of a right triangle,
return the other side
"""
return (hypotenuse**2 - adjacent**2) ** 0.5
def hypotenuse(adjacent, opposite):
"""
Given two sides of a right triangle,
return the hypotenuse
"""
return (adjacent**2 + opposite**2) ** 0.5
def tower_base(tower_hypot, tower_height=300):
return side(tower_height, tower_hypot)
def fire_hypot(fire_base, fire_height=500):
return hypotenuse(fire_base, fire_height)
This is general enough to be reusable, has meaningful but not ridiculously long variable names, and can easily be tested for correctness:
assert side(3, 5) == 4
assert side(5, 13) == 12
assert hypotenuse(3, 4) == 5
assert hypotenuse(5, 12) == 13
# a (300, 400, 500) triangle
assert tower_base(500) == 400
# a (500, 1200, 1300) triangle
assert fire_hypot(1200) == 1300
Testing your previous code:
# should make a (300, 400, 500) triangle
assert first_triangle(500) == 400 # 5.04017 ?! FAIL
And there is the math error: first_triangle returns tower_hypot**0.5 - 300**0.5 which is a meaningless quantity; it should be (tower_hypot**2 - 300**2)**0.5.
Unit analysis gives us a quick way to double-check; if tower_hypot is in meters, the first equation returns root-of-meters (which makes no sense) while the second returns meters (which is what we expected). That does not necessarily make it correct - but it makes it not obviously incorrect, which is a good start!
while True:
tower_hypot += 0.01
first_triangle(first_triangle_longest_side_length)
You called the function correctly, but you didn't keep the result anywhere; try a_dist = tower_base(tower_hypot).
canal_length_left = 1000 - a_dist
second_triangle(canal_length_left)
Again you haven't kept the function result; try fire_dist = fire_hypot(1000 - a_dist).
if first_triangle_longest_side_length == 1044.03:
break
Magic numbers! What fun!
it is not clear what this value means (it is (300**2 + 1000**2)**0.5 which is the maximum possible value of tower_hypot, but that is unclear at first glance)
floating point math means == is almost never going to work; you want > or >= instead
you have hard-coded in values for tower_height, canal_length, fire_height - which is bad practice - but you have now also hard-coded in values derived from those values, making your program very difficult to maintain (what happens next week, when the ranger sees a fire 1200 meters away and 200 meters from the canal? Does he have to rewrite the program from scratch to figure out where to go?)
then
total_distance = first_triangle_longest_side_length + second_triangle_longest_side_length
numbers_total.append(total_distance)
numbers_canal.append(first_trangle_bottom_side_length)
minimal_total_distance = min(numbers_total)
number_on_the_list = numbers_total.index(minimal_total_distance)
print "The distance of the shortest route is: " + "%.1f" % minimal_total_distance
print "The distance of the canal from point A is: " + "%.1f" % numbers_canal[number_on_the_list]
With a few more modifications the code looks like
# use named variables!
# - makes it easy to modify the program later
# - makes it easier to figure out what's going on
TOWER_HEIGHT = 300
CANAL_LENGTH = 1000
FIRE_HEIGHT = 500
# generic functions which can be reused!
def side(adjacent, hypotenuse):
"""
Given the side and hypotenuse of a right triangle,
return the other side
"""
return (hypotenuse**2 - adjacent**2) ** 0.5
def hypotenuse(adjacent, opposite):
"""
Given two sides of a right triangle,
return the hypotenuse
"""
return (adjacent**2 + opposite**2) ** 0.5
# work from the most obvious control value
def total_dist(a_dist):
tower_hypot = hypotenuse(a_dist, TOWER_HEIGHT)
b_dist = CANAL_LENGTH - a_dist
fire_hypot = hypotenuse(b_dist, FIRE_HEIGHT)
return tower_hypot + fire_hypot
def main():
step_size = 0.1
# equivalent of
# a_dists = numpy.arange(0.0, CANAL_LENGTH, step_size)
num_steps = int(CANAL_LENGTH / step_size)
a_dists = (k*step_size for k in range(num_steps + 1))
# find minimum distance
best_a_dist = min(a_dists, key=total_dist)
best_total_dist = total_dist(best_a_dist)
print("The distance of the shortest route is: {:0.1f}".format(best_total_dist))
print("The distance of the canal from point A is: {:0.1f}".format(best_a_dist))
main()
It is exactly what the error says. Python works line by line. Look above it inside your function. You never define `first_triangle_bottom_side_length". Define it in the function and the error will go away.
The variable first_triangle_bottom_side_length might be being declared as local inside the function, to solve this you return the variable and set it outside of the function.
(Inside first triangle):
Return first_triangle_bottom_side_length
...
firsttrianglebottomsidelength = first_triangle(first_triangle_longest_side_length)
canal_length_left = 1000 - firsttrianglebottomsidelength
Like Tim Castelijns wrote - it's a matter of scopes.
first_triangle_bottom_side_length is defined within the function first_triangle but you never returns it to your main program.
You should return it:
def first_triangle(first_triangle_longest_side_length):
calculation_one = sqrt(first_triangle_longest_side_length)
return calculation_one - sqrt(300)
[...]
[...]
while True:
first_triangle_longest_side_length = first_triangle_longest_side_length + 0.01
first_triangle_bottom_side_length = first_triangle(first_triangle_longest_side_length)
canal_length_left = 1000 - first_triangle_bottom_side_length
Read about scopes, but more important - learn how to work with functions.
Good luck!