BONUS

Below is my explanation of DeMorgan’s Law for the bonus

DeMorgan’s Law is a rule in boolean algebra that helps simplify logical expressions, by distributing NOT or OR operations.

The law states:

NOT (A AND B) is the same as (NOT A) OR (NOT B) NOT (A OR B) is the same as (NOT A) AND (NOT B)

It is especially helpful when working with simple boolean logic.

Here, the key points are that:

  1. Helps rewrite negative conditions with clarity
  2. Simplifies expressions in code and algebra
  3. Applicable in both math and computer science

An example of a DeMorgan’s Law demonstration is:

A = True
B = False

print(not (A and B) == (not A or not B))
print(not (A or B) == (not A and not B))
True
True

Mathematical Expressions

Popcorn Hack 1

a = int(input("Enter first number: "))
b = int(input("Enter second number: "))

Add = a + b
Subtract = a - b
Multiply = a * b
Divide = a / b if b != 0 else 'undefined'

print(f"Add: {Add}")
print(f"Subtract: {Subtract}")
print(f"Multiply: {Multiply}")
print(f"Divide: {Divide}")

Add: 3
Subtract: -1
Multiply: 2
Divide: 0.5

Popcorn Hack 2

def fibonacc(n):
    if n <= 0:
        return "invalid"
    elif n == 1:
        return 0
    elif n == 2:
        return 1
    else:
        return fibonacc(n - 1) + fibonacc(n - 2)


n = int(input("To what iteration do you want to calculate the Fibonacci number? "))
print(f"The {n}th Fibonacci number is: {fibonacc(n)}")
The 20th Fibonacci number is: 4181

Homework Hack 1

I don’t have access to the numpy module so this will not work.

#Python: Fibonacci Using Matrix Exponentiation

import numpy as np
import logging
import sys

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(message)s')

def matrix_multiply(A, B):
    """
    Perform matrix multiplication between two numpy arrays A and B.
    """
    logging.debug(f"Multiplying matrices:\n{A}\n{B}")
    return np.dot(A, B)

def matrix_power(M, power):
    """
    Raise matrix M to the specified power using binary exponentiation.
    """
    if power < 0:
        raise ValueError("Power must be a non-negative integer.")
    
    result = np.identity(len(M), dtype=object)
    logging.debug(f"Initial identity matrix:\n{result}")
    
    while power > 0:
        if power % 2 == 1:
            result = matrix_multiply(result, M)
            logging.debug(f"Result after multiplying by M:\n{result}")
        M = matrix_multiply(M, M)
        logging.debug(f"Matrix M squared:\n{M}")
        power = power // 2
        logging.debug(f"Power reduced to: {power}")
    
    return result

def fibonacci_matrix(n):
    """
    Calculate the nth Fibonacci number using matrix exponentiation.
    """
    if not isinstance(n, int):
        raise TypeError("Input must be an integer.")
    if n < 0:
        raise ValueError("Fibonacci number is not defined for negative integers.")
    elif n == 0:
        return 0
    elif n == 1:
        return 1
    
    F = np.array([[1, 1],
                  [1, 0]], dtype=object)
    
    result = matrix_power(F, n-1)
    
    logging.info(f"Matrix raised to power {n-1}:\n{result}")
    
    return result[0][0]

def validate_input(user_input):
    """
    Validate the user input to ensure it's a non-negative integer.
    """
    try:
        value = int(user_input)
        if value < 0:
            raise ValueError
        return value
    except ValueError:
        raise ValueError("Please enter a valid non-negative integer.")

def main():
    """
    Main function to execute the Fibonacci calculation.
    """
    try:
        user_input = input("Enter the position of the Fibonacci number you want to calculate: ")
        n = validate_input(user_input)
        fib_n = fibonacci_matrix(n)
        print(f"Fibonacci number at position {n} is: {fib_n}")
    except ValueError as ve:
        logging.error(ve)
    except Exception as e:
        logging.error(f"An unexpected error occurred: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()
---------------------------------------------------------------------------

ModuleNotFoundError                       Traceback (most recent call last)

Cell In[12], line 3
      1 #Python: Fibonacci Using Matrix Exponentiation
----> 3 import numpy as np
      4 import logging
      5 import sys


ModuleNotFoundError: No module named 'numpy'

Booleans

Popcorn Hack 1

def is_raining():
    return True

def wearing_boots():
    return False

if is_raining():
    print("It is raining, so I must be wearing my boots:", wearing_boots())
else:
    print("It is not raining, we cannot conclude anything about my boots.")

if not wearing_boots():
    print("I am not wearing my boots, therefore it must not be raining:", not is_raining())
else:
    print("I am wearing my boots, we cannot conclude anything about the rain.")
It is raining, so I must be wearing my boots: False
I am not wearing my boots, therefore it must not be raining: False

Homework Hack 1

I did not do the Java hacks because we’re supposed to do Javascript

def AND(A, B):
    return A and B

def OR(A, B):
    return A or B

def NOT(A):
    return not A

print("A     B | AND | OR | NOT A")
print("---------------------------")
for A in [True, False]:
    for B in [True, False]:
        print(f"{A:<5} {B:<5} | {AND(A, B):<4} | {OR(A, B):<3} | {NOT(A)}")
A     B | AND | OR | NOT A
---------------------------
1     1     | 1    | 1   | False
1     0     | 0    | 1   | False
0     1     | 0    | 1   | True
0     0     | 0    | 0   | True