'''
A statement is a string that contains two parts, both of which use x as
a variable. The two parts are seperated by one of the
following signs:
<, >, <=, >=, ==, !=
When x is given a value and then the statement is evaluated,
it should return a bool.
ex. '2 ** x == 2 ** x' is a statement
'''
Now that it has been defined, I wrote down the following:
def inductor(statement, value=1):
""" (statement, int) -> bool
Precondition: value > 0
Return whether induction works given the statement and the value
"""
x = value
y = value + 1
antecedent = statement.replace('x', str(x))
consequent = statement.replace('x', str(y))
if eval(antecedent) == True:
if eval(consequent) == True:
return True
else:
return False
else:
return False
The idea behind inductor is that we give it a statement and then input a start value to first check that the antecedent is true. If it is, we then see if the consequent is true. If it is, then we return True to prove induction works and if it is false, we know that induction cannot work. I did consider the antecedent to be false to return False in inductor despite rules of vacuous truth.
Let's consider the lecture example of 3 to the power of x being greater than or equal to x to the power of 4. The statement is written as so:
'3 ** x >= x ** 3'
When we type inductor('3 ** x >= x ** 3'), the following occurs:
1. The antecedent becomes '3 ** 1 >= 1 ** 3' since x = 1, which can be simplified to '3 >= 1'. Since it is True, we can then check the consequent.
2. The consequent becomes '3 ** 2 >= 2 ** 3' since y = x + 1, which can be simplified to '9 >= 8'. Since it is True, we return True.
3. Thus we can conclude that the statement '3 ** x >= x ** 3' can be inducted from its base case.
Now we could type inductor('3 ** x >= x ** 3', 2) and check to see if that's True. If it does return True (which it does), we can conclude that the statement works from 1 to 2 and then we can check to see if it works for 3. And we could keep going on and on until we hit a brick wall or we get tired of checking cases. To simplify this process, I created a second function called inductable_within.
def inductable_within(statement, end_value, start_value=1):
''' (statement, int, int) -> str
Precondition: start_value < end_value
Return if the statement can be proven by induction within the range of start_value and end_value
'''
for i in range(start_value, end_value):
is_ind = inductor(statement, i)
if is_ind:
pass
else:
if start_value == i:
return 'This statement cannot be inducted with the start value: {0}'.format(i)
else:
return 'This statement can be inducted from {0} up until {1}'.format(start_value, i)
return 'This statement can be inducted within {0} and {1}'.format(start_value, end_value)
This allows us to check if the statement can be inducted within a certain range. So rather than inserting the statement into inductor 10 times and changing the start value, we can type inductable_within('3 ** x >= x ** 3', 10) and get the following string:
'This statement can be inducted within 1 and 10'
This can also indicate when a statement breaks like so:
inductable_within('x + 2 < 10 - x', 5)
'This statement can be inducted from 1 up until 3'
If we plug in all the numbers in [0, 5], we get this:
1 + 2 < 10 - 1 | 3 < 9 | True
2 + 2 < 10 - 2 | 4 < 8 | True
2 + 2 < 10 - 2 | 4 < 8 | True
3 + 2 < 10 - 3 | 5 < 7 | True
4 + 2 < 10 - 4 | 6 < 6 | False
5 + 2 < 10 - 5 | 7 < 5 | False
It is evident that this statement will not work for all natural numbers, since it will stop being true when x > 3. But what about the statement '3 ** x >= x ** 3'? Is it true for all natural numbers or will it break? If we try inductable_within('3 ** x >= x ** 3', 100), we get:
'This statement can be inducted within 1 and 100'
How about inductable_within('3 ** x >= x ** 3', 1000)?
'This statement can be inducted within 1 and 1000'
And inductable_within('3 ** x >= x ** 3', 10000)?
'This statement can be inducted within 1 and 10000'
Dare we go to inductable_within('3 ** x >= x ** 3', 100000)? After a while it does return:
'This statement can be inducted within 1 and 100000'
But these large ranges don't do much to prove it works for all natural numbers, just that it works for these large ranges. If we did have some representation of the set of natural numbers and we ran it with a modified form of inductable_within, how would we know whether it loops infinitely (since the set is practically infinite) or if it eventually halts to produce: 'This statement can be inducted from 1 up until (the number in which the induction implication is no longer true)'? The only way to know for sure is if we had some sort of function that could determine if inductable_within halts for all natural numbers. But we don't have that so therefore we cannot be certain of any statement being true for all natural numbers. We either would have to confide that it is true for all natural numbers or find one example in which the statement breaks.
Conclusion:
Conclusion:
- inductor works to create a base case
- inductable_within works to find the range in which a statement can be inducted
- inductable_within cannot fully prove that induction works for all set of natural numbers since there does not exist a halting function