if statements or while loop conditions? - python

So for an assignment, I'm supposed to write a function that evaluates two other functions that I previously defined in the program. How, the intricacies of this next function I must define is confusing me how I should set it up. Basically, I have determined that I have to write a while loop, but I can't decide whether to have three different conditions or if statements to evaluate this function. The thing is, the loop must end after one of the three conditions is met; I just don't know how to lay it out currently.
These are the three conditions (where only one must be met in order for the loop/function to terminate):
the absolute value of the polynomial at the current estimate is less than epsilon, in
which case the method is successful.
the absolute value of the derivative of the polynomial at the current estimate is less
than epsilon (this could lead to division by 0), in which case the method failed, or
the number of revisions of the estimate has exceeded timeout (the estimate is not
converging on a solution). This case is also a failure.
This is currently what I have as my code (and it hasn't been running obviously):
def newtonsMethod(poly, x_, epislon, timeout):
"""Calculating root of polynomial using newton's Method."""
estimate = 0
epislon = 1e-20
while (abs(evaluatePoly(poly, x_)) < epislon and \
abs(evaluatePoly(findDerivative(poly), x_)) and estimate > timeout):
estimate = x_ - (evaluatePoly(poly) / evaluatePoly(findDerivative(poly)))
x_ = estimate
print(x_)
How should I go about this? The function name is a requirement of the assignment so it cannot be changed. Also, I am a complete beginner at this stuff (just started last month) and I'm only basically required to have knowledge of data structures, loops, and if statements (and functions). So please keep your responses as simple/dumby proof as possible.
This is all the code I have before that pertains to this question:
def findDerivative(poly):
"""Find the derivative of the polynomial and return it as a list of
coefficents"""
count = 0
polyList = []
for nn in poly:
polyList += [nn * count]
count += 1
return polyList[1:]
def evaluatePoly(poly, x_):
"""Evaluates the polynomial at x = x_ and returns the result as a floating-
point number using Horner's rule"""
#http://mathworld.wolfram.com/HornersRule.html
count = 0
polyEval = []
for nn in poly:
xVal = x_**count
polyEval += [xVal * nn]
count += 1
polySum = sum(polyEval)
return float(polySum)
Edit: 10/23/2016
I should have mentioned this before or explained the assignment in more detail, but estimate is a parameter for the function because it is given as a list later on in the assignment. I have understood that timeout represents that the loop can run through so many times before it "breaks" or ends. The function is to return a two-part tuple where the first variable of the tuple is the refined x_ value and the second variable is a boolean value saying whether the method was successful or not. Using advice from both #Blckknght and #David Bowling , I was able to refine my code to the following:
def newtonsMethod(poly, x_, epsilon, timeout):
"""Calculating root of polynomial using newton's Method."""
deriv_poly = findDerivative(poly)
deriv = evaluatePoly(deriv_poly, x_)
value = evaluatePoly(poly, x_)
count = 1
while True:
x_ -= value / deriv
if abs(value) < epsilon:
boolean = abs(value) < epsilon
xTuple = (x_, boolean)
return xTuple
if abs(deriv) < epsilon or count > timeout:
boolean = abs(deriv) < epsilon or count > timeout
xTuple = (x_, boolean)
return xTuple
count += 1
However, I am still experiencing crashing problems when I run the code. I realized belatedly that I cannot have both boolean variables to equal to True (for my following code, I need boolean to equal True or False) but in order for the loop to stop, one of the if statements must equal True.
I apologize for all the confusion and specifications this code requires; I hope this explanation helps understanding what I need.

The advice given by others to break up your complicated conditional into simpler statements is very good. The logic in your original conditional was faulty, but could be adjusted to work. Yet there were other problems in your function.
There is no need to assign epsilon a value before the loop, because this value is supplied as a function parameter. estimate should be functioning as a counter, but then confusingly gets assigned the value to be used for x_ in the next iteration. I have renamed estimate as iterations in my code below.
You should have used:
abs(evaluatePoly(poly, x_)) > epsilon
since you want the loop to continue so long as the value of the polynomial evaluated at x_ is larger than epsilon. And, to avoid difficulties in the statement that updates the value of x_, you want to continue looping only if:
abs(evaluatePoly(findDerivative(poly), x_)) > epsilon
There was a missing conditional here in your original code. Finally, you want to continue looping if the number of iterations has not yet reached the timeout value. You only want to loop if all of the above conditions are met, so your conditional expression should be:
while abs(evaluatePoly(poly, x_)) > epsilon and \
abs(evaluatePoly(findDerivative(poly), x_)) > epsilon and \
iterations < timeout:
I changed your next assignment statement in two ways. First, the assignment is now made to x_ instead of the old, confusing estimate variable. Second, you were missing the second argument in both of the evaluatePoly() functions. I added a line to increment the iterations counter, and moved the print() out of the loop so that you only see the final result.
Here is the modified code:
def newtonsMethod(poly, x_, epsilon, timeout):
"""Calculating root of polynomial using newton's Method."""
iterations = 0
while abs(evaluatePoly(poly, x_)) > epsilon and \
abs(evaluatePoly(findDerivative(poly), x_)) > epsilon and \
iterations < timeout:
x_ = x_ - (evaluatePoly(poly, x_) / evaluatePoly(findDerivative(poly), x_))
iterations += 1
print(x_)
Here is a sample run using the findDerivative() and evaluatePoly() functions that you provided:
>>> xpr = [0, 0, 5]
>>> newtonsMethod(xpr, -1, 1e-20, 1000)
-2.91038304567e-11
>>> evaluatePoly(xpr, -2.91038304567e-11)
4.235164736261692e-21
Update:
I have looked at the new function definition that you posted, and found the problem. The fundamental problem in your code is that value and deriv are evaluated only once, outside the loop. You need to move these two statements inside of the loop so that they can be updated after each iteration. Also, I would move the assigment to x_ to the end of the loop so that your first guess gets tested before it is updated. You can simplify the bodies of your if statements a bit also. As it is, when you escape the function due to an unacceptably small value for deriv or a timeout, your function reports True. I assume that you want it to report False. Here is how I modified your code:
def newtonsMethod(poly, x_, epsilon, timeout):
"""Calculating root of polynomial using newton's Method."""
deriv_poly = findDerivative(poly)
count = 1
while True:
deriv = evaluatePoly(deriv_poly, x_)
value = evaluatePoly(poly, x_)
if abs(value) < epsilon:
boolean = True
return (x_, boolean)
if abs(deriv) < epsilon or count > timeout:
boolean = False
return (x_, boolean)
x_ -= value / deriv
count += 1
Here is a sample run:
>>> xpr = [0, 0, 5]
>>> newtonsMethod(xpr, -1, 1e-20, 1000)
(-2.9103830456733704e-11, True)
>>> evaluatePoly(xpr, -2.9103830456733704e-11)
4.235164736271502e-21
I am guessing that the slight difference between these results and the earlier results is due to rounding errors and the differing procedures for calculation.

As Barmar commented, using a simpler while condition (possible just while True) is almost always better than a very complicated condition that can't even fit on one line. You'd put the actual logic for ending the loop in one or more if statements inside the loop body:
while True: # no condition here
# do stuff
if failure_condition1():
break # stop looping
if success_condition():
return result() # another way to stop looping is to return a value
if failure_condition2():
raise SomeException() # you could also raise an exception on failure
# do other stuff
Any combination of return, raise or break could be correct for your function, it depends exactly what you want to do when each condition is met (and what you want the API to be).
One advantage to this style of loop is that you can check the conditions wherever it makes sense in your algorithm. The test doesn't have to be at the start of the loop (which often requires you to initialize your variables with made up values that will pass the condition the first time through).
Here's how I'd apply this kind of control flow in your specific problem:
def newtonsMethod(poly, x_, timeout):
"""Calculating root of polynomial using newton's Method."""
estimate = 0
epsilon = 1e-20
deriv_poly = findDerivative(poly)
while True:
value = evaluatePoly(poly, x_)
if abs(value) < epsilon:
return x_
deriv = evaluatePoly(deriv_poly, x_)
if abs(deriv) < epsilon or estimate > timeout:
raise ValueError("Not converging")
#print(x_, value, deriv)
x_ -= value / deriv
estimate += 1
Note that we only need to call evaluatePoly twice per pass, since we save the results rather than recomputing them.
I also fixed a few errors in your code. I use estimate as a counter, rather than an alias for x_ and no longer have epsilon as a parameter that is overwritten in the function body (you also had it misspelled as epislon).

Related

MIT 6.00 Newton's Method in Python 3

This is part of the second problem set for MIT's OCW 6.00 Intro to Computation and Programming using Python. First, I created a function that evaluates a polynomial for a given x value. Then a function that computes the derivative for a given polynomial. Using those, I created a function that evaluates the first derivative for a given polynomial and x value.
Then I tried to create a function to estimate the root of any given polynomial within a tolerance (epsilon).
Test case is at bottom with expected output.
I am new to programming and new to python, so I have included some comments in the code to explain what I think the code should be doing.
def evaluate_poly(poly, x):
""" Computes the polynomial function for a given value x. Returns that value."""
answer = poly[0]
for i in range (1, len(poly)):
answer = answer + poly[i] * x**i
return answer
def compute_deriv(poly):
"""
#Computes and returns the derivative of a polynomial function. If the
#derivative is 0, returns (0.0,)."""
dpoly = ()
for i in range(1,len(poly)):
dpoly = dpoly + (poly[i]*i,)
return dpoly
def df(poly, x):
"""Computes and returns the solution as a float to the derivative of a polynomial function
"""
dx = evaluate_poly(compute_deriv(poly), x)
#dpoly = compute_deriv(poly)
#dx = evaluate_poly(dpoly, x)
return dx
def compute_root(poly, x_0, epsilon):
"""
Uses Newton's method to find and return a root of a polynomial function.
Returns a float containing the root"""
iteration = 0
fguess = evaluate_poly(poly, x_0) #evaluates poly for first guess
print(fguess)
x_guess = x_0 #initialize x_guess
if fguess > 0 and fguess < epsilon: #if solution for first guess is close enough to root return first guess
return x_guess
else:
while fguess > 0 and fguess > epsilon:
iteration+=1
x_guess = x_0 - (evaluate_poly(poly,x_0)/df(poly, x_0))
fguess = evaluate_poly(poly, x_guess)
if fguess > 0 and fguess < epsilon:
break #fguess where guess is close enough to root, breaks while loop, skips else, return x_guess
else:
x_0 = x_guess #guess again with most recent guess as x_0 next time through while loop
print(iteration)
return x_guess
#Example:
poly = (-13.39, 0.0, 17.5, 3.0, 1.0) #x^4 + 3x^3 + 17.5x^2 - 13.39
x_0 = 0.1
epsilon = .0001
print (compute_root(poly, x_0, epsilon))
#answer should be 0.80679075379635201
The first 3 functions return correct answers, but compute_root (Newton's method) does not seem to enter the while loop because when I run the cell print(iteration) prints 0. I would think that since if fguess > 0 and fguess < epsilon: should return false for the test case (statement print(fguess) prints -13.2119), the interpreter would go to else and enter the while loop until it finds a solution that is within epsilon of 0.
I have tried eliminating the first if else conditions so that I only have one return statement and I get the same problem.
What could be causing the function to skip the else case / while loop altogether? I'm stumped!
Thanks for looking and/or helping!
It seems to be just a small oversight. Notice how fguess is printed with a value of -13.2119. In your while condition (in else from compute_root) you require fguess > 0 and fguess < epsilon, which is not met so nothing is done further and you exit without iterations.
Instead:
while fguess < 0 or fguess > epsilon:
Will give you what you need:
-13.2119
7
0.806790753796352

Using recursion to calculate powers of large digit numbers

The goal is to calculate large digit numbers raised to other large digit numbers, e.g., 100 digit number raised to another 100 digit number, using recursion.
My plan was to recursively calculate exp/2, where exp is the exponent, and making an additional calculation depending on if exp is even or odd.
My current code is:
def power(y, x, n):
#Base Case
if x == 0:
return 1
#If d is even
if (x%2==0):
m = power(y, x//2, n)
#Print statment only used as check
print(x, m)
return m*m
#If d is odd
else:
m = y*power(y, x//2, n)
#Print statement only used as check
print(x, m)
return m*m
The problem I run into is that it makes one too many calculations, and I'm struggling to figure out how to fix it. For example, 2^3 returns 64, 2^4 returns 256, 2^5 returns 1024 and so on. It's calculating the m*m one too many times.
Note: this is part of solving modulus of large numbers. I'm strictly testing the exponent component of my code.
First of all there is a weird thing with your implementation: you use a parameter n that you never use, but simply keep passing and you never modify.
Secondly the second recursive call is incorrect:
else:
m = y*power(y, x//2, n)
#Print statement only used as check
print(x, m)
return m*m
If you do the math, you will see that you return: (y yx//2)2=y2*(x//2+1) (mind the // instead of /) which is thus one y too much. In order to do this correctly, you should thus rewrite it as:
else:
m = power(y, x//2, n)
#Print statement only used as check
print(x, m)
return y*m*m
(so removing the y* from the m part and add it to the return statement, such that it is not squared).
Doing this will make your implementation at least semantically sound. But it will not solve the performance/memory aspect.
Your comment makes it clear that you want to do a modulo on the result, so this is probably Project Euler?
The strategy is to make use of the fact that modulo is closed under multiplication. In other words the following holds:
(a b) mod c = ((a mod c) * (b mod c)) mod c
You can use this in your program to prevent generating huge numbers and thus work with small numbers that require little computational effort to run.
Another optimization is that you can simply use the square in your argument. So a faster implementation is something like:
def power(y, x, n):
if x == 0: #base case
return 1
elif (x%2==0): #x even
return power((y*y)%n,x//2,n)%n
else: #x odd
return (y*power((y*y)%n,x//2,n))%n
If we do a small test with this function, we see that the two results are identical for small numbers (where the pow() can be processed in reasonable time/memory): (12347**2742)%1009 returns 787L and power(12347,2742,1009) 787, so they generate the same result (of course this is no proof), that both are equivalent, it's just a short test that filters out obvious mistakes.
here is my approach accornding to the c version of this problem it works with both positives and negatives exposents:
def power(a,b):
"""this function will raise a to the power b but recursivelly"""
#first of all we need to verify the input
if isinstance(a,(int,float)) and isinstance(b,int):
if a==0:
#to gain time
return 0
if b==0:
return 1
if b >0:
if (b%2==0):
#this will reduce time by 2 when number are even and it just calculate the power of one part and then multiply
if b==2:
return a*a
else:
return power(power(a,b/2),2)
else:
#the main case when the number is odd
return a * power(a, b- 1)
elif not b >0:
#this is for negatives exposents
return 1./float(power(a,-b))
else:
raise TypeError('Argument must be interfer or float')

My short recursive function takes too long to execute, how can I optimize it

I am trying to solve this problem on CodeChef: http://www.codechef.com/problems/COINS
But when I submit my code, it apparently takes too long to execute, and says the time has expired. I am not sure if my code is inefficient (it doesn't seem like it to me) or if it I am having trouble with I/O. There is a 9 second time limit, to solve maximum 10 inputs, 0 <= n <= 1 000 000 000.
In Byteland they have a very strange monetary system.
Each Bytelandian gold coin has an integer number written on it. A coin
n can be exchanged in a bank into three coins: n/2, n/3 and n/4. But
these numbers are all rounded down (the banks have to make a profit).
You can also sell Bytelandian coins for American dollars. The exchange
rate is 1:1. But you can not buy Bytelandian coins.
You have one gold coin. What is the maximum amount of American dollars
you can get for it?
Here is my code: It seems to take too long for an input of 1 000 000 000
def coinProfit(n):
a = n/2
b = n/3
c = n/4
if a+b+c > n:
nextProfit = coinProfit(a)+coinProfit(b)+coinProfit(c)
if nextProfit > a+b+c:
return nextProfit
else:
return a+b+c
return n
while True:
try:
n = input()
print(coinProfit(n))
except Exception:
break
The problem is that your code branches each recursive call into three new ones. This leads to exponential behavior.
The nice thing however is that most calls are duplcates: if you call coinProfit with 40, this will cascade to:
coinProfit(40)
- coinProfit(20)
- coinProfit(10)
- coinProfit(6)
- coinProfit(5)
- coinProfit(13)
- coinProfit(10)
What you see is that a lot of effort is repeated (in this small example, coinProfit is called already twice on 10).
You can use Dynamic programming to solve this: store earlier computed results preventing you from branching again on this parts.
One can implement dynamic programing him/herself, but one can use the #memoize decorator to do this automatically.
Now the function does a lot of work way too much times.
import math;
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#memoize
def coinProfit(n):
a = math.floor(n/2)
b = math.floor(n/3)
c = math.floor(n/4)
if a+b+c > n:
nextProfit = coinProfit(a)+coinProfit(b)+coinProfit(c)
if nextProfit > a+b+c:
return nextProfit
else:
return a+b+c
return n
The #memoize transforms the function such that: for the function, an array of already calculated outputs is maintained. If for a given input, the output has already been computed, it is stored in the array, and immediately returned. Otherwise it is computed as defined by your method, stored in the array (for later use) and returned.
As #steveha points out, python already has a built-in memoize function called lru_cache, more info can be found here.
A final note is that #memoize or other Dynamic programming constructs, are not the solution to all efficiency problems. First of all #memoize can have an impact on side-effects: say your function prints something on stdout, then with #memoize this will have an impact on the number of times something is printed. And secondly, there are problems like the SAT problem where #memoize simply doesn't work at all, because the context itself is exponential (this as far as we know). Such problems are called NP-hard.
You can optimize the program by storing result in some sort of cache. So if the result exist in cache then no need to perform the calculation , otherwise calculate and put the value in the cache. By this way you avoid calculating already calculated values. E.g.
cache = {0: 0}
def coinProfit(num):
if num in cache:
return cache[num]
else:
a = num / 2
b = num / 3
c = num / 4
tmp = coinProfit(c) + coinProfit(b) + coinProfit(a)
cache[num] = max(num, tmp)
return cache[num]
while True:
try:
print coinProfit(int(raw_input()))
except:
break
I just tried and noticed a few things... This doesn't have to be considered as The answer.
On my (recent) machine, it takes a solid 30 seconds to compute with n = 100 000 000. I imagine that it's pretty normal for the algorithm you just wrote, because it computes the same values times and times again (you didn't optimise your recursion calls with caching as suggested in other answers).
Also, the problem definition is pretty gentle because it insists: each Bytelandian gold coin has an integer number written on it, but these numbers are all rounded down. Knowing this, you should be turning the three first lines of your function into:
import math
def coinProfit(n):
a = math.floor(n/2)
b = math.floor(n/3)
c = math.floor(n/4)
This will prevent a, b, c to be turned into float numbers (Python3 at least) which would make your computer go like crazy into a big recursive mess, even with the smallest values of n.

Finding the root of an equation with a constraint

In python, I would like to find the roots of equations of the form:
-x*log(x) + (1-x)*log(n) - (1-x)*log(1 - x) - k = 0
where n and k are parameters that will be specified.
An additional constraint on the roots is that x >= (1-x)/n. So just for what it's worth, I'll be filtering out roots that don't satisfy that.
My first attempt was to use scipy.optimize.fsolve (note that I'm just setting k and n to be 0 and 1 respectively):
def f(x):
return -x*log(x) + (1-x)*log(1) - (1-x)*log(1-x)
fsolve(f, 1)
Using math.log, I got value-errors because I was supplying bad input to log. Using numpy.log gave me some divide by zeros and invalid values in multiply.
I adjusted f as so, just to see what it would do:
def f(x):
if x <= 0:
return 1000
if x >= 1:
return 2000
return -x*log(x) + (1-x)*log(1) - (1-x)*log(1-x)
Now I get
/usr/lib/python2.7/dist-packages/scipy/optimize/minpack.py:221: RuntimeWarning: The iteration is not making good progress, as measured by the
improvement from the last ten iterations.
warnings.warn(msg, RuntimeWarning)
Using python, how can I solve for x for various n and k parameters in the original equation?
fsolve also allows guesses to be inserted for where to start. My suggestion would be to plot the equation and have the user type a initial guess either with the mouse or via text to use as an initial guess. You may also want to change the out of bounds values:
if x <= 0:
return 1000 + abs(x)
if x >= 1:
return 2000 + abs(x)
This way the function has a slope outside of the region of interest that will guide the solver back into the interesting region.

successive approximation in python

Successive approximation is a general method in which on each iteration of an algorithm, we find a closer estimate of the answer for which we are seeking. One class of successive approximation algorithms uses the idea of a fixed point. If f(x) is a mathematical function, then finding the x such that f(x) = x gives us the fixed point of f.
One way to find a fixed point is to start with some guess (e.g. guess = 1.0) and, if this is not good enough, use as a next guess the value of f(guess). We can keep repeating this process until we get a guess that is within epsilon of f(guess).
here's my code:
def fixedPoint(f, epsilon):
"""
f: a function of one argument that returns a float
epsilon: a small float
returns the best guess when that guess is less than epsilon
away from f(guess) or after 100 trials, whichever comes first.
"""
guess = 1.0
for i in range(100):
if abs(f(guess) - guess) < epsilon:
return guess
else:
guess = f(guess)
return guess
further now...
def sqrt(a):
def tryit(x):
return 0.5 * (a/x + x)
return fixedPoint(tryit, 0.0001)
I want to compute square root of a number "a", is the fixed point of the function f(x) = 0.5 * (a/x + x). AND DONE.
(Above solutions are correct)
Successive approximation is a general method in which on each iteration of an algorithm, we find a closer estimate of the answer for which we are seeking. One class of successive approximation algorithms uses the idea of a fixed point. If f(x) is a mathematical function, then finding the x such that f(x) = x gives us the fixed point of f.
One way to find a fixed point is to start with some guess (e.g. guess = 1.0) and, if this is not good enough, use as a next guess the value of f(guess). We can keep repeating this process until we get a guess that is within epsilon of f(guess).
example in python:
def fixedPoint(f, epsilon):
"""
f: a function of one argument that returns a float
epsilon: a small float
returns the best guess when that guess is less than epsilon
away from f(guess) or after 100 trials, whichever comes first.
"""
guess = 1.0
for i in range(100):
if -epsilon < f(guess) - guess < epsilon:
return guess
else:
guess = f(guess)
return guess
further let function f be for finding square root using babylon method:
def sqrt(a):
def babylon(x):
def test(x):
return 0.5 * ((a / x) + x)
return test(x)
return fixedPoint(babylon, 0.0001)
You might want to take a look at the optimization and root-finding functions in scipy.
Especially scipy.optimize.fixed_point. The actual source code is here.

Categories

Resources