import timeit
import numpy as np

def mse_scalar_for(x, y, w):
    N = len(y)
    sum_sq_err = 0
    for i in range(N):
        err = y[i] - w*x[i]
        sum_sq_err += err*err
    mse = sum_sq_err / N
    return mse

def mse_scalar_numpy(x, y, w):
    N = len(y)
    err = y - w*x
    sum_sq_err = err.T @ err
    mse = sum_sq_err / N
    return mse

def mse_vector_for(X, y, w):
    N, M = X.shape
    sum_sq_err = 0
    for i in range(N):
        wx = 0
        for j in range(M):
            wx += w[j]*X[i,j]
        err = y[i] - wx
        sum_sq_err += err*err
    mse = sum_sq_err / N
    return mse

def mse_vector_numpy(X, y, w):
    N = len(y)
    err = y - X @ w
    sum_sq_err = err.T @ err
    mse = sum_sq_err / N
    return mse

N = 1000000

x = np.random.uniform(-10, 10, (N,1))
y = np.random.uniform(-10, 10, (N,1))
w = 3

print('Scalar, numpy:')
print(mse_scalar_numpy(x, y, w))

print('Scalar, for loop:')
print(mse_scalar_for(x, y, w))


N = 1000
M = 900

X = np.random.uniform(-10, 10, (N, M))
y = np.random.uniform(-10, 10, (N,1))
w = np.random.uniform(-10, 10, (M,1))

print('Vector, numpy:')
print(mse_vector_numpy(X, y, w))

print('Vector, for loop:')
print(mse_vector_for(X, y, w))

print('Done')


