import numpy as np

x = np.random.randn(1000)

"""
Explanation: Make My Python Code Faster
John Parejko, Phil Marshall and Your Name Here>
This notebook demonstrates some ways to make your python code go faster.
Step 1: Profile and improve your code
Because how can you optimize something if you haven't first evaluated it?
Step 2: Parallelize your code
Because you probably own more than one CPU.
Profiling
End of explanation
"""


%timeit np.power(x,2)

%timeit x**2

import cProfile
import pstats

def square(x):
    for k in range(1000):
        sq = np.power(x,2)
        sq = x**2
        sq = x*x
    return 

log = 'square.profile'
cProfile.run('square(x)',filename=log)

stats = pstats.Stats(log)
stats.strip_dirs()

stats.sort_stats('cumtime').print_stats(20)

# OK - so all the time is being taken by the function "square".
# We need to re-write with the lines separated into functions - 
# which is a better way to code anyway.

def bettersquare(x):
    
    def powersquare(x):
        return np.power(x,2)
    def justsquare(x):
        return x**2
    def selfmultiply(x):
        return x*x
    
    for k in range(1000):
        sq = powersquare(x)
        sq = justsquare(x)
        sq = selfmultiply(x)
    
    return 

log = 'bettersquare.profile'
cProfile.run('bettersquare(x)',filename=log)

stats = pstats.Stats(log)
stats.strip_dirs()

stats.sort_stats('cumtime').print_stats(20)

# Much better - you can see the cumulative time spent in each function.

# We could also try the line profiler, from rkern on GitHub.

!pip install --upgrade line_profiler

"""
Explanation: Inline Timing
Use %timeit in the notebook, and other commands in functions... Need examples of these!
End of explanation
"""


