truth table: Binary Operations part 2


requirements

Binary Operations part 1

how to get back to the automated tests

If your tests stopped after the previous chapter, heres’s how to get back to the tests


test_negate_first

RED: make it fail

I add a test to the TestBinaryOperations class in test_truth_table.py for negate_first

49        self.assertFalse(src.truth_table.converse_non_implication(False, False))
50
51    def test_negate_first(self):
52        self.assertFalse(src.truth_table.negate_first(True, True))
53
54
55# Exceptions seen

the terminal shows AttributeError

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

there is no definition for negate_first in truth_table.py

GREEN: make it pass

I add the function definition in truth_table.py

29def converse_non_implication(first_input, second_input):
30    return not first_input and second_input
31
32
33def negate_first(first_input, second_input):
34    return False

the test passes. negate_first returns False when the first and second inputs are both True

REFACTOR: make it better

  • I add the second case - where the first input is True and the second input is False, to test_negate_first in test_truth_table.py

    51    def test_negate_first(self):
    52        self.assertFalse(src.truth_table.negate_first(True, True))
    53        self.assertFalse(src.truth_table.negate_first(True, False))
    

    the test is still green. negate_first returns

  • I add the next case - when the first input is False and the second input is True

    51    def test_negate_first(self):
    52        self.assertFalse(src.truth_table.negate_first(True, True))
    53        self.assertFalse(src.truth_table.negate_first(True, False))
    54        self.assertTrue(src.truth_table.negate_first(False, True))
    

    the terminal shows AssertionError

    AssertionError: False is not true
    
  • I add if statements for this case to negate_first in truth_table.py

    33def negate_first(first_input, second_input):
    34    if first_input == False:
    35        if second_input == True:
    36            return True
    37    return False
    

    the test passes

  • this is the same as the first if statement in converse_non_implication. I change the two if statements to one if statement with Logical Conjunction (and)

    33def negate_first(first_input, second_input):
    34    if first_input == False and second_input == True:
    35    # if first_input == False:
    36    #     if second_input == True:
    37            return True
    38    return False
    

    the test is still green

  • I remove the commented lines and move the first return statement to the left

    33def negate_first(first_input, second_input):
    34    if first_input == False and second_input == True:
    35        return True
    36    return False
    

    negate_first returns

  • I add the last case - when the first and second inputs are both False, to test_negate_first in test_truth_table.py

    51    def test_negate_first(self):
    52        self.assertFalse(src.truth_table.negate_first(True, True))
    53        self.assertFalse(src.truth_table.negate_first(True, False))
    54        self.assertTrue(src.truth_table.negate_first(False, True))
    55        self.assertTrue(src.truth_table.negate_first(False, False))
    56
    57
    58# Exceptions seen
    

    the terminal shows AssertionError

    AssertionError: False is not true
    
  • I add if statements for this case to the negate_first function in truth_table.py

    33def negate_first(first_input, second_input):
    34    if first_input == False:
    35        if second_input == False:
    36            return True
    37    if first_input == False and second_input == True:
    38        return True
    39    return False
    

    the test passes

  • I change the two if statements to one if statement with and

    33def negate_first(first_input, second_input):
    34    if first_input == False and second_input == False:
    35    # if first_input == False:
    36    #     if second_input == False:
    37            return True
    38    if first_input == False and second_input == True:
    39        return True
    40    return False
    

    the test is still green

  • I remove the commented lines and move the new return statement to the left

    33def negate_first(first_input, second_input):
    34    if first_input == False and second_input == False:
    35        return True
    36    if first_input == False and second_input == True:
    37        return True
    38    return False
    

    negate_first returns

  • since the 2 cases where the negate_first function returns True are when the first input is False. I can write it as an if statement with an else clause

    33def negate_first(first_input, second_input):
    34    if first_input == False:
    35        return True
    36    else:
    37        return False
    38    if first_input == False and second_input == False:
    39        return True
    40    if first_input == False and second_input == True:
    41        return True
    42    return False
    

    the test is still green

  • I remove the other if statement then use logical_negation (not) to write the first if statement in terms of True

    33def negate_first(first_input, second_input):
    34    if not first_input == True:
    35    # if first_input == False:
    36        return True
    37    else:
    38        return False
    

    the test is still passing

  • I remove the commented line and use bool with the if statement

    33def negate_first(first_input, second_input):
    34    if not bool(first_input):
    35    # if not first_input == True:
    36        return True
    37    else:
    38        return False
    

    still green

  • I remove the commented line and make the if statement simpler

    33def negate_first(first_input, second_input):
    34    if not first_input:
    35    # if not bool(first_input):
    36        return True
    37    else:
    38        return False
    

    the test is still green

  • I remove the commented line then add a ternary operator (conditional expression)

    33def negate_first(first_input, second_input):
    34    return True if not first_input else False
    35    if not first_input:
    36        return True
    37    else:
    38        return False
    

    still green

  • I remove the if statement and else clause, then use the simpler form of the return statement

    33def negate_first(first_input, second_input):
    34    return not first_input
    35    return True if not first_input else False
    

    the test is still green

  • I remove the second return statement

    33def negate_first(first_input, second_input):
    34    return not first_input
    

Negate First negates the first input, it always returns


test_logical_nand

RED: make it fail

I add a new test to test_truth_table.py

55        self.assertTrue(src.truth_table.negate_first(False, False))
56
57    def test_logical_nand(self):
58        self.assertFalse(src.truth_table.logical_nand(True, True))
59
60
61# Exceptions seen

the terminal shows AttributeError

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

there is no definition for logical_nand in truth_table.py

GREEN: make it pass

I add a definition for the function to truth_table.py

33def negate_first(first_input, second_input):
34    return not first_input
35
36
37def logical_nand(first_input, second_input):
38    return False

the test passes.

logical_nand returns False when the first and second inputs are both True

REFACTOR: make it better

  • I add the second case - where the first input is True and the second input is False, to test_logical_nand in test_truth_table.py

    57    def test_logical_nand(self):
    58        self.assertFalse(src.truth_table.logical_nand(True, True))
    59        self.assertTrue(src.truth_table.logical_nand(True, False))
    

    the terminal shows AssertionError

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

    37def logical_nand(first_input, second_input):
    38    if first_input == True:
    39        if second_input == False:
    40            return True
    41    return False
    

    the test passes

  • I comment out the two if statements, and change them to one if statement

    37def logical_nand(first_input, second_input):
    38    if first_input == True and second_input == False:
    39    # if first_input == True:
    40    #     if second_input == False:
    41            return True
    42    return False
    

    the test is still green

  • I remove the commented lines, and move the first return statement to the left

    37def logical_nand(first_input, second_input):
    38    if first_input == True and second_input == False:
    39        return True
    40    return False
    

    the terminal still shows green. the logical_nand function returns

    • True when the first input is True and the second input is False

    • False when the first and second inputs are both True

  • I add another case, where the first input is False and the second input is True, to test_logical_nand in test_truth_table.py

    57    def test_logical_nand(self):
    58        self.assertFalse(src.truth_table.logical_nand(True, True))
    59        self.assertTrue(src.truth_table.logical_nand(True, False))
    60        self.assertTrue(src.truth_table.logical_nand(False, True))
    

    the terminal shows AssertionError

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

    37def logical_nand(first_input, second_input):
    38    if first_input == False:
    39        if second_input == True:
    40            return True
    41    if first_input == True and second_input == False:
    42        return True
    43    return False
    

    the test passes

  • I change the two if statements to one if statement with logical_conjunction (and)

    37def logical_nand(first_input, second_input):
    38    if first_input == False and second_input == True:
    39    # if first_input == False:
    40    #     if second_input == True:
    41            return True
    42    if first_input == True and second_input == False:
    43        return True
    44    return False
    

    the test is still green

  • I remove the commented lines and move the new return statement to the left

    37def logical_nand(first_input, second_input):
    38    if first_input == False and second_input == True:
    39        return True
    40    if first_input == True and second_input == False:
    41        return True
    42    return False
    

    still green. logical_nand returns

    • True when the first input is False and the second input is True

    • True when the first input is True and the second input is False

    • False when the first and second inputs are both True

  • I add the last case - where the first and second inputs are both False, to test_logical_nand in test_truth_table.py

    57    def test_logical_nand(self):
    58        self.assertFalse(src.truth_table.logical_nand(True, True))
    59        self.assertTrue(src.truth_table.logical_nand(True, False))
    60        self.assertTrue(src.truth_table.logical_nand(False, True))
    61        self.assertTrue(src.truth_table.logical_nand(False, False))
    62
    63
    64# Exceptions seen
    

    the terminal shows AssertionError

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

    37def logical_nand(first_input, second_input):
    38    if first_input == False:
    39        if second_input == False:
    40            return True
    41    if first_input == False and second_input == True:
    42        return True
    43    if first_input == True and second_input == False:
    44        return True
    45    return False
    

    the test passes

  • I change the two if statements to one if statement

    37def logical_nand(first_input, second_input):
    38    if first_input == False and second_input == False:
    39    # if first_input == False:
    40    #     if second_input == False:
    41            return True
    42    if first_input == False and second_input == True:
    43        return True
    44    if first_input == True and second_input == False:
    45        return True
    46    return False
    

    the test is still green

  • I remove the comments and move the new return statement to the left

    37def logical_nand(first_input, second_input):
    38    if first_input == False and second_input == False:
    39        return True
    40    if first_input == False and second_input == True:
    41        return True
    42    if first_input == True and second_input == False:
    43        return True
    44    return False
    

    the terminal still shows green. logical_nand returns

    • True when the first and second inputs are both False

    • True when the first input is False and the second input is True

    • True when the first input is True and the second input is False

    • False when the first and second inputs are both True

  • I add one if statement for the one case that returns False with an else clause for the other three cases since they all return True

    37def logical_nand(first_input, second_input):
    38    if first_input == True and second_input == True:
    39        return False
    40    else:
    41        return True
    42    if first_input == False and second_input == False:
    43        return True
    44    if first_input == False and second_input == True:
    45        return True
    46    if first_input == True and second_input == False:
    47        return True
    48    return False
    

    the test is still green

  • I remove the other if statement and use bool to change the new if statement

    37def logical_nand(first_input, second_input):
    38    if bool(first_input) and bool(second_input):
    39    # if first_input == True and second_input == True:
    40        return False
    41    else:
    42        return True
    

    the terminal still shows green

  • I remove the commented line and use the simpler if statement that checks if the inputs are True behind the scenes

    37def logical_nand(first_input, second_input):
    38    if first_input and second_input:
    39    # if bool(first_input) and bool(second_input):
    40        return False
    41    else:
    42        return True
    

    still green

  • I want to use one return statement (a conditional expression) for everything, which means I need an if statement that returns True. I use logical negation (not) to change the else clause to the opposite of the if statement

    37def logical_nand(first_input, second_input):
    38    if first_input and second_input:
    39        return False
    40    if not (first_input and second_input):
    41    # else:
    42        return True
    

    the test is still green

  • I remove the commented line and move the new if statement to the top

    37def logical_nand(first_input, second_input):
    38    if not (first_input and second_input):
    39        return True
    40    if first_input and second_input:
    41        return False
    

    the terminal still shows green

  • I change the second if statement to an else clause

    37def logical_nand(first_input, second_input):
    38    if not (first_input and second_input):
    39        return True
    40    else:
    41    # if first_input and second_input:
    42        return False
    

    green, green, green again 🎶

  • I remove the comment, then add a conditional expression

    37def logical_nand(first_input, second_input):
    38    return True if not (first_input and second_input) else False
    39    if not (first_input and second_input):
    40        return True
    41    else:
    42        return False
    

    still green

  • I remove the if statement and use the simpler form of the ternary operator

    37def logical_nand(first_input, second_input):
    38    return not (first_input and second_input)
    39    return True if not (first_input and second_input) else False
    

    the test is still passing

  • I remove the second return statement

    37def logical_nand(first_input, second_input):
    38    return not (first_input and second_input)
    

Logical NAND

  • returns False only when the first input and second input are both True

  • returns not (first_input and second_input) which is the Logical Negation of the Logical Conjunction of the first input and the second input, many words

  • is the not of the and of the first input and second input, confusing?

  • it is the opposite of Logical Conjunction which only returns True when the first input and second input are both True or returns first_input and second_input

Tip

When there is only one if statement that returns False with an else clause, for example

if condition:
    return False
else:
    return True

I can rewrite it in terms of True with its logical negation with not

if not condition:
    return True
else:
    return False

I can then write it as a ternary operator (conditional expression)

return True if not (condition) else False

which can be made simpler as

return not (condition)

test_tautology

RED: make it fail

I add a test for the next Binary Operation in test_truth_table.py with the first case where the two inputs are True

61        self.assertTrue(src.truth_table.logical_nand(False, False))
62
63    def test_tautology(self):
64        self.assertTrue(src.truth_table.tautology(True, True))
65
66
67# Exceptions seen

the terminal shows AttributeError

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

truth_table.py does not have tautology defined inside it

GREEN: make it pass

I add a function definition in truth_table.py

37def logical_nand(first_input, second_input):
38    return not (first_input and second_input)
39
40
41def tautology(first_input, second_input):
42    return True

the test passes. tatutology returns True when the two inputs are True

REFACTOR: make it better

  • I add the next case to test_tautology in test_truth_table.py - when first_input is True and second_input is False

    63    def test_tautology(self):
    64        self.assertTrue(src.truth_table.tautology(True, True))
    65        self.assertTrue(src.truth_table.tautology(True, False))
    

    the terminal still shows green. tautology returns

  • I add the next case - when the first input is False and the second input is True

    63    def test_tautology(self):
    64        self.assertTrue(src.truth_table.tautology(True, True))
    65        self.assertTrue(src.truth_table.tautology(True, False))
    66        self.assertTrue(src.truth_table.tautology(False, True))
    

    the test is still green. tautology returns True

    • when the first input is False and the second input is True

    • when the first input is True

  • I add the last case - when the two inputs are False

    63    def test_tautology(self):
    64        self.assertTrue(src.truth_table.tautology(True, True))
    65        self.assertTrue(src.truth_table.tautology(True, False))
    66        self.assertTrue(src.truth_table.tautology(False, True))
    67        self.assertTrue(src.truth_table.tautology(False, False))
    68
    69
    70# Exceptions seen
    

    still green, there is only one result for this operation.

Tautology returns True

  • when the two inputs are False

  • when the first input is False and the second input is True

  • when the first input is False

  • when the first input is True

It always returns True, it is the opposite of Contradiction which always returns False


test_logical_disjunction

RED: make it fail

I add another test to test_truth_table.py with the first case, where the two inputs are True

67        self.assertTrue(src.truth_table.tautology(False, False))
68
69    def test_logical_disjunction(self):
70        self.assertTrue(src.truth_table.logical_disjunction(True, True))
71
72
73# Exceptions seen

the terminal shows AttributeError

AttributeError: module 'src.truth_table' has no attribute 'logical_disjunction'. Did you mean: 'logical_conjunction'?

there is no definition for logical_disjunction in truth_table.py in the src folder yet

GREEN: make it pass

I add the function to truth_table.py

41def tautology(first_input, second_input):
42    return True
43
44
45def logical_disjunction(first_input, second_input):
46    return True

the test passes. logical_disjunction returns True when the two inputs are True

REFACTOR: make it better

  • I add the next case - when first_input is True and second_input is False, to test_logical_disjunction in test_truth_table.py

    69    def test_logical_disjunction(self):
    70        self.assertTrue(src.truth_table.logical_disjunction(True, True))
    71        self.assertTrue(src.truth_table.logical_disjunction(True, False))
    

    the terminal still shows green. logical_disjunction returns

    so far this is the same as Tautology

  • I add the next case - where the first input is False and the second input is True

    69    def test_logical_disjunction(self):
    70        self.assertTrue(src.truth_table.logical_disjunction(True, True))
    71        self.assertTrue(src.truth_table.logical_disjunction(True, False))
    72        self.assertTrue(src.truth_table.logical_disjunction(False, True))
    

    the test is still green. logical_disjunction still looks like Tautology, it returns

  • I add the fourth case, where the two inputs are False

    69    def test_logical_disjunction(self):
    70        self.assertTrue(src.truth_table.logical_disjunction(True, True))
    71        self.assertTrue(src.truth_table.logical_disjunction(True, False))
    72        self.assertTrue(src.truth_table.logical_disjunction(False, True))
    73        self.assertFalse(src.truth_table.logical_disjunction(False, False))
    74
    75
    76# Exceptions seen
    

    the terminal shows AssertionError

    AssertionError: True is not false
    
  • I add if statements for the new case to logical_disjunction in truth_table.py

    45def logical_disjunction(first_input, second_input):
    46    if first_input == False:
    47        if second_input == False:
    48            return False
    49    return True
    

    the test passes. logical_disjunction returns

  • I change the two if statements to one if statement with and

    45def logical_disjunction(first_input, second_input):
    46    if first_input == False and second_input == False:
    47    # if first_input == False:
    48    #     if second_input == False:
    49            return False
    50    return True
    

    the test is still green

  • I remove the commented line and move the first return statement to the left

    45def logical_disjunction(first_input, second_input):
    46    if first_input == False and second_input == False:
    47        return False
    48    return True
    

    still green

  • I use not to write the statements in terms of True

    45def logical_disjunction(first_input, second_input):
    46    if (not first_input == True) and (not second_input == True):
    47    # if first_input == False and second_input == False:
    48        return False
    49    return True
    

    the terminal still shows green

  • I use bool to make the if statement simpler

    45def logical_disjunction(first_input, second_input):
    46    if (not bool(first_input)) and (not bool(second_input)):
    47    # if (not first_input == True) and (not second_input == True):
    48        return False
    49    return True
    

    the terminal shows green

  • I use a simpler if statement

    45def logical_disjunction(first_input, second_input):
    46    if (not first_input) and (not second_input):
    47    # if (not bool(first_input)) and (not bool(second_input)):
    48        return False
    49    return True
    

    how many green bottles standing on a wall?

  • I add a second if statement for the cases where logical_disjunction returns True like I did with Logical NAND

    45def logical_disjunction(first_input, second_input):
    46    if (not first_input) and (not second_input):
    47        return False
    48    if not ((not first_input) and (not second_input)):
    49        return True
    

    the test is still green

  • I move the new if statement to the top

    45def logical_disjunction(first_input, second_input):
    46    if not ((not first_input) and (not second_input)):
    47        return True
    48    if (not first_input) and (not second_input):
    49        return False
    

    green

  • I change the second if statement to an else clause

    45def logical_disjunction(first_input, second_input):
    46    if not ((not first_input) and (not second_input)):
    47        return True
    48    else:
    49    # if (not first_input) and (not second_input):
    50        return False
    
  • I add a conditional expression

    45def logical_disjunction(first_input, second_input):
    46    return True if not ((not first_input) and (not second_input)) else False
    47    if not ((not first_input) and (not second_input)):
    48        return True
    49    else:
    50        return False
    
  • I make the return statement simpler

    45def logical_disjunction(first_input, second_input):
    46    return not ((not first_input) and (not second_input))
    47    return True if not ((not first_input) and (not second_input)) else False
    

    the terminal still shows green. A reminder that I can return the Logical Negation (not) of an if statement that returns False like I did with Logical NAND

  • not” appears 3 times in this statement, I want to change that. I “multiply” it by each thing inside the parentheses to try to make the statement simpler

    45def logical_disjunction(first_input, second_input):
    46    return (not not first_input) (not and) (not not second_input)
    47    return not ((not first_input) and (not second_input))
    

    the terminal shows SyntaxError

    SyntaxError: invalid syntax
    
  • I add it to the list of Exceptions seen in test_truth_table.py

    76# Exceptions seen
    77# AssertionError
    78# AttributeError
    79# TypeError
    80# SyntaxError
    
  • I fix the failing line by changing “not and” to “or” in truth_table.py

    45def logical_disjunction(first_input, second_input):
    46    return (not not first_input) or (not not second_input)
    47    return not ((not first_input) and (not second_input))
    

    the test passes

  • I remove “not not” from the return statement because it cancels out

    45def logical_disjunction(first_input, second_input):
    46    return first_input or second_input
    47    return (not not first_input) or (not not second_input)
    

    the test is still green. Do two nots make a right?

  • I remove the second return statement

    45def logical_disjunction(first_input, second_input):
    46    return first_input or second_input
    

    green everywhere

Logical Disjunction aka or returns

  • first_input or second_input

  • False only when the two inputs are False


review

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

and

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


code from the chapter

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


what is next?

Would you like test even more binary operations?


please leave a review