truth table: Binary Operations 3
requirements
preview
These are the tests I have at the end of the chapter
1import src.truth_table
2import unittest
3
4
5class TestBinaryOperations(unittest.TestCase):
6
7 def test_contradiction(self):
8 contradiction = src.truth_table.contradiction
9 self.assertFalse(contradiction(True, True))
10 self.assertFalse(contradiction(True, False))
11 self.assertFalse(contradiction(False, True))
12 self.assertFalse(contradiction(False, False))
13
14 def test_logical_conjunction(self):
15 logical_conjunction = (
16 src.truth_table.logical_conjunction
17 )
18 self.assertTrue(logical_conjunction(True, True))
19 self.assertFalse(logical_conjunction(True, False))
20 self.assertFalse(logical_conjunction(False, True))
21 self.assertFalse(logical_conjunction(False, False))
23 def test_project_second(self):
24 project_second = src.truth_table.project_second
25 self.assertTrue(project_second(True, True))
26 self.assertFalse(project_second(True, False))
27 self.assertTrue(project_second(False, True))
28 self.assertFalse(project_second(False, False))
29
30 def test_converse_non_implication(self):
31 converse_non_implication = (
32 src.truth_table.converse_non_implication
33 )
34 self.assertFalse(converse_non_implication(True, True))
35 self.assertFalse(converse_non_implication(True, False))
36 self.assertTrue(converse_non_implication(False, True))
37 self.assertFalse(converse_non_implication(False, False))
39 def test_negate_first(self):
40 negate_first = src.truth_table.negate_first
41 self.assertFalse(negate_first(True, True))
42 self.assertFalse(negate_first(True, False))
43 self.assertTrue(negate_first(False, True))
44 self.assertTrue(negate_first(False, False))
45
46 def test_logical_nand(self):
47 nand = src.truth_table.logical_nand
48 self.assertFalse(nand(True, True))
49 self.assertTrue(nand(True, False))
50 self.assertTrue(nand(False, True))
51 self.assertTrue(nand(False, False))
53 def test_tautology(self):
54 tautology = src.truth_table.tautology
55 self.assertTrue(tautology(True, True))
56 self.assertTrue(tautology(True, False))
57 self.assertTrue(tautology(False, True))
58 self.assertTrue(tautology(False, False))
59
60 def test_logical_disjunction(self):
61 logical_disjunction = (
62 src.truth_table.logical_disjunction
63 )
64 self.assertTrue(logical_disjunction(True, True))
65 self.assertTrue(logical_disjunction(True, False))
66 self.assertTrue(logical_disjunction(False, True))
67 self.assertFalse(logical_disjunction(False, False))
69 def test_exclusive_disjunction(self):
70 xor = src.truth_table.exclusive_disjunction
71 self.assertFalse(xor(True, True))
72 self.assertTrue(xor(True, False))
73 self.assertTrue(xor(False, True))
74 self.assertFalse(xor(False, False))
75
76 def test_material_non_implication(self):
77 material_non_implication = (
78 src.truth_table.material_non_implication
79 )
80 self.assertFalse(material_non_implication(True, True))
81 self.assertTrue(material_non_implication(True, False))
82 self.assertFalse(material_non_implication(False, True))
83 self.assertFalse(material_non_implication(False, False))
85 def test_project_first(self):
86 project_first = src.truth_table.project_first
87 self.assertTrue(project_first(True, True))
88 self.assertTrue(project_first(True, False))
89 self.assertFalse(project_first(False, True))
90 self.assertFalse(project_first(False, False))
91
92 def test_converse_implication(self):
93 converse_implication = (
94 src.truth_table.converse_implication
95 )
96 self.assertTrue(converse_implication(True, True))
97 self.assertTrue(converse_implication(True, False))
98 self.assertFalse(converse_implication(False, True))
99 self.assertTrue(converse_implication(False, False))
100
101
102# Exceptions seen
103# AttributeError
104# TypeError
105# AssertionError
106# SyntaxError
open the project
Make sure you are in the
pumping_pythonfolder with pwd in the terminalpwdif the terminal does not show
.../pumping_pythonchange directory to the
pumping_pythonfolderOnce in
pumping_python, change directory to the projectcd truth_tablethe terminal shows
.../pumping_python/truth_tableI run the tests with pytest-watcher
uv run pytest-watcher . --nowthe terminal is my friend, and shows
rootdir: .../pumping_python/truth_table configfile: pyproject.toml collected 12 items tests/test_binary.py ........ [ 66%] tests/test_nullary_unary.py .... [100%] ================== 12 passed in G.HIs ===================I hold ctrl (Windows) or option (MacOS) on the keyboard, then click on
tests/test_binary.pywith the mouse to open itUp to this point I have tested
contradiction which always returns False
logical_conjunction aka and which returns
first_input and second_inputproject_second which always returns
second_inputconverse_non_implication which returns
not first_input and second_inputnegate_first which always returns
not first_inputlogical_nand which returns
not (first_input and second_input)tautology which always returns True
logical_disjunction which returns
first_input or second_input
test_exclusive_disjunction
The truth table for exclusive_disjunction is
first input |
second input |
return |
|---|---|---|
True |
True |
False |
True |
False |
True |
False |
True |
True |
False |
False |
False |
RED: make it fail
I add a test for exclusive_disjunction with an assertion for the case when the first input is True and the second input is True, to test_binary.py
first input |
second input |
return |
|---|---|---|
True |
True |
False |
67 self.assertFalse(logical_disjunction(False, False))
68
69 def test_exclusive_disjunction(self):
70 xor = src.truth_table.exclusive_disjunction
71 self.assertFalse(xor(True, True))
72
73
74# Exceptions seen
the terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table'
has no attribute 'exclusive_disjunction'
because truth_table.py does not have anything in it with that name.
GREEN: make it pass
I open
truth_table/__init__.pyfrom thesrcfolderI add exclusive_disjunction to
truth_table.py52def logical_disjunction(first_input, second_input): 53 return logical_negation( 54 logical_conjunction( 55 logical_negation(first_input), 56 logical_negation(second_input) 57 ) 58 ) 59 return first_input or second_input 60 61 62def exclusive_disjunction(first_input, second_input): 63 return Falsethe test passes. exclusive_disjunction returns False, if the first input is True and the second input is True.
exclusive_disjunction(True , True ) -> False
REFACTOR: make it better
I add an assertion for the next case, which is if the first input is True and the second input is False, to test_exclusive_disjunction in
test_binary.pyfirst input
second input
return
True
False
True
69 def test_exclusive_disjunction(self): 70 xor = src.truth_table.exclusive_disjunction 71 self.assertFalse(xor(True, True)) 72 self.assertTrue(xor(True, False)) 73 74 75# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause the function returns False and the assertion expects True.
I add an if statement to the exclusive_disjunction function in
truth_table.py62def exclusive_disjunction(first_input, second_input): 63 if second_input == False: 64 return True 65 return Falsethe test passes. exclusive_disjunction returns
True, if the second input is False
False, if the above condition is NOT met
exclusive_disjunction(True , False) -> True exclusive_disjunction(True , True ) -> FalseI add an assertion for the third case, which is if the first input is False and the second input is True, to
test_binary.pyfirst input
second input
return
False
True
True
69 def test_exclusive_disjunction(self): 70 xor = src.truth_table.exclusive_disjunction 71 self.assertFalse(xor(True, True)) 72 self.assertTrue(xor(True, False)) 73 self.assertTrue(xor(False, True)) 74 75 76# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause Python checks if
second_inputis equal to False whenif second_input == False:runsif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falsethen leaves the function since the return statement is the last thing to run in a functionsecond_inputis True in this case, which raises AssertionError since the function returns False and the assertion expects True
I add an if statement to exclusive_disjunction in
truth_table.py62def exclusive_disjunction(first_input, second_input): 63 if first_input == False: 64 return True 65 if second_input == False: 66 return True 67 return Falsethe test passes because Python checks if
first_inputis equal to False whenif first_input == False:runsif
first_inputis NOT equal to False, it leaves the if statement and continues to the next if statement in the function -if second_input == False:.which checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falsethen leaves the function since the return statement is the last thing to run in a functionif
second_inputis equal to False, it goes to the next line -return Truethen leaves the function since the return statement is the last thing to run in a function
if
first_inputis equal to False, it goes to the next line -return Truethen leaves the function since the return statement is the last thing to run in a functionso far this is the same as the first three cases of logical_nand
I add an assertion for the last case, which is if the first input is False and the second input is False to test_exclusive_disjunction, in
test_binary.pyfirst input
second input
return
False
False
False
69 def test_exclusive_disjunction(self): 70 xor = src.truth_table.exclusive_disjunction 71 self.assertFalse(xor(True, True)) 72 self.assertTrue(xor(True, False)) 73 self.assertTrue(xor(False, True)) 74 self.assertFalse(xor(False, False)) 75 76 77# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause Python checks if
first_inputis equal to False whenif first_input == False:runsif
first_inputis equal to False, it goes to the next line -return Trueif
first_inputis NOT equal to False, it leaves the if statement and continues to the next if statement at the same indentation level in the function -if second_input == False:, which checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falseif
second_inputis equal to False, it goes to the next line -return Truesecond_inputis False in this case, which raises AssertionError since the function returns True and the assertion expects False
I add an if statement for this case, to the one for when the first input is False in the exclusive_disjunction function in
truth_table.py62def exclusive_disjunction(first_input, second_input): 63 if first_input == False: 64 if second_input == False: 65 return False 66 return True 67 if second_input == False: 68 return True 69 return Falsethe test passes because Python checks if
first_inputis equal to False whenif first_input == False:runsif
first_inputis NOT equal to False, it leaves the if statement and continues to the next if statement at the same indentation level in the function -if second_input == False:, which checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falseexclusive_disjunction(True , True ) -> False └── def exclusive_disjunction(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ if second_input == False: │ return False │ return True ├── if second_input == False: │ return True └── return Falseif
second_inputis equal to False, it goes to the next line -return Trueexclusive_disjunction(True , False) -> True └── def exclusive_disjunction(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ if second_input == False: │ return False │ return True └── if second_input == False: └── return True return False
if
first_inputis equal to False, it goes to the next line -if second_input == False, which checks ifif second_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to the next line forif first_input == False:-return Trueexclusive_disjunction(False, True ) -> True └── def exclusive_disjunction(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == False: ├── if second_input == False: │ return False └── return True if second_input == False: return True return Falseif
second_inputis equal to False, it goes to the next line -return Falseexclusive_disjunction(False, False) -> False └── def exclusive_disjunction(first_input, second_input): ├── first_input == False ├── second_input == False └── if first_input == False: └── if second_input == False: └── return False return True if second_input == False: return True return False
there are two cases where exclusive_disjunction returns False and two cases where it returns True. I add an if statement for the other case where it returns True, to make it clearer
62def exclusive_disjunction(first_input, second_input): 63 if first_input == False: 64 if second_input == False: 65 return False 66 return True 67 if first_input == True: 68 if second_input == False: 69 return True 70 return Falsethe test is still green because Python checks if
first_inputis equal to False whenif first_input == False:runsif
first_inputis NOT equal to False, it leaves the if statement and continues to the next if statement at the same indentation level in the function -if first_input == True:, which checks iffirst_inputis equal to Trueif
first_inputis NOT equal to True, it leaves the if statement and continues to run the rest of the function -return Falsethen leaves the function since the return statement is the last thing to run in a functionif
first_inputis equal to True, it goes to the next line -if second_input == False:, which checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to run the rest of the function -return Falsethen leaves the function since the return statement is the last thing to run in a functionif
second_inputis equal to False, it runs the next line -return Truethen leaves the function since the return statement is the last thing to run in a function
if
first_inputis equal to False, it goes to the next line -if second_input == False, which checks ifsecond_inputis equal to Falseif
second_inputis NOT equal to False, it leaves the if statement and continues to the next line forif first_input == False:-return Truethen leaves the function since the return statement is the last thing to run in a functionif
second_inputis equal to False, it runs the next line -return Falsethen leaves the function since the return statement is the last thing to run in a function
I add the bool built-in function
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 if bool(first_input) == False: 65 # if second_input == False: 66 if bool(second_input) == False: 67 return False 68 return True 69 # if first_input == True: 70 if bool(first_input) == True: 71 # if second_input == False: 72 if bool(second_input) == False: 73 return True 74 return Falsestill green.
I use Logical Negation (NOT) to write three of the if statements in terms of True
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 if not bool(first_input) == True: 66 # if second_input == False: 67 # if bool(second_input) == False: 68 if not bool(second_input) == True: 69 return False 70 return True 71 # if first_input == True: 72 if bool(first_input) == True: 73 # if second_input == False: 74 # if bool(second_input) == False: 75 if not bool(second_input) == True: 76 return True 77 return Falsegreen.
I remove
== True62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 # if not bool(first_input) == True: 66 if not bool(first_input): 67 # if second_input == False: 68 # if bool(second_input) == False: 69 # if not bool(second_input) == True: 70 if not bool(second_input): 71 return False 72 return True 73 # if first_input == True: 74 # if bool(first_input) == True: 75 if bool(first_input): 76 # if second_input == False: 77 # if bool(second_input) == False: 78 # if not bool(second_input) == True: 79 if not bool(second_input): 80 return True 81 return Falsestill green.
I remove bool
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 # if not bool(first_input) == True: 66 # if not bool(first_input): 67 if not first_input: 68 # if second_input == False: 69 # if bool(second_input) == False: 70 # if not bool(second_input) == True: 71 # if not bool(second_input): 72 if not second_input: 73 return False 74 return True 75 # if first_input == True: 76 # if bool(first_input) == True: 77 # if bool(first_input): 78 if first_input: 79 # if second_input == False: 80 # if bool(second_input) == False: 81 # if not bool(second_input) == True: 82 # if not bool(second_input): 83 if not second_input: 84 return True 85 return Falsethe test is still green, because
Python checks if
somethingis equal to False whenif something == False:runs. I can assume the following substitutionsif the value of
somethingis Falsesomething = False if something == False if bool(something) == False if bool(False ) == False # use the value if False == False # bool(False) returns False if True == True # write in terms of True if True # remove '== True' if not False # not False == True if not something # use the name for the valueif the value of
somethingis Truesomething = True if something == False if bool(something) == False if bool(True ) == False # use the value if True == False # bool(True) returns True if False == True # write in terms of True if not True == True # write in terms of True if not True # remove '== True' if not something # use the name for the value
Python checks if
(something)is equal to True whenif something == True:runs. I can assume the following substitutionsif the value of
somethingis Falsesomething = False if something == True if bool(something) == True if bool(False ) == True # use the value if False == True # bool(False) returns False if not True == True # write in terms of True if not True # remove '== True' if False # not True == False if something # use the name for the valueif the value of
somethingis Truesomething = True if something == True if bool(something) == True if bool(True ) == True # use the value if True == True # bool(True) returns True if True # remove '== True' if something # use the name for the value
if bool(something) == Falseis the same asif not bool(something) == Trueis the same asif not bool(something)is the same asif not something.if bool(something) == Trueis the same asif bool(something)is the same asif something.
I move the if statements to put them together
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 # if not bool(first_input) == True: 66 # if not bool(first_input): 67 # if second_input == False: 68 # if bool(second_input) == False: 69 # if not bool(second_input) == True: 70 # if not bool(second_input): 71 # if first_input == True: 72 # if bool(first_input) == True: 73 # if bool(first_input): 74 # if second_input == False: 75 # if bool(second_input) == False: 76 # if not bool(second_input) == True: 77 # if not bool(second_input): 78 if not first_input: 79 if not second_input: 80 return False 81 return True 82 if first_input: 83 if not second_input: 84 return True 85 return Falsestill green.
I add if statements for the other two cases to make it clearer
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 # if not bool(first_input) == True: 66 # if not bool(first_input): 67 # if second_input == False: 68 # if bool(second_input) == False: 69 # if not bool(second_input) == True: 70 # if not bool(second_input): 71 # if first_input == True: 72 # if bool(first_input) == True: 73 # if bool(first_input): 74 # if second_input == False: 75 # if bool(second_input) == False: 76 # if not bool(second_input) == True: 77 # if not bool(second_input): 78 if not first_input: 79 if not second_input: 80 return False 81 if second_input: 82 return True 83 if first_input: 84 if not second_input: 85 return True 86 if second_input: 87 return Falsegreen.
I use Logical Conjunction (AND) to write the if statements for all the cases
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 # if not bool(first_input) == True: 66 # if not bool(first_input): 67 # if second_input == False: 68 # if bool(second_input) == False: 69 # if not bool(second_input) == True: 70 # if not bool(second_input): 71 # if first_input == True: 72 # if bool(first_input) == True: 73 # if bool(first_input): 74 # if second_input == False: 75 # if bool(second_input) == False: 76 # if not bool(second_input) == True: 77 # if not bool(second_input): 78 # if not first_input: 79 # if not second_input: 80 # return False 81 # if second_input: 82 # return True 83 # if first_input: 84 # if not second_input: 85 # return True 86 # if second_input: 87 # return False 88 if not first_input and not second_input: 89 return False 90 if not first_input and second_input: 91 return True 92 if first_input and not second_input: 93 return True 94 if first_input and second_input: 95 return Falsestill green, because I can put two if statements together when one is indented under the other
if something: if something_else:can also be written as
if something and something_else:I move the first if statement to the bottom to be with the other statement that returns the same thing (False)
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 # if not bool(first_input) == True: 66 # if not bool(first_input): 67 # if second_input == False: 68 # if bool(second_input) == False: 69 # if not bool(second_input) == True: 70 # if not bool(second_input): 71 # if first_input == True: 72 # if bool(first_input) == True: 73 # if bool(first_input): 74 # if second_input == False: 75 # if bool(second_input) == False: 76 # if not bool(second_input) == True: 77 # if not bool(second_input): 78 # if not first_input: 79 # if not second_input: 80 # return False 81 # if second_input: 82 # return True 83 # if first_input: 84 # if not second_input: 85 # return True 86 # if second_input: 87 # return False 88 if not first_input and second_input: 89 return True 90 if first_input and not second_input: 91 return True 92 if first_input and second_input: 93 return False 94 if not first_input and not second_input: 95 return Falsethe test is still green.
I use Logical Disjunction (OR) to put the if statements that return the same thing together
62def exclusive_disjunction(first_input, second_input): 63 # if first_input == False: 64 # if bool(first_input) == False: 65 # if not bool(first_input) == True: 66 # if not bool(first_input): 67 # if second_input == False: 68 # if bool(second_input) == False: 69 # if not bool(second_input) == True: 70 # if not bool(second_input): 71 # if first_input == True: 72 # if bool(first_input) == True: 73 # if bool(first_input): 74 # if second_input == False: 75 # if bool(second_input) == False: 76 # if not bool(second_input) == True: 77 # if not bool(second_input): 78 # if not first_input: 79 # if not second_input: 80 # return False 81 # if second_input: 82 # return True 83 # if first_input: 84 # if not second_input: 85 # return True 86 # if second_input: 87 # return False 88 # if not first_input and second_input: 89 # return True 90 # if first_input and not second_input: 91 if ( 92 (not first_input and second_input) 93 or 94 (first_input and not second_input) 95 ): 96 return True 97 # if first_input and second_input: 98 # return False 99 # if not first_input and not second_input: 100 if ( 101 (first_input and second_input) 102 or 103 (not first_input and not second_input) 104 ): 105 return Falsestill green, because I can put two if statements together if they both return the same thing and are at the same indentation level
if something: return this if something_else: return thiscan also be written as
if something or something_else: return thisI change the second if statement to an else clause
91 if ( 92 (not first_input and second_input) 93 or 94 (first_input and not second_input) 95 ): 96 return True 97 # if first_input and second_input: 98 # return False 99 # if not first_input and not second_input: 100 # if ( 101 # (first_input and second_input) 102 # or 103 # (not first_input and not second_input) 104 # ): 105 else: 106 return Falsegreen.
I add a conditional expression
91 # if ( 92 # (not first_input and second_input) 93 # or 94 # (first_input and not second_input) 95 # ): 96 # return True 97 # if first_input and second_input: 98 # return False 99 # if not first_input and not second_input: 100 # if ( 101 # (first_input and second_input) 102 # or 103 # (not first_input and not second_input) 104 # ): 105 # else: 106 # return False 107 return True if ( 108 (not first_input and second_input) 109 or 110 (first_input and not second_input) 111 ) else Falsestill green.
I remove
True ifandelse Falseto make it simpler105 # else: 106 # return False 107 # return True if ( 108 return ( 109 (not first_input and second_input) 110 or 111 (first_input and not second_input) 112 # ) else False 113 )the test is still green.
exclusive_disjunction returns
((not first_input and second_input) or (first_input and not second_input))not first_input and second_inputis the Logical Conjunction (AND), of the Logical Negation (NOT) of the first input, and the second inputlogical_conjunction( logical_negation(first_input), second_input )not first_inputis the Logical Negation (NOT) offirst_inputif the first input is True, this part of the statement is False
if the first input is False, this part of the statement is True
first_input and not second_inputis the Logical Conjunction (AND), of the first input, and the Logical Negation (NOT) of the second inputlogical_conjunction( first_input, logical_negation(second_input) )not second_inputis the Logical Negation (NOT) ofsecond_inputif the second input is True, this part of the statement is False
if the second input is False, this part of the statement is True
((not first_input and second_input) or (first_input and not second_input))can be thought of as the Logical Disjunction (OR), of the Logical Conjunction (AND), of the Logical Negation (NOT) of the first input, and the second input, and the Logical Conjunction (AND) of the first input and the Logical Negation (NOT) of the second input. Confusing when written in English. If we use the function names we getlogical_disjunction( logical_conjunction( logical_negation(first_input), second_input ), logical_conjunction( first_input, logical_negation(second_input) ) )Exclusive Disjunction can also be thought of as the Logical Disjunction (OR), of the Converse Non-Implication of the first input and the second input, and the Logical Conjunction (AND) of the first input, and the Logical Negation (NOT) of the second input
logical_disjunction( converse_non_implication( first_input, second_input ), logical_conjunction( first_input, logical_negation(second_input) ) )because converse_non_implication returns
not first_input and second_inputlogical_disjunction(first_input, second_input) first_input == (not first_input and second_input) converse_non_implication == (not first_input and second_input) second_input == (first_input and not second_input)
This means that in the four cases
if the first input is True and the second input is True, exclusive_disjunction returns
(not first and second) or (first and not second) (not True and True ) or (True and not True ) (False and True ) or (True and False ) False or False False # logical_disjunction(False, False)if the first input is True and the second input is False, exclusive_disjunction returns
(not first and second) or (first and not second) (not True and False ) or (True and not False ) (False and False ) or (True and True ) False or True True # logical_disjunction(False, True)if the first input is False and the second input is True, exclusive_disjunction returns
(not first and second) or (first and not second) (not False and True ) or (False and not True ) (True and True ) or (False and False ) True or False True # logical_disjunction(True, False)if the first input is False and the second input is False, exclusive_disjunction returns
(not first and second) or (first and not second) (not False and False ) or (False and not False ) (True and False ) or (False and True ) False or False False # logical_disjunction(False, False)
first
second
not first
not second
((not first) and second)
(first and (not second))
((not first) and second) or (first and (not second))
True
True
False
False
False
False
False
True
False
False
True
False
True
True
False
True
True
False
True
False
True
False
False
True
True
False
False
False
I add a return statement to show this
107 # return True if ( 108 return logical_disjunction( 109 converse_non_implication( 110 first_input, second_input 111 ), 112 logical_conjunction( 113 first_input, 114 logical_negation(second_input) 115 ) 116 ) 117 return ( 118 (not first_input and second_input) 119 or 120 (first_input and not second_input) 121 # ) else False 122 )the test is still green.
exclusive_disjunction returns False when the two inputs are equal, it returns True when the two inputs are NOT equal. I add an if statement to show this
107 # return True if ( 108 if first_input == second_input: 109 return False 110 else: 111 return True 112 return logical_disjunction( 113 converse_non_implication( 114 first_input, second_input 115 ), 116 logical_conjunction( 117 first_input, 118 logical_negation(second_input) 119 ) 120 ) 121 return ( 122 (not first_input and second_input) 123 or 124 (first_input and not second_input) 125 # ) else False 126 )green.
I change the else clause to the Logical Negation (NOT) of the new if statement so I can write a conditional expression
107 # return True if ( 108 if first_input == second_input: 109 return False 110 # else: 111 if not (first_input == second_input): 112 return True 113 return logical_disjunction( 114 converse_non_implication( 115 first_input, second_input 116 ), 117 logical_conjunction( 118 first_input, 119 logical_negation(second_input) 120 ) 121 ) 122 return ( 123 (not first_input and second_input) 124 or 125 (first_input and not second_input) 126 # ) else False 127 )still green.
I add a conditional expression
107 # return True if ( 108 # if first_input == second_input: 109 # return False 110 # else: 111 # if not (first_input == second_input): 112 # return True 113 return ( 114 True if 115 not (first_input == second_input) 116 else False 117 ) 118 return logical_disjunction( 119 converse_non_implication( 120 first_input, second_input 121 ), 122 logical_conjunction( 123 first_input, 124 logical_negation(second_input) 125 ) 126 ) 127 return ( 128 (not first_input and second_input) 129 or 130 (first_input and not second_input) 131 # ) else False 132 )the test is still green.
I remove
True ifandelse Falseto make the statement simpler107 # return True if ( 108 # if first_input == second_input: 109 # return False 110 # else: 111 # if not (first_input == second_input): 112 # return True 113 return ( 114 # True if 115 not (first_input == second_input) 116 # else False 117 ) 118 return logical_disjunction( 119 converse_non_implication( 120 first_input, second_input 121 ), 122 logical_conjunction( 123 first_input, 124 logical_negation(second_input) 125 ) 126 ) 127 return ( 128 (not first_input and second_input) 129 or 130 (first_input and not second_input) 131 # ) else False 132 )still green.
I can also write the conditional expression with the NOT equal symbol (
!=) (exclamation mark and equal symbol !+= on the keyboard)107 # return True if ( 108 # if first_input == second_input: 109 # return False 110 # else: 111 # if not (first_input == second_input): 112 # return True 113 return first_input != second_input 114 return ( 115 # True if 116 not (first_input == second_input) 117 # else False 118 ) 119 return logical_disjunction( 120 converse_non_implication( 121 first_input, second_input 122 ), 123 logical_conjunction( 124 first_input, 125 logical_negation(second_input) 126 ) 127 ) 128 return ( 129 (not first_input and second_input) 130 or 131 (first_input and not second_input) 132 # ) else False 133 )green.
I remove the commented lines
62def exclusive_disjunction(first_input, second_input): 63 return first_input != second_input 64 return not (first_input == second_input) 65 return logical_disjunction( 66 converse_non_implication( 67 first_input, second_input 68 ), 69 logical_conjunction( 70 first_input, 71 logical_negation(second_input) 72 ) 73 ) 74 return ( 75 (not first_input and second_input) 76 or 77 (first_input and not second_input) 78 )I can use any of these return statements. The first return statement is the only one that runs in this case, because the return statement is the last thing to run in a function.
I add a git commit message in the other terminal
git commit -am 'add exclusive_disjunction'
Exclusive Disjunction returns
True, if
first_inputis NOT EQUAL tosecond_input.False, if
first_inputis EQUAL to thesecond_input.first_input != second_input- which reads asfirst_inputis NOT equal tosecond_input.not (first_input == second_input)- which can be read as the Logical Negation of the Logical Equality of the first input and the second input.(not first_input and second_input) or (first_input and not second_input)which is the Logical Disjunction of the Logical Conjunction of the Logical Negation of the first input, and the second input, and the Logical Conjunction of the first input and the Logical Negation of the second input. Wow! That’s a lot.
Exclusive Disjunction is also known as Exclusive OR or XOR. Would “Logical Inequality” be a better name?
examples of Exclusive Disjunction
two light switches for one bulb, if the inputs are
is switch A on?
is switch B on?
switch A?
switch B?
bulb on?
on
on
no
on
off
yes
off
on
yes
off
off
no
magnets attract, if the inputs are
what is the direction of magnet A?
what is the direction of magnet B?
magnet A?
magnet B?
attract?
north
north
no
north
south
yes
south
north
yes
south
south
no
a coin toss, if the inputs are
my choice
your choice
my choice
your choice
there is a winner
heads
heads
no
heads
tails
yes
tails
heads
yes
tails
tails
no
two people meet at a door that can only take one person at a time, if the inputs are
I go
You go
I go
you go
we both go
go
go
no
go
stop
yes
stop
go
yes
stop
stop
no
A broken vending machine, if the inputs are
did I put money in the machine?
did I get what I picked?
I paid
I got what I want
machine is broken
yes
yes
no
yes
no
yes
no
yes
yes
no
no
no
should I complain when
I did not payandI got what I want?
test_material_non_implication
The truth table for material_non_implication is
first input |
second input |
return |
|---|---|---|
True |
True |
False |
True |
False |
True |
False |
True |
False |
False |
False |
False |
RED: make it fail
I go back to the terminal where the tests are running
I add a test for material_non_implication with an assertion for if the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
False
74 self.assertFalse(xor(False, False)) 75 76 def test_material_non_implication(self): 77 material_non_implication = ( 78 src.truth_table.material_non_implication 79 ) 80 self.assertFalse(material_non_implication(True, True)) 81 82 83# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'material_non_implication'. Did you mean: 'converse_non_implication'?material_non_implication is not in
truth_table.py.
GREEN: make it pass
I add material_non_implication to truth_table.py
74 return (
75 (not first_input and second_input)
76 or
77 (first_input and not second_input)
78 )
79
80
81def material_non_implication(first_input, second_input):
82 return False
the test passes. material_non_implication returns False, if the first input is True and the second input is True.
material_non_implication(True , True ) -> False
REFACTOR: make it better
I add an assertion for the second case, which is if the first input is True and the second input is False to test_material_non_implication in
test_binary.pyfirst input
second input
return
True
False
True
76 def test_material_non_implication(self): 77 material_non_implication = ( 78 src.truth_table.material_non_implication 79 ) 80 self.assertFalse(material_non_implication(True, True)) 81 self.assertTrue(material_non_implication(True, False)) 82 83 84# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause the function returns False and the assertion expects True.
I add an if statement to material_non_implication in
truth_table.py81def material_non_implication(first_input, second_input): 82 if second_input == False: 83 return True 84 return Falsethe test passes because material_non_implication is called, it runs
if second_input == False:if
second_inputis NOT equal to False, it leaves the if statement then runsreturn Falseif
second_inputis equal to False, it runsreturn True
material_non_implication(True , False) -> True material_non_implication(True , True ) -> FalseI add an assertion for the third case to test_material_non_implication, for when the first input is False and the second input is True, in
test_binary.pyfirst input
second input
return
False
True
False
76 def test_material_non_implication(self): 77 material_non_implication = ( 78 src.truth_table.material_non_implication 79 ) 80 self.assertFalse(material_non_implication(True, True)) 81 self.assertTrue(material_non_implication(True, False)) 82 self.assertFalse(material_non_implication(False, True)) 83 84 85# Exceptions seenthe test is still green.
material_non_implication(False, True ) -> False material_non_implication(True , False) -> True material_non_implication(True , True ) -> FalseI add an assertion for the fourth case, which is if the first input is False and the second input is False
first input
second input
return
False
False
False
76 def test_material_non_implication(self): 77 material_non_implication = ( 78 src.truth_table.material_non_implication 79 ) 80 self.assertFalse(material_non_implication(True, True)) 81 self.assertTrue(material_non_implication(True, False)) 82 self.assertFalse(material_non_implication(False, True)) 83 self.assertFalse(material_non_implication(False, False)) 84 85 86# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause when material_non_implication is called, it runs
if second_input == False:if
second_inputis NOT equal to False, it leaves the if statement then runsreturn Falseif
second_inputis equal to False, it runsreturn Truesecond_inputis False in this case, which raises AssertionError since the assertion expects False and the function returns True
I add an if statement for the one case that returns True, to the material_non_implication function in
truth_table.py81def material_non_implication(first_input, second_input): 82 if first_input == True: 83 if second_input == False: 84 return True 85 return Falsethe test passes.
material_non_implication(False, False) -> False material_non_implication(False, True ) -> False material_non_implication(True , False) -> True material_non_implication(True , True ) -> FalseWhen material_non_implication is called Python checks
if first_input == True:if
first_inputis NOT equal to True, it leaves the if statement then runsreturn Falsematerial_non_implication(False, False) -> False └── def material_non_implication(first_input, second_input): ├── first_input == False ├── second_input == False ├── if first_input == True: │ if second_input == False: │ return True └── return Falsematerial_non_implication(False, True ) -> False └── def material_non_implication(first_input, second_input): ├── first_input == False ├── second_input == True ├── if first_input == True: │ if second_input == False: │ return True └── return Falseif
first_inputis equal to True, it runsif second_input == False:if
second_inputis NOT equal to False, it leavesif first_input == True:then runs the next line in the function -return Falsematerial_non_implication(True , True ) -> False └── def material_non_implication(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == True: ┌───┴── if second_input == False: │ return True └── return Falseif
second_inputis equal to False, it runsreturn Truematerial_non_implication(True , True ) -> False └── def material_non_implication(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == True: └── if second_input == False: └── return True return False
it only checks the second input if the first input is True
I use the bool built-in function
81def material_non_implication(first_input, second_input): 82 # if first_input == True: 83 if bool(first_input) == True: 84 # if second_input == False: 85 if bool(second_input) == False: 86 return True 87 return Falsethe test is still green.
I use Logical Negation (NOT) to write the second if statement in terms of True
81def material_non_implication(first_input, second_input): 82 # if first_input == True: 83 if bool(first_input) == True: 84 # if second_input == False: 85 # if bool(second_input) == False: 86 if not bool(second_input) == True: 87 return True 88 return Falsestill green.
I remove
== True81def material_non_implication(first_input, second_input): 82 # if first_input == True: 83 # if bool(first_input) == True: 84 if bool(first_input): 85 # if second_input == False: 86 # if bool(second_input) == False: 87 # if not bool(second_input) == True: 88 if not bool(second_input): 89 return True 90 return Falsegreen.
I remove bool
81def material_non_implication(first_input, second_input): 82 # if first_input == True: 83 # if bool(first_input) == True: 84 # if bool(first_input): 85 if first_input: 86 # if second_input == False: 87 # if bool(second_input) == False: 88 # if not bool(second_input) == True: 89 # if not bool(second_input): 90 if not second_input: 91 return True 92 return Falsestill green, because
if bool(something) == Trueis the same asif bool(something)is the same asif something.if bool(something) == Falseis the same asif not bool(something) == Trueis the same asif not bool(something)is the same asif not something.
I use Logical Conjunction (AND) to put the two if statements together
81def material_non_implication(first_input, second_input): 82 # if first_input == True: 83 # if bool(first_input) == True: 84 # if bool(first_input): 85 # if first_input: 86 # if second_input == False: 87 # if bool(second_input) == False: 88 # if not bool(second_input) == True: 89 # if not bool(second_input): 90 # if not second_input: 91 if first_input and not second_input: 92 return True 93 return Falsethe test is still green, because I can put two if statements together when one is indented under the other
if something: if something_else:can also be written as
if something and something_else:I add a conditional expression
81def material_non_implication(first_input, second_input): 82 # if first_input == True: 83 # if bool(first_input) == True: 84 # if bool(first_input): 85 # if first_input: 86 # if second_input == False: 87 # if bool(second_input) == False: 88 # if not bool(second_input) == True: 89 # if not bool(second_input): 90 # if not second_input: 91 # if first_input and not second_input: 92 # return True 93 # return False 94 return ( 95 True if 96 first_input and not second_input 97 else False 98 )still green.
if ( vs return True first_input and not second_input ): return True vs if first_input and not second_input return False vs else FalseI remove
True ifandelse Falseto make the statement simpler94 return ( 95 # True if 96 first_input and not second_input 97 # else False 98 )green.
material_non_implication returns
first_input and not second_inputnot second_inputis the Logical Negation (NOT) ofsecond_inputif the second input is True, this part of the statement is False
if the second input is False, this part of the statement is True
first_input and not second_inputis the Logical Conjunction (AND) of the first input and the Logical Negation (NOT) of the second inputlogical_conjunction( first_input, logical_negation(second_input) )
this means that in the four cases
if the first input is True and the second input is True, material_non_implication returns
first_input and not second_input True and not True True and False # logical_conjunction(True, False) Falseif the first input is True and the second input is False, material_non_implication returns
first_input and not second_input True and not False True and True # logical_conjunction(True, True) Trueif the first input is False and the second input is True, material_non_implication returns
first_input and not second_input False and not True False and False # logical_conjunction(False, False) Falseif the first input is False and the second input is False, material_non_implication returns
first_input and not second_input False and not False False and True # logical_conjunction(False, True) False
first
second
not second
(first and not second)
True
True
False
False
True
False
True
True
False
True
False
False
False
False
True
False
I add a return statement to show this
81def material_non_implication(first_input, second_input): 82 # if first_input == True: 83 # if bool(first_input) == True: 84 # if bool(first_input): 85 # if first_input: 86 # if second_input == False: 87 # if bool(second_input) == False: 88 # if not bool(second_input) == True: 89 # if not bool(second_input): 90 # if not second_input: 91 # if first_input and not second_input: 92 # return True 93 # return False 94 return logical_conjunction( 95 first_input, 96 logical_negation(second_input) 97 ) 98 return ( 99 # True if 100 first_input and not second_input 101 # else False 102 )still green.
material_non_implication(False, False) -> False └── logical_conjunction(False, True ) -> False material_non_implication(False, True ) -> False └── logical_conjunction(False, False) -> False material_non_implication(True , False) -> True └── logical_conjunction(True , True ) -> True material_non_implication(True , True ) -> False └── logical_conjunction(True , False) -> FalseI remove the comments
81def material_non_implication(first_input, second_input): 82 return logical_conjunction( 83 first_input, 84 logical_negation(second_input) 85 ) 86 return first_input and not second_inputI can use either of these return statements. The first return statement is the only one that runs in this case, because the return statement is the last thing to run in a function.
I add a git commit message in the other terminal
git commit -am \ 'add material_non_implication'
returns
first_input and not second_inputwhich is the Logical Conjunction of the first input and the Logical Negation of the second input.returns True, only if the first input is True and the second input is False.
is the Logical Negation of Material/Logical Implication which returns False only if the first input is True and the second input is False.
can be thought of as a claim that does not deliver.
examples of Material Non-Implication
A broken promise, if the inputs are
did I make a promise?
did I do something?
I promised
I did something
broken promise
yes
yes
no
yes
no
yes
no
yes
no
no
no
no
A false alarm, if the inputs are
did alarm ring?
was there a bad event?
alarm rang
bad event
false alarm
yes
yes
no
yes
no
yes
no
yes
no (alarm is broken)
no
no
no
the boy who cried wolf, if the inputs are
did the boy cry?
was there a wolf?
boy cried
wolf
false claim
yes
yes
no
yes
no
yes
no
yes
no
no
no
no
more about Exclusive Disjunction
I can also think of Exclusive Disjunction which returns (not first_input and second_input) or (first_input and not second_input) as
return logical_disjunction(
converse_non_implication(
first_input, second_input
),
material_non_implication(
first_input, second_input
)
)
because logical_disjunction returns first_input or second_input
first_inputin this case is(not first_input and second_input)converse_non_implication returns
not first_input and second_inputsecond_inputin this case is(first_input and not second_input)material_non_implication returns
first_input and not second_input
logical_disjunction(first_input, second_input)
first_input == (not first_input and second_input)
converse_non_implication == (not first_input and second_input)
second_input == (first_input and not second_input)
material_non_implication == (first_input and not second_input)
I change the return statement in the exclusive_disjunction function in
truth_table.py62def exclusive_disjunction(first_input, second_input): 63 # return first_input != second_input 64 # return not (first_input == second_input) 65 return logical_disjunction( 66 converse_non_implication( 67 first_input, second_input 68 ), 69 # logical_conjunction( 70 # first_input, 71 # logical_negation(second_input) 72 # ) 73 material_non_implication( 74 first_input, second_input 75 ) 76 ) 77 return ( 78 (not first_input and second_input) 79 or 80 (first_input and not second_input) 81 )the test is still green.
I put the first two return statements back, then remove the commented lines
62def exclusive_disjunction(first_input, second_input): 63 return first_input != second_input 64 return not (first_input == second_input) 65 return logical_disjunction( 66 converse_non_implication( 67 first_input, second_input 68 ), 69 material_non_implication( 70 first_input, second_input 71 ) 72 ) 73 return ( 74 (not first_input and second_input) 75 or 76 (first_input and not second_input) 77 ) 78 79 80def material_non_implication(first_input, second_input): 81 return logical_conjunction( 82 first_input, 83 logical_negation(second_input) 84 ) 85 return first_input and not second_inputstill green.
I add a git commit message in the other terminal
git commit -am \ 'refactor exclusive_disjunction'
test_project_first
The truth table for project_first is
first input |
second input |
return |
|---|---|---|
True |
True |
True |
True |
False |
True |
False |
True |
False |
False |
False |
False |
RED: make it fail
I go back to the terminal where the tests are running
I add a test for project_first with an assertion for if the first input is True and the second input is True, in
test_binary.pyfirst input
second input
return
True
True
True
83 self.assertFalse(material_non_implication(False, False)) 84 85 def test_project_first(self): 86 project_first = src.truth_table.project_first 87 self.assertTrue(project_first(True, True)) 88 89 90# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'project_first'there is nothing named project_first in
truth_table.py
GREEN: make it pass
I add a function for project_first to truth_table.py
80def material_non_implication(first_input, second_input):
81 return logical_conjunction(
82 first_input,
83 logical_negation(second_input)
84 )
85 return first_input and not second_input
86
87
88def project_first(first_input, second_input):
89 return True
the test passes. project_first returns True, if the first input is True and the second input is True.
project_first(True , True ) -> True
REFACTOR: make it better
I add an assertion for the second case, which is if the first input is True and the second input is False, to test_project_first in
test_binary.pyfirst input
second input
return
True
False
True
85 def test_project_first(self): 86 project_first = src.truth_table.project_first 87 self.assertTrue(project_first(True, True)) 88 self.assertTrue(project_first(True, False)) 89 90 91# Exceptions seenthe test is still green. project_first returns
True, if the first input is True and the second input is False
True, if the first input is True and the second input is True
True, if the first input is True
project_first(True , False) -> True project_first(True , True ) -> Trueon to the next case, which is if the first input is False and the second input is True
first input
second input
return
False
True
False
85 def test_project_first(self): 86 project_first = src.truth_table.project_first 87 self.assertTrue(project_first(True, True)) 88 self.assertTrue(project_first(True, False)) 89 self.assertFalse(project_first(False, True)) 90 91 92# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause the function returns True and the assertion expects False.
I add an if statement for this case to the project_first function in
truth_table.py88def project_first(first_input, second_input): 89 if first_input == False: 90 return False 91 return Truethe test passes because when project_first is called, Python checks
if first_input == False:if
first_inputis NOT equal to False, it leaves the if statement then runsreturn Trueproject_first(True , True ) -> True └── def project_first(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ return False └── return Trueproject_first(True , False) -> True └── def project_first(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ return False └── return Trueif
first_inputis equal to False, it runsreturn Falseproject_first(False, False) -> False └── def project_first(first_input, second_input): ├── first_input == False ├── second_input == False └── if first_input == False: └── return False return Trueproject_first(False, True ) -> False └── def project_first(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == False: └── return False return True
I add an assertion for the last case, which is if the first input is False and the second input is False, to test_project_first in
test_binary.pyfirst input
second input
return
False
False
False
85 def test_project_first(self): 86 project_first = src.truth_table.project_first 87 self.assertTrue(project_first(True, True)) 88 self.assertTrue(project_first(True, False)) 89 self.assertFalse(project_first(False, True)) 90 self.assertFalse(project_first(False, False)) 91 92 93# Exceptions seenthe test is still green.
project_first(False, False) -> False project_first(False, True ) -> False project_first(True , False) -> True project_first(True , True ) -> TrueI add the bool built-in function to the if statement in the project_first function in
truth_table.py88def project_first(first_input, second_input): 89 # if first_input == False: 90 if bool(first_input) == False: 91 return False 92 return Truestill green.
I use Logical Negation (NOT) to write it in terms of True
88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 if not bool(first_input) == True: 92 return False 93 return Truegreen.
I remove
== True88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 # if not bool(first_input) == True: 92 if not bool(first_input): 93 return False 94 return Truestill green.
I remove bool
88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 # if not bool(first_input) == True: 92 # if not bool(first_input): 93 if not first_input: 94 return False 95 return Truethe test is still green, because
if bool(something) == Falseis the same asif not bool(something) == Trueis the same asif not bool(something)is the same asif not something.I add an else clause to make it clearer
88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 # if not bool(first_input) == True: 92 # if not bool(first_input): 93 if not first_input: 94 return False 95 else: 96 return Truestill green.
I use Logical Negation (NOT) for the else clause
88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 # if not bool(first_input) == True: 92 # if not bool(first_input): 93 if not first_input: 94 return False 95 # else: 96 if not (not first_input): 97 return Truegreen.
I remove the nots because they cancel out
88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 # if not bool(first_input) == True: 92 # if not bool(first_input): 93 if not first_input: 94 return False 95 # else: 96 # if not (not first_input): 97 if first_input: 98 return Truestill green.
I add a conditional expression
88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 # if not bool(first_input) == True: 92 # if not bool(first_input): 93 # if not first_input: 94 # return False 95 # else: 96 # if not (not first_input): 97 # if first_input: 98 # return True 99 return True if first_input else Falsethe test is still green.
if first_input: vs return True return True vs if first_input else: vs else return False vs FalseI remove
True ifandelse False88def project_first(first_input, second_input): 89 # if first_input == False: 90 # if bool(first_input) == False: 91 # if not bool(first_input) == True: 92 # if not bool(first_input): 93 # if not first_input: 94 # return False 95 # else: 96 # if not (not first_input): 97 # if first_input: 98 # return True 99 # return True if first_input else False 100 return first_inputstill green.
I remove the other statements
88def project_first(first_input, second_input): 89 return first_inputI add a git commit message in the other terminal
git commit -am 'add project_first'
Project First always returns the first input it does not care about the second input, like Project Second which always returns the second input and does not care about the first input.
examples of Project First
did the event happen, if the inputs are
did the event happen?
did I get a notification?
event
notification
event happened
yes
yes
yes
yes
no
yes (notification is broken)
no
yes
no (notification is broken)
no
no
no
“if a tree falls in the forest, does it make a sound?”
able to login with or without Multi Factor Authentication, if the inputs are
did user provide the right password?
does user have MFA?
right password
right MFA code
log in
yes
yes
yes
yes
no
yes
no
yes
no (how did user get the MFA code?)
no
no
no
my actions, if the inputs are
what I want to do?
what you think I should do?
what I want
your thoughts
my actions
yes
yes
yes
yes
no
yes
no
yes
no
no
no
no
autocorrect, if the inputs are
autocorrect suggests a word
I write what I want
autocorrect
what I want
what I get
yes
yes
yes
yes
no
yes
no
yes
no
no
no
no
test_converse_implication
The truth table for converse_implication is
first input |
second input |
return |
|---|---|---|
True |
True |
True |
True |
False |
True |
False |
True |
False |
False |
False |
True |
RED: make it fail
I go back to the terminal where the tests are running
I add a test for converse_implication with an assertion for if the first input is True and the second input is True, to
test_binary.pyfirst input
second input
return
True
True
True
90 self.assertFalse(project_first(False, False)) 91 92 def test_converse_implication(self): 93 converse_implication = ( 94 src.truth_table.converse_implication 95 ) 96 self.assertTrue(converse_implication(True, True)) 97 98 99# Exceptions seenthe terminal is my friend, and shows AttributeError
AttributeError: module 'src.truth_table' has no attribute 'converse_implication'. Did you mean: 'converse_non_implication'?because
truth_table.pydoes not have anything named converse_implication in it.
GREEN: make it pass
I add a function definition for converse_implication to truth_table.py
88def project_first(first_input, second_input):
89 return first_input
90
91
92def converse_implication(first_input, second_input):
93 return True
the test passes. converse_implication returns True, if the first input is True and the second input is True.
converse_implication(True , True ) -> True
REFACTOR: make it better
I add an assertion for the second case, which is if the first input is True and the second input is False, to test_converse_implication in
test_binary.pyfirst input
second input
return
True
False
True
92 def test_converse_implication(self): 93 converse_implication = ( 94 src.truth_table.converse_implication 95 ) 96 self.assertTrue(converse_implication(True, True)) 97 self.assertTrue(converse_implication(True, False)) 98 99 100# Exceptions seenthe test is still green. converse_implication returns True
if the first input is True and the second input is False
if the first input is True and the second input is True
if the first input is True
converse_implication(True , False) -> True converse_implication(True , True ) -> Truetime for the next case, which is if the first input is False and the second input is True
92 def test_converse_implication(self): 93 converse_implication = ( 94 src.truth_table.converse_implication 95 ) 96 self.assertTrue(converse_implication(True, True)) 97 self.assertTrue(converse_implication(True, False)) 98 self.assertFalse(converse_implication(False, True)) 99 100 101# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: True is not falsebecause the converse_implication function returns True and the assertion expects False.
I add an if statement to converse_implication in
truth_table.py92def converse_implication(first_input, second_input): 93 if first_input == False: 94 return False 95 return Truethe test passes because when converse_implication is called, it runs
if first_input == False:if
first_inputis NOT equal to False, it leaves the if statement then runsreturn Trueif
first_inputis equal to False, it runsreturn False
converse_implication(False, True ) -> False converse_implication(True , False) -> True converse_implication(True , True ) -> TrueI add an assertion for the last case, which is if the first input is False and the second input is False, to test_converse_implication in
test_binary.pyfirst input
second input
return
False
False
True
92 def test_converse_implication(self): 93 converse_implication = ( 94 src.truth_table.converse_implication 95 ) 96 self.assertTrue(converse_implication(True, True)) 97 self.assertTrue(converse_implication(True, False)) 98 self.assertFalse(converse_implication(False, True)) 99 self.assertTrue(converse_implication(False, False)) 100 101 102# Exceptions seenthe terminal is my friend, and shows AssertionError
AssertionError: False is not truebecause when converse_implication is called, Python checks
if first_input == False:if
first_inputis NOT equal to False, it leaves the if statement then runsreturn Trueif
first_inputis equal to False, it runsreturn Falsefirst_inputis False in this case, which raises AssertionError since the assertion expects True and the function returns False
I add an if statement for the only case that returns False
92def converse_implication(first_input, second_input): 93 if first_input == False: 94 if second_input == True: 95 return False 96 return Truethe test passes.
converse_implication(False, False) -> True converse_implication(False, True ) -> False converse_implication(True , False) -> True converse_implication(True , True ) -> TruePython
if first_input == False:when converse_implication is calledif
first_inputis NOT equal to False, it leaves the if statement then runsreturn Trueconverse_implication(True , True ) -> True └── def converse_implication(first_input, second_input): ├── first_input == True ├── second_input == True ├── if first_input == False: │ if second_input == True: │ return False └── return Trueconverse_implication(True , False) -> True └── def converse_implication(first_input, second_input): ├── first_input == True ├── second_input == False ├── if first_input == False: │ if second_input == True: │ return False └── return Trueif
first_inputis equal to False, Python checksif second_input == True:if
second_inputis NOT equal to True, it leavesif first_input == False:and runsreturn Trueconverse_implication(False, False) -> True └── def converse_implication(first_input, second_input): ├── first_input == False ├── second_input == False └── if first_input == False: ┌───┴── if second_input == True: │ return False └── return Trueif
second_inputis equal to True, it runsreturn Falseconverse_implication(False, True ) -> False └── def converse_implication(first_input, second_input): ├── first_input == False ├── second_input == True └── if first_input == False: └── if second_input == True: └── return False return True
it only checks the second input if the first input is True.
I add the bool built-in function
92def converse_implication(first_input, second_input): 93 # if first_input == False: 94 if bool(first_input) == False: 95 # if second_input == True: 96 if bool(second_input) == True: 97 return False 98 return Truethe test is still green.
I use Logical Negation (NOT) to write the first if statement in terms of True
92def converse_implication(first_input, second_input): 93 # if first_input == False: 94 # if bool(first_input) == False: 95 if not bool(first_input) == True: 96 # if second_input == True: 97 if bool(second_input) == True: 98 return False 99 return Truestill green.
I remove
== True92def converse_implication(first_input, second_input): 93 # if first_input == False: 94 # if bool(first_input) == False: 95 # if not bool(first_input) == True: 96 if not bool(first_input): 97 # if second_input == True: 98 # if bool(second_input) == True: 99 if bool(second_input): 100 return False 101 return Truegreen.
I remove bool
92def converse_implication(first_input, second_input): 93 # if first_input == False: 94 # if bool(first_input) == False: 95 # if not bool(first_input) == True: 96 # if not bool(first_input): 97 if not first_input: 98 # if second_input == True: 99 # if bool(second_input) == True: 100 # if bool(second_input): 101 if second_input: 102 return False 103 return Truestill green, because
if bool(something) == Falseis the same asif not bool(something) == Trueis the same asif not bool(something)is the same asif not something.if bool(something) == Trueis the same asif bool(something)is the same asif something.
I use Logical Conjunction (AND) to put the two if statements together
92def converse_implication(first_input, second_input): 93 # if first_input == False: 94 # if bool(first_input) == False: 95 # if not bool(first_input) == True: 96 # if not bool(first_input): 97 # if not first_input: 98 # if second_input == True: 99 # if bool(second_input) == True: 100 # if bool(second_input): 101 # if second_input: 102 if not first_input and second_input: 103 return False 104 return Truethe test is still green, because I can put two if statements together when one is indented under the other
if something: if something_else:can also be written as
if something and something_else:I add an else clause to make it clearer
92def converse_implication(first_input, second_input): 93 # if first_input == False: 94 # if bool(first_input) == False: 95 # if not bool(first_input) == True: 96 # if not bool(first_input): 97 # if not first_input: 98 # if second_input == True: 99 # if bool(second_input) == True: 100 # if bool(second_input): 101 # if second_input: 102 if not first_input and second_input: 103 return False 104 else: 105 return Truestill green.
I use the Logical Negation (NOT) of the if statement for the else clause
102 if not first_input and second_input: 103 return False 104 # else: 105 if not (not first_input and second_input): 106 return Truegreen.
I “multiply” the not by every symbol in the parentheses
102 if not first_input and second_input: 103 return False 104 # else: 105 # if not (not first_input and second_input): 106 if ( 107 (not not first_input) 108 (not and) 109 (not second_input) 110 ): 111 return Truethe terminal is my friend, and shows SyntaxError
SyntaxError: invalid syntaxI change
not andto or102 if not first_input and second_input: 103 return False 104 # else: 105 # if not (not first_input and second_input): 106 if ( 107 (not not first_input) 108 # (not and) 109 or 110 (not second_input) 111 ): 112 return Truethe test is green again.
I remove
not not102 if not first_input and second_input: 103 return False 104 # else: 105 # if not (not first_input and second_input): 106 if ( 107 # (not not first_input) 108 first_input 109 # (not and) 110 or 111 (not second_input) 112 ): 113 return Truethe test is still green because two nots cancel out.
I add a conditional expression
102 # if not first_input and second_input: 103 # return False 104 # else: 105 # if not (not first_input and second_input): 106 # if ( 107 # (not not first_input) 108 # first_input 109 # (not and) 110 # or 111 # (not second_input) 112 # ): 113 # return True 114 return ( 115 True if 116 first_input or not second_input 117 else False 118 )still green.
I remove
True ifandelse False102 # if not first_input and second_input: 103 # return False 104 # else: 105 # if not (not first_input and second_input): 106 # if ( 107 # (not not first_input) 108 # first_input 109 # (not and) 110 # or 111 # (not second_input) 112 # ): 113 # return True 114 return ( 115 # True if 116 first_input or not second_input 117 # else False 118 )green.
converse_implication returns
first_input or not second_inputnot second_inputis the Logical Negation (NOT) ofsecond_inputif the second input is True, this part of the statement is False
if the second input is False, this part of the statement is True
first_input or not second_inputis the Logical Disjunction (OR) of the first input and the Logical Negation (NOT) of the second inputlogical_disjunction( first_input, logical_negation(second_input) )
this means that in the four cases
if the first input is True and the second input is True, converse_implication returns
first_input or not second_input True or not True True or False # logical_disjunction(True, False) Trueif the first input is True and the second input is False, converse_implication returns
first_input or not second_input True or not False True or True # logical_disjunction(True, True) Trueif the first input is False and the second input is True, converse_implication returns
first_input or not second_input False or not True False or False # logical_disjunction(False, False) Falseif the first input is False and the second input is False, converse_implication returns
first_input or not second_input False or not False False or True # logical_disjunction(False, True) True
first
second
not second
(first or not second)
True
True
False
True
True
False
True
True
False
True
False
False
False
False
True
True
I add a return statement to show this
106 # if ( 107 # (not not first_input) 108 # (not and) 109 # first_input 110 # or 111 # (not second_input) 112 # ): 113 # return True 114 return logical_disjunction( 115 first_input, 116 logical_negation(second_input) 117 ) 118 return ( 119 # True if 120 first_input or not second_input 121 # else False 122 )still green.
converse_implication(False, False) -> True └── logical_disjunction(False, True ) -> True converse_implication(False, True ) -> False └── logical_disjunction(False, False) -> False converse_implication(True , False) -> True └── logical_disjunction(True , True ) -> True converse_implication(True , True ) -> True └── logical_disjunction(True , False) -> TrueI remove the comments
92def converse_implication(first_input, second_input): 93 return logical_disjunction( 94 first_input, 95 logical_negation(second_input) 96 ) 97 return first_input or not second_inputI can use either of these return statements. The first return statement is the only one that runs in this case, because the return statement is the last thing to run in a function.
I add a git commit message in the other terminal
git commit -am 'add converse_implication'
Converse Implication returns
first_input or not second_input.False, only if the first input is False and the second input is True.
the Logical Disjunction of the first input and the Logical Negation of the second input.
It is the opposite of Converse Non-Implication which always returns
not first_input and second_inputor True, only if the first input is False and the second input is True.
examples of Converse Implication
I cannot get a table at a restaurant, if the inputs are
do I have a reservation?
is the place full?
reservation
place is full
I get a table
yes
yes
yes
yes
no
yes
no
yes
no
no
no
yes
sleep through alarm, if the inputs are
am I too deep in sleep to hear the alarm?
is the alarm ringing?
too tired
alarm rings
I sleep
yes
yes
yes
yes
no
yes
no
yes
no
no
no
yes
staying dry outside, if the inputs are
do I have an umbrella?
is it raining?
umbrella?
raining?
dry
yes
yes
yes
yes
no
yes
no
yes
no
no
no
yes
close the project
I close
test_binary.pyandtruth_table.pyI click in the terminal where the tests are running
I use q on the keyboard to leave the tests. The terminal goes back to the command line.
I change directory to the parent of
truth_tablecd ..the terminal shows
.../pumping_pythonI am back in the
pumping_pythondirectory.
review
Binary Operations take two inputs, each input can be True or False. If I name the first input first_input and the second input second_input, the tests show that
-
returns
first_input or not second_inputreturns False if
first_inputis False andsecond_inputis Trueis the Logical Negation (NOT) of Converse Non-Implication which returns True only if
first_inputis False andsecond_inputis True
first input
second input
return
True
True
True
True
False
True
False
True
False
False
False
True
-
always returns
first_inputreturns True only if
first_inputis Trueis the Logical Negation (NOT) of Negate First which returns True only if
first_inputis False
first input
second input
return
True
True
True
True
False
True
False
True
False
False
False
False
-
returns
first_input and not second_inputreturns True only if
first_inputis True andsecond_inputis Falseis the Logical Negation (NOT) of Material/Logical Implication which returns False only if
first_inputis True andsecond_inputis False
first input
second input
return
True
True
False
True
False
True
False
True
False
False
False
False
-
returns
first_input != second_inputreturns True only if
first_inputandsecond_inputare NOT equalis the Logical Negation (NOT) of Logical Equality which returns True only if
first_inputandsecond_inputare equal
first input
second input
return
True
True
False
True
False
True
False
True
True
False
False
False
-
returns
first_input or second_inputreturns False only if
first_inputis False andsecond_inputis Falseis the Logical Negation (NOT) of Logical NOR which returns True only if
first_inputis False andsecond_inputis False
first input
second input
return
True
True
True
True
False
True
False
True
True
False
False
False
-
always returns True
never returns False
is the Logical Negation (NOT) of contradiction which always returns False
first input
second input
return
True
True
True
True
False
True
False
True
True
False
False
True
-
returns
not (first_input and second_input)returns False only if
first_inputis True andsecond_inputis Trueis the Logical Negation (NOT) of Logical Conjunction (AND) which returns True only if
first_inputis True andsecond_inputis True
first input
second input
return
True
True
False
True
False
True
False
True
True
False
False
True
-
always returns
not first_inputreturns True only if
first_inputis Falseis the Logical Negation (NOT) of Project First which returns True only if
first_inputis True
first input
second input
return
True
True
False
True
False
False
False
True
True
False
False
True
-
returns
not first_input and second_inputreturns True only if
first_inputis False andsecond_inputis Trueis the Logical Negation (NOT) of Converse Implication which returns False if
first_inputis False andsecond_inputis True
first input
second input
return
True
True
False
True
False
False
False
True
True
False
False
False
-
always returns
second_inputreturns True only if
second_inputis Trueis the Logical Negation (NOT) of Negate Second which returns True only if
second_inputis False
first input
second input
return
True
True
True
True
False
False
False
True
True
False
False
False
Logical Conjunction returns
returns
first_input and second_inputreturns True only if
first_inputis True andsecond_inputis Trueis the Logical Negation (NOT) of Logical NAND which returns False only if
first_inputis True andsecond_inputis True
first input
second input
return
True
True
True
True
False
False
False
True
False
False
False
False
-
always returns False
never returns True
is the Logical Negation (NOT) of Tautology which always returns True
first input
second input
return
True
True
False
True
False
False
False
True
False
False
False
False
All the binary operations or conditions have been written with some combination of some or all of these three
return |
True, True |
True, False |
False, True |
False, False |
name of operation |
|---|---|---|---|---|---|
False |
False |
False |
False |
False |
|
first and second |
True |
False |
False |
False |
|
second |
True |
False |
True |
False |
|
(not first) and second |
False |
False |
True |
False |
|
not first |
False |
False |
True |
True |
|
not (first and second) |
False |
True |
True |
True |
|
True |
True |
True |
True |
True |
|
first or second |
True |
True |
True |
False |
|
(not (first and second)) and (first or second) |
False |
True |
True |
False |
|
first and (not second) |
False |
True |
False |
False |
|
first |
True |
True |
False |
False |
|
first or (not second) |
True |
True |
False |
True |
code from the chapter
Do you want to see all the CODE I typed for the Truth Table?
what is next?
rate pumping python
If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too.