truth table: Binary Operations 3


requirements

Binary Operations 2


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        self.assertFalse(
  9            src.truth_table.contradiction(True, True)
 10        )
 11        self.assertFalse(
 12            src.truth_table.contradiction(True, False)
 13        )
 14        self.assertFalse(
 15            src.truth_table.contradiction(False, True)
 16        )
 17        self.assertFalse(
 18            src.truth_table.contradiction(False, False)
 19        )
 20
 21    def test_logical_conjunction(self):
 22        self.assertTrue(
 23            src.truth_table.logical_conjunction(True, True)
 24        )
 25        self.assertFalse(
 26            src.truth_table.logical_conjunction(True, False)
 27        )
 28        self.assertFalse(
 29            src.truth_table.logical_conjunction(False, True)
 30        )
 31        self.assertFalse(
 32            src.truth_table.logical_conjunction(False, False)
 33        )
 34
 35    def test_project_second(self):
 36        self.assertTrue(
 37            src.truth_table.project_second(True, True)
 38        )
 39        self.assertFalse(
 40            src.truth_table.project_second(True, False)
 41        )
 42        self.assertTrue(
 43            src.truth_table.project_second(False, True)
 44        )
 45        self.assertFalse(
 46            src.truth_table.project_second(False, False)
 47        )
 48
 49    def test_converse_non_implication(self):
 50        self.assertFalse(
 51            src.truth_table.converse_non_implication(True, True)
 52        )
 53        self.assertFalse(
 54            src.truth_table.converse_non_implication(True, False)
 55        )
 56        self.assertTrue(
 57            src.truth_table.converse_non_implication(False, True)
 58        )
 59        self.assertFalse(
 60            src.truth_table.converse_non_implication(False, False)
 61        )
 62
 63    def test_negate_first(self):
 64        self.assertFalse(src.truth_table.negate_first(True, True))
 65        self.assertFalse(src.truth_table.negate_first(True, False))
 66        self.assertTrue(src.truth_table.negate_first(False, True))
 67        self.assertTrue(src.truth_table.negate_first(False, False))
 68
 69    def test_logical_nand(self):
 70        self.assertFalse(src.truth_table.logical_nand(True, True))
 71        self.assertTrue(src.truth_table.logical_nand(True, False))
 72        self.assertTrue(src.truth_table.logical_nand(False, True))
 73        self.assertTrue(src.truth_table.logical_nand(False, False))
 74
 75    def test_tautology(self):
 76        self.assertTrue(src.truth_table.tautology(True, True))
 77        self.assertTrue(src.truth_table.tautology(True, False))
 78        self.assertTrue(src.truth_table.tautology(False, True))
 79        self.assertTrue(src.truth_table.tautology(False, False))
 80
 81    def test_logical_disjunction(self):
 82        self.assertTrue(
 83            src.truth_table.logical_disjunction(True, True)
 84        )
 85        self.assertTrue(
 86            src.truth_table.logical_disjunction(True, False)
 87        )
 88        self.assertTrue(
 89            src.truth_table.logical_disjunction(False, True)
 90        )
 91        self.assertFalse(
 92            src.truth_table.logical_disjunction(False, False)
 93        )
 94
 95    def test_exclusive_disjunction(self):
 96        self.assertFalse(src.truth_table.exclusive_disjunction(True, True))
 97        self.assertTrue(src.truth_table.exclusive_disjunction(True, False))
 98        self.assertTrue(src.truth_table.exclusive_disjunction(False, True))
 99        self.assertFalse(src.truth_table.exclusive_disjunction(False, False))
100
101    def test_material_non_implication(self):
102        self.assertFalse(
103            src.truth_table.material_non_implication(True, True)
104        )
105        self.assertTrue(
106            src.truth_table.material_non_implication(True, False)
107        )
108        self.assertFalse(
109            src.truth_table.material_non_implication(False, True)
110        )
111        self.assertFalse(
112            src.truth_table.material_non_implication(False, False)
113        )
114
115    def test_project_first(self):
116        self.assertTrue(src.truth_table.project_first(True, True))
117        self.assertTrue(src.truth_table.project_first(True, False))
118        self.assertFalse(src.truth_table.project_first(False, True))
119        self.assertFalse(src.truth_table.project_first(False, False))
120
121    def test_converse_implication(self):
122        self.assertTrue(src.truth_table.converse_implication(True, True))
123        self.assertTrue(src.truth_table.converse_implication(True, False))
124        self.assertFalse(src.truth_table.converse_implication(False, True))
125        self.assertTrue(src.truth_table.converse_implication(False, False))
126
127
128# Exceptions seen
129# AttributeError
130# TypeError
131# AssertionError
132# SyntaxError

continue the project

  • Make sure you are in the pumping_python folder with pwd in the terminal

    pwd
    

    if the terminal does not show

    .../pumping_python
    

    change directory to the pumping_python folder

  • Once in pumping_python, change directory to the project

    cd truth_table
    

    the terminal shows

    .../pumping_python/truth_table
    
  • I run the tests with pytest-watcher

    uv run pytest-watcher . --now
    

    the 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.py with the mouse to open it in the editor


test_exclusive_disjunction


RED: make it fail


I add a new test to test_binary.py

 82    def test_logical_disjunction(self):
 83        self.assertTrue(
 84            src.truth_table.logical_disjunction(True, True)
 85        )
 86        self.assertTrue(
 87            src.truth_table.logical_disjunction(True, False)
 88        )
 89        self.assertTrue(
 90            src.truth_table.logical_disjunction(False, True)
 91        )
 92        self.assertFalse(
 93            src.truth_table.logical_disjunction(False, False)
 94        )
 95
 96    def test_exclusive_disjunction(self):
 97        self.assertFalse(src.truth_table.exclusive_disjunction(True, True))
 98
 99
100# Exceptions seen

the terminal is my friend, and shows AttributeError

AttributeError: module 'src.truth_table' has no attribute 'exclusive_disjunction'

GREEN: make it pass


I add exclusive_disjunction to truth_table.py

47def logical_disjunction(first_input, second_input):
48    return first_input or second_input
49
50
51def exclusive_disjunction(first_input, second_input):
52    return False

the test passes. exclusive_disjunction returns False, if the first input is True and the second input is True

first input

second input

return

True

True

False


REFACTOR: make it better


  • I add an assertion for the next case, which is when the first input is True and the second input is False, to test_exclusive_disjunction in test_binary.py

    95    def test_exclusive_disjunction(self):
    96        self.assertFalse(src.truth_table.exclusive_disjunction(True, True))
    97        self.assertTrue(src.truth_table.exclusive_disjunction(True, False))
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    
  • I add if statements to exclusive_disjunction in truth_table.py

    51def exclusive_disjunction(first_input, second_input):
    52    if first_input == True:
    53        if second_input == False:
    54            return True
    55    return False
    

    the test passes. exclusive_disjunction returns

    • True, if the first input is True and the second input is False

    • False, if the first input is True and the second input is True

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

  • I add an assertion for the third case, which is when the first input is False and the second input is True, to test_binary.py

    95    def test_exclusive_disjunction(self):
    96        self.assertFalse(src.truth_table.exclusive_disjunction(True, True))
    97        self.assertTrue(src.truth_table.exclusive_disjunction(True, False))
    98        self.assertTrue(src.truth_table.exclusive_disjunction(False, True))
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    
  • I add if statements to exclusive_disjunction in truth_table.py

    51def exclusive_disjunction(first_input, second_input):
    52    if first_input == False:
    53        if second_input == True:
    54            return True
    55    if first_input == True:
    56        if second_input == False:
    57            return True
    58    return False
    

    the test passes. exclusive_disjunction returns

    • True, if the first input is False and the second input is True

    • True, if the first input is True and the second input is False

    • False, if the first input is True and the second input is True

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

    False

    True

    True

  • I add an assertion for the last case, which is when the first input is False and the second input is False to test_exclusive_disjunction, in test_binary.py

     95    def test_exclusive_disjunction(self):
     96        self.assertFalse(src.truth_table.exclusive_disjunction(True, True))
     97        self.assertTrue(src.truth_table.exclusive_disjunction(True, False))
     98        self.assertTrue(src.truth_table.exclusive_disjunction(False, True))
     99        self.assertFalse(src.truth_table.exclusive_disjunction(False, False))
    100
    101
    102# Exceptions seen
    

    the test is still green. exclusive_disjunction returns

    • False, if the first input is False and the second input is False

    • True, if the first input is False and the second input is True

    • True, if the first input is True and the second input is False

    • False, if the first input is True and the second input is True

  • I put the first two if statements together to make them simpler in exclusive_disjunction in truth_table.py

    51def exclusive_disjunction(first_input, second_input):
    52    # if first_input == False:
    53    #     if second_input == True:
    54    if first_input == False and second_input == True:
    55            return True
    56    if first_input == True:
    57        if second_input == False:
    58            return True
    59    return False
    

    the test is still green

  • I do the same thing with the next two if statements

    51def exclusive_disjunction(first_input, second_input):
    52    if first_input == False and second_input == True:
    53            return True
    54    # if first_input == True:
    55    #     if second_input == False:
    56    if first_input == True and second_input == False:
    57            return True
    58    return False
    

    still green

  • I add not to the first if statement

    51def exclusive_disjunction(first_input, second_input):
    52    # if first_input == False and second_input == True:
    53    if not first_input == True and second_input == True:
    54            return True
    55    if first_input == True and second_input == False:
    56            return True
    57    return False
    

    green

  • I do the same thing to the second if statement

    51def exclusive_disjunction(first_input, second_input):
    52    if not first_input == True and second_input == True:
    53            return True
    54    # if first_input == True and second_input == False:
    55    if first_input == True and not second_input == True:
    56            return True
    57    return False
    

    still green

  • I use the bool built-in function

    51def exclusive_disjunction(first_input, second_input):
    52    # if not first_input == True and second_input == True:
    53    if not bool(first_input) == True and bool(second_input) == True:
    54            return True
    55    # if first_input == True and not second_input == True:
    56    if bool(first_input) == True and not bool(second_input) == True:
    57            return True
    58    return False
    

    green

  • I remove == True

    51def exclusive_disjunction(first_input, second_input):
    52    # if not bool(first_input) == True and bool(second_input) == True:
    53    if not bool(first_input) and bool(second_input):
    54            return True
    55    # if bool(first_input) == True and not bool(second_input) == True:
    56    if bool(first_input) and not bool(second_input):
    57            return True
    58    return False
    

    still green

  • I remove bool

    51def exclusive_disjunction(first_input, second_input):
    52    # if not bool(first_input) and bool(second_input):
    53    if not first_input and second_input:
    54            return True
    55    # if bool(first_input) and not bool(second_input):
    56    if first_input and not second_input:
    57            return True
    58    return False
    

    the test is still green

  • I use Logical Disjunction to put the two if statements together because they both return True

    Tip

    I can put two if statements together with Logical Disjunction (or) when they are at the same indentation level and return the same thing.

    For example

    if something:
        return this
    if something_else:
        return this
    

    can also be written as

    if something or something_else:
        return this
    
    51def exclusive_disjunction(first_input, second_input):
    52    # if not first_input and second_input:
    53    #         return True
    54    # if first_input and not second_input:
    55    #         return True
    56    if (
    57        (not first_input and second_input)
    58        or
    59        (first_input and not second_input)
    60    ):
    61        return True
    62    return False
    

    still green

  • I use a conditional expression

    51def exclusive_disjunction(first_input, second_input):
    52    return True if (
    53        (not first_input and second_input)
    54        or
    55        (first_input and not second_input)
    56    ) else False
    57    if (
    58        (not first_input and second_input)
    59        or
    60        (first_input and not second_input)
    61    ):
    62        return True
    63    return False
    

    green

  • I remove the other statements in the function and make the ternary operator simpler

    51def exclusive_disjunction(first_input, second_input):
    52    return (
    53        (not first_input and second_input)
    54        or
    55        (first_input and not second_input)
    56    )
    57    return True if (
    58        (not first_input and second_input)
    59        or
    60        (first_input and not second_input)
    61    ) else False
    

    why is the grass greener on the other side?

  • I remove the second return statement

    51def exclusive_disjunction(first_input, second_input):
    52    return (
    53        (not first_input and second_input)
    54        or
    55        (first_input and not second_input)
    56    )
    

    still green

  • exclusive_disjunction returns False when first_input and second_input are the same and returns True, if they are NOT. I add an if statement to show this with the equality symbol (2 equal signs together =+=)

    51def exclusive_disjunction(first_input, second_input):
    52    if first_input == second_input:
    53        return False
    54    else:
    55        return True
    56    return (
    57        (not first_input and second_input)
    58        or
    59        (first_input and not second_input)
    60    )
    

    the test is still green

  • I change the new if statement to a simple return statement

    51def exclusive_disjunction(first_input, second_input):
    52    return not (first_input == second_input)
    53    if first_input == second_input:
    54        return False
    55    else:
    56        return True
    57    return (
    58        (not first_input and second_input)
    59        or
    60        (first_input and not second_input)
    61    )
    

    still green

  • I remove the commented lines, then use an even simpler return statement with the NOT equal symbol (!=) (exclamation mark and equal symbol !+= on the keyboard)

    51def exclusive_disjunction(first_input, second_input):
    52    return first_input != second_input
    53    return not (first_input == second_input)
    54    return (
    55        (not first_input and second_input)
    56        or
    57        (first_input and not second_input)
    58    )
    

Exclusive Disjunction returns

  • True, if the first input is NOT EQUAL to the second input

  • False, if the first input is EQUAL to the second input

  • first_input != second_input - which reads as first input is NOT equal to second input

  • not (first_input == second_input) - which reads 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.

All of the above statements mean the same thing. Exclusive Disjunction is also known as Exclusive OR or XOR. Would “Logical Inequality” be a better name?

first input

second input

return

True

True

False

True

False

True

False

True

True

False

False

False


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

    off

    on

    off

    on

    off

    on

    on

    off

    off

    off

  • magnets attract or repel, if the inputs are

    • what is the direction of magnet A?

    • what is the direction of magnet B?

    magnet A?

    magnet B?

    attract/repel

    north

    north

    repel

    north

    south

    attract

    south

    north

    attract

    south

    south

    repel

  • 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


test_material_non_implication


RED: make it fail


I add another test to test_binary.py

 95    def test_exclusive_disjunction(self):
 96        self.assertFalse(src.truth_table.exclusive_disjunction(True, True))
 97        self.assertTrue(src.truth_table.exclusive_disjunction(True, False))
 98        self.assertTrue(src.truth_table.exclusive_disjunction(False, True))
 99        self.assertFalse(src.truth_table.exclusive_disjunction(False, False))
100
101    def test_material_non_implication(self):
102        self.assertFalse(
103            src.truth_table.material_non_implication(True, True)
104        )
105
106
107# Exceptions seen

the terminal is my friend, and shows AttributeError

AttributeError: module 'src.truth_table' has no attribute 'material_non_implication'. Did you mean: 'converse_non_implication'?

GREEN: make it pass


I add material_non_implication to truth_table.py

51def exclusive_disjunction(first_input, second_input):
52    return first_input != second_input
53    return not (first_input == second_input)
54    return (
55        (not first_input and second_input)
56        or
57        (first_input and not second_input)
58    )
59
60
61def material_non_implication(first_input, second_input):
62    return False

the test passes. material_non_implication returns False, if the first input is True and the second input is True

first input

second input

return

True

True

False


REFACTOR: make it better


  • I add an assertion for the second case, which is when the first input is True and the second input is False to test_material_non_implication in test_binary.py

    101    def test_material_non_implication(self):
    102        self.assertFalse(
    103            src.truth_table.material_non_implication(True, True)
    104        )
    105        self.assertTrue(
    106            src.truth_table.material_non_implication(True, False)
    107        )
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    
  • I add an if statement to material_non_implication in truth_table.py

    61def material_non_implication(first_input, second_input):
    62    if first_input == True:
    63        if second_input == False:
    64            return True
    65    return False
    

    the test passes. material_non_implication returns

    • True, if the first input is True and the second input is False

    • False, if the first input is True and the second input is True

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

  • I add an assertion for the third case, where the first input is False and the second input is True in test_binary.py

    101    def test_material_non_implication(self):
    102        self.assertFalse(
    103            src.truth_table.material_non_implication(True, True)
    104        )
    105        self.assertTrue(
    106            src.truth_table.material_non_implication(True, False)
    107        )
    108        self.assertFalse(
    109            src.truth_table.material_non_implication(False, True)
    110        )
    

    the test is still green. material_non_implication returns

    • False, if the first input is False and the second input is True

    • True, if the first input is True and the second input is False

    • False, if the first input is True and the second input is True

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

    False

    True

    False

  • I add an assertion for the fourth case, where the first input is False and the second input is False

    101    def test_material_non_implication(self):
    102        self.assertFalse(
    103            src.truth_table.material_non_implication(True, True)
    104        )
    105        self.assertTrue(
    106            src.truth_table.material_non_implication(True, False)
    107        )
    108        self.assertFalse(
    109            src.truth_table.material_non_implication(False, True)
    110        )
    111        self.assertFalse(
    112            src.truth_table.material_non_implication(False, False)
    113        )
    114
    115
    116# Exceptions seen
    

    still green. material_non_implication returns

    • False, if the first input is False and the second input is False

    • False, if the first input is False and the second input is True

    • True, if the first input is True and the second input is False - this is the only case where it returns True

    • False, if the first input is True and the second input is True

  • I change the two if statements to one, in truth_table.py

    61def material_non_implication(first_input, second_input):
    62    # if first_input == True:
    63        # if second_input == False:
    64    if first_input == True and second_input == False:
    65            return True
    66    return False
    

    green

  • I add not

    61def material_non_implication(first_input, second_input):
    62    # if first_input == True and second_input == False:
    63    if first_input == True and not second_input == True:
    64            return True
    65    return False
    

    still green

  • I use the bool built-in function

    61def material_non_implication(first_input, second_input):
    62    # if first_input == True and not second_input == True:
    63    if bool(first_input) == True and not bool(second_input) == True:
    64            return True
    65    return False
    

    the test is still green

  • I remove == True

    61def material_non_implication(first_input, second_input):
    62    # if bool(first_input) == True and not bool(second_input) == True:
    63    if bool(first_input) and not bool(second_input):
    64            return True
    65    return False
    

    still green

  • I remove bool

    61def material_non_implication(first_input, second_input):
    62    # if bool(first_input) and not bool(second_input):
    63    if first_input and not second_input:
    64            return True
    65    return False
    

    green

  • I add a conditional expression

    61def material_non_implication(first_input, second_input):
    62    return True if first_input and not second_input else False
    63    if first_input and not second_input:
    64            return True
    65    return False
    

    still green

  • I make the statement simpler

    61def material_non_implication(first_input, second_input):
    62    return first_input and not second_input
    63    return True if first_input and not second_input else False
    

    the test is still green

  • I remove the other statement in the function

    61def material_non_implication(first_input, second_input):
    62    return first_input and not second_input
    

Material NonImplication

  • returns first_input and not second_input which 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

first input

second input

return

True

True

False

True

False

True

False

True

False

False

False

False


examples of Material NonImplication


  • 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

    • did the boy cry?

    • was there a wolf?

    boy cried

    wolf

    boy cried wolf

    yes

    yes

    no

    yes

    no

    yes

    no

    yes

    no

    no

    no

    no

Note

return first_input and not second_input returns the Logical Conjunction of the first input and the Logical Negation of the second input. This means that in the 4 cases

  • if the first input is True and the second input is True, material_non_implication returns

    first and not second
    True  and not True
    True  and False     # logical_conjunction(True, False)
    False               # logical_conjunction(True, False)
    
  • if the first input is True and the second input is False, material_non_implication returns

    first and not second
    True  and not False
    True  and True      # logical_conjunction(True, True)
    True                # logical_conjunction(True, True)
    
  • if the first input is False and the second input is True, material_non_implication returns

    first and not second
    False and not True
    False and False     # logical_conjunction(False, False)
    False               # logical_conjunction(False, False)
    
  • if the first input is False and the second input is False, material_non_implication returns

    first and not second
    False and not False
    False and True      # logical_conjunction(False, True)
    False               # logical_conjunction(False, True)
    

    first

    second

    not second

    first and (not second)

    True

    True

    False

    False

    True

    False

    True

    True

    False

    True

    False

    False

    False

    False

    True

    False


test_project_first


RED: make it fail


I add a new test in test_binary.py

101    def test_material_non_implication(self):
102        self.assertFalse(
103            src.truth_table.material_non_implication(True, True)
104        )
105        self.assertTrue(
106            src.truth_table.material_non_implication(True, False)
107        )
108        self.assertFalse(
109            src.truth_table.material_non_implication(False, True)
110        )
111        self.assertFalse(
112            src.truth_table.material_non_implication(False, False)
113        )
114
115    def test_project_first(self):
116        self.assertTrue(src.truth_table.project_first(True, True))
117
118
119# Exceptions seen

the terminal is my friend, and shows AttributeError

AttributeError: module 'src.truth_table' has no attribute 'project_first'

GREEN: make it pass


I add a function for project_first in truth_table.py

61def material_non_implication(first_input, second_input):
62    return first_input and not second_input
63
64
65def project_first(first_input, second_input):
66    return True

the test passes. project_first returns True, if the first input is True and the second input is True

first input

second input

return

True

True

True


REFACTOR: make it better


  • I add the second case to test_project_first in test_binary.py

    115    def test_project_first(self):
    116        self.assertTrue(src.truth_table.project_first(True, True))
    117        self.assertTrue(src.truth_table.project_first(True, False))
    

    the 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

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

  • on to the next case

    115    def test_project_first(self):
    116        self.assertTrue(src.truth_table.project_first(True, True))
    117        self.assertTrue(src.truth_table.project_first(True, False))
    118        self.assertFalse(src.truth_table.project_first(False, True))
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    
  • I add if statements for this case to project_first in truth_table.py

    65def project_first(first_input, second_input):
    66    if first_input == False:
    67        if second_input == True:
    68            return False
    69    return True
    

    the test passes. project_first returns

    • False, if the first input is False and the second input is True

    • True, if the first input is True

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

    False

    True

    False

  • I add an assertion for the last case to test_project_first in test_binary.py

    115    def test_project_first(self):
    116        self.assertTrue(src.truth_table.project_first(True, True))
    117        self.assertTrue(src.truth_table.project_first(True, False))
    118        self.assertFalse(src.truth_table.project_first(False, True))
    119        self.assertFalse(src.truth_table.project_first(False, False))
    120
    121
    122# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    
  • I add more if statements to project_first in truth_table.py

    65def project_first(first_input, second_input):
    66    if first_input == False:
    67        if second_input == False:
    68            return False
    69        if second_input == True:
    70            return False
    71    return True
    

    the test passes. project_first returns

    • False, if the first input is False and the second input is False

    • False, if the first input is False and the second input is True

    • False, if the first input is False

    • True, if the first input is True

    • the first input in every case

  • I add a return statement

    65def project_first(first_input, second_input):
    66    return first_input
    67    if first_input == False:
    68        if second_input == False:
    69            return False
    70        if second_input == True:
    71            return False
    72    return True
    

    the test is still green

  • I remove the other statements

    65def project_first(first_input, second_input):
    66    return first_input
    

Project First always returns the first input, like Project Second which always returns the second input

first input

second input

return

True

True

True

True

False

True

False

True

False

False

False

False


examples of Project First


  • did the event happen, if the inputs are

    • did the event happen?

    • did we get a notification about it?

    event

    notification

    event happened

    yes

    yes

    yes

    yes

    no

    yes

    no

    yes

    no (notification is broken)

    no

    no

    no

  • 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

    what happens

    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


RED: make it fail


I add a new test to test_binary.py

115    def test_project_first(self):
116        self.assertTrue(src.truth_table.project_first(True, True))
117        self.assertTrue(src.truth_table.project_first(True, False))
118        self.assertFalse(src.truth_table.project_first(False, True))
119        self.assertFalse(src.truth_table.project_first(False, False))
120
121    def test_converse_implication(self):
122        self.assertTrue(src.truth_table.converse_implication(True, True))
123
124
125# Exceptions seen

the terminal is my friend, and shows AttributeError

AttributeError: module 'src.truth_table' has no attribute 'converse_implication'. Did you mean: 'converse_non_implication'?

GREEN: make it pass


I add a function for converse_implication to truth_table.py

65def project_first(first_input, second_input):
66    return first_input
67
68
69def converse_implication(first_input, second_input):
70    return True

the test passes. converse_implication returns True, if the first input is True and the second input is True

first input

second input

return

True

True

True


REFACTOR: make it better


  • I add the second case to test_converse_implication in test_binary.py

    121    def test_converse_implication(self):
    122        self.assertTrue(src.truth_table.converse_implication(True, True))
    123        self.assertTrue(src.truth_table.converse_implication(True, False))
    

    the test is still green. converse_implication 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

  • time for the next case

    121    def test_converse_implication(self):
    122        self.assertTrue(src.truth_table.converse_implication(True, True))
    123        self.assertTrue(src.truth_table.converse_implication(True, False))
    124        self.assertFalse(src.truth_table.converse_implication(False, True))
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    
  • I add if statements to converse_implication in truth_table.py

    69def converse_implication(first_input, second_input):
    70    if first_input == False:
    71        if second_input == True:
    72            return False
    73    return True
    

    the test passes. converse_implication returns

    • False, if the first input is False and the second input is True

    • True, if the first input is True

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

  • I add an assertion for the last case to test_converse_implication in test_binary.py

    121    def test_converse_implication(self):
    122        self.assertTrue(src.truth_table.converse_implication(True, True))
    123        self.assertTrue(src.truth_table.converse_implication(True, False))
    124        self.assertFalse(src.truth_table.converse_implication(False, True))
    125        self.assertTrue(src.truth_table.converse_implication(False, False))
    126
    127
    128# Exceptions seen
    

    the test is still green. converse_implication returns

    • True, if the first input is False and the second input is False

    • False, if the first input is False and the second input is True - this is the only case where it returns False

    • True, if the first input is True

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

    False

    True

    False

  • I change the two if statements to one in truth_table.py

    69def converse_implication(first_input, second_input):
    70    # if first_input == False:
    71    #     if second_input == True:
    72    if first_input == False and second_input == True:
    73            return False
    74    return True
    

    still green

  • I use not to write the if statement with True

    69def converse_implication(first_input, second_input):
    70    # if first_input == False and second_input == True:
    71    if not first_input == True and second_input == True:
    72            return False
    73    return True
    

    green

  • I use the bool built-in function

    69def converse_implication(first_input, second_input):
    70    # if not first_input == True and second_input == True:
    71    if not bool(first_input) == True and bool(second_input) == True:
    72            return False
    73    return True
    

    still green

  • I remove == True

    69def converse_implication(first_input, second_input):
    70    # if not bool(first_input) == True and bool(second_input) == True:
    71    if not bool(first_input) and bool(second_input):
    72            return False
    73    return True
    

    the test is still green

  • I remove bool

    69def converse_implication(first_input, second_input):
    70    # if not bool(first_input) and bool(second_input):
    71    if not first_input and second_input:
    72            return False
    73    return True
    

    do you like green eggs and ham?

  • I add the opposite of the if statement for the second return statement

    69def converse_implication(first_input, second_input):
    70    if not first_input and second_input:
    71            return False
    72    if not (not first_input and second_input):
    73        return True
    

    still green

  • I move the new if statement to the top

    69def converse_implication(first_input, second_input):
    70    if not (not first_input and second_input):
    71        return True
    72    if not first_input and second_input:
    73            return False
    

    green

  • I add a conditional expression

    69def converse_implication(first_input, second_input):
    70    return True if not (not first_input and second_input) else False
    71    if not (not first_input and second_input):
    72        return True
    73    if not first_input and second_input:
    74            return False
    

    still green

  • I remove the other statements and write a simpler conditional expression

    69def converse_implication(first_input, second_input):
    70    return not (not first_input and second_input)
    71    return True if not (not first_input and second_input) else False
    

    the test is still green

  • I remove the commented lines and “multiply not” by the symbols in the parentheses

    69def converse_implication(first_input, second_input):
    70    return (not not first_input) (not and) (not second_input)
    71    return not (not first_input and second_input)
    

    the terminal is my friend, and shows SyntaxError

    SyntaxError: invalid syntax
    
  • I change “not and” to “or” to be correct

    69def converse_implication(first_input, second_input):
    70    return (not not first_input) or (not second_input)
    71    return not (not first_input and second_input)
    

    back to green

  • I remove the other return statement then remove not not because they cancel out - the negation of the negation of something is something

    69def converse_implication(first_input, second_input):
    70    return first_input or not second_input
    71    return (not not first_input) or (not second_input)
    

    the test is still green

  • I remove the other return statement

    69def converse_implication(first_input, second_input):
    70    return first_input or not second_input
    

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 NonImplication which always returns not first_input and second_input or True, only if the first input is False and the second input is True

first input

second input

return

True

True

True

True

False

True

False

True

False

False

False

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/wet

    yes

    yes

    dry

    yes

    no

    dry

    no

    yes

    wet

    no

    no

    dry


more about Exclusive Disjunction


Exclusive Disjunction can also be thought of as

return (
    converse_non_implication(first_input, second_input)
    or
    material_non_implication(first_input, second_input)
)

because

return (not first_input and second_input) or (first_input and not second_input) can be thought of as the logical_disjunction of converse_non_implication and material_non_implication

logical_disjunction(
    converse_non_implication(first_input, second_input),
    material_non_implication(first_input, second_input)
)

This means that in the 4 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


close the project

  • I close test_binary.py and truth_table.py in the editor

  • I click in the terminal, then 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_table

    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory


review

Binary Operations take 2 inputs, each input can be True or False, if I name the first input first_input and the second one second_input, the tests show that

  • Converse Implication

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

    False

    True

    False

    False

    False

    True

  • Project First

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

    False

    True

    False

    False

    False

    False

  • Material NonImplication

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

    False

    True

    False

    False

    False

    False

  • Exclusive Disjunction

    • returns first_input != second_input

    • returns True only if first_input and second_input are NOT equal

    • is the opposite (Logical Negation) of Logical Equality which returns True only if first_input and second_input are equal

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

    False

    True

    True

    False

    False

    False

  • Logical Disjunction

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

    False

    True

    True

    False

    False

    False

  • Tautology

    first input

    second input

    return

    True

    True

    True

    True

    False

    True

    False

    True

    True

    False

    False

    True

  • Logical NAND

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

    False

    True

    True

    False

    False

    True

  • Negate First

    first input

    second input

    return

    True

    True

    False

    True

    False

    False

    False

    True

    True

    False

    False

    True

  • Converse NonImplication

    • returns not first_input and second_input

    • returns True only if first_input is False and second_input is True

    • is the opposite (Logical Negation) of Converse Implication which returns False if first_input is False and second_input is True

    first input

    second input

    return

    True

    True

    False

    True

    False

    False

    False

    True

    True

    False

    False

    False

  • Project Second

    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_input

    • returns True only if first_input is True and second_input is True

    • is the opposite (Logical Negation) of Logical NAND which returns False only if first_input is True and second_input is True

    first input

    second input

    return

    True

    True

    True

    True

    False

    False

    False

    True

    False

    False

    False

    False

  • Contradiction

    first input

    second input

    return

    True

    True

    False

    True

    False

    False

    False

    True

    False

    False

    False

    False

and

All the logic statements or conditions have been written with some or all of the above 3.

return

True, True

True, False

False, True

False, False

name of operation

False

False

False

False

False

contradiction

first and second

True

False

False

False

logical_conjunction

second

True

False

True

False

project_second

(not first) and second

False

False

True

False

converse_non_implication

not first

False

False

True

True

negate_first

not (first and second)

False

True

True

True

logical_nand

True

True

True

True

True

tautology

first or second

True

True

True

False

logical_disjunction

(not (first and second)) and (first or second)

False

True

True

False

exclusive_disjunction

first and (not second)

False

True

False

False

material_non_implication

first

True

True

False

False

project_first

first or (not second)

True

True

False

True

converse_implication


code from the chapter

Do you want to see all the CODE I typed for the Truth Table?


what is next?

Would you like to test the last binary operations?


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