import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns

"""
Explanation: Numpy Exercise 2
Imports
End of explanation
"""


def np_fact(n):
    """Compute n! = n*(n-1)*...*1 using Numpy."""
    if n>0:
        array = np.arange(1,n+1) #The arrange function counts by 1 for the range of the array.  With a factorial that range is 1 to n
        x = np.cumprod(array) #This multiplies the values of the array
        y = x[n-1]
    else:
        y = 1 #I couldn't get a function to work with the factorial of 0, so I made it a special case
    return y
#print np_fact(6)        
    #raise NotImplementedError()

assert np_fact(0)==1
assert np_fact(1)==1
assert np_fact(10)==3628800
assert [np_fact(i) for i in range(0,11)]==[1,1,2,6,24,120,720,5040,40320,362880,3628800]

"""
Explanation: Factorial
Write a function that computes the factorial of small numbers using np.arange and np.cumprod.
End of explanation
"""


def loop_fact(n):
    """Compute n! using a Python for loop."""
    if n > 0:  
        n = n+1 #To offset the first step of the while loop
        x = 1
        while n > 1:
            n = n - 1
            x = n*x #Multiply n and subtract 1 from n
    else: #Special case for 0!
        x = 1
    return x
print loop_fact(5)
    #raise NotImplementedError()

assert loop_fact(0)==1
assert loop_fact(1)==1
assert loop_fact(10)==3628800
assert [loop_fact(i) for i in range(0,11)]==[1,1,2,6,24,120,720,5040,40320,362880,3628800]

"""
Explanation: Write a function that computes the factorial of small numbers using a Python loop.
End of explanation
"""


%timeit -n1 -r1 np_fact(100000) #I didn't get the expected result until I called larger numbers
%timeit -n1 -r1 loop_fact(100000)
#raise NotImplementedError()

"""
Explanation: Use the %timeit magic to time both versions of this function for an argument of 50. The syntax for %timeit is:
python
%timeit -n1 -r1 function_to_time()
End of explanation
"""


