# imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
from IPython.display import (
    display, 
    Math, 
    Latex
)
%matplotlib inline

df = pd.read_csv("ex1data1.txt", header=None)
df.columns = columns=['x', 'y']

"""
Explanation: Linear regresion - part 1
One variable
End of explanation
"""


df.plot(kind='scatter', x='x', y='y')

"""
Explanation: Visualise data
End of explanation
"""


def h(theta, x):
    return theta[0] + theta[1]*x

theta = [-10, 1.7]
df.plot(kind='scatter', x='x', y='y')
x = np.linspace(5, 25, 100)
plt.plot(
    x,
    h(theta, x),
    c='r'
)

"""
Explanation: We want create a function $h_{\theta}(x) = \theta_0 + \theta_1 x$ which will predict y for new unseen x.
Example $h_{\theta}(x) = 1 + 1.7x$
End of explanation
"""


def J(h, theta, x, y):
    m = len(y)
    return (1./(2*m) * np.sum((h(theta, x[i]) - y[i])**2 for i in xrange(m)))

display(Math(r"\Large J(\theta) = %.4f" % J(h, theta, df.x, df.y)))

"""
Explanation: Is it a good $h_{\theta}(x)$?
How can we measure how good is $h_{\theta}(x)$?
Cost Function $J(\theta)$
We want to find such $\hat\theta$ that it minimize $J(\theta)$:
$$\theta = \left[\begin{array}{c} \theta_0 \ \theta_1 \end{array}\right] \in \mathbb{R}^2 \quad J:\mathbb{R^2} \rightarrow \mathbb{R}$$
$$ \hat\theta = \underset{{\theta \in \mathbb{R}^{2}}}{\operatorname{arg\,min}} J(\theta)$$
$$\begin{array}{rll} J(\theta) &=& \dfrac{1}{2m} \displaystyle\sum_{i=1}^{m} \left(h_{\theta}(x^{(i)})  - y^{(i)}\right)^2  \
& = & \dfrac{1}{2m} \displaystyle \sum_{i=1}^{m} \left(\theta_0 + \theta_1 x^{(i)}  - y^{(i)}\right)^2
\end{array} $$
where $m$ is # of examples in train data
End of explanation
"""


def errorSurface(x, y):
    pX = np.arange(-10,10.1,0.1)
    pY = np.arange(-1,4.1,0.1)
    pX, pY = np.meshgrid(pX, pY)
    
    pZ = np.matrix([[J(h,[t0, t1], x, y) 
                     for t0, t1 in zip(xRow, yRow)] 
                     for xRow, yRow in zip(pX, pY)])
    
    fig = plt.figure(figsize=(16*.6,9*.6))
    ax = fig.add_subplot(111, projection='3d')
    plt.subplots_adjust(left=0.0, right=1, bottom=0.0, top=1)
    ax.plot_surface(pX ,pY, pZ, rstride=2, cstride=8, linewidth=0.5,
                    alpha=0.5, cmap='jet', zorder=0,
                    label=r"$J(\theta)$")
    ax.view_init(elev=20., azim=-150)

    ax.set_xlim3d(-10, 10);
    ax.set_ylim3d(-1, 4);
    ax.set_zlim3d(-100, 800);

    N = range(0,800,20)
    plt.contour(pX, pY, pZ, N, zdir='z',offset=-100, cmap='coolwarm', alpha=1)
    
    ax.set_zlabel(r"$J(\theta)$", fontsize="15")
    ax.set_xlabel(r"$\theta_0$", fontsize="15")
    ax.set_ylabel(r"$\theta_1$", fontsize="15")
    ax.margins(0,0,0)
    fig.tight_layout()
    return fig, ax
fig, ax = errorSurface(df.x, df.y)

"""
Explanation: Is it a big number or small? Is it a minimum?
End of explanation
"""


