Day 3: Advanced Conditionals
CMSC 201: Conditionals P2
Agenda:
Goal: Understand booleans and conditions VERY well; be able to write an if statement for anything! Maybe have some fun :)
Also my email is: sdonahue@umbc.edu (Shane Donahue)
HW1
Still exists. Still due 2024-09-13 23:59.99999.... Any more questions?
HW1"Fun": Compsci "laws"
People in computer science love making up or referencing "laws" (and effects, and rules, and such). Here are some of my favorites:
Who cares (about advanced conditionals)?
Advanced conditionals (and logic gates) make up literally all of computing! And leads to one of the hardest problems in computer science. But this example code is going to be a bit more boring... Let's do some programming interview practice problems! (FizzBuzz)
Advanced Conditionals
Review: Conditionals take an action based on a condition. Think: IF this, then THAT.
if temperature > 70: print("summer clothes!")
if temperature > 70: print("summer clothes!") else: print("maybe wear a jacket")
if temperature > 70: print("summer clothes!") elif hvac_working: print("who cares, technology saves us from the environment") else: print("maybe wear a jacket")
The None type
Python has a special "type" or object: None. It's the closest thing Python has to a NULL or empty value. It represents a value of nothingness. It is always considered false (False).
Truthy/Falsy values
Python tries to be helpful by having things that are not booleans still evaluate to true or false.
- ints and floats: anything except 0 is true
- string: any non-empty string
- None: always false
- ...not None: always true?
Truthy/falsy values only happen in a "boolean context". (What does that mean? Whenever it's used by itself in some conditonal.)
# Not truthy/falsy if 5 == int(input()): print("Nice number!")
# Truthy/falsy! if int(input()): print("Nice number!")
Negation
Want the opposite of something? Use not!
not True == False
if not 100 >= 1000: print("100 is not >= 1000!")
Combining conditions
Python keywords and and or let us combine multiple conditionals into one statement.
Truth tables
AND | True | False |
---|---|---|
True | TRUE | FALSE |
False | FALSE | FALSE |
OR | True | False |
---|---|---|
True | TRUE | TRUE |
False | TRUE | FALSE |
if temperature > 70 and ac_broken == True: print("summer clothes!")
We can group these with parentheses. Normally they are evaluated left to right.
True and False
True and (False or True)
De Morgan's law
When you negate something, there is an equivalence rule you can use (known as De Morgan's laws). Sometimes this is useful for simplifying expressions. It is:
not (A or B) --(is equivalent to)--> (not A) and (not B) not (A and B) --(is equivalent to)--> (not A) or (not B)
Some intuition: A AND B will only be if both A or B and true. To negate this (NOT AND), we need to have either A or B be true-- but not both! (Think: we're inverting the table.)
AND | True | False |
---|---|---|
True | TRUE | FALSE |
False | FALSE | FALSE |
NOT AND (NAND) | True | False |
---|---|---|
True | FALSE | TRUE |
False | TRUE | TRUE |
Let's simplify this:
if not (user_input > 10 and user_input % 2 == 0) \ and user_input != 12: print("I like that number!")
if user_input <= 10 or user_input % 2 != 0 \ and user_input != 12: print("I like that number!")
Short circuiting
When the outcome of a condition with multiple parts is obvious, Python won't bother evaulating unnecessary parts.
Why are these two code blocks different?
temperature = 60 if temperature > 70 and ac_broken == True: print("summer clothes!")
temperature = 80 if temperature > 70 and ac_broken == True: print("summer clothes!")
Combining our Type lore knowledge: What would this print?
if print("condition one") and print("condition two"): print("wow!")
What about this one:
if (print("condition one") or not print("condition two")) \ and print("condition three") \ and not print("condition four"): print("wow!")
Speaking of circuits...
AND, OR, and NOT gates make up all of computation. Using just those three logic gates gates, you can do anything with a computer. CMPE people are destined to learn all about that in gratuitous detail... but the rest of us can too! (Recommended resources if you're interested: nand2tetris and Code by Charles Petzold).
Theoretical CS time! (now former Python experience people can't say nothing in CMSC201 was new...)
Boolean satisfiability problem...
This example is pretty obnoxious:
if (print("condition one") or not print("condition two")) \ and print("condition three") \ and not print("condition four"): print("wow!")
What if you we replaced all the conditions with variables?
if (A or not B) \ and C \ and not D: print("wow!")
What True or False values do these variables need to have in order to execute the if body? Simple sounding question, right?
Is NP-Complete 😱😱😱😱
It gets difficult quick:
if (A or not B) \ and C \ and Z or not Y \ or E or W and Z \ or (Z and A and C or X): print("wow!")
The boolean satisfiability problem is the first problem proven to be NP-complete (non-polynomial) (Cook-Levin). Put another way: there is no efficient solution.
If you can find an efficient solution to this problem (in "polynomial", or efficient, time), you solve basically every hard computer science problem. This is an active area of research (SAT solvers)! And it's very cool.
SAT solvers can solve SAT problems! Very slowly. This is code for z3
, the most popular SAT solver. Here is our first example before:
(declare-const A Bool) (declare-const B Bool) (declare-const C Bool) (declare-const D Bool) (assert (and (and (or A (not B)) C) (not D))) (check-sat) (get-model)
sat ( (define-fun A () Bool false) (define-fun D () Bool false) (define-fun B () Bool false) (define-fun C () Bool true) )
Brain expansion: let's prove DeMorgan's law with z3!
(declare-const a Bool) (declare-const b Bool) (define-fun demorgan () Bool (= (and a b) (not (or (not a) (not b))))) (assert (not demorgan)) (check-sat)
Outputs, "proving" by lack of counter-example:
unsat
Takeaway: simple problems can very complex very quickly. P problems are "easy" and NP are "hard". Computer science is cool?
Some code and preview of next time: Loops and lists!
Loops let you do something as many times as you want! And lists let you store lists of things.
Trial by FizzBuzz... Legendary interview screening question.
[...] Replace any number divisible by three with the word "fizz", and any number divisible by five with the word "buzz", and any number divisible by both three and five with the word "fizzbuzz". (via Wikipedia).
My solution:
for x in range(1, 101): if x % 3 == 0: print("Fizz", end="") if x % 5 == 0: print("Buzz", end="") if not (x % 3 == 0) and not (x % 5 == 0): print(x, end="") print()
Can we do it with elif?
Can we do it with a list?