Tower of Hanoi, problem with understanding the code - python

I have a problem with understanding this code.
code:
def hanoi(n, A, B, C) :
' ' ' n - number of discs
A - initial stick
B - Middle stick
C - Goal stick ' ' '
if n > 0:
hanoi(n - 1, A, C, B)
print('Disc', n, 'from', A, 'to', C)
hanoi(n - 1, B, A, C)
hanoi(3, 'A', 'B', 'C')
When I use debugger I see in if loop, the control flow first checks the if condition, and after that it goes down in hanoi(n - 1, A, C, B), and when it executes that for the first time, It does it again three more times, instead to going on print('disc', n, 'from', A, 'on', C). I can't figure it out why it is doing that, and what kind of rules it uses for doing this. I working in IDLE environment.
Here is results of compiled program:
Disc 1 from A on C
Disc 2 from A to B
Disc 1 from C to B
Disc 3 form A to C
Disc 1 from B to A
Disc 2 from B to C
Disc 1 from A to C

It's because
hanoi(n - 1, A, C, B)
#is before
print(...)
So it will destack before printing every subchild
Switch those two lines like
print('Disc', n, 'from', A, 'to', C)
hanoi(n - 1, A, C, B)
hanoi(n - 1, B, A, C)
And the code works fine :)

You must understand the implications of the code flow going down a branch such as hanoi(n - 1, A, C, B) . That statement is before the print statement, and makes a recursive call to the function in a lower stack. The lower stack must be evaluated completely before you can proceed further with the print statement.
The issue here is that you may find it hard to visualize "lower stacks" and recursion in a simple IDE. Here is a pythontutor visualization for the same. link
Bottom line though: The print statement did not execute simply because the control flow/code flow never encountered the print statement, and branched off to a lower stack because of the recursive call. The print happens exactly when it's supposed to, because that's how the code is written.

Related

Count the moves of hanoi tower

I am trying to count the moves of hanoi tower
In [4]: %paste
count = 0
def hanoi(n, a, b, c):
global count
if n == 1:
count += 1
else:
hanoi(n - 1, a, c, b)
hanoi(1, a, b, c)
hanoi(n - 1, b, a, c)
hanoi(10, "A", "B", "C")
## -- End pasted text --
In [5]: print(count)
1023
The above solution employed the global keyword,
How could get it done if not introducing global?
With a bit of refactoring to make the function recursive with a common count variable:
def hanoi(n, a, b, c):
count = 0
if n == 1:
count += 1
else:
count += hanoi(n - 1, a, c, b)
count += hanoi(1, a, b, c)
count += hanoi(n - 1, b, a, c)
return count
Output
>>> hanoi(10, "A", "B", "C")
1023
Or even without any count variable:
def hanoi(n, a, b, c):
if n != 1:
return hanoi(n - 1, a, c, b) + hanoi(1, a, b, c) + hanoi(n - 1, b, a, c)
return 1
print (hanoi(10, "A", "B", "C"))
Output
1023
There is no need to use complex codes for that. After all, that is math based, so just use this simple one line solution, that works every time in every code.
Place it in the end of hanoi code using tab ofc... but before
hanoi(10, "A", "B", "C")
and remove all that "count" staff that was never even needed.
print(2**n-1)
Lets say, your hanoi code ends like this, with this math code:
def hanoi(n,f,h,t,):
if n==0:
pass
else:
hanoi(n-1,f,t,h)
move(f,t)
hanoi(n-1,h,f,t)
print(2**n-1)
hanoi(4,"A","B","C")
And you do not have to make an other code to count that. Just chance the number at the and of code. Less is better and faster...
If you make all codes long and spread, it will slow down the results. PC:s are made to do math, so why should we not use that!?
The other thing is that, hanoi code itself is easier to make than these count codes. Lets compare with this randint code...
Hanoi code needs just one print/format on it like this:
print("Move object from {} to {}!" .format(f,t))
You can also get rid of int and str in code. Any option, you can cut out of code, makes its faster and cleaner. When there is millions of codes, this comes reasonable to do. Unless you want to hide something in/out of master code.
Reason is, there is only one starting/end point. Empty points (when ever they are empty) are only "help" points. I'm not going to go too deep to that.
But in the end...
Combinatorics in math or even in Python, gives your starting/end points and numbers of events in how many(n), where(A,B,C...) and some times when and even timers/triggers(there is many options)
Learning Hanoi Tower is useful and powerful, to understand, so when your make your code, your can use these given options and print them, with simple math code instead, of doing complex codes with errors. If you like, you can ad there as many tiny hanoi codes as you like and still, you can get right answer(just separate them with r or n option to row or new line).
I hope this was better answer now, after explanation of combinatorics.

how to avoid unnecessary computations in a sorted nested loop generator?

I have a generator that implements evaluation of function f() over a grid of parameters:
def gen():
for a in vec_a:
for b in vec_b:
for c in vec_c:
for ...
res = f(a, b, c, ...)
yield (a, b, c, ...), res
vec_* are sorted such that f() is an increasing function of corresponding parameter given all others fixed. More precisely:
if (a2 >= a1) and (b2 >= b1) and (c2 >= c1) and ...:
assert f(a2, b2, c2, ...) >= f(a1, b1, c1, ...)
Thus, for example, if f(a0, b0, c0, ...) == np.inf, then:
f(a, b0, c0, ...) == np.inf for every a >= a0
f(a0, b, c0, ...) == np.inf for every b >= b0
f(a0, b0, c, ...) == np.inf for every c >= c0
Now I want to write a generic generator that accepts gen and skips unnecessary evaluations of f according to the following rules:
if f(.) == np.inf at some point then I break the innermost loop
if the innermost loop was interrupted at the very first iteration, I should break the penultimate loop level
rule #3 applies to all other levels of the nested loop
Example: If I get np.inf at the very first iteration of the grid, I should skip the entire grid and not perform any more evaluations of f.
Example: If I have a grid [0,1,2] x [0,1,2] x [0,1,2] and f(0,1,0) == np.inf, then I jump to evaluation f(1, 0, 0).
How would I implement such a generator?
Use recursion to simplify the generator:
def shortcircuit_eval(*vecs, f, prefix=tuple()):
if len(vecs) == 0:
yield prefix, f(*prefix), True
return
first_vec, *rest_vecs = vecs
for i, x in enumerate(first_vec):
inner = shortcircuit_eval(rest_vecs, f=f, prefix=prefix + (x,))
for args, res, all_inner_first_iter in inner:
yield args, res, all_inner_first_iter and i == 0
if res == np.inf and all_inner_first_iter:
return
Then you can use it like shortcircuit_eval(vec_a, vec_b, vec_c, f=f). It does generate some auxiliary information as a third element of the tuples it yields, you can write a short wrapper to strip those if necessary.
Note that this is a direct implementation of your idea for an algorithm, but this isn't optimal. E.g. when iterating over [0..10]^3 if you find that [1, 5, 2] is infinite, you know that [3, 6, 3] is as well, but your algorithm will not skip over it. Write a new question asking for an optimal algorithm if you're interested :) This dominance graph should illustrate how much work you can actually save:
If any node is infinite you no longer have to compute the entire subgraph that has that node as an ancestor.
I read about methods of breaking out of loops (see for example this and this), and finally came to the conclusion that this approach will probably lead to some confusing and badly readable code.
If you look at your grid, you can think of an INF element as the corner of a rectangle (or hyperrectangle, in the n-dimensional case), making all other elements inside the area also INF:
In this example, you would somehow have to remember that for a >= 3 you will have to continue running through the inner b loop with b in (0, 1) only.
Also note that you can possibly have more than one INF element, giving you several INF areas possibly overlapping each other.
So my suggestion is not to break the loops, but rather to decide for each element if you have to evaluate f() or if you can skip it, based on whether or not it is inside an INF area.
Example for three dimensions:
inf_list = []
def can_skip(a, b, c):
for inf_element in inf_list:
if a >= inf_element[0] and b >= inf_element[1] and c >= inf_element[2]:
return True
return False
def gen():
for a in vec_a:
for b in vec_b:
for c in vec_c:
if can_skip(a, b, c):
# print("Skipping element ", a, b, c)
yield (a, b, c), np.inf
else:
# print ("Calculating f for element", a, b, c)
res = f(a, b, c)
if res == np.inf:
inf_list.append((a, b, c))
yield (a, b, c), res

I'm brand new and working on Project Euler #2 in python

The goal is to sum up every even number up to 4 million.
I thought this would work but the program gets stuck running. Think it has to do with the if statement, but lost otherwise. Here's what I have.
list = []
a, b = 0, 1
while b <40:
if b%2 == 0:
list.append(b)
a, b = b, a+b
t=sum(list)
print(t)
This here is your biggest problem:
a, b = b, a+b
It has so much potential to mess up your loop! And like others mentioned it doesn't even update anything when b is odd, only when it is even, and then you're stuck.
Why not do this the simple way, with range:
mysum = sum([i for i in range(0, 40, 2)])
Will take care of everything with one line (and of course, replace 40 with 4,000,001 for your question, if you want to include the number 4,000,000 as well. If you just want everything up to it but not to include it, use just 4,000,000)
a, b = b, a+b
This line only runs if b % 2 == 0. I think you meant to run it every time. It should be indented one layer further out.
One can also use the mathematics rule where the sum of integers between 1 and n is equal to n*(n+1)/2. If we want to sum only even numbers, it is like considering only half the number to sum and multiply the result with two.
fSumEvenNumbers = lambda x: (x//2)*(x//2+1)
This would give
fSumEvenNumbers(40000000)
which is equivalent to
(2e7)**2 + 2e7
4e14 + 2e7
400000020000000

python find GCD recursively meet error

I have two pieces of python code finding two positive integers' GCD.
Here is the correct one:
def gcdRecur(a, b):
if b == 0:
return a
return gcdRecur(b, a%b)
Here is the one with bug:
def gcdRecur(a, b):
a = max(a, b)
b = min(a, b)
if b == 0:
return a
return gcdRecur(b, a%b)
It's easy to see the differences between these two pieces of code. And I know that there is no need to add
a = max(a, b)
b = min(a, b)
before the control flow. I can't find any logic mistakes in the latter code, but it print out the wrong result.
------use former code find GCD of 182 ans 224------
print out 14
------use former code find GCD of 182 ans 224------
print out 224(wrong answer)
So I guess it may be associated with the principle of recursion in python which I don't know at all. Can anyone help me and tell me what's going on T T.
Thank you.
The problem is when you call a = max(a,b) and b is the max value, the old a will be missing, and a will equal b which leads to gcd(b,b) == b

Getting two largest numbers from three numbers without using conditional statement or loop in python 3.5

Complete the function1() function which is passed three whole
numbers.The function returns the total of the two bigger numbers.
print()
print(1, function1(1, 2, 3))
print(2, function1(11, 12, 3))
print(3, function1(6, 2, 5))
output should be
1 5
2 23
3 11
This was the question. I try googling but all I have found was using conditional
statement or loop. I was wondering if there is other way to do this without using both? Reason being is that this question was on before the introduction of conditional statement and loop. I can advance my self-studying and do it however
there must be a reason why it poped up before we go onto the next chapter.
What do you reckon?.. (During self-studying for CS101) `
you could sort the tuple of the numbers and add the first 2 values:
def function1(a, b, c):
s = sorted((a, b, c), reverse=True)
return s[0] + s[1]
sorted starts with the smalles item normally that's why you need to set reverse=True.
or you could sum the three and subtract the minimal value:
def function1(a, b, c):
return sum((a, b, c)) - min(a, b, c)

Categories