import time
import matplotlib.pyplot as plt
import numpy as np
# Runtime complexity

def sum_up(n):
    total = 0
    for i in range(1, n + 1):
        total = total + i
    return total

# Assume: if n = 1, let's say it takes 1 second to run the function
# if n = 2, how long do you expect this function to run?
    # we expect it takes around 2 seconds because we have to
    # double the number of loop iterations
# if n = 4: 4 seconds

# Let's define f(n) to be # of seconds for sum_up to complete on n
# Let's also it takes 15 seconds for the first assignment statement
# and the return statement together.
# f(n) = n + 15

# However, we care only about how it grows with the input,
#  which is always linear
# We use a notation called 'Big-O' to describe the running time
# O(n + 15) = O(n) 
# The runtime complexity of sum_up(n) is O(n)

nums = [10000, 20000, 30000, 40000]
times = []
for num in nums:
    start_time = time.time()
    sum_up(num)
    end_time = time.time()
    
    times.append(end_time - start_time)
    
plt.plot(np.arange(len(times)), times)
plt.show()

# We say the runtime for sum_up(n) grows linearly

# Let's try another function
def sum_up2(n):
    total = 0
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            total = total + i
    return total

# If n = 1, it takes 1 second
# If n = 2, it takes 

# Let's say it takes 30 seconds for the assignment statement at the top and the return statement
# f(n) = n^2 + 30
# What is the Big-O? O(n^2 + 30) = O(n^2)
# Big-O only cares about how the function grows, not the 30 seconds
#  that are going to happen regardless at every run of the function.

nums = [100, 200, 300, 400]
times = []
for num in nums:
    start_time = time.time()
    sum_up2(num)
    end_time = time.time()
    
    times.append(end_time - start_time)
    
plt.plot(np.arange(len(times)), times)
plt.show()


# O(n^2 + n + 1) = O(n^2)
# Big-O cares about the run time over large n




