import numpy as np
from my_logistic_regression import MyLogisticRegression

def newton(dataset, w_init, bias=True):
    """Implementation of the newton method with linesearch without privacy constraints

        dataset = dataset
        w_init = initialization point

        output is the model parameter
    """
    X, y = dataset
    if bias:
        X = np.hstack((np.ones(shape=(np.shape(X)[0], 1)), X))
    lr = MyLogisticRegression(X, y, reg=1e-9)
    w = w_init
    for _ in range(10):
        H = lr.hess(w)
        dir = np.linalg.solve(H, lr.grad(w))
        step_size = backtracking_ls(lr, dir, w)
        w = w - step_size * dir
    if lr.loss_wor(w) < lr.loss_wor(w_init):
        w_out = w
    else:
        w_out = w_init
    return w_out


def backtracking_ls(lr,dir, w_0, alpha=0.4, beta=0.95):
    """Implementation of backtracking line search

        lr = logistic regression
        dir = the "noisy" gradient direction
        w_0 = current point
        alpha and beta tradeoff the precision and complexity of the linesearch

        output is an (close to) optimal stepsize
    """
    t = 100
    while lr.loss(w_0 - t*dir) >= lr.loss(w_0) - t*alpha* np.dot(dir, lr.grad(w_0)):
        t = beta * t
        if t < 1e-6:
            break
    return t
