import numpy as np
import time

x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]

### CLASSIC DOT PRODUCT OF VECTORS IMPLEMENTATION ###
tic = time.process_time()
dot = 0
for i in range(len(x1)):
    dot += x1[i] * x2[i]
toc = time.process_time()
print (1.1, "dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")

### CLASSIC OUTER PRODUCT IMPLEMENTATION ###
tic = time.process_time()
outer = np.zeros((len(x1), len(x2))) # we create a len(x1)*len(x2) matrix with only zeros
for i in range(len(x1)):
    for j in range(len(x2)):
        outer[i, j] = x1[i] * x2[j]
toc = time.process_time()
print (1.2, "outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")

### CLASSIC ELEMENTWISE IMPLEMENTATION ###
tic = time.process_time()
mul = np.zeros(len(x1))
for i in range(len(x1)):
    mul[i] = x1[i] * x2[i]
toc = time.process_time()
print (1.3, "elementwise multiplication = " + str(mul) + "\n ----- Computationtime=" + str(1000*(toc-tic)) + "ms")

### CLASSIC GENERAL DOT PRODUCT IMPLEMENTATION ###
W = np.random.rand(3,len(x1)) # Random 3*len(x1) numpy array tic = time.process_time()
gdot = np.zeros(W.shape[0])
for i in range(W.shape[0]):
    for j in range(len(x1)):
        gdot[i] += W[i, j]*x1[j]
toc = time.process_time()
print (1.4, "gdot = " + str(gdot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")




### VECTORIZED DOT PRODUCT OF VECTORS ###
tic = time.process_time()
dot = np.dot(x1, x2)
toc = time.process_time()
print (2.1, "dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")
### VECTORIZED OUTER PRODUCT ###
tic = time.process_time()
outer = np.outer(x1, x2)
toc = time.process_time()
print (2.2, "outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")
### VECTORIZED ELEMENTWISE MULTIPLICATION ###
tic = time.process_time()
mul = np.multiply(x1, x2)
toc = time.process_time()
print (2.3, "elementwise multiplication = " + str(mul) + "\n -----Computationtime=" + str(1000*(toc-tic)) + "ms")
### VECTORIZED GENERAL DOT PRODUCT ###
tic = time.process_time()
dot = np.dot(W, x1)
toc = time.process_time()
print (2.4, "gdot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc-tic)) + "ms")



def L1(yhat, y):
    loss = sum(abs(y - yhat))
    return loss
yhat = np.array([.9, 0.2, 0.1, .4, .9])
y = np.array([1, 0, 0, 1, 1])
print(3, "L1 = " + str(L1(yhat,y)))

def L2(yhat, y):
    loss = np.dot(y-yhat, y-yhat)
    return loss
print(4, "L2 = " + str(L2(yhat, y)))