Visualize the process of expand and contraction of recursion - python-3.x

I am practicing Exercise 1.17 of SICP
#+begin_src ipython :session alinbx :results output
def fast_mul(a, b):
if b == 1: return a
else:
if even(b): return 2 * fast_mul(a, b//2)
if odd(b): return a + 2 * fast_mul(a, b//2)
def even(n):
return n % 2 == 0
def odd(n):
return n % 2 == 1
print(fast_mul(3, 7))
#+end_src
#+RESULTS:
: 21
How could I see the process of expanding and contraction by adding print as
fast_mul(3,7)
3 + 2 * fast_mul(3, 3)
3 + 2 * (3 + 2 * fast_mul(3, 1))
3 + 2 * (3 + 2 * 3)
21

It sounds like you are looking for a trace, although the defaults may take some hacking to return the specific details you are looking for, eg.
python -m trace -t fast_mul.py
In elisp, default tracing is closer to your desired output, eg.
(defun fast-mul (a b)
(if (eq 1 b) a
(+ (if (evenp b) 0 a) (* 2 (fast-mul a (/ b 2))))))
(trace-function 'fast-mul)
(fast-mul 3 7)
;; 1 -> (fast-mul 3 7)
;; | 2 -> (fast-mul 3 3)
;; | | 3 -> (fast-mul 3 1)
;; | | 3 <- fast-mul: 3
;; | 2 <- fast-mul: 9
;; 1 <- fast-mul: 21

def fast_mul(a, b, s, d):
if b == 1:
print(s,a,') '*d)
return a
else:
if even(b):
print(s+f'2 * fast_mul({a}, {b//2})',') '*d)
return 2 * fast_mul(a, b//2, s+'2 * ( ',d+1)
if odd(b):
print(s+f'{a} + 2 * fast_mul({a}, {b//2})', ') '*d)
return a + 2 * fast_mul(a, b//2,s+f'{a} + 2 * ( ',d+1)
def even(n):
return n % 2 == 0
def odd(n):
return n % 2 == 1
print(fast_mul(3, 7,'',0))
I added two more parameters in the function, s and d.
s stores the string that's carried over from the previous recursion call
d stores the depth of recursion so we can figure out how many closing brackets to add to the string.

Related

How do I translate a math formula to python code?

I need to translate this formula into python:
x = b + (sqrt((b^2)-1)) / 2a
Can somebody please help me?
import math
x = b + (math.sqrt((b ** 2) - 1 )) / (2 * a)
Mathematically correct this solution is
import math
import cmath
def quadratic(a, b, c):
if b == 0:
f = (cmath.sqrt(b ** 2 - 1 )) / (2 * a)
else:
f = (math.sqrt(b ** 2 - 1 )) / (2 * a)
return b + f, b -f
print(quadratic(1, 2, 3))
This will give you the two roots.
You can access the roots by indexing:
my_roots = quadratic(1, 2, 3)
x_1 = my_roots[0]
x_2 = my_roots[1]
By using a Python function , you can re-use this code.
This should work as well. No need to import any library.
Assuming a != 0.
When b >= 1:
x = b + (((b ** 2) - 1 ) ** 0.5) / (2 * a)
NOTE: You should ideally have two roots for sqrt(b^2 - 1). Your function should return both values. Now, I am guessing that, under certain prior knowledge you have decided to only keep the positive root.
When b == 0, you get two roots. Note that sqrt(-1) = j or -j (complex roots).
x = (+1j) / (2 * a) # positive root
# OR
x = (-1j) / (2 * a) # negative root
More generally, when b**2 < 1, you get two complex roots.
x = b + (k*1j) ((1 - (b ** 2)) ** 0.5) / (2 * a)
# positive root: k = +1
# OR
# negative root: k = -1

Implement a function that rounds a number to the nearest number that is divisible by X

I have the following code.
Implement the function nearestX that rounds a number to the nearest number that is divisible by X. For example, if 13 is being rounded to the nearest 5 it rounds to 15. If the number is exactly between two possible numbers, it should be rounded up.
def nearestX(num, x):
if x == 0:
return num
remainder = abs(num % x)
print(remainder)
if remainder == 0:
return num
if num < 0:
return -(abs(num) - remainder)
else:
return num + x - remainder
But it doesn't work for nearest(12,5) for example which should give 10 as this is closer than 15 but it returns 15 instead.
You can convert the given number to a decimal.Decimal object so that you can specify the type of rounding based on whether the number of positive or negative when you convert it back to an integer with the to_integral_exact method:
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_DOWN
def nearestX(num, x):
return (Decimal(num) / x).to_integral_exact(
rounding=ROUND_HALF_DOWN if num < 0 else ROUND_HALF_UP) * x
Note that nearestX(num, x) is either x * (num // x) or (x + 1) * (num // x). Accounting for the round up rule, we have:
def nearestX(num, x):
d = num // x
a = d * x
b = a + x
if b - num <= num - a:
return b
else:
return a
e.g.
for i in range(10):
print(i, nearestX(i, 3))
0 0
1 0
2 3
3 3
4 3
5 6
6 6
7 6
8 9
9 9

How do I calculate a factorial for a specific amount of iterations in Python

I am trying to calculate a factorial for the number 56 for only 5 times, such that my answer should be = 458,377,920; where the factorial looks like this:
56 x 55 x 54 x 53 x 52 = 458,377,920.
my current code looks like the following and it is not working:
def my_factorial(n, b):
count = 1
vlue = n
if n == 1:
return n
else:
while b > count:
for i in range(b):
vlue = vlue * (vlue - 1)
b -= 1
print(vlue)
return vlue
my_factorial(56, 5)
the results are not as expected:
3080
9483320
89933348739080
8088007215424892292570507320
65415860716765120080996841652938441974495741189603075080
The body of the loop never decrement or used n
n -= 1
vlue = vlue * n
b -= 1
Try this
def my_factorial(n, b):
vlue = n
if n == 1:
return n
else:
for _ in range(b):
vlue = vlue * (n - 1)
n = n - 1
return vlue
print(my_factorial(56, 5))
FWIW, I rewrote the function from the ground up, as an exercise.
def falling_factorial(n, b):
"""
Return the product of n..n-b+1.
>>> falling_factorial(4, 2) # 4*3
12
>>> falling_factorial(5, 3) # 5*4*3
60
>>> falling_factorial(56, 1)
56
>>> falling_factorial(56, 0)
1
"""
r = 1 # Running product
for i in range(n, n-b, -1):
r *= i
return r
Usage:
>>> falling_factorial(56, 5)
458377920

Path finding: A star not same length from A to B than from B to A

I am implementing the A star algorithm with the Manhattan distance for the 8 puzzle. [ The solution is in spiral form]
1 2 3
8 0 4
7 6 5
In some case, going from A to B will not take the same number of steps as going from B to A.
I think this is because it does not pick the same state on the open list, when they have the same cost, thus, not expanding the same nodes.
From
7 6 4
1 0 8
2 3 5
(A -> B)
7 6 4
1 8 0
2 3 5
(B -> A)
7 6 4
1 3 8
2 0 5
Which both have the same value using Manhattan distance.
Should I explore all path with the same value?
Or should I change the heuristic to have some kind of tie-breaker?
Here is the relevant part of the code
def solve(self):
cost = 0
priority = 0
self.parents[str(self.start)] = (None, 0, 0)
open = p.pr() #priority queue
open.add(0, self.start, cost)
while open:
current = open.get()
if current == self.goal:
return self.print_solution(current)
parent = self.parents[str(current)]
cost = self.parents[str(current)][2] + 1
for new_state in self.get_next_states(current):
if str(new_state[0]) not in self.parents or cost < self.parents[str(new_state[0])][2]:
priority = self.f(new_state) + cost
open.add(priority, new_state[0], cost)
self.parents[str(new_state[0])] = (current, priority, cost)
After wasting so much time re-writing my "solve" function many different ways, for nothing,
I finally found the problem.
def get_next_states(self, mtx, direction):
n = self.n
pos = mtx.index(0)
if direction != 1 and pos < self.length and (pos + 1) % n:
yield (self.swap(pos, pos + 1, mtx),pos, 3)
if direction != 2 and pos < self.length - self.n:
yield (self.swap(pos, pos + n, mtx),pos, 4)
if direction != 3 and pos > 0 and pos % n:
yield (self.swap(pos, pos - 1, mtx),pos, 1)
if direction != 4 and pos > n - 1:
yield (self.swap(pos, pos - n, mtx),pos, 2)
It was in this function. The last if used to be "if 4 and pos > n:"
So there were unexplored states..
2 days for a "-1"
It will teach me to do more unit testing

How to write cos(1)

I need to find a way to write cos(1) in python using a while loop. But i cant use any math functions. Can someone help me out?
for example I also had to write the value of exp(1) and I was able to do it by writing:
count = 1
term = 1
expTotal = 0
xx = 1
while abs(term) > 1e-20:
print("%1d %22.17e" % (count, term))
expTotal = expTotal + term
term=term * xx/(count)
count+=1
I amm completely lost as for how to do this with the cos and sin values though.
Just change your expression to compute the term to:
term = term * (-1 * x * x)/( (2*count) * ((2*count)-1) )
Multiplying the count by 2 could be changed to increment the count by 2, so here is your copypasta:
import math
def cos(x):
cosTotal = 1
count = 2
term = 1
x=float(x)
while abs(term) > 1e-20:
term *= (-x * x)/( count * (count-1) )
cosTotal += term
count += 2
print("%1d %22.17e" % (count, term))
return cosTotal
print( cos(1) )
print( math.cos(1) )
You can calculate cos(1) by using the Taylor expansion of this function:
You can find more details on Wikipedia, see an implementation below:
import math
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
def cos(order):
a = 0
for i in range(0, order):
a += ((-1)**i)/(factorial(2*i)*1.0)
return a
print cos(10)
print math.cos(1)
This gives as output:
0.540302305868
0.540302305868
EDIT: Apparently the cosine is implemented in hardware using the CORDIC algorithm that uses a lookup table to calculate atan. See below a Python implementation of the CORDIS algorithm based on this Google group question:
#atans = [math.atan(2.0**(-i)) for i in range(0,40)]
atans =[0.7853981633974483, 0.4636476090008061, 0.24497866312686414, 0.12435499454676144, 0.06241880999595735, 0.031239833430268277, 0.015623728620476831, 0.007812341060101111, 0.0039062301319669718, 0.0019531225164788188, 0.0009765621895593195, 0.0004882812111948983, 0.00024414062014936177, 0.00012207031189367021, 6.103515617420877e-05, 3.0517578115526096e-05, 1.5258789061315762e-05, 7.62939453110197e-06, 3.814697265606496e-06, 1.907348632810187e-06, 9.536743164059608e-07, 4.7683715820308884e-07, 2.3841857910155797e-07, 1.1920928955078068e-07, 5.960464477539055e-08, 2.9802322387695303e-08, 1.4901161193847655e-08, 7.450580596923828e-09, 3.725290298461914e-09, 1.862645149230957e-09, 9.313225746154785e-10, 4.656612873077393e-10, 2.3283064365386963e-10, 1.1641532182693481e-10, 5.820766091346741e-11, 2.9103830456733704e-11, 1.4551915228366852e-11, 7.275957614183426e-12, 3.637978807091713e-12, 1.8189894035458565e-12]
def cosine_sine_cordic(beta,N=40):
# in hardware, put this in a table.
def K_vals(n):
K = []
acc = 1.0
for i in range(0, n):
acc = acc * (1.0/(1 + 2.0**(-2*i))**0.5)
K.append(acc)
return K
#K = K_vals(N)
K = 0.6072529350088812561694
x = 1
y = 0
for i in range(0,N):
d = 1.0
if beta < 0:
d = -1.0
(x,y) = (x - (d*(2.0**(-i))*y), (d*(2.0**(-i))*x) + y)
# in hardware put the atan values in a table
beta = beta - (d*atans[i])
return (K*x, K*y)
if __name__ == '__main__':
beta = 1
cos_val, sin_val = cosine_sine_cordic(beta)
print "Actual cos: " + str(math.cos(beta))
print "Cordic cos: " + str(cos_val)
This gives as output:
Actual cos: 0.540302305868
Cordic cos: 0.540302305869

Resources