truth table: Binary Operations 4


requirements

Binary Operations 3


preview

These are the tests I have at the end of the chapter

truth_table/tests/test_binary.py
 1import src.truth_table
 2import unittest
 3
 4
 5TT = True, True
 6TF = True, False
 7FT = False, True
 8FF = False, False
 9
10
11class TestBinaryOperations(unittest.TestCase):
12
13    def test_contradiction(self):
14        contradiction = src.truth_table.contradiction
15        self.assertFalse(contradiction(*TT))
16        self.assertFalse(contradiction(*TF))
17        self.assertFalse(contradiction(*FT))
18        self.assertFalse(contradiction(*FF))
19
20    def test_logical_conjunction(self):
21        logical_conjunction = (
22            src.truth_table.logical_conjunction
23        )
24        self.assertTrue(logical_conjunction(*TT))
25        self.assertFalse(logical_conjunction(*TF))
26        self.assertFalse(logical_conjunction(*FT))
27        self.assertFalse(logical_conjunction(*FF))
truth_table/tests/test_binary.py
29    def test_project_second(self):
30        project_second = src.truth_table.project_second
31        self.assertTrue(project_second(*TT))
32        self.assertFalse(project_second(*TF))
33        self.assertTrue(project_second(*FT))
34        self.assertFalse(project_second(*FF))
35
36    def test_converse_non_implication(self):
37        converse_non_implication = (
38            src.truth_table.converse_non_implication
39        )
40        self.assertFalse(converse_non_implication(*TT))
41        self.assertFalse(converse_non_implication(*TF))
42        self.assertTrue(converse_non_implication(*FT))
43        self.assertFalse(converse_non_implication(*FF))
truth_table/tests/test_binary.py
45    def test_negate_first(self):
46        negate_first = src.truth_table.negate_first
47        self.assertFalse(negate_first(*TT))
48        self.assertFalse(negate_first(*TF))
49        self.assertTrue(negate_first(*FT))
50        self.assertTrue(negate_first(*FF))
51
52    def test_logical_nand(self):
53        nand = src.truth_table.logical_nand
54        self.assertFalse(nand(*TT))
55        self.assertTrue(nand(*TF))
56        self.assertTrue(nand(*FT))
57        self.assertTrue(nand(*FF))
truth_table/tests/test_binary.py
59    def test_tautology(self):
60        tautology = src.truth_table.tautology
61        self.assertTrue(tautology(*TT))
62        self.assertTrue(tautology(*TF))
63        self.assertTrue(tautology(*FT))
64        self.assertTrue(tautology(*FF))
65
66    def test_logical_disjunction(self):
67        logical_disjunction = (
68            src.truth_table.logical_disjunction
69        )
70        self.assertTrue(logical_disjunction(*TT))
71        self.assertTrue(logical_disjunction(*TF))
72        self.assertTrue(logical_disjunction(*FT))
73        self.assertFalse(logical_disjunction(*FF))
truth_table/tests/test_binary.py
75    def test_exclusive_disjunction(self):
76        xor = src.truth_table.exclusive_disjunction
77        self.assertFalse(xor(*TT))
78        self.assertTrue(xor(*TF))
79        self.assertTrue(xor(*FT))
80        self.assertFalse(xor(*FF))
81
82    def test_material_non_implication(self):
83        material_non_implication = (
84            src.truth_table.material_non_implication
85        )
86        self.assertFalse(material_non_implication(*TT))
87        self.assertTrue(material_non_implication(*TF))
88        self.assertFalse(material_non_implication(*FT))
89        self.assertFalse(material_non_implication(*FF))
truth_table/tests/test_binary.py
 91    def test_project_first(self):
 92        project_first = src.truth_table.project_first
 93        self.assertTrue(project_first(*TT))
 94        self.assertTrue(project_first(*TF))
 95        self.assertFalse(project_first(*FT))
 96        self.assertFalse(project_first(*FF))
 97
 98    def test_converse_implication(self):
 99        converse_implication = (
100            src.truth_table.converse_implication
101        )
102        self.assertTrue(converse_implication(*TT))
103        self.assertTrue(converse_implication(*TF))
104        self.assertFalse(converse_implication(*FT))
105        self.assertTrue(converse_implication(*FF))
truth_table/tests/test_binary.py
107    def test_negate_second(self):
108        negate_second = src.truth_table.negate_second
109        self.assertFalse(negate_second(*TT))
110        self.assertTrue(negate_second(*TF))
111        self.assertFalse(negate_second(*FT))
112        self.assertTrue(negate_second(*FF))
113
114    def test_logical_nor(self):
115        logical_nor = src.truth_table.logical_nor
116        self.assertFalse(logical_nor(*TT))
117        self.assertFalse(logical_nor(*TF))
118        self.assertFalse(logical_nor(*FT))
119        self.assertTrue(logical_nor(*FF))
truth_table/tests/test_binary.py
121    def test_logical_equality(self):
122        logical_equality = (
123            src.truth_table.logical_equality
124        )
125        self.assertTrue(logical_equality(*TT))
126        self.assertFalse(logical_equality(*TF))
127        self.assertFalse(logical_equality(*FT))
128        self.assertTrue(logical_equality(*FF))
129
130    def test_material_implication(self):
131        material_implication = (
132            src.truth_table.material_implication
133        )
134        self.assertTrue(material_implication(*TT))
135        self.assertFalse(material_implication(*TF))
136        self.assertTrue(material_implication(*FT))
137        self.assertTrue(material_implication(*FF))
138
139
140# Exceptions seen
141# AttributeError
142# TypeError
143# AssertionError
144# SyntaxError

open the project


test_negate_second

The truth table for negate_second is

first input

second input

return

True

True

False

True

False

True

False

True

False

False

False

True


RED: make it fail


I add a new test for negate_second with an assertion for if the first input is True and the second input is True, to tests/test_binary.py

first input

second input

return

True

True

False

 99        self.assertTrue(converse_implication(False, False))
100
101    def test_negate_second(self):
102        negate_second = src.truth_table.negate_second
103        self.assertFalse(negate_second(True, True))
104
105
106# Exceptions seen

the terminal is my friend, and shows AttributeError

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

I do not have a definition for negate_second in src/truth_table/__init__.py


GREEN: make it pass


  • I open __init__.py from the truth_table folder in the src folder

  • I add a function definition for negate_second to src/truth_table/__init__.py

     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_input
     98
     99
    100def negate_second(first_input, second_input):
    101    return False
    

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

    negate_second(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_negate_second in tests/test_binary.py

    first input

    second input

    return

    True

    False

    True

    101    def test_negate_second(self):
    102        negate_second = src.truth_table.negate_second
    103        self.assertFalse(negate_second(True, True))
    104        self.assertTrue(negate_second(True, False))
    105
    106
    107# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    

    because the negate_second function returns False and the assertion expects True.

  • I add an if statement to negate_second in src/truth_table/__init__.py

    100def negate_second(first_input, second_input):
    101    if second_input == False:
    102        return True
    103    return False
    

    the test passes because Python checks if second_input == False: when negate_second is called

    • if second_input is NOT equal to False, it runs return False

      negate_second(True , True ) -> False
      └── def negate_second(first_input, second_input):
          ├── first_input  = True
          ├── second_input = True
          ├── if second_input == False:
          │       return True
          └── return False
      
    • if second_input is equal to False, it runs return True

      negate_second(True , False) -> True
      └── def negate_second(first_input, second_input):
          ├── first_input  = True
          ├── second_input = False
          └── if second_input == False:
              └── return True
              return False
      
    negate_second(True , False) -> True
    negate_second(True , True ) -> False
    
  • I add an assertion for the third case, which is if the first input is False and the second input is True, to test_negate_second in tests/test_binary.py

    first input

    second input

    return

    False

    True

    False

    101    def test_negate_second(self):
    102        negate_second = src.truth_table.negate_second
    103        self.assertFalse(negate_second(True, True))
    104        self.assertTrue(negate_second(True, False))
    105        self.assertFalse(negate_second(False, True))
    106
    107
    108# Exceptions seen
    

    the test is still green. negate_second returns the logical negation of the second input in all 3 cases.

    negate_second(False, True ) -> False
    negate_second(True , False) -> True
    negate_second(True , True ) -> False
    
  • I add an assertion for the last case, which is if the first input is False and the second input is False

    first input

    second input

    return

    False

    False

    True

    101    def test_negate_second(self):
    102        negate_second = src.truth_table.negate_second
    103        self.assertFalse(negate_second(True, True))
    104        self.assertTrue(negate_second(True, False))
    105        self.assertFalse(negate_second(False, True))
    106        self.assertTrue(negate_second(False, False))
    107
    108
    109# Exceptions seen
    

    the test is still green.

    negate_second(False, False) -> True
    negate_second(False, True ) -> False
    negate_second(True , False) -> True
    negate_second(True , True ) -> False
    
  • I add the bool built-in function to the negate_second function in src/truth_table/__init__.py

    100def negate_second(first_input, second_input):
    101    # if second_input == False:
    102    if bool(second_input) == False:
    103        return True
    104    return False
    

    still green.

  • I use Logical Negation (NOT) to write the statement in terms of True

    100def negate_second(first_input, second_input):
    101    # if second_input == False:
    102    # if bool(second_input) == False:
    103    if not bool(second_input) == True:
    104        return True
    105    return False
    

    green.

  • I remove == True

    100def negate_second(first_input, second_input):
    101    # if second_input == False:
    102    # if bool(second_input) == False:
    103    # if not bool(second_input) == True:
    104    if not bool(second_input):
    105        return True
    106    return False
    

    still green.

  • I remove bool

    100def negate_second(first_input, second_input):
    101    # if second_input == False:
    102    # if bool(second_input) == False:
    103    # if not bool(second_input) == True:
    104    # if not bool(second_input):
    105    if not second_input:
    106        return True
    107    return False
    

    the test is still green, because Python checks if second_input is equal to False when if second_input == False: runs. I assume the following substitutions

    • if the value of something is False

      something = 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 value
      
    • if the value of something is True

      something = 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
      

    if bool(something) == False is the same as if not bool(something) == True is the same as if not bool(something) is the same as if not something.

  • I add a conditional expression to negate_second

    100def negate_second(first_input, second_input):
    101    return True if not second_input else False
    102    # if second_input == False:
    

    still green.

    if not second_input vs return True
        return True     vs if not second_input
    return False        vs else False
    
  • I remove True if and else False to make the statement simpler

    100def negate_second(first_input, second_input):
    101    return not second_input
    102    return True if not second_input else False
    
  • I remove the commented lines and other statements from negate_second

    100def negate_second(first_input, second_input):
    101    return not second_input
    
  • I add a git commit message in the other terminal

    git commit -am 'add negate_second'
    

Negate Second always returns

It is the Logical Negation (NOT) of Project Second which always returns the second input. It always negates the second input.


examples of Negate Second


  • returning a defective product, if the inputs are

    • do I have the original receipt?

    • does the product work?

    receipt?

    product works?

    return?

    yes

    yes

    no

    yes

    no

    yes

    no

    yes

    no

    no

    no

    yes

  • I do not pick up calls from numbers that are not in my contact list, if the inputs are

    • am I busy?

    • is the number saved in my phone?

    busy?

    number saved?

    send to voicemail?

    yes

    yes

    no

    yes

    no

    yes

    no

    yes

    no

    no

    no

    yes


test_logical_nor

The truth table for logical_nor is

first input

second input

return

True

True

False

True

False

False

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 logical_nor with an assertion for if the first input is True and the second input is True, to tests/test_binary.py

    first input

    second input

    return

    True

    True

    False

    106        self.assertTrue(negate_second(False, False))
    107
    108    def test_logical_nor(self):
    109        logical_nor = src.truth_table.logical_nor
    110        self.assertFalse(logical_nor(True, True))
    111
    112
    113# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.truth_table'
                    has no attribute 'logical_nor'.
                    Did you mean: 'logical_nand'?
    

    src/truth_table/__init__.py does not have any definition for logical_nor.


GREEN: make it pass


I add logical_nor to src/truth_table/__init__.py

100def negate_second(first_input, second_input):
101    return not second_input
102
103
104def logical_nor(first_input, second_input):
105    return False

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

logical_nor(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_logical_nor in tests/test_binary.py

    first input

    second input

    return

    True

    False

    False

    100    def test_logical_nor(self):
    101        logical_nor = src.truth_table.logical_nor
    102        self.assertFalse(logical_nor(True, True))
    103        self.assertFalse(logical_nor(True, False))
    104
    105
    106# Exceptions seen
    

    the test is still green. logical_nor returns

    • False, 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

    • False, if the first input is True

    logical_nor(True , False) -> False
    logical_nor(True , True ) -> False
    
  • I add an assertion for 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

    100    def test_logical_nor(self):
    101        logical_nor = src.truth_table.logical_nor
    102        self.assertFalse(logical_nor(True, True))
    103        self.assertFalse(logical_nor(True, False))
    104        self.assertFalse(logical_nor(False, True))
    105
    106
    107# Exceptions seen
    

    the test is still green. logical_nor returns

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

    • False, if the first input is True

    logical_nor(False, True ) -> False
    logical_nor(True , False) -> False
    logical_nor(True , True ) -> False
    
  • I add an assertion for the last case, which is if the first input is False and the second input is False

    first input

    second input

    return

    False

    False

    True

    100    def test_logical_nor(self):
    101        logical_nor = src.truth_table.logical_nor
    102        self.assertFalse(logical_nor(True, True))
    103        self.assertFalse(logical_nor(True, False))
    104        self.assertFalse(logical_nor(False, True))
    105        self.assertTrue(logical_nor(False, False))
    106
    107
    108# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    

    because the logical_nor function returns False and the assertion expects True.

  • I add if statements for this case to logical_nor in src/truth_table/__init__.py

    104def logical_nor(first_input, second_input):
    105    if first_input == False:
    106        if second_input == False:
    107            return True
    108    return False
    

    the test passes.

    logical_nor(False, False) -> True
    logical_nor(False, True ) -> False
    logical_nor(True , False) -> False
    logical_nor(True , True ) -> False
    

    because Python checks if first_input is equal to False when the logical_nor function is called. When if first_input == False: runs,

    • if first_input is NOT equal to False, it leaves the if statement to run the rest of the function - return False

      logical_nor(True , True ) -> False
      └── def logical_nor(first_input, second_input):
          ├── first_input  = True
          ├── second_input = True
          ├── if first_input == False:
          │       if second_input == False:
          │           return True
          └── return False
      
      logical_nor(True , False) -> False
      └── def logical_nor(first_input, second_input):
          ├── first_input  = True
          ├── second_input = False
          ├── if first_input == False:
          │       if second_input == False:
          │           return True
          └── return False
      
    • if first_input is equal to False, it checks if second_input is equal to False

      • if second_input is NOT equal to False, it leaves if first_input == False: then runs return False

        logical_nor(False, True ) -> False
        └── def logical_nor(first_input, second_input):
            ├── first_input  = False
            ├── second_input = True
            ├── if first_input == False:
            │       if second_input == False:
            │           return True
            └── return False
        
      • if second_input is equal to False, it runs return True

        logical_nor(False, False) -> True
        └── def logical_nor(first_input, second_input):
            ├── first_input  = False
            ├── second_input = False
            └── if first_input == False:
                └── if second_input == False:
                    └── return True
                return False
        
    • it only checks second_input if first_input is equal to False.

  • I add the bool built-in function

    104def logical_nor(first_input, second_input):
    105    # if first_input == False:
    106    if bool(first_input) == False:
    107        # if second_input == False:
    108        if bool(second_input) == False:
    109            return True
    110    return False
    

    the test is still green.

  • I use Logical Negation (NOT) to write the if statements in terms of True

    104def logical_nor(first_input, second_input):
    105    # if first_input == False:
    106    # if bool(first_input) == False:
    107    if not bool(first_input) == True:
    108        # if second_input == False:
    109        # if bool(second_input) == False:
    110        if not bool(second_input) == True:
    111            return True
    112    return False
    

    still green.

  • I remove == True

    104def logical_nor(first_input, second_input):
    105    # if first_input == False:
    106    # if bool(first_input) == False:
    107    # if not bool(first_input) == True:
    108    if not bool(first_input):
    109        # if second_input == False:
    110        # if bool(second_input) == False:
    111        # if not bool(second_input) == True:
    112        if not bool(second_input):
    113            return True
    114    return False
    

    green.

  • I remove bool

    104def logical_nor(first_input, second_input):
    105    # if first_input == False:
    106    # if bool(first_input) == False:
    107    # if not bool(first_input) == True:
    108    # if not bool(first_input):
    109    if not first_input:
    110        # if second_input == False:
    111        # if bool(second_input) == False:
    112        # if not bool(second_input) == True:
    113        # if not bool(second_input):
    114        if not second_input:
    115            return True
    116    return False
    

    still green, because I can assume the following substitutions for when if something == False: runs

    • if the value of something is False

      something = 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 value
      
    • if the value of something is True

      something = 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
      

    if bool(something) == False is the same as if not bool(something) == True is the same as if not bool(something) is the same as if not something.

  • I use Logical Conjunction (AND) to put the two if statements together

    104def logical_nor(first_input, second_input):
    105    # if first_input == False:
    106    # if bool(first_input) == False:
    107    # if not bool(first_input) == True:
    108    # if not bool(first_input):
    109    # if not first_input:
    110        # if second_input == False:
    111        # if bool(second_input) == False:
    112        # if not bool(second_input) == True:
    113        # if not bool(second_input):
    114        # if not second_input:
    115    if not first_input and not second_input:
    116            return True
    117    return False
    

    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 to logical_nor

    104def logical_nor(first_input, second_input):
    105    return (
    106        True if
    107        not first_input and not second_input
    108        else False
    109    )
    110    # if first_input == False:
    

    the test is still green.

  • I remove True if and else False

    104def logical_nor(first_input, second_input):
    105    return (
    106        # True if
    107        not first_input and not second_input
    108        # else False
    109    )
    

    still green.

  • I write the statement in terms of not because it happens 2 times

    104def logical_nor(first_input, second_input):
    105    return (
    106        # True if
    107        # not first_input and not second_input
    108        (not first_input)
    109        (not or)
    110        (not second_input)
    111        # else False
    112    )
    

    the terminal is my friend, and shows SyntaxError

    SyntaxError: invalid syntax
    

    because I cannot negate or this way.

  • I “factor” out the nots

    105    return (
    106        # True if
    107        # not first_input and not second_input
    108        # (not first_input)
    109        # (not or)
    110        # (not second_input)
    111        not (first_input or second_input)
    112        # else False
    113    )
    

    the test is green again.

  • logical_nor returns not (first_input or second_input) which is the Logical Negation (NOT) of the Logical Disjunction (OR) of the first input and the second input

    logical_negation(
        logical_disjunction(
            first_input, second_input
        )
    )
    

    this means that in the four cases

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

      not (first_input or second_input)
      not (True        or True        )
      not (True                       )
      False # not logical_disjunction(True, True)
      
    • if the first input is True and the second input is False, logical_nor returns

      not (first_input or second_input)
      not (True        or False       )
      not (True                       )
      False # not logical_disjunction(True, False)
      
    • if the first input is False and the second input is True, logical_nor returns

      not (first_input or second_input)
      not (False       or True        )
      not (True                       )
      False # not logical_disjunction(False, True)
      
    • if the first input is False and the second input is False, logical_nor returns

      not (first_input or second_input)
      not (False       or False       )
      not (False                      )
      True  # not logical_disjunction(False, False)
      

    first

    second

    first or second

    not (first or second)

    True

    True

    True

    False

    True

    False

    True

    False

    False

    True

    True

    False

    False

    False

    False

    True

    I add a return statement to show this

    104def logical_nor(first_input, second_input):
    105    return logical_negation(
    106        logical_disjunction(
    107            first_input, second_input
    108        )
    109    )
    110    return (
    111        # True if
    112        # not first_input and not second_input
    113        # (not first_input)
    114        # (not or)
    115        # (not second_input)
    116        not (first_input or second_input)
    117        # else False
    118    )
    

    still green.

    logical_nor(False, False) -> True
    └── not logical_disjunction(False, False) -> True
    
    logical_nor(False, True ) -> False
    └── not logical_disjunction(False, True ) -> False
    
    logical_nor(True , False) -> False
    └── not logical_disjunction(True , False) -> False
    
    logical_nor(True , True ) -> False
    └── not logical_disjunction(True , True ) -> False
    
  • I remove the commented lines and other statements from logical_nor

    104def logical_nor(first_input, second_input):
    105    return logical_negation(
    106        logical_disjunction(
    107            first_input, second_input
    108        )
    109    )
    110    return not (first_input or second_input)
    
  • I add a git commit message in the other terminal

    git commit -am 'add logical_nor'
    

    I 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.

Logical NOR returns

  • not (first_input or second_input).

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

  • the Logical Negation of the Logical Disjunction (OR) of the first input and second input.

  • not or of the first input and second input.

  • the not of the or.


examples of Logical Nor


  • fitness discipline, if the inputs are

    • did I eat cake?

    • did I skip the workout?

    eat cake

    skip workout

    disciplined

    yes

    yes

    no

    yes

    no

    no

    no

    yes

    no

    no

    no

    yes

  • a late fee, if the inputs are

    • did I make the payment?

    • am I within the grace period?

    made payment

    grace period

    late fee charged

    yes

    yes

    no

    yes

    no

    no

    no

    yes

    no

    no

    no

    yes


test_logical_equality

The truth table for logical_equality is

first input

second input

return

True

True

True

True

False

False

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 Logical Equality with an assertion for if the first input is True and the second input is True to tests/test_binary.py

    first input

    second input

    return

    True

    True

    True

    113        self.assertTrue(logical_nor(False, False))
    114
    115    def test_logical_equality(self):
    116        logical_equality = (
    117            src.truth_table.logical_equality
    118        )
    119        self.assertTrue(logical_equality(True, True))
    120
    121
    122# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.truth_table'
                    has no attribute 'logical_equality'.
                    Did you mean: 'logical_identity'?
    

    because there is no definition for logical_equality in src/truth_table/__init__.py.


GREEN: make it pass


I add a function definition for logical_equality in src/truth_table/__init__.py

104def logical_nor(first_input, second_input):
105    return logical_negation(
106        logical_disjunction(
107            first_input, second_input
108        )
109    )
110    return not (first_input or second_input)
111
112
113def logical_equality(first_input, second_input):
114    return True

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

logical_equality(True , True ) -> True

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_logical_equality in tests/test_binary.py

    first input

    second input

    return

    True

    False

    False

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

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    

    because the logical_equality function returns True and the assertion expects False.

  • I add an if statement to logical_equality in src/truth_table/__init__.py

    113def logical_equality(first_input, second_input):
    114    if second_input == False:
    115        return False
    116    return True
    

    the test passes because when logical_equality is called, it runs if second_input == False:

    • if second_input is NOT equal to False, it leaves the if statement then runs return True.

    • if second_input is equal to False, it runs return False.

    logical_equality(True , False) -> False
    logical_equality(True , True ) -> True
    
  • I add an assertion for the next case, which is if the first input is False and the second input is True, to test_logical_equality in tests/test_binary.py

    first input

    second input

    return

    False

    True

    False

    115    def test_logical_equality(self):
    116        logical_equality = (
    117            src.truth_table.logical_equality
    118        )
    119        self.assertTrue(logical_equality(True, True))
    120        self.assertFalse(logical_equality(True, False))
    121        self.assertFalse(logical_equality(False, True))
    122
    123
    124# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    

    because when logical_equality is called, Python runs if second_input == False:

    • if second_input is equal to False, it runs return False

    • if second_input is NOT equal to False, it leaves the if statement then runs return True.

    • second_input is True in this case, which raises AssertionError since the assertion expects False and the function returns True.

  • I add another if statement to the logical_equality function in src/truth_table/__init__.py

    113def logical_equality(first_input, second_input):
    114    if first_input == False:
    115        return False
    116    if second_input == False:
    117        return False
    118    return True
    

    the test passes because when logical_equality is called, Python runs if first_input == False:

    logical_equality(False, True ) -> False
    logical_equality(True , False) -> False
    logical_equality(True , True ) -> 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_logical_equality in tests/test_binary.py

    first input

    second input

    return

    False

    False

    True

    115    def test_logical_equality(self):
    116        logical_equality = (
    117            src.truth_table.logical_equality
    118        )
    119        self.assertTrue(logical_equality(True, True))
    120        self.assertFalse(logical_equality(True, False))
    121        self.assertFalse(logical_equality(False, True))
    122        self.assertTrue(logical_equality(False, False))
    123
    124
    125# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    

    because when logical_equality is called, Python runs if first_input == False:

    • if first_input is equal to False, it runs return False.

    • if first_input is NOT equal to False, it runs the next if statement - if second_input == False:.

      • if second_input is NOT equal to False, it leaves the if statement then runs return True.

      • if second_input is equal to False, it runs return False.

      • second_input is False in this case, which raises AssertionError since the assertion expects True and the function returns False.

  • I add an if statement to the logical_equality function in src/truth_table/__init__.py

    113def logical_equality(first_input, second_input):
    114    if first_input == False:
    115        if second_input == False:
    116            return True
    117        return False
    118    if second_input == False:
    119        return False
    120    return True
    

    the test passes.

    logical_equality(False, False) -> True
    logical_equality(False, True ) -> False
    logical_equality(True , False) -> False
    logical_equality(True , True ) -> True
    

    Python checks if first_input == False: when logical_equality is called

    • if first_input is NOT equal to False, it runs the next if statement - if second_input == False:

      • if second_input is NOT equal to False, it leaves the if statement then runs return True

        logical_equality(True , True ) -> True
        └── def logical_equality(first_input, second_input):
            ├── first_input  = True
            ├── second_input = True
            ├── if first_input == False:
            │       if second_input == False:
            │           return True
            │       return False
            ├── if second_input == False:
            │       return False
            └── return True
        
      • if second_input is equal to False, it runs return False

        logical_equality(True , False) -> False
        └── def logical_equality(first_input, second_input):
            ├── first_input  = True
            ├── second_input = False
            ├── if first_input == False:
            │       if second_input == False:
            │           return True
            │       return False
            └── if second_input == False:
                └── return False
                return True
        
    • if first_input is equal to False, it runs if second_input == False:

      • if second_input is NOT equal to False, it leaves the if statement then runs the next line - return False

        logical_equality(False, True ) -> False
        └── def logical_equality(first_input, second_input):
            ├── first_input  = False
            ├── second_input = True
            └── if first_input == False:
                ├── if second_input == False:
                │       return True
                └── return False
                if second_input == False:
                    return False
                return True
        
      • if second_input is equal to False, it runs return True

        logical_equality(False, False) -> True
        └── def logical_equality(first_input, second_input):
            ├── first_input  = False
            ├── second_input = False
            └── if first_input == False:
                └── if second_input == False:
                    └── return True
                    return False
                if second_input == False:
                    return False
                return True
        
  • I add the bool built-in function

    113def logical_equality(first_input, second_input):
    114    # if first_input == False:
    115    if bool(first_input) == False:
    116        # if second_input == False:
    117        if bool(second_input) == False:
    118            return True
    119        return False
    120    # if second_input == False:
    121    if bool(second_input) == False:
    122        return False
    123    return True
    

    the test is still green.

  • I use Logical Negation (NOT) to write the statements in terms of True

    113def logical_equality(first_input, second_input):
    114    # if first_input == False:
    115    # if bool(first_input) == False:
    116    if not bool(first_input) == True:
    117        # if second_input == False:
    118        # if bool(second_input) == False:
    119        if not bool(second_input) == True:
    120            return True
    121        return False
    122    # if second_input == False:
    123    # if bool(second_input) == False:
    124    if not bool(second_input) == True:
    125        return False
    126    return
    

    still green.

  • I remove == True

    113def logical_equality(first_input, second_input):
    114    # if first_input == False:
    115    # if bool(first_input) == False:
    116    # if not bool(first_input) == True:
    117    if not bool(first_input):
    118        # if second_input == False:
    119        # if bool(second_input) == False:
    120        # if not bool(second_input) == True:
    121        if not bool(second_input):
    122            return True
    123        return False
    124    # if second_input == False:
    125    # if bool(second_input) == False:
    126    # if not bool(second_input) == True:
    127    if not bool(second_input):
    128        return False
    129    return True
    

    green.

  • I remove bool

    113def logical_equality(first_input, second_input):
    114    # if first_input == False:
    115    # if bool(first_input) == False:
    116    # if not bool(first_input) == True:
    117    # if not bool(first_input):
    118    if not first_input:
    119        # if second_input == False:
    120        # if bool(second_input) == False:
    121        # if not bool(second_input) == True:
    122        # if not bool(second_input):
    123        if not second_input:
    124            return True
    125        return False
    126    # if second_input == False:
    127    # if bool(second_input) == False:
    128    # if not bool(second_input) == True:
    129    # if not bool(second_input):
    130    if not second_input:
    131        return False
    132    return True
    

    still green because I can assume the following substitutions for when if something == False: runs

    • if the value of something is False

      something = 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 value
      
    • if the value of something is True

      something = 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
      

    if bool(something) == False is the same as if not bool(something) == True is the same as if not bool(something) is the same as if not something.

  • I use Logical Conjunction (AND) to make two of the cases clearer

    113def logical_equality(first_input, second_input):
    114    # if first_input == False:
    115    # if bool(first_input) == False:
    116    # if not bool(first_input) == True:
    117    # if not bool(first_input):
    118    # if not first_input:
    119        # if second_input == False:
    120        # if bool(second_input) == False:
    121        # if not bool(second_input) == True:
    122        # if not bool(second_input):
    123        # if not second_input:
    124        #     return True
    125        # return False
    126    # if second_input == False:
    127    # if bool(second_input) == False:
    128    # if not bool(second_input) == True:
    129    # if not bool(second_input):
    130    # if not second_input:
    131    if not first_input and not second_input:
    132        return True
    133    if not first_input and second_input:
    134        return False
    135    if not second_input:
    136        return False
    137    return True
    

    the 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 do the same thing for the other two cases

    130    # if not second_input:
    131    if not first_input and not second_input:
    132        return True
    133    if not first_input and second_input:
    134        return False
    135    # if not second_input:
    136    if first_input and not second_input:
    137        return False
    138    if first_input and second_input:
    139        return True
    

    still green.

  • I put the if statements that return the same thing together

    130    # if not second_input:
    131    if not first_input and second_input:
    132        return False
    133    # if not second_input:
    134    if first_input and not second_input:
    135        return False
    136    if first_input and second_input
    137        return True
    138    if not first_input and not second_input:
    139        return True
    
  • I use Logical Disjunction (OR) to put the two if statements that return True together, then use an else clause for when logical_equality returns False

    130    # if not second_input:
    131    # if not first_input and second_input:
    132    #     return False
    133    # if not second_input:
    134    # if first_input and not second_input:
    135    #     return False
    136    # if first_input and second_input:
    137    #     return True
    138    # if not first_input and not second_input:
    139    #     return True
    140    if (
    141        (first_input and second_input)
    142        or
    143        (not first_input and not second_input)
    144    ):
    145        return True
    146    else:
    147        return False
    

    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 this
    

    can also be written as

    if something or something_else:
        return this
    
  • I add a conditional expression to logical_equality

    113def logical_equality(first_input, second_input):
    114    return (
    115        True if
    116        (first_input and second_input)
    117        or
    118        (not first_input and not second_input)
    119        else False
    120    )
    121    # if first_input == False:
    

    still green.

  • I remove True if and else False

    113def logical_equality(first_input, second_input):
    114    return (
    115        # True if
    116        (first_input and second_input)
    117        or
    118        (not first_input and not second_input)
    119        # else False
    120    )
    

    the test is still green.

  • I write the second part of the statement in terms of not because it happens twice

    113def logical_equality(first_input, second_input):
    114    return (
    115        # True if
    116        (first_input and second_input)
    117        or
    118        # (not first_input and not second_input)
    119        (
    120            (not first_input)
    121            (not or)
    122            (not second_input)
    123        )
    124        # else False
    125    )
    

    the terminal is my friend, and shows SyntaxError

    SyntaxError: invalid syntax
    

    because I cannot negate or this way.

  • I “factor” out the nots

    113def logical_equality(first_input, second_input):
    114    return (
    115        # True if
    116        (first_input and second_input)
    117        or
    118        # (not first_input and not second_input)
    119        # (
    120        #     (not first_input)
    121        #     (not or)
    122        #     (not second_input)
    123        # )
    124        not (first_input or second_input)
    125        # else False
    126    )
    

    the test is green again.

  • Logical Equality returns ((first_input and second_input) or not (first_input or second_input)), which can be thought of as the Logical Disjunction (OR), of the Logical Conjunction (AND) of the first input and second input, and the Logical Negation (NOT) of the Logical Disjunction (OR) of the first input and second input also known as the Logical NOR of the first input and second input

    return logical_disjunction(
        logical_conjunction(first_input, second_input),
        logical_nor(first_input, second_input)
    )
    

    because

    logical_disjunction(first_input, second_input)
    
            first_input == (first_input and second_input)
    logical_conjunction == (first_input and second_input)
    
           second_input == not (first_input or second_input)
            logical_nor == not (first_input or second_input)
    

    or

    return logical_disjunction(
        logical_conjunction(first_input, second_input),
        logical_negation(
            logical_disjunction(first_input, second_input)
        )
    )
    

    This means that in the four cases

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

      (first and second) or (not (first or second))
      (True  and True  ) or (not (True  or True  ))
       True              or (not  True            )
       True              or  False
       True              # logical_disjunction(True, False)
      
    • if the first input is True and the second input is False, logical_equality returns

      (first and second) or (not (first or second))
      (True  and False ) or (not (True  or False ))
       False             or (not  True            )
       False             or  False
       False             # logical_disjunction(False, False)
      
    • if the first input is False and the second input is True, logical_equality returns

      (first and second) or (not (first or second))
      (False and True  ) or (not (False or True  ))
       False             or (not  True            )
       False             or  False
       False             # logical_disjunction(False, False)
      
    • if the first input is False and the second input is False, logical_equality returns

      (first and second) or (not (first or second))
      (False and False ) or (not (False or False ))
       False             or (not  False           )
       False             or  True
       True              # logical_disjunction(False, True)
      

    first

    second

    first and second

    first or second

    not (first or second)

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

    True

    True

    True

    False

    True

    True

    True

    False

    False

    True

    True

    False

    False

    True

    False

    False

    False

    False

    False

    False

    False

    True

    True

    True

    I add a return statement to show this

    113def logical_equality(first_input, second_input):
    114    return logical_disjunction(
    115        logical_conjunction(first_input, second_input),
    116        logical_nor(first_input, second_input)
    117    )
    118    return (
    119        # True if
    120        (first_input and second_input)
    121        or
    122        # (not first_input and not second_input)
    123        # (
    124        #     (not first_input)
    125        #     (not or)
    126        #     (not second_input)
    127        # )
    128        not (first_input or second_input)
    129        # else False
    130    )
    

    still green.

  • logical_equality returns True, if the first input and second input are equal, which means I can write a much simpler return statement thanks to the equality (==) symbol (two equal signs together =+= on the keyboard)

    113def logical_equality(first_input, second_input):
    114    return first_input == second_input
    115    return logical_disjunction(
    116        logical_conjunction(first_input, second_input),
    117        logical_nor(first_input, second_input)
    118    )
    

    the test is still green.

  • I remove the commented lines and other statements from logical_equality

    113def logical_equality(first_input, second_input):
    114    return first_input == second_input
    115    return logical_disjunction(
    116        logical_conjunction(first_input, second_input),
    117        logical_nor(first_input, second_input)
    118    )
    119    return (
    120        (first_input and second_input)
    121        or
    122        not (first_input or second_input)
    123    )
    

    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 logical_equality'
    

Logical Equality


examples of Logical Equality


  • my expectation matches reality, if the inputs are

    • reality

    • expectation

    reality

    my expectation

    expectation matches reality

    yes

    yes

    yes

    yes

    no

    no

    no

    yes

    no

    no

    no

    yes

  • a market is balanced, if the inputs are

    • supply

    • demand

    supply

    demand

    balance

    high

    high

    yes

    high

    low

    no

    low

    high

    no

    low

    low

    yes

  • we are in agreement, if the inputs are

    • what did I say?

    • what did you say?

    I said

    You said

    agreement

    yes

    yes

    yes

    yes

    no

    no

    no

    yes

    no

    no

    no

    yes


test_material_implication

The truth table for material_implication is

first input

second input

return

True

True

True

True

False

False

False

True

True

False

False

True


RED: make it fail


  • I go back to the terminal where the tests are running

  • I add a test for material_implication with an assertion for if the first input is True and the second input is True, to tests/test_binary.py

    first input

    second input

    return

    True

    True

    True

    122        self.assertTrue(logical_equality(False, False))
    123
    124    def test_material_implication(self):
    125        material_implication = (
    126            src.truth_table.material_implication
    127        )
    128        self.assertTrue(material_implication(True, True))
    129
    130
    131# Exceptions seen
    

    the terminal is my friend, and shows AttributeError

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

    because there is no definition for material_implication in src/truth_table/__init__.py.


GREEN: make it pass


I add a function for material_implication to src/truth_table/__init__.py

122    return (
123        (first_input and second_input)
124        or
125        not (first_input or second_input)
126    )
127
128
129def material_implication(first_input, second_input):
130    return True

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

material_implication(True , True ) -> True

REFACTOR: make it better


  • I add an assertion to test_material_implication for the next case, which is if the first input is True and the second input is False, in tests/test_binary.py

    first input

    second input

    return

    True

    False

    False

    124    def test_material_implication(self):
    125        material_implication = (
    126            src.truth_table.material_implication
    127        )
    128        self.assertTrue(material_implication(True, True))
    129        self.assertFalse(material_implication(True, False))
    130
    131
    132# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: True is not false
    

    because the function returns True and the assertion expects False.

  • I add an if statement to material_implication in src/truth_table/__init__.py

    126def material_implication(first_input, second_input):
    127    if second_input == False:
    128        return False
    129    return True
    

    the test passes because when material_implication is called, it runs if second_input == False:

    • if second_input is NOT equal to False, it runs return True

    • if second_input is equal to False, it runs return False

    material_implication(True , False) -> False
    material_implication(True , True ) -> True
    
  • I add an assertion to test_material_implication for the next case, which is if the first input is False and the second input is True in tests/test_binary.py

    first input

    second input

    return

    False

    True

    True

    124    def test_material_implication(self):
    125        material_implication = (
    126            src.truth_table.material_implication
    127        )
    128        self.assertTrue(material_implication(True, True))
    129        self.assertFalse(material_implication(True, False))
    130        self.assertTrue(material_implication(False, True))
    131
    132
    133# Exceptions seen
    

    the test is still green. material_implication returns

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

    • False, 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.

    • the second input in these three cases.

    material_implication(False, True ) -> True
    material_implication(True , False) -> False
    material_implication(True , True ) -> True
    
  • I 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

    True

    124    def test_material_implication(self):
    125        material_implication = (
    126            src.truth_table.material_implication
    127        )
    128        self.assertTrue(material_implication(True, True))
    129        self.assertFalse(material_implication(True, False))
    130        self.assertTrue(material_implication(False, True))
    131        self.assertTrue(material_implication(False, False))
    132
    133
    134# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: False is not true
    

    because when material_implication gets called, it runs if second_input == False:

    • if second_input is NOT equal to False, it runs return True.

    • if second_input is equal to False, it runs return False.

    • second_input is False in this case, which causes AssertionError since the assertion expects True and the function returns False.

  • I add an if statement to the material_implication function for the one case where it returns False, in src/truth_table/__init__.py

    126def material_implication(first_input, second_input):
    127    if first_input == True:
    128        if second_input == False:
    129            return False
    130    return True
    

    the test passes.

    material_implication(False, False) -> True
    material_implication(False, True ) -> True
    material_implication(True , False) -> False
    material_implication(True , True ) -> True
    

    Python checks if first_input == True: when material_implication is called

    • if first_input is NOT equal to True, it leaves the if statement to run the rest of the function - return True

      material_implication(False, False) -> True
      └── def material_implication(first_input, second_input):
          ├── first_input  = False
          ├── second_input = False
          ├── if first_input == True:
          │       if second_input == False:
          │           return False
          └── return True
      
      material_implication(False, True ) -> True
      └── def material_implication(first_input, second_input):
          ├── first_input  = False
          ├── second_input = True
          ├── if first_input == True:
          │       if second_input == False:
          │           return False
          └── return True
      
    • if first_input is equal to True, it checks if second_input is equal to False

      • if second_input is NOT equal to False, it leaves if first_input == True: to run the rest of the function - return True

        material_implication(True , True ) -> True
        └── def material_implication(first_input, second_input):
            ├── first_input  = True
            ├── second_input = True
            └── if first_input == True:
            ┌───┴── if second_input == False:
            │           return False
            └── return True
        
      • if second_input is equal to False it runs return False

        material_implication(True , False) -> False
        └── def material_implication(first_input, second_input):
            ├── first_input  = True
            ├── second_input = False
            └── if first_input == True:
                └── if second_input == False:
                    └── return False
                return True
        
    • it only checks the second input if the first input is True.

  • I use the bool built-in function

    126def material_implication(first_input, second_input):
    127    # if first_input == True:
    128    if bool(first_input) == True:
    129        # if second_input == False:
    130        if bool(second_input) == False:
    131            return False
    132    return True
    

    the test is still green.

  • I use Logical Negation (NOT) to write the second if statement in terms of True

    126def material_implication(first_input, second_input):
    127    # if first_input == True:
    128    if bool(first_input) == True:
    129        # if second_input == False:
    130        # if bool(second_input) == False:
    131        if not bool(second_input) == True:
    132            return False
    133    return True
    

    still green.

  • I remove == True

    126def material_implication(first_input, second_input):
    127    # if first_input == True:
    128    # if bool(first_input) == True:
    129    if bool(first_input):
    130        # if second_input == False:
    131        # if bool(second_input) == False:
    132        # if not bool(second_input) == True:
    133        if not bool(second_input):
    134            return False
    135    return True
    

    green.

  • I remove bool

    126def material_implication(first_input, second_input):
    127    # if first_input == True:
    128    # if bool(first_input) == True:
    129    # if bool(first_input):
    130    if first_input:
    131        # if second_input == False:
    132        # if bool(second_input) == False:
    133        # if not bool(second_input) == True:
    134        # if not bool(second_input):
    135        if not second_input:
    136            return False
    137    return True
    

    still green, because

    • when if something == False: runs, Python checks if something is equal to False. I can assume the following substitutions

      • if the value of something is False

        something = 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 value
        
      • if the value of something is True

        something = 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
        
    • when if something == True: runs, Python checks if (something) is equal to True. I can assume the following substitutions

      • if the value of something is False

        something = 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 value
        
      • if the value of something is True

        something = 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) == False is the same as if not bool(something) == True is the same as if not bool(something) is the same as if not something.

    • if bool(something) == True is the same as if bool(something) is the same as if something.

  • I use Logical Conjunction (AND) to put the two if statements together

    126def material_implication(first_input, second_input):
    127    # if first_input == True:
    128    # if bool(first_input) == True:
    129    # if bool(first_input):
    130    # if first_input:
    131        # if second_input == False:
    132        # if bool(second_input) == False:
    133        # if not bool(second_input) == True:
    134        # if not bool(second_input):
    135        # if not second_input:
    136    if first_input and not second_input:
    137            return False
    138    return True
    

    the 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

    136    if first_input and not second_input:
    137        return False
    138    else:
    139        return True
    

    still green.

  • I change the else clause to the Logical Negation (NOT) of the if statement

    136    if first_input and not second_input:
    137        return False
    138    # else:
    139    if not (first_input and not second_input):
    140        return True
    

    green.

  • I add a conditional expression to material_implication

    126def material_implication(first_input, second_input):
    127    return (
    128        True if
    129        not (first_input and not second_input)
    130        else False
    131    )
    132    # if first_input == True:
    

    still green.

  • I remove True if and else False to make it simpler

    126def material_implication(first_input, second_input):
    127    return (
    128        # True if
    129        not (first_input and not second_input)
    130        # else False
    131    )
    

    the test is still green.

  • I “multiply” not by the symbols in parentheses

    126def material_implication(first_input, second_input):
    127    return (
    128        # True if
    129        # not (first_input and not second_input)
    130        (not first_input)
    131        (not and)
    132        (not not second_input)
    133        # else False
    134    )
    

    the terminal is my friend, and shows SyntaxError

    SyntaxError: invalid syntax
    

    because I cannot negate and this way.

  • I change not and to or

    126def material_implication(first_input, second_input):
    127    return (
    128        # True if
    129        # not (first_input and not second_input)
    130        (not first_input)
    131        # (not and)
    132        or
    133        (not not second_input)
    134        # else False
    135    )
    

    the test is green again.

  • I remove not not because they cancel out

    126def material_implication(first_input, second_input):
    127    return (
    128        # True if
    129        # not (first_input and not second_input)
    130        (not first_input)
    131        # (not and)
    132        or
    133        # (not not second_input)
    134        second_input
    135        # else False
    136    )
    

    is the test still green because two nots make a “right”?

  • material_implication returns not first_input or second_input

    • not first_input is the Logical Negation (NOT) of first_input

      • if 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

    • not first_input or second_input is the Logical Disjunction (OR) of the Logical Negation (NOT) of the first input, and the second input

      logical_disjunction(
          logical_negation(first_input),
          second_input
      )
      

    this means that in the four cases

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

      not first_input or second_input
      not True        or True
      False           or True
      True            # logical_disjunction(False, True)
      
    • if the first input is True and the second input is False, material_implication returns

      not first_input or second_input
      not True        or False
      False           or False
      False           # logical_disjunction(False, False)
      
    • if the first input is False and the second input is True, material_implication returns

      not first_input or second_input
      not False       or True
      True            or True
      True            # logical_disjunction(True, True)
      
    • if the first input is False and the second input is False, material_implication returns

      not first_input or second_input
      not False       or False
      True            or False
      True            # logical_disjunction(True, False)
      

    first

    not first

    second

    (not first or second)

    True

    False

    True

    True

    True

    False

    False

    False

    False

    True

    True

    True

    False

    True

    False

    True

    I add a return statement to show this

    126def material_implication(first_input, second_input):
    127    return logical_disjunction(
    128        logical_negation(first_input),
    129        second_input
    130    )
    131    return (
    132        # True if
    133        # not (first_input and not second_input)
    134        (not first_input)
    135        # (not and)
    136        or
    137        # (not not second_input)
    138        second_input
    139        # else False
    140    )
    

    still green.

    material_implication(False, False) -> True
    └── logical_disjunction(True , False) -> True
    
    material_implication(False, True ) -> True
    └── logical_disjunction(True , True ) -> True
    
    material_implication(True , False) -> False
    └── logical_disjunction(False, False) -> False
    
    material_implication(True , True ) -> True
    └── logical_disjunction(False, True ) -> True
    
  • I remove the commented lines and other statements from material_implication

    126def material_implication(first_input, second_input):
    127    return logical_disjunction(
    128        logical_negation(first_input),
    129        second_input
    130    )
    131    return not first_input or second_input
    

    I 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_implication'
    

Material Implication also known as Logical Implication returns

It is the Logical Negation (NOT) of Material Non-Implication which returns True only if the first input is True and the second input is False.


examples of Material Implication


  • does the fire alarm work, if the inputs are

    • is there a fire?

    • is the alarm ringing?

    fire?

    alarm?

    alarm works

    yes

    yes

    yes

    yes

    no

    no

    no

    yes

    yes (false positive)

    no

    no

    yes


extract global variables for truth table cases

  • I go back to the terminal where the tests are running

  • I add variables for the four test cases that are repeated in every test, in tests/test_binary.py

     1import src.truth_table
     2import unittest
     3
     4
     5TT = True, True
     6TF = True, False
     7FT = False, True
     8FF = False, False
     9
    10
    11class TestBinaryOperations(unittest.TestCase):
    12
    13    def test_contradiction(self):
    
  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_contradiction

    13    def test_contradiction(self):
    14        contradiction = src.truth_table.contradiction
    15        # self.assertFalse(contradiction(True, True))
    16        self.assertFalse(contradiction(*TT))
    17        # self.assertFalse(contradiction(True, True))
    18        self.assertFalse(contradiction(*TF))
    19        # self.assertFalse(contradiction(False, True))
    20        self.assertFalse(contradiction(*FT))
    21        # self.assertFalse(contradiction(False, False))
    22        self.assertFalse(contradiction(*FF))
    23
    24    def test_logical_conjunction(self):
    

    the test is still green.

  • I remove the commented lines from test_logical_conjunction

    13    def test_contradiction(self):
    14        contradiction = src.truth_table.contradiction
    15        self.assertFalse(contradiction(*TT))
    16        self.assertFalse(contradiction(*TF))
    17        self.assertFalse(contradiction(*FT))
    18        self.assertFalse(contradiction(*FF))
    19
    20    def test_logical_conjunction(self):
    
  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_logical_conjunction

    20    def test_logical_conjunction(self):
    21        logical_conjunction = (
    22            src.truth_table.logical_conjunction
    23        )
    24        self.assertTrue(logical_conjunction(*TT))
    25        self.assertFalse(logical_conjunction(*TF))
    26        self.assertFalse(logical_conjunction(*FT))
    27        self.assertFalse(logical_conjunction(*FF))
    28
    29    def test_project_second(self):
    

    still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_project_second

    29    def test_project_second(self):
    30        project_second = src.truth_table.project_second
    31        self.assertTrue(project_second(*TT))
    32        self.assertFalse(project_second(*TF))
    33        self.assertTrue(project_second(*FT))
    34        self.assertFalse(project_second(*FF))
    35
    36    def test_converse_non_implication(self):
    

    green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_converse_non_implication

    36    def test_converse_non_implication(self):
    37        converse_non_implication = (
    38            src.truth_table.converse_non_implication
    39        )
    40        self.assertFalse(converse_non_implication(*TT))
    41        self.assertFalse(converse_non_implication(*TF))
    42        self.assertTrue(converse_non_implication(*FT))
    43        self.assertFalse(converse_non_implication(*FF))
    44
    45    def test_negate_first(self):
    

    still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_negate_first

    45    def test_negate_first(self):
    46        negate_first = src.truth_table.negate_first
    47        self.assertFalse(negate_first(*TT))
    48        self.assertFalse(negate_first(*TF))
    49        self.assertTrue(negate_first(*FT))
    50        self.assertTrue(negate_first(*FF))
    51
    52    def test_logical_nand(self):
    

    the test is still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_logical_nand

    52    def test_logical_nand(self):
    53        nand = src.truth_table.logical_nand
    54        self.assertFalse(nand(*TT))
    55        self.assertTrue(nand(*TF))
    56        self.assertTrue(nand(*FT))
    57        self.assertTrue(nand(*FF))
    58
    59    def test_tautology(self):
    

    still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_tautology

    59    def test_tautology(self):
    60        tautology = src.truth_table.tautology
    61        self.assertTrue(tautology(*TT))
    62        self.assertTrue(tautology(*TF))
    63        self.assertTrue(tautology(*FT))
    64        self.assertTrue(tautology(*FF))
    65
    66    def test_logical_disjunction(self):
    

    green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_logical_disjunction

    66    def test_logical_disjunction(self):
    67        logical_disjunction = (
    68            src.truth_table.logical_disjunction
    69        )
    70        self.assertTrue(logical_disjunction(*TT))
    71        self.assertTrue(logical_disjunction(*TF))
    72        self.assertTrue(logical_disjunction(*FT))
    73        self.assertFalse(logical_disjunction(*FF))
    74
    75    def test_exclusive_disjunction(self):
    

    still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_exclusive_disjunction

    75    def test_exclusive_disjunction(self):
    76        xor = src.truth_table.exclusive_disjunction
    77        self.assertFalse(xor(*TT))
    78        self.assertTrue(xor(*TF))
    79        self.assertTrue(xor(*FT))
    80        self.assertFalse(xor(*FF))
    81
    82    def test_material_non_implication(self):
    

    the test is still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_material_non_implication

    82    def test_material_non_implication(self):
    83        material_non_implication = (
    84            src.truth_table.material_non_implication
    85        )
    86        self.assertFalse(material_non_implication(*TT))
    87        self.assertTrue(material_non_implication(*TF))
    88        self.assertFalse(material_non_implication(*FT))
    89        self.assertFalse(material_non_implication(*FF))
    90
    91    def test_project_first(self):
    

    still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_project_first

    91    def test_project_first(self):
    92        project_first = src.truth_table.project_first
    93        self.assertTrue(project_first(*TT))
    94        self.assertTrue(project_first(*TF))
    95        self.assertFalse(project_first(*FT))
    96        self.assertFalse(project_first(*FF))
    97
    98    def test_converse_implication(self):
    

    green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_converse_implication

     98    def test_converse_implication(self):
     99        converse_implication = (
    100            src.truth_table.converse_implication
    101        )
    102        self.assertTrue(converse_implication(*TT))
    103        self.assertTrue(converse_implication(*TF))
    104        self.assertFalse(converse_implication(*FT))
    105        self.assertTrue(converse_implication(*FF))
    106
    107    def test_negate_second(self):
    

    still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_negate_second

    107    def test_negate_second(self):
    108        negate_second = src.truth_table.negate_second
    109        self.assertFalse(negate_second(*TT))
    110        self.assertTrue(negate_second(*TF))
    111        self.assertFalse(negate_second(*FT))
    112        self.assertTrue(negate_second(*FF))
    113
    114    def test_logical_nor(self):
    

    the test is still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_logical_nor

    114    def test_logical_nor(self):
    115        logical_nor = src.truth_table.logical_nor
    116        self.assertFalse(logical_nor(*TT))
    117        self.assertFalse(logical_nor(*TF))
    118        self.assertFalse(logical_nor(*FT))
    119        self.assertTrue(logical_nor(*FF))
    120
    121    def test_logical_equality(self):
    

    still green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_logical_equality

    121    def test_logical_equality(self):
    122        logical_equality = (
    123            src.truth_table.logical_equality
    124        )
    125        self.assertTrue(logical_equality(*TT))
    126        self.assertFalse(logical_equality(*TF))
    127        self.assertFalse(logical_equality(*FT))
    128        self.assertTrue(logical_equality(*FF))
    129
    130    def test_material_implication(self):
    

    green.

  • I use the variables with a single starred expression to remove repetition of True, True, True, False, False, True and False, False from test_material_implication

    130    def test_material_implication(self):
    131        material_implication = (
    132            src.truth_table.material_implication
    133        )
    134        self.assertTrue(material_implication(*TT))
    135        self.assertFalse(material_implication(*TF))
    136        self.assertTrue(material_implication(*FT))
    137        self.assertTrue(material_implication(*FF))
    138
    139
    140# Exceptions seen
    141# AttributeError
    142# TypeError
    143# AssertionError
    144# SyntaxError
    

    still green.

  • I add a git commit message in the other terminal

    git commit -am \
    'extract global variables for truth table cases'
    

close the project

  • I close tests/test_binary.py and src/truth_table/__init__.py

  • I 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_table

    cd ..
    

    the terminal shows

    .../pumping_python
    

    I am back in the pumping_python directory.


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

  • Material/Logical Implication

    • returns not first_input or second_input

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

    • is the Logical Negation (NOT) of Material Non-Implication which returns True only if first_input is True and second_input is False

    first input

    second input

    return

    True

    True

    True

    True

    False

    False

    False

    True

    True

    False

    False

    True

  • Logical Equality

    first input

    second input

    return

    True

    True

    True

    True

    False

    False

    False

    True

    False

    False

    False

    True

  • Logical NOR

    • returns not (first_input or second_input)

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

    • is the Logical Negation (NOT) of Logical Disjunction which returns False only if first_input is False and second_input is False

    first input

    second input

    return

    True

    True

    False

    True

    False

    False

    False

    True

    False

    False

    False

    True

  • Negate Second

    first input

    second input

    return

    True

    True

    False

    True

    False

    True

    False

    True

    False

    False

    False

    True

  • Converse Implication

    • returns first_input or not second_input

    • returns False if first_input is False and second_input is True

    • is the Logical Negation (NOT) of Converse Non-Implication which returns True only if first_input is False and second_input is True

    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 Non-Implication

    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 Logical Negation (NOT) 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

    • returns first_input or second_input

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

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

    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

    • returns not (first_input and second_input)

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

    • is the Logical Negation (NOT) of Logical Conjunction (AND) which returns True only if first_input is True and second_input is True

    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 Non-Implication

    • returns not first_input and second_input

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

    • is the Logical Negation (NOT) 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 first_input and second_input

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

    • is the Logical Negation (NOT) 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

The binary operations can be written with some combination of AND, NOT and OR.

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

not second

False

True

False

True

negate_second

not (first or second)

False

False

False

True

logical_nor

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

True

False

False

True

logical_equality

(not first) or second

True

False

True

True

material_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 see more examples of the truth table?


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.