Lecture 3 | Problem Solving

Lecture 3 | Problem Solving

Decrementing Function.

Consider the following Cube Root code, which we have already seen.

x = int(raw_input('Enter an integer: '))
ans = 0
while ans*ans*ans < abs(x):
ans = ans + 1
#print 'current guess =', ans
if ans*ans*ans != abs(x):
print x, 'is not a perfect cube'
else:
if x < 0:
ans = -ans
print 'Cube root of ' + str(x) + ' is ' + str(ans)

In this code, what is the value of x is it a guarantee that it will stop.
* Is it all positive number
* Is it all negative number
* It is 0
* Or is it all integers

Basically it terminates for all integer value of x, this is because of the presence of a Decrementing Function in the code, which guarantees to stop a loop execution.

Properties of Decrementing Function

  1. It will map some set of program variables to an integer.
  2. The value of the variable is non-negative when entering the loop for first time.
  3. When the value of the integer is less than 0, loop terminates.
  4. The value is decreased each time in the loop.

These 4 property guarantees to terminate the loop, Also there is a possibility to count up to a value, but we can always use some logic to always decrement in place of increment.

So how do we find the decrementing function of the above code?

As per the first property we have to find a program variable which can store integers, and we have only 2 program variables in the code, x and ans.

The decrementing function will be,

abs(x) - ans**3

Considering x=8 to start with the steps will be as shown below

x ans abs(x) - ans**3
8 0                    8
8 1                    7
8 2                    0

So when the ans becomes 2, the loop exits.

Now a lot of you might be thinking where is this abs(x) - ans**3 in the actual code mentioned above, it is explicitly not present, so if you look in the code, we are actually doing this step, in a multiple ways.

We are incrementing the ans variable each time in the while loop. And the while condition test the condition ans*ans*ans &lt; abs(x) which can rather be modified to abs(x) - ans**3 as both means the same.

Exhaustive Enumeration/Brute Force

The above code uses the method called Guess and Check, where we are basically Guessing a answer and then checking. This is also called Exhaustive Enumeration.

The reason it is called Exhaustive Enumeration, because we go through the complete answer set and then decide if we have achieved the answer. So by this we mean we are exhausting the answer space.

For awful set of problem a Exhaustive Enumeration technique will work, for the simple reason that today’s computer are very fast.

The Exhaustive Enumeration Technique is also called Brute Force technique.

for  and while Loop

There is a variation in looping construct, what we saw in the last example was while loop, now we will see the same program with for loop.

x = int(raw_input('Enter an integer: '))
for ans in range(0, abs(x)+1):
if ans**3 == abs(x):
break
if ans**3 != abs(x):
print x, 'is not a perfect cube'
else:
if x < 0:
ans = -ans
print 'Cube root of ' + str(x) + ' is ' + str(ans)

The major difference is this line:-

for ans in range(0, abs(x)+1):

basically range(from,to) generate number starting from from and ending at to - 1 numbers.

we also have another interesting code construct in the above code

if ans**3 == abs(x):
break

What this break basically does is, it break from the loop, and executes the statement followed by it. This is similar to the condition check we had in while loop.

Since we can also nest for loop’s, the break will break from inner for loop, if the code is like this.

for ans in range(1,10):
for x in xrange(1,10):
print "ans: ", ans, " x " , x
if x == 3:
break

for and while loops are interchangeable, there is nothing which we can do with one which cannot be done with other.

Approximation

Now we have seen the logic to find the cube root of a number, let say we want to extend that logic to find the square root of a number.

To find the square root of 2, is basically a very large decimal point number, not this provides us with a very nice programming construct called Approximation.

In Approximation, we basically find answers which are close enough to be called and answer but may not be exact ans.

So in Approximation we need to find answers within a epsilon value. So the Square root problem can be re-written as.

Find a y such that y * y = x +- e where e is epsilon value.

To solve the above problem, here is the code for the same

x = int(raw_input("Enter a Number to Find its Square Root: "))
epsilon = 0.01
numOfGuesses = 0
ans = 0

while abs(ans**2 - x) > epsilon and ans <= x:
ans += 0.00001
numOfGuesses += 1
print "Number of Guess: ", numOfGuesses
if abs(ans ** 2 - x) >= epsilon:
print "Failed to find Square Root"
else:
print ans, " is close to square root of ", x

When we run, we get the following output

Enter a Number to Find its Square Root: 25
Number of Guess:  499900
4.99899999998  is close to square root of  25

Now there are few things to note in the above code and the answer which we got.

The first thing to note is what is the Decrementing Function for the above code, the easiest thing to understand about the Decrementing Function is that it should be part of the condition check of the loop.

Now in this regard we would have 2 decrementing function
1. abs(ans**2 - x) &gt; epsilon or
2. ans &lt;= x

Now we might be thinking that the 1st one is the decrementing function, but it is actually the 2nd one which guarantees the exit of loop, the 1st condition is just an optimization to reach the exit of the loop faster.

Now the Second thing to note about the output is, if we gave input as 25, we did not get 5 as the square root, but we got 4.99899999998 instead, this is because we did not ask for closest square root of a number, but we asked for Find a y such that y * y = x +- e where e is epsilon value.

Now this is called Specification of a Problem

Another thing which is noticeable in the output of the program is

Number of Guess:  499900

We got the answer, in roughly .5 million number of guesses, this again proves that exhaustive enumeration is most of the time good enough.

So one question arises, Can we see the code and find out the number of guesses it will make to find the answer?

We can find that, basically by figuring out the distance from the starting point of guess to the actual answer, it also depends on the value of epsilon, and the number of increment which it takes.

These are the lines of code, which help in finding out the running time as discussed in the previous paragraph.

  • Distance from the starting point of the guess
  • ans = 0
  • value of epsilon
  • epsilon = 0.01
  • number of increment
  • ans += 0.00001

Now we can increase the increment, but it will sometimes jump over the real answer. So basically we need a better algorithm to find an answer.

Specification of a Problem

Bisection search

Now as we saw in the last section, the Exhaustive Enumeration is very slow in some of the case, though it gives a correct ans. So if we have to better the algorithm we have to go for Bisection Search.

In Bisection Search we have a technique which is called Cut Search Space in Half as described below.

Cut search space in half

In this what we do, is we try to reduce the search space into half in each iteration. In the previous examples we did tiny increment in a liner fashion.

So what we do is, we start with the Guess somewhere in the midpoint of the Search space, and the check if the answer is too big or too small, depending on the answer we can figure out if we have to see which section for the answer, and then we repeat these till we get a answer.

Here is the Square root code, using the bisection search.

x = int(raw_input("Enter a Number to find the square root: "))
epsilon = 0.01
numOfGuesses = 0
low = 0
high = x
ans = (low + high)/2.0

while abs(ans**2 - x) > epsilon and ans <= x:
print "LOW: ", low, " HIGH: ", high, " ANS: ", ans
numOfGuesses += 1
if ans**2 < x:
low = ans
else:
high = ans
ans = (low + high)/2.0

print 'numOfGuesses =', numOfGuesses
print ans, 'is close to square root of', x

TODO: Not able understand the number of search space?
TODO: What is the positive integer for with the bisection search does not work?

References

Links

  1. MIT OCW
  2. Lecture code handout (PDF)
  3. Lecture code (PY)

Check Yourself

What does it mean for a program to terminate?

When a program either runs to its completion or terminates with a exception, this is said to be program have to terminate, but if it enters a infinite loop it will never exit.

What is a for loop?

This is the construct of a for loop

for ans in range(0, abs(x)+1):

where ans get the value from 0 till abs(x) + 1 -1 in the increment of 1

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s