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
 5CASE_1 = True, True
 6CASE_2 = True, False
 7CASE_3 = False, True
 8CASE_4 = False, False
 9
10
11class TestBinaryOperations(unittest.TestCase):
12
13    def test_contradiction(self):
14        contradiction = src.truth_table.contradiction
15        self.assertFalse(contradiction(*CASE_1))
16        self.assertFalse(contradiction(*CASE_2))
17        self.assertFalse(contradiction(*CASE_3))
18        self.assertFalse(contradiction(*CASE_4))
19
20    def test_logical_conjunction(self):
21        logical_conjunction = (
22            src.truth_table.logical_conjunction
23        )
24        self.assertTrue(logical_conjunction(*CASE_1))
25        self.assertFalse(logical_conjunction(*CASE_2))
26        self.assertFalse(logical_conjunction(*CASE_3))
27        self.assertFalse(logical_conjunction(*CASE_4))
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(*CASE_1))
32        self.assertFalse(project_second(*CASE_2))
33        self.assertTrue(project_second(*CASE_3))
34        self.assertFalse(project_second(*CASE_4))
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(*CASE_1))
41        self.assertFalse(converse_non_implication(*CASE_2))
42        self.assertTrue(converse_non_implication(*CASE_3))
43        self.assertFalse(converse_non_implication(*CASE_4))
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(*CASE_1))
48        self.assertFalse(negate_first(*CASE_2))
49        self.assertTrue(negate_first(*CASE_3))
50        self.assertTrue(negate_first(*CASE_4))
51
52    def test_logical_nand(self):
53        nand = src.truth_table.logical_nand
54        self.assertFalse(nand(*CASE_1))
55        self.assertTrue(nand(*CASE_2))
56        self.assertTrue(nand(*CASE_3))
57        self.assertTrue(nand(*CASE_4))
truth_table/tests/test_binary.py
59    def test_tautology(self):
60        tautology = src.truth_table.tautology
61        self.assertTrue(tautology(*CASE_1))
62        self.assertTrue(tautology(*CASE_2))
63        self.assertTrue(tautology(*CASE_3))
64        self.assertTrue(tautology(*CASE_4))
65
66    def test_logical_disjunction(self):
67        logical_disjunction = (
68            src.truth_table.logical_disjunction
69        )
70        self.assertTrue(logical_disjunction(*CASE_1))
71        self.assertTrue(logical_disjunction(*CASE_2))
72        self.assertTrue(logical_disjunction(*CASE_3))
73        self.assertFalse(logical_disjunction(*CASE_4))
truth_table/tests/test_binary.py
75    def test_exclusive_disjunction(self):
76        xor = src.truth_table.exclusive_disjunction
77        self.assertFalse(xor(*CASE_1))
78        self.assertTrue(xor(*CASE_2))
79        self.assertTrue(xor(*CASE_3))
80        self.assertFalse(xor(*CASE_4))
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(*CASE_1))
87        self.assertTrue(material_non_implication(*CASE_2))
88        self.assertFalse(material_non_implication(*CASE_3))
89        self.assertFalse(material_non_implication(*CASE_4))
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(*CASE_1))
 94        self.assertTrue(project_first(*CASE_2))
 95        self.assertFalse(project_first(*CASE_3))
 96        self.assertFalse(project_first(*CASE_4))
 97
 98    def test_converse_implication(self):
 99        converse_implication = (
100            src.truth_table.converse_implication
101        )
102        self.assertTrue(converse_implication(*CASE_1))
103        self.assertTrue(converse_implication(*CASE_2))
104        self.assertFalse(converse_implication(*CASE_3))
105        self.assertTrue(converse_implication(*CASE_4))
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(*CASE_1))
110        self.assertTrue(negate_second(*CASE_2))
111        self.assertFalse(negate_second(*CASE_3))
112        self.assertTrue(negate_second(*CASE_4))
113
114    def test_logical_nor(self):
115        logical_nor = src.truth_table.logical_nor
116        self.assertFalse(logical_nor(*CASE_1))
117        self.assertFalse(logical_nor(*CASE_2))
118        self.assertFalse(logical_nor(*CASE_3))
119        self.assertTrue(logical_nor(*CASE_4))
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(*CASE_1))
126        self.assertFalse(logical_equality(*CASE_2))
127        self.assertFalse(logical_equality(*CASE_3))
128        self.assertTrue(logical_equality(*CASE_4))
129
130    def test_material_implication(self):
131        material_implication = (
132            src.truth_table.material_implication
133        )
134        self.assertTrue(material_implication(*CASE_1))
135        self.assertFalse(material_implication(*CASE_2))
136        self.assertTrue(material_implication(*CASE_3))
137        self.assertTrue(material_implication(*CASE_4))
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 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 truth_table.py


GREEN: make it pass


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

  • I add a function definition for negate_second to truth_table.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 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 truth_table.py

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

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

    • 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 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 truth_table.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

    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
    108    return True if not second_input else 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    # 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
    108    # return True if not second_input else False
    109    return not second_input
    
  • I remove the comments

    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 test_binary.py

    first input

    second input

    return

    True

    True

    False

    104        self.assertTrue(negate_second(False, False))
    105
    106    def test_logical_nor(self):
    107        logical_nor = src.truth_table.logical_nor
    108        self.assertFalse(logical_nor(True, True))
    109
    110
    111# 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'?
    

    truth_table.py does not have any definition for logical_nor.


GREEN: make it pass


I add logical_nor to truth_table.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 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 truth_table.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 the 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

    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
    118    return (
    119        True if
    120        not first_input and not second_input
    121        else False
    122    )
    

    the test is still green.

  • I remove True if and else False

    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
    118    return (
    119        # True if
    120        not first_input and not second_input
    121        # else False
    122    )
    

    still green.

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

    118    return (
    119        # True if
    120        # not first_input and not second_input
    121        (not first_input)
    122        (not or)
    123        (not second_input)
    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

    118    return (
    119        # True if
    120        # not first_input and not second_input
    121        # (not first_input)
    122        # (not or)
    123        # (not second_input)
    124        not (first_input or second_input)
    125        # else False
    126    )
    

    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

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

    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 comments

    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 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 truth_table.py.


GREEN: make it pass


I add a function definition for logical_equality in truth_table.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 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 truth_table.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 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 truth_table.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 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 truth_table.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    if not first_input and not second_input:
    125        return True
    126    if not first_input and second_input:
    127        return False
    128    # if second_input == False:
    129    # if bool(second_input) == False:
    130    # if not bool(second_input) == True:
    131    # if not bool(second_input):
    132    if not second_input:
    133        return False
    134    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

    124    if not first_input and not second_input:
    125        return True
    126    if not first_input and second_input:
    127        return False
    128    # if second_input == False:
    129    # if bool(second_input) == False:
    130    # if not bool(second_input) == True:
    131    # if not bool(second_input):
    132    # if not second_input:
    133    if first_input and not second_input:
    134        return False
    135    if first_input and second_input:
    136        return True
    

    still green.

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

    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    # if second_input == False:
    125    # if bool(second_input) == False:
    126    # if not bool(second_input) == True:
    127    # if not bool(second_input):
    128    # if not second_input:
    129    if not first_input and second_input:
    130        return False
    131    if first_input and not second_input:
    132        return False
    133    if first_input and second_input:
    134        return True
    135    if not first_input and not second_input:
    136        return True
    
  • I use Logical Disjunction (OR) to put the two if statements that return True together

    129    # if not first_input and second_input:
    130    #     return False
    131    # if first_input and not second_input:
    132    #     return False
    133    # if first_input and second_input:
    134    #     return True
    135    # if not first_input and not second_input:
    136    #     return True
    137    if (
    138        (first_input and second_input)
    139        or
    140        (not first_input and not second_input)
    141    ):
    142        return True
    143    else:
    144        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

    137    # if (
    138    #     (first_input and second_input)
    139    #     or
    140    #     (not first_input and not second_input)
    141    # ):
    142    #     return True
    143    # else:
    144    #     return False
    145    return True if (
    146        (first_input and second_input)
    147        or
    148        (not first_input and not second_input)
    149    ) else False
    

    still green.

  • I remove True if and else False

    145    # return True if (
    146    return (
    147        (first_input and second_input)
    148        or
    149        (not first_input and not second_input)
    150    # ) else False
    151    )
    

    the test is still green.

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

    145    # return True if (
    146    return (
    147        (first_input and second_input)
    148        or
    149        # (not first_input and not second_input)
    150        (
    151            (not first_input)
    152            (not or)
    153            (not second_input)
    154        )
    155    # ) else False
    156    )
    

    the terminal is my friend, and shows SyntaxError

    SyntaxError: invalid syntax
    

    because I cannot negate or this way.

  • I “factor” out the nots

    100    # return True if (
    101    return (
    102        (first_input and second_input)
    103        or
    104        # (not first_input and not second_input)
    105        # (
    106        #     (not first_input)
    107        #     (not or)
    108        #     (not second_input)
    109        # )
    110        not (first_input or second_input)
    111    # ) else False
    112    )
    

    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

    145    # return True if (
    146    return logical_disjunction(
    147        logical_conjunction(first_input, second_input),
    148        logical_nor(first_input, second_input)
    149    )
    150    return (
    151        (first_input and second_input)
    152        or
    153        # (not first_input and not second_input)
    154        # (
    155        #     (not first_input)
    156        #     (not or)
    157        #     (not second_input)
    158        # )
    159        not (first_input or second_input)
    160    # ) else False
    161    )
    

    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 (2 equal signs together =+= on the keyboard)

    145    # return True if (
    146    return first_input == second_input
    147    return logical_disjunction(
    148        logical_conjunction(first_input, second_input),
    149        logical_nor(first_input, second_input)
    150    )
    151    return (
    152        (first_input and second_input)
    153        or
    154        # (not first_input and not second_input)
    155        # (
    156        #     (not first_input)
    157        #     (not or)
    158        #     (not second_input)
    159        # )
    160        not (first_input or second_input)
    161    # ) else False
    162    )
    

    the test is still green.

  • I remove the commented lines

    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 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 truth_table.py.


GREEN: make it pass


I add a function for material_implication to truth_table.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 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 truth_table.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 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 truth_table.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

    136    # if first_input and not second_input:
    137    #     return False
    138    # else:
    139    # if not (first_input and not second_input):
    140    #     return
    141    return (
    142        True if
    143        not (first_input and not second_input)
    144        else False
    145    )
    

    still green.

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

    136    # if first_input and not second_input:
    137    #     return False
    138    # else:
    139    # if not (first_input and not second_input):
    140    #     return
    141    return (
    142        # True if
    143        not (first_input and not second_input)
    144        # else False
    145    )
    

    the test is still green.

  • I “multiply” not by the symbols in parentheses

    136    # if first_input and not second_input:
    137    #     return False
    138    # else:
    139    # if not (first_input and not second_input):
    140    #     return
    141    return (
    142        # True if
    143        # not (first_input and not second_input)
    144        (not first_input)
    145        (not and)
    146        (not not second_input)
    147        # else False
    148    )
    

    the terminal is my friend, and shows SyntaxError

    SyntaxError: invalid syntax
    

    because I cannot negate and this way.

  • I change not and to or

    136    # if first_input and not second_input:
    137    #     return False
    138    # else:
    139    # if not (first_input and not second_input):
    140    #     return
    141    return (
    142        # True if
    143        # not (first_input and not second_input)
    144        (not first_input)
    145        # (not and)
    146        or
    147        (not not second_input)
    148        # else False
    149    )
    

    the test is green again.

  • I remove not not because they cancel out

    136    # if first_input and not second_input:
    137    #     return False
    138    # else:
    139    # if not (first_input and not second_input):
    140    #     return
    141    return (
    142        # True if
    143        # not (first_input and not second_input)
    144        (not first_input)
    145        # (not and)
    146        or
    147        # (not not second_input)
    148        second_input
    149        # else False
    150    )
    

    the test is 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

    136    # if first_input and not second_input:
    137    #     return False
    138    # else:
    139    # if not (first_input and not second_input):
    140    #     return
    141    return logical_disjunction(
    142        logical_negation(first_input),
    143        second_input
    144    )
    145    return (
    146        # True if
    147        # not (first_input and not second_input)
    148        (not first_input)
    149        # (not and)
    150        or
    151        # (not not second_input)
    152        second_input
    153        # else False
    154    )
    

    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 comments

    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

  • 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 test_binary.py

     1import src.truth_table
     2import unittest
     3
     4
     5CASE_1 = True, True
     6CASE_2 = True, False
     7CASE_3 = False, True
     8CASE_4 = 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(*CASE_1))
    17        # self.assertFalse(contradiction(True, True))
    18        self.assertFalse(contradiction(*CASE_2))
    19        # self.assertFalse(contradiction(False, True))
    20        self.assertFalse(contradiction(*CASE_3))
    21        # self.assertFalse(contradiction(False, False))
    22        self.assertFalse(contradiction(*CASE_4))
    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(*CASE_1))
    16        self.assertFalse(contradiction(*CASE_2))
    17        self.assertFalse(contradiction(*CASE_3))
    18        self.assertFalse(contradiction(*CASE_4))
    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(*CASE_1))
    25        self.assertFalse(logical_conjunction(*CASE_2))
    26        self.assertFalse(logical_conjunction(*CASE_3))
    27        self.assertFalse(logical_conjunction(*CASE_4))
    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(*CASE_1))
    32        self.assertFalse(project_second(*CASE_2))
    33        self.assertTrue(project_second(*CASE_3))
    34        self.assertFalse(project_second(*CASE_4))
    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(*CASE_1))
    41        self.assertFalse(converse_non_implication(*CASE_2))
    42        self.assertTrue(converse_non_implication(*CASE_3))
    43        self.assertFalse(converse_non_implication(*CASE_4))
    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(*CASE_1))
    48        self.assertFalse(negate_first(*CASE_2))
    49        self.assertTrue(negate_first(*CASE_3))
    50        self.assertTrue(negate_first(*CASE_4))
    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(*CASE_1))
    55        self.assertTrue(nand(*CASE_2))
    56        self.assertTrue(nand(*CASE_3))
    57        self.assertTrue(nand(*CASE_4))
    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(*CASE_1))
    62        self.assertTrue(tautology(*CASE_2))
    63        self.assertTrue(tautology(*CASE_3))
    64        self.assertTrue(tautology(*CASE_4))
    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(*CASE_1))
    71        self.assertTrue(logical_disjunction(*CASE_2))
    72        self.assertTrue(logical_disjunction(*CASE_3))
    73        self.assertFalse(logical_disjunction(*CASE_4))
    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(*CASE_1))
    78        self.assertTrue(xor(*CASE_2))
    79        self.assertTrue(xor(*CASE_3))
    80        self.assertFalse(xor(*CASE_4))
    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(*CASE_1))
    87        self.assertTrue(material_non_implication(*CASE_2))
    88        self.assertFalse(material_non_implication(*CASE_3))
    89        self.assertFalse(material_non_implication(*CASE_4))
    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(*CASE_1))
    94        self.assertTrue(project_first(*CASE_2))
    95        self.assertFalse(project_first(*CASE_3))
    96        self.assertFalse(project_first(*CASE_4))
    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(*CASE_1))
    103        self.assertTrue(converse_implication(*CASE_2))
    104        self.assertFalse(converse_implication(*CASE_3))
    105        self.assertTrue(converse_implication(*CASE_4))
    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(*CASE_1))
    110        self.assertTrue(negate_second(*CASE_2))
    111        self.assertFalse(negate_second(*CASE_3))
    112        self.assertTrue(negate_second(*CASE_4))
    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(*CASE_1))
    117        self.assertFalse(logical_nor(*CASE_2))
    118        self.assertFalse(logical_nor(*CASE_3))
    119        self.assertTrue(logical_nor(*CASE_4))
    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(*CASE_1))
    126        self.assertFalse(logical_equality(*CASE_2))
    127        self.assertFalse(logical_equality(*CASE_3))
    128        self.assertTrue(logical_equality(*CASE_4))
    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(*CASE_1))
    135        self.assertFalse(material_implication(*CASE_2))
    136        self.assertTrue(material_implication(*CASE_3))
    137        self.assertTrue(material_implication(*CASE_4))
    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 variables for cases'
    

close the project

  • I close test_binary.py and truth_table.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

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