Basics of Simulated Annealing in Python [closed] - python

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I have to use simulated annealing for a certain optimization problem. To get a 'feel' of the technique, I wrote a small python code and tried to run it. However, it doesn't seem to be giving satisfactory results.
import random;
import math;
from math import *;
LIMIT=100000;
def update_temperature(T,k):
T1=T/log(k+1);
# print "temp now is " + str(T1);
return T1;
def get_neighbors(i,l):
if(l>1):
if(0<=i and i<l):
if(i==0):
return [1];
if(i==l-1):
return [l-2];
return [i-1,i+1];
return [];
def make_move(x,A,T):
nhbs=get_neighbors(x,len(A));
nhb=nhbs[random.choice(range(0,len(nhbs)))];
delta=A[nhb]-A[x];
if(delta < 0):
return nhb;
else:
r=random.random();
if(r <= (e**(-1*delta)/(T*1.0))):
return nhb;
return x;
def simulated_annealing(A):
l=len(A);
init_pos=random.choice(xrange(0,l));
T=10000**30;
k=1;
x_best=init_pos;
x=x_best;
while(T>0.0000001 ):
x=make_move(x,A,T);
if(A[x] < A[x_best]):
x_best=x;
T=update_temperature(T,k);
k+=1;
return [x,x_best,init_pos];
def isminima_local(p,A):
l=len(A);
if(l==1 and p==0):
return True;
if(l>1):
if(p==0):
if(A[0] <=A[1]):
return True;
if(p==l-1):
if(A[p-1] >=A[p]):
return True;
if(0<=p and p<l and A[p-1]>=A[p] and A[p]<=A[p+1]):
return True;
return False;
def func(x):
F=sin(x);
return F;
def initialize(l):
A=[0]*l;
for i in xrange(0,l):
A[i]=func(i);
return A;
def main():
A=initialize(LIMIT);
local_minima=[];
for i in xrange(0,LIMIT):
if( isminima_local(i,A)):
local_minima.append([i,A[i]]);
sols=simulated_annealing(A);
m,p=A[0],0;
for i in xrange(1,LIMIT):
if(m>A[i]):
m=A[i];
p=i;
print "Global Minima at \n";
print p,m;
print "After annealing\n";
print "Solution is " + str(sols[0]) + " " + str(A[sols[0]]);
print "Best Solution is " + str(sols[1]) + " " + str(A[sols[1]]);
print "Start Solution is " + str(sols[2]) + " " + str(A[sols[2]]);
for i in xrange(0,len(local_minima)):
if([sols[0],A[sols[0]]]==local_minima[i]):
print "Solution in local Minima";
if([sols[1],A[sols[1]]]==local_minima[i]):
print "Best Solution in local Minima";
for i in local_minima:
print i;
main();
I am unable to understand where I am going wrong. Is there something wrong with the implementation or is there something wrong in my understanding about simulated annealing ? Please point out the error..
My rough idea about SA:
Pick a random neighbor
If neighbor improves your condition, move there,
Else, move there with certain probability.
The probability is such that initially bad moves are 'allowed' but they are 'prohibited' later on. Finally you will converge to your solution.
I have found the set of local minima and global minima using brute force. Then I run SA. I was expecting that SA will atleast converge to a local minima but that doesn't seem to be the case always. Also, I am not sure if at every step I choose a neighbor randomly and then try to move or I choose the best neighbor ( even if none of the neighbors improve my condition) and then try to move there.

For the most part, your code seems to work well. The main reason that it's slow to converge is that you only look at the two neighbors on either side of your current point: if you expand your search to include any point in A, or even just a wider neighborhood around your current point, you'll be able to move around the search space much more quickly.
Another trick with simulated annealing is determining how to adjust the temperature. You started with a very high temperature, where basically the optimizer would always move to the neighbor, no matter what the difference in the objective function value between the two points. This kind of random movement doesn't get you to a better point on average. The trick is finding a low enough starting temperature value such that the optimizer will move to better points significantly more often than it moves to worse points, but at the same time having a starting temperature that is high enough to allow the optimizer to explore the search space. As I mentioned in my first point, if the neighborhood that you select points from is too limited, then you'll never be able to properly explore the search space even if you have a good temperature schedule.
Your original code was somewhat hard to read, both because you used a lot of conventions that Python programmers try to avoid (e.g., semicolons at ends of lines), and because you did a few things that programmers in general try to avoid (e.g., using lowercase L as a variable name, which looks very similar to the numeral 1). I rewrote your code to make it both more readable and more Pythonic (with the help of autopep8). Check out the pep8 standard for more information.
In make_move, my rewrite picks one random neighbor from across the whole search space. You can try rewriting it to look in an expanded local neighborhood of the current point, if you're interested in seeing how well that works (something between what you had done above and what I've done here).
import random
import math
LIMIT = 100000
def update_temperature(T, k):
return T - 0.001
def get_neighbors(i, L):
assert L > 1 and i >= 0 and i < L
if i == 0:
return [1]
elif i == L - 1:
return [L - 2]
else:
return [i - 1, i + 1]
def make_move(x, A, T):
# nhbs = get_neighbors(x, len(A))
# nhb = nhbs[random.choice(range(0, len(nhbs)))]
nhb = random.choice(xrange(0, len(A))) # choose from all points
delta = A[nhb] - A[x]
if delta < 0:
return nhb
else:
p = math.exp(-delta / T)
return nhb if random.random() < p else x
def simulated_annealing(A):
L = len(A)
x0 = random.choice(xrange(0, L))
T = 1.
k = 1
x = x0
x_best = x0
while T > 1e-3:
x = make_move(x, A, T)
if(A[x] < A[x_best]):
x_best = x
T = update_temperature(T, k)
k += 1
print "iterations:", k
return x, x_best, x0
def isminima_local(p, A):
return all(A[p] < A[i] for i in get_neighbors(p, len(A)))
def func(x):
return math.sin((2 * math.pi / LIMIT) * x) + 0.001 * random.random()
def initialize(L):
return map(func, xrange(0, L))
def main():
A = initialize(LIMIT)
local_minima = []
for i in xrange(0, LIMIT):
if(isminima_local(i, A)):
local_minima.append([i, A[i]])
x = 0
y = A[x]
for xi, yi in enumerate(A):
if yi < y:
x = xi
y = yi
global_minumum = x
print "number of local minima: %d" % (len(local_minima))
print "global minimum #%d = %0.3f" % (global_minumum, A[global_minumum])
x, x_best, x0 = simulated_annealing(A)
print "Solution is #%d = %0.3f" % (x, A[x])
print "Best solution is #%d = %0.3f" % (x_best, A[x_best])
print "Start solution is #%d = %0.3f" % (x0, A[x0])
main()

Related

I am passing a set of N values to a loop but cant get it to print an ouput

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.

Newton’s method on functions that contains matrices using Python

I was able to find several implementations of Newton's methods, for example, this link or maybe this one.
However, most of the time the examples are with simple functions such as:
x^2−9=0 or x^3-x^2-1=0. I am looking for something that would work for:
My question for that I am lost in how to use this code to solve my problem. For example, I am not sure how I would apply the derivative (dfdx) on my F(x) that contain matrices. Also, if I should direct input the matrices on my "def f(x)"
The code that I am using:
def Newton(f, dfdx, x, eps):
f_value = f(x)
iteration_counter = 0
while abs(f_value) > eps and iteration_counter < 100:
try:
x = x - float(f_value)/dfdx(x)
except ZeroDivisionError:
print "Error! - derivative zero for x = ", x
sys.exit(1) # Abort with error
f_value = f(x)
iteration_counter += 1
# Here, either a solution is found, or too many iterations
if abs(f_value) > eps:
iteration_counter = -1
return x, iteration_counter
def f(x):
return x**2 - 9
def dfdx(x):
return 2*x
solution, no_iterations = Newton(f, dfdx, x=1000, eps=1.0e-6)
if no_iterations > 0: # Solution found
print "Number of function calls: %d" % (1 + 2*no_iterations)
print "A solution is: %f" % (solution)
else:
print "Solution not found!"
There aren't any special rules for deriving matrices - the derivative is just calculated for each element separately. I would suggest evaluating the $[x1,x2]' * M * [x1,x2]$ expression on paper to get a matrix of polynomials, and then calculating the derivative of each one.

Python 2.7 Improving recursive pollard rho factorization with memoize

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

Name error: Variable not defined

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!

How to define codependent functions in Python?

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

Categories

Resources