Newton Recursive Method for Square Root Problem in Python - python

For a=13 and a precision epsilon=10^-7. How many times do you apply the newton recursion formula in newton_sqrt(13,10^-7)? Hint: use global variables.
My current newton_sqrt(a, epsilon) function is the following:
def newton_sqrt(a, epsilon):
global count
if a < 0:
print("Error: a < 0")
return -1
elif a == 0.0:
return 0
else:
x = abs(a)
newx = 0.5*(x + a/x)
if abs(x - newx) > epsilon:
newton_sqrt(newx, epsilon)
count = count + 1
if not abs(x-newx) > epsilon:
print (count)
return newx
newton_sqrt(13, 0.000001)
For whatever reason, I get
918488688 None
as my output.
Please help.

There is no output since you never reach the print line:
basically, you have:
if x:
if not x:
print(something)
what you want, i'm guessing is:
if x:
#do something
else:
#do somthing else
not knowing the math of your function I would change it into:
def newton_sqrt(a, epsilon, count):
if a < 0:
print("Error: a < 0")
return -1
elif a == 0.0:
return 0
else:
x = abs(a)
newx = 0.5*(x + a/x)
if abs(x - newx) > epsilon:
count = count + 1
newton_sqrt(newx, epsilon, count)
else:
print (count)
return newx
which will give you:
newton_sqrt(13, 0.000001, 0)
23

First, let's be clear that your newton_sqrt() function doesn't work. Either you're trying to instrument the recursion depth to fix it, or you're unaware it's broken.
A working newton_sqrt() would be along the lines of:
import sys
def newton_sqrt(a, epsilon, x=None):
if a < 0:
print("Error: a < 0", file=sys.stderr)
return -1
if a == 0:
return 0
if x is None: # initial guess
x = a
new_x = (x + a / x) / 2 # refine guess
if abs(new_x * new_x - a) < epsilon: # test guess
return new_x
return newton_sqrt(a, epsilon, new_x) # (better) guess again
print(newton_sqrt(13, 1e-06))
Once that's working, instrumenting the recursion depth using a global variable, count, is simple:
import sys
count = 0
def newton_sqrt(a, epsilon, x=None):
global count
count += 1
if a < 0:
print("Error: a < 0", file=sys.stderr)
return -1
if a == 0:
return 0
if x is None: # initial guess
x = a
new_x = (x + a / x) / 2 # refine guess
if abs(new_x * new_x - a) < epsilon: # test guess
return new_x
return newton_sqrt(a, epsilon, new_x) # (better) guess again
print(newton_sqrt(13, 1e-06), count)
OUTPUT
> python3 test.py
3.6055513629176015 5
>
Where 3.6055513629176015 is the square root of 13 and 5 is the recursion depth needed to compute it with an error of less than 1e-06.

Related

Unable to use recursion

Problem link = https://leetcode.com/problems/minimum-operations-to-reduce-x-to-zero/
Was practicing on leetcode and came around the above the Q. Wrote the code written below, no idea why it is not running!
def min_num(nums,x):
f_ele = nums[0]
l_ele = nums[-1]
count = 0
if min(x - f_ele, x - l_ele ) >= 0:
count += 1
#modifying x and nums
if x - f_ele == min(x - f_ele, x - l_ele ):
x = x - f_ele
nums.remove(f_ele)
else:
x = x - l_ele
nums.remove(l_ele)
#Comparing x to use recursion or return the count
if x != 0:
min_num(nums,x)
else:
return count
elif x == 0:
return count
else:
return -1
Please help!!
When you do recursion and want to return something you need to also return the result from the recursion itself.
You also can't set the count to zero in the min_num function because then the count will constantly be set to zero when you run the recursion.
Here is your code with these two small changes:
def min_num(nums, x, count=0):
f_ele = nums[0]
l_ele = nums[-1]
if min(x - f_ele, x - l_ele) >= 0:
count += 1
# modifying x and nums
if x - f_ele == min(x - f_ele, x - l_ele):
x = x - f_ele
nums.remove(f_ele)
else:
x = x - l_ele
nums.remove(l_ele)
# Comparing x to use recursion or return the count
if x != 0:
return min_num(nums, x, count)
else:
return count
elif x == 0:
return count
else:
return -1
nums = [1, 1, 4, 2, 3]
x = 5
print(min_num(nums, x))
This returns 2
def find_min(x,arrayin):
if (len(arrayin)==0 or x==-1):
return -1
elif x==0:
return len(arrayin)
left=arrayin[0]
right=arrayin[len(arrayin)-1]
if x-min(left,right)<0:
return find_min(-1,arrayin)
if x-max(left,right)>=0:
if left>right: ##Remove left
return find_min(x-left,arrayin[1:len(arrayin)])
else:##Remove right
return find_min(x-right,arrayin[0:len(arrayin)-1])
elif x-min(left,right)>=0:
if left>right: ##Remove left
return find_min(x-right,arrayin[0:len(arrayin)-1])
else:
return find_min(x-left,arrayin[1:len(arrayin)])
nums = [3,2,20,1,1,3]
x = 10
res=find_min(x,nums)
if res==-1:
print("-1")
else:
Answer=len(nums)-res
print(str(Answer))

How to compare float and decimal in python?

I have a (decimal.Decimal) column in a dataframe as below:
dt = pd.DataFrame({"OPEN": [-0.00010,-0.0114, 0.0066,-0.0044,-0.0012,-0.0005,
0.0005,-0.0037, -0.0029, 0.0034, 0.0003, 0.0001 ]})
dt["OPEN"] = dt["OPEN"].apply(Decimal)
and I would like to apply the following method over the Open column:
def label_change_price(delta):
if 0 < abs(delta) < 0.0001:
print(" Return value: ",0, "Delta: ",delta)
return 0
elif 0.0001 <= abs(delta) < 0.0002:
print(" Return value: ",1, "Delta: ",delta)
return int(np.sign(delta)) * 1
elif 0.0002 <= abs(delta) < 0.0003:
print(" Return value: ",2, "Delta: ",delta)
return int(np.sign(delta)) * 2
elif 0.0003 <= abs(delta):
print(" Return value: ",3, "Delta: ",delta)
return int(np.sign(delta)) * 3
When i run the code, for the very first row (-0.00010) it print
Return value: 0 Delta: -0.00010
which is wrong, as it must return 1, however it returns 0.
In other word, the first condition in if comes True and it does not continue to the second elif.
So, I am wondering, why my second elif 0.0001 <= abs(delta) < 0.0002: is not working well, when the delta is 0.0001 ? And how i can fix it ?
You might try comparisons like this:
if abs(Decimal(0)) < abs(delta) < abs(Decimal(0.0001)):
Comparisons seem tricksy:
from decimal import Decimal
Decimal(0.0001) == 0.0001
# True
abs(Decimal(0.0001)) == 0.0001
# False
Decimal(0.0001) == Decimal(0.0001)
# True
abs(Decimal(0.0001)) == Decimal(0.0001)
# False
abs(Decimal(0.0001)) == abs(Decimal(0.0001))
# True

How can I implement IDA* algorithm in Python for 15-Puzzle problem?

I'm trying to solve the 15-Puzzle problem using IDA* algorithm and Manhattan heuristic.
I already implemented the algorithm from the pseudocode in this Wikipedia page (link).
Here's my code so far :
def IDA(initial_state, goal_state):
initial_node = Node(initial_state)
goal_node = Node(goal_state)
threshold = manhattan_heuristic(initial_state, goal_state)
path = [initial_node]
while 1:
tmp = search(path, goal_state, 0, threshold)
if tmp == True:
return path, threshold
elif tmp == float('inf'):
return False
else:
threshold = tmp
def search(path, goal_state, g, threshold):
node = path[-1]
f = g + manhattan_heuristic(node.state, goal_state)
if f > threshold:
return f
if np.array_equal(node.state, goal_state):
return True
minimum = float('inf')
for n in node.nextnodes():
if n not in path:
path.append(n)
tmp = search(path, goal_state, g + 1, threshold)
if tmp == True:
return True
if tmp < minimum:
minimum = tmp
path.pop()
return minimum
def manhattan_heuristic(state1, state2):
size = range(1, len(state1) ** 2)
distances = [count_distance(num, state1, state2) for num in size]
return sum(distances)
def count_distance(number, state1, state2):
position1 = np.where(state1 == number)
position2 = np.where(state2 == number)
return manhattan_distance(position1, position2)
def manhattan_distance(a, b):
return abs(b[0] - a[0]) + abs(b[1] - a[1])
class Node():
def __init__(self, state):
self.state = state
def nextnodes(self):
zero = np.where(self.state == 0)
y,x = zero
y = int(y)
x = int(x)
up = (y - 1, x)
down = (y + 1, x)
right = (y, x + 1)
left = (y, x - 1)
arr = []
for direction in (up, down, right, left):
if len(self.state) - 1 >= direction[0] >= 0 and len(self.state) - 1 >= direction[1] >= 0:
tmp = np.copy(self.state)
tmp[direction[0], direction[1]], tmp[zero] = tmp[zero], tmp[direction[0], direction[1]]
arr.append(Node(tmp))
return arr
I'm testing this code with a 3x3 Puzzle and here's the infinite loop! Due to the recursion I have some trouble testing my code...
I think the error might be here : tmp = search(path, goal_state, g + 1, threshold) (in the search function). I'm adding only one to the g cost value. It should be correct though, because I can only move a tile 1 place away.
Here's how to call the IDA() function:
initial_state = np.array([8 7 3],[4 1 2],[0 5 6])
goal_state = np.array([1 2 3],[8 0 4],[7 6 5])
IDA(initial_state, goal_state)
Can someone help me on this ?
There are couple of issues in your IDA* implementation. First, what is the purpose of the variable path? I found two purposes of path in your code:
Use as a flag/map to keep the board-states that is already been visited.
Use as a stack to manage recursion states.
But, it is not possible to do both of them by using a single data structure. So, the first modification that your code requires:
Fix-1: Pass current node as a parameter to the search method.
Fix-2: flag should be a data structure that can perform a not in query efficiently.
Now, fix-1 is easy as we can just pass the current visiting node as the parameter in the search method. For fix-2, we need to change the type of flag from list to set as:
list's average case complexity for x in s is: O(n)
set's
Average case complexity for x in s is: O(1)
Worst case complexity for x in s is: O(n)
You can check more details about performance for testing memberships: list vs sets for more details.
Now, to keep the Node information into a set, you need to implement __eq__ and __hash__ in your Node class. In the following, I have attached the modified code.
import timeit
import numpy as np
def IDA(initial_state, goal_state):
initial_node = Node(initial_state)
goal_node = Node(goal_state)
threshold = manhattan_heuristic(initial_state, goal_state)
#print("heuristic threshold: {}".format(threshold))
loop_counter = 0
while 1:
path = set([initial_node])
tmp = search(initial_node, goal_state, 0, threshold, path)
#print("tmp: {}".format(tmp))
if tmp == True:
return True, threshold
elif tmp == float('inf'):
return False, float('inf')
else:
threshold = tmp
def search(node, goal_state, g, threshold, path):
#print("node-state: {}".format(node.state))
f = g + manhattan_heuristic(node.state, goal_state)
if f > threshold:
return f
if np.array_equal(node.state, goal_state):
return True
minimum = float('inf')
for n in node.nextnodes():
if n not in path:
path.add(n)
tmp = search(n, goal_state, g + 1, threshold, path)
if tmp == True:
return True
if tmp < minimum:
minimum = tmp
return minimum
def manhattan_heuristic(state1, state2):
size = range(1, len(state1) ** 2)
distances = [count_distance(num, state1, state2) for num in size]
return sum(distances)
def count_distance(number, state1, state2):
position1 = np.where(state1 == number)
position2 = np.where(state2 == number)
return manhattan_distance(position1, position2)
def manhattan_distance(a, b):
return abs(b[0] - a[0]) + abs(b[1] - a[1])
class Node():
def __init__(self, state):
self.state = state
def __repr__(self):
return np.array_str(self.state.flatten())
def __hash__(self):
return hash(self.__repr__())
def __eq__(self, other):
return self.__hash__() == other.__hash__()
def nextnodes(self):
zero = np.where(self.state == 0)
y,x = zero
y = int(y)
x = int(x)
up = (y - 1, x)
down = (y + 1, x)
right = (y, x + 1)
left = (y, x - 1)
arr = []
for direction in (up, down, right, left):
if len(self.state) - 1 >= direction[0] >= 0 and len(self.state) - 1 >= direction[1] >= 0:
tmp = np.copy(self.state)
tmp[direction[0], direction[1]], tmp[zero] = tmp[zero], tmp[direction[0], direction[1]]
arr.append(Node(tmp))
return arr
initial_state = np.array([[8, 7, 3],[4, 1, 2],[0, 5, 6]])
goal_state = np.array([[1, 2, 3],[8, 0, 4],[7, 6, 5]])
start = timeit.default_timer()
is_found, th = IDA(initial_state, goal_state)
stop = timeit.default_timer()
print('Time: {} seconds'.format(stop - start))
if is_found is True:
print("Solution found with heuristic-upperbound: {}".format(th))
else:
print("Solution not found!")
Node: Please double check your Node.nextnodes() and manhattan_heuristic() methods as I did not pay much attention in those areas. You can check this GitHub repository for other algorithmic implementations (i.e., A*, IDS, DLS) to solve this problem.
References:
Python Wiki: Time Complexity
TechnoBeans: Performance for testing memberships: list vs tuples vs sets
GitHub: Puzzle Solver (by using problem solving techniques)

How to generate alternating substrings using recursion

I have a practice question that requires me to generate x number of alternating substrings, namely "#-" & "#--" using both recursion as well as iteration. Eg.string_iteration(3) generates "#-#--#-".
I have successfully implemented the solution for the iterative method,
but I'm having trouble getting started on the recursive method. How can I proceed?
Iterative method
def string_iteration(x):
odd_block = '#-'
even_block = '#--'
current_block = ''
if x == 0:
return ''
else:
for i in range(1,x+1):
if i % 2 != 0:
current_block += odd_block
elif i % 2 == 0:
current_block += even_block
i += 1
return current_block
For recursion, you almost always just need a base case and everything else. Here, your base case it pretty simple — when x < 1, you can return an empty string:
if x < 1:
return ''
After than you just need to return the block + the result of string_iteration(x-1). After than it's just a matter of deciding which block to choose. For example:
def string_iteration(x):
# base case
if x < 1:
return ''
blocks = ('#--', '#-')
# recursion
return string_iteration(x-1) + blocks[x % 2]
string_iteration(5)
# '#-#--#-#--#-'
This boils down to
string_iteration(1) + string_iteration(2) ... string_iteration(x)
The other answer doesn't give the same result as your iterative method. If you always want it to start with the odd block, you should add the block on the right of the recursive call instead of the left:
def string_recursion(x):
odd_block = '#-'
even_block = '#--'
if x == 0:
return ''
if x % 2 != 0:
return string_recursion(x - 1) + odd_block
elif x % 2 == 0:
return string_recursion(x - 1) + even_block
For recursive solution, you need a base case and calling the function again with some other value so that at the end you will have the desired output. Here, we can break this problem recursively like - string_recursive(x) = string_recursive(x-1) + string_recursive(x-2) + ... + string_recursive(1).
def string_recursion(x, parity):
final_str = ''
if x == 0:
return ''
if parity == -1: # when parity -1 we will add odd block
final_str += odd_block
elif parity == 1:
final_str += even_block
parity *= -1 # flip the parity every time
final_str += string_recursion(x-1, parity)
return final_str
odd_block = '#-'
even_block = '#--'
print(string_recursion(3, -1)) # for x=1 case we have odd parity, hence -1
# Output: #-#--#-

How to break out of a nested while loop

I am having trouble breaking out of while loops. Here is my code
while (True):
if (dem_arr[randx, randy] > -100):
ticker = 0
while stack:
x, y = stack.pop()
mask[x, y] = True
for dx, dy in neighbors:
nx, ny = x + dx, y + dy
print ticker
if (0 <= nx < dem_arr.shape[0] and 0 <= ny < dem_arr.shape[1] and dem_arr[x, y] > -100 and dem_arr[nx, ny] > -100 and not mask[nx, ny] and abs(dem_arr[nx, ny] - dem_arr[x, y]) <= 1): #set elevation differnce
stack.append((nx, ny)) #if point is selected (true) array position gets added to stack and process runs over again
if ((nx, ny) not in counterStack):
counterStack.append((nx, ny))
dem_copy[(nx, ny)] = 8888
if (ticker >= 121):
print 'ticker ticked'
#if in this for loop need to break out of while stack:
else:
ticker += 1
else:
print '!!!Point chosen has no data!!!'
randx = random.randint(0, row-1) #array begins at position 0,0
randy = random.randint(0, col-1)
continue
What I need to happen is if (ticker >= 121):is entered I need to break out of the while stack:and while(True).Any ideas on how to do this?
A simplified example illustrating the concept of using functions to control the inner loop:
stack = range(1, 500)
def stack_loop():
ticker = 0
while stack:
x = stack.pop()
# Your implementation here
if ticker >= 121:
print("Ticker ticked")
return True
else:
print("Ticker increased")
ticker += 1
return False
while True:
if stack_loop():
break
Move the inner loop's logic to an external function and use the return statement to control if you have to break out of the main loop or not.
Hope it helps :)
EDIT: You could also move the entire block to the function and simply return from it:
stack = range(1, 500)
def main_loop():
while True:
ticker = 0
while stack:
x = stack.pop()
# Your implementation here
if ticker >= 121:
print("Ticker ticked")
return
else:
print("Ticker increased")
ticker += 1
main_loop()
One possible solution is to use a variable to keep track (breakout in this case):
while (True):
if (dem_arr[randx, randy] > -100):
ticker = 0
breakout = False
while stack and not breakout:
x, y = stack.pop()
mask[x, y] = True
for dx, dy in neighbors:
nx, ny = x + dx, y + dy
print ticker
if (0 <= nx < dem_arr.shape[0] and 0 <= ny < dem_arr.shape[1] and dem_arr[x, y] > -100 and dem_arr[nx, ny] > -100 and not mask[nx, ny] and abs(dem_arr[nx, ny] - dem_arr[x, y]) <= 1): #set elevation differnce
stack.append((nx, ny)) #if point is selected (true) array position gets added to stack and process runs over again
if ((nx, ny) not in counterStack):
counterStack.append((nx, ny))
dem_copy[(nx, ny)] = 8888
if (ticker >= 121):
print 'ticker ticked'
#if in this for loop need to break out of while stack:
breakout = True
break
else:
ticker += 1
else:
print '!!!Point chosen has no data!!!'
randx = random.randint(0, row-1) #array begins at position 0,0
randy = random.randint(0, col-1)
continue
Consider the comments already made. In addition, think about the while loop. While True: is inherently an infinite loop. You could return to the caller from within a function, you could break in the same level as the loop, or you could replace True with an expression that starts False and becomes True under the appropriate condition.
edit:
You aren't programming in Java or C anymore. No need to put parentheses around "True". :) - Or the other conditionals.

Categories

Resources