# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

def rectangle(f, a, b, N):
    h = (b-a) / N
    d = np.arange(a, b, h) + h/2
    return h * np.sum(f(d))

def trapez(f, a, b, N):
    h = (b-a) / N
    y = f(np.arange(a, b+h, h))
    y[0] /= 2
    y[-1] /= 2
    return h * np.sum(y)

def simpson(f, a, b, N):
    h = (b-a) / N
    d = np.arange(a, b+h, h)
    ar = f(d[0]) + f(d[-1])
    au = np.sum(f(d[1:-1:2]))
    ag = np.sum(f(d[2:-2:2]))
    return h * (ar + 4*au + 2*ag) / 3

test_functions = {
    'x^3 - x^2' : (lambda x: x**3-x**2,
                   lambda x: x**4/4-x**3/3),
    'sin^2 x'   : (lambda x: np.sin(x)**2,
                   lambda x: x/2-np.sin(x)*np.cos(x)/2),
    # divide by zero in [0, 1] (log(0), duh...)
    #  'x * log(x)': (lambda x: x*np.log(x),
    #                 lambda x: x**2*np.log(x)/2-x**2/4),
    'x * e^{-x}': (lambda x: x*np.exp(-x),
                   lambda x: -(x+1)*np.exp(-x)),
    'fn' : (lambda x: np.exp(-x)*np.sin(x),
            lambda x: -np.exp(-x)*np.sin(x)/2-np.exp(-x)*np.cos(x)/2)
}

A, B = 0., 1.
#  M = 25
#  Ns = np.arange(2, 2*M+2, 2)
Ns = 2**np.arange(0, 13)
M = len(Ns)
L = len(test_functions)

res = {
    'rectangle' : (rectangle, np.zeros((M, L)), np.zeros(M)),
    'trapez'    : (trapez, np.zeros((M, L)), np.zeros(M)),
    'simpson'   : (simpson, np.zeros((M, L)), np.zeros(M))
}

fig, ax = plt.subplots()
ax.set_xscale('log')
ax.set_yscale('log')

for ni, (integ, resarr, errarr) in res.items():
    for i, (nf, (f, F)) in enumerate(test_functions.items()):
        resarr[:,i] = np.array([integ(f, A, B, n) for n in Ns])
        print(ni, nf, np.min(resarr[:,i]))
        resarr[:,i] = np.abs(resarr[:,i] - (F(B)-F(A)))
    errarr = np.mean(resarr, axis=1)
    ax.plot(Ns, errarr, label=ni)

plt.legend()


from sympy.ntheory import count_digits, digits, is_palindromic

def test_digits():
    assert all([digits(n, 2)[1:] == [int(d) for d in format(n, 'b')]
                for n in range(20)])
    assert all([digits(n, 8)[1:] == [int(d) for d in format(n, 'o')]
                for n in range(20)])
    assert all([digits(n, 16)[1:] == [int(d, 16) for d in format(n, 'x')]
                for n in range(20)])
    assert digits(2345, 34) == [34, 2, 0, 33]
    assert digits(384753, 71) == [71, 1, 5, 23, 4]
    assert digits(93409) == [10, 9, 3, 4, 0, 9]
    assert digits(-92838, 11) == [-11, 6, 3, 8, 2, 9]

def test_count_digits():
    assert count_digits(55, 2) == {1: 5, 0: 1}
    assert count_digits(55, 10) == {5: 2}
    n = count_digits(123)
    assert n[4] == 0 and type(n[4]) is int

def test_is_palindromic():
    assert is_palindromic(-11)
    assert is_palindromic(11)
    assert is_palindromic(0o121, 8)
    assert not is_palindromic(123)


import pandas as pd
import numpy as np
import matplotlib.pyplot as plot
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

source_url = ("https://github.com/SerkanKorkusuz/Machine-Learning/blob/master/polynomial-regression.csv")
myData = pd.read_csv(source_url, header = 0, prefix = "V", sep = ";")
print(myData)

att = myData.araba_fiyat.values.reshape(-1,1)
label = myData.araba_max_hiz.values.reshape(-1,1)
print(att)
print(label)

plot.scatter(att, label)
plot.xlabel("Price of Car")
plot.ylabel("Velocity")
plot.show()

#trying to execute linear regression
linear_model = LinearRegression()
my_model = linear_model.fit(att, label)

#print(my_model.predict([[0]]))
#print(my_model.intercept_)
#print(my_model.coef_)
#print(my_model.predict([[15000]]))

plot.scatter(att,label)
attX=np.linspace(0, 3000, 30).reshape(-1,1)
plot.plot(attX, my_model.predict((attX)))
plot.xlabel("Price of Car")
plot.ylabel("Velocity")
plot.show()
#noticed that it is not a good approach to implement linear regression method on this problem

#So trying Polynomialfatures seems better to fit on the graph.
polynomial_model = PolynomialFeatures(degree=4)
x_polynomial = polynomial_model.fit_transform(att)
linear_model2 = LinearRegression()
linear_model2.fit(x_polynomial, label)

plot.scatter(att,label)
labelY = linear_model2.predict(x_polynomial)
plot.plot(att, labelY)
plot.xlabel("Price of Car")
plot.ylabel("Velocity")
plot.show()

#with numpy, I think it gives better result
attForNumpy = myData.araba_fiyat.values
labelForNumpy = myData.araba_max_hiz.values

polyRegress =np.poly1d(np.polyfit(attForNumpy, labelForNumpy, 4))

plot.scatter(att,label)
plot.plot(attX, polyRegress(attX))
plot.xlabel("Price of Car")
plot.ylabel("Velocity")
plot.show()

print(polyRegress(10000))


import numpy as np

from .utils import nans_in_same_positions

def se(arr1: np.ndarray, arr2: np.ndarray) -> np.ndarray:
    """
    Computes SE – squared error
    """
    return (arr1 - arr2) ** 2

def ae(arr1: np.ndarray, arr2: np.ndarray) -> np.ndarray:
    """
    Computes AE – absolute error
    """
    return np.abs(arr1 - arr2)

def is_(y: np.ndarray, u: np.ndarray, l: np.ndarray, a=0.05) -> np.ndarray:
    """
    Computes IS (Interval Score), used in M4 competition.

    :param y: predicted mean values
    :param u: prediction interval upper bound
    :param l: prediction interval lower bound
    :return: IS
    """
    assert nans_in_same_positions(y, u, l), "Arrays have NaNs in different positions"

    ml = u - l

    # NaNs can be in the dataset and this will cause lt/gt comparisons to raise a warning
    with np.errstate(invalid="ignore"):
        p1 = 2 / a * np.where(y < l, l - y, 0)
        p2 = 2 / a * np.where(y > u, y - u, 0)

    return ml + p1 + p2

def mse(arr1: np.ndarray, arr2: np.ndarray) -> np.ndarray:
    return se(arr1, arr2).mean()

def mae(arr1: np.ndarray, arr2: np.ndarray) -> np.ndarray:
    return ae(arr1, arr2).mean()

def mis(y: np.ndarray, u: np.ndarray, l: np.ndarray, a=0.05) -> np.ndarray:
    """
    Computes MIS (Mean Interval Score), used in M4 competition. Lower = better.

    Resources:
        - https://www.m4.unic.ac.cy/wp-content/uploads/2018/03/M4-Competitors-Guide.pdf
        - https://stats.stackexchange.com/questions/194660/forecast-accuracy-metric-that-involves-prediction-intervals

    :param y: predicted mean values
    :param u: prediction interval upper bound
    :param l: prediction interval lower bound
    :return: IS
    """
    return is_(y, u, l, a=a).mean()

def smape(a, b):
    """
    From the M4 repo

    Calculates sMAPE
    :param a: actual values
    :param b: predicted values
    :return: sMAPE
    """
    a = np.reshape(a, (-1,))
    b = np.reshape(b, (-1,))
    return np.mean(2.0 * np.abs(a - b) / (np.abs(a) + np.abs(b))).item()

def mase(insample, y_test, y_hat_test, freq):
    """
    From the M4 repo

    Calculates MAsE
    :param insample: insample data
    :param y_test: out of sample target values
    :param y_hat_test: predicted values
    :param freq: data frequency
    :return:
    """
    y_hat_naive = []
    for i in range(freq, len(insample)):
        y_hat_naive.append(insample[(i - freq)])

    masep = np.mean(abs(insample[freq:] - y_hat_naive))

    return np.mean(abs(y_test - y_hat_test)) / masep


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 16 13:50:20 2020

@author: joaovitor
"""

import time
import multiprocessing as mp
import numpy as np
from scipy import signal as ss
from matplotlib import pyplot as plt
#import sounddevice as sd

# 1. Variáveis e álgebra
fs = 44100  # taxa de amostragem [Hz]
dt = 1/fs  # intervalo de tempo entre amostras [s]
nsamp = 2**9  # número total de amostras [-]
tlen = (nsamp - 1) / fs  # duração do sinal [s]

print (f"{fs=}    {dt=}\n{nsamp=}    {tlen=}")

b = 0  # Número de semitons  [-]
c = 343  # Velocidade de propagação do som no ar [m/s]
f = 440 * 2**(b/12)  # frequência [Hz]
T = 1/f  #  Período [s]
l = c / f  # comprimento de onda [m]

print(f"{c=}    {f=}\n{T=}    {l=}")

omega = 2 * np.pi * f  # frequencia angular [rad/s]
k = 2 * np.pi / l  # número de onda [rad/m]
kl = 1/l

print (f"{omega=}    {k=}    {kl=}")

nmark = 2 * nsamp  # número de marcações no espaço [-]
dx = 1 / nmark  # intervalo entre as marcações [m]

print (f"{nmark=}    {dx=}")

xm = np.linspace(0, 1 - dx, nmark)  # [m] marcações no espaço
ts = np.linspace(0, tlen, nsamp)  # [s] instantes de tempo

cosx = np.exp(k * xm * 1j)
cost = np.exp(-omega * ts * 1j)
"""
Explique o que está sendo calculado nas linhas 59 e 60:

    Escreva aqui

"""

print (f"{xm.shape=}    {cosx.shape=}")
print (f"{ts.shape=}    {cost.shape=}")

fig1, axs = plt.subplots(2, 1)

xlines = []
xlines.append(*axs[0].plot(xm, np.real(cosx)))
xlines.append(*axs[0].plot(xm, np.imag(cosx)))
xlines.append(axs[0].hlines(np.abs(cosx)/(2**0.5), xm[0], xm[-1]))

tlines = []
tlines.append(*axs[1].plot(ts, np.real(cost)))
tlines.append(*axs[1].plot(ts, np.imag(cost)))
tlines.append(axs[1].hlines(np.abs(cost)/(2**0.5), ts[0], ts[-1]))

axs[0].set_title("Gráfico de Re{exp(jkx)} variando no tempo")
axs[0].set_xlabel("Posição [m]")
axs[0].set_ylabel("Amplitude [-]")

axs[1].set_title("Gráfico de Re{exp(-jωt)} variando no espaço")
axs[1].set_xlabel("Tempo [s]")
axs[1].set_ylabel("Amplitude [-]")

fig1.tight_layout()
fig1.canvas.draw()
fig1.show()

def loop(fig1, axs, xlines, tlines, cosx, cost, nsamp):
    from time import time
    tstart = time()
    for n in range(nsamp):
        extn = cosx * cost[n]
        exnt = cosx[2*n] * cost

        xlines[0].set_ydata(np.real(extn))
        xlines[1].set_ydata(np.imag(extn))
        tlines[0].set_ydata(np.real(exnt))
        tlines[1].set_ydata(np.imag(exnt))

        axs[0].draw_artist(axs[0].patch)
        [axs[0].draw_artist(xline) for xline in xlines]

        axs[1].draw_artist(axs[1].patch)
        [axs[1].draw_artist(tline) for tline in tlines]

        fig1.canvas.update()
        fig1.canvas.flush_events()
    tend = time()
    return tend - tstart

tloop = loop(fig1, axs, xlines, tlines, cosx, cost, nsamp)
print(f"{tloop=:.6f}")

def rms(x: np.ndarray):
    return (x**2).mean(axis=0)**0.5

def dB(x: np.ndarray):
    return 20*np.log10(rms(x))

print(f"{rms(np.real(cosx))=:.3f}  {dB(np.real(cosx))=:.1f}")
print(f"{rms(np.real(cost))=:.3f}  {dB(np.real(cost))=:.1f}")

cos_xt = np.zeros((xm.size, ts.size), dtype='complex64')

print (f"{cos_xt.shape=}")

print(f"começo do cálculo de exp(jkx - jωt)")

tstart = time.time()

for n, x in enumerate(xm):

    cos_xt[n, :] = np.exp(1j*k*x - 1j*omega*ts)
    # print(f"{n=}  {x=:.2f}  {dB(np.real(cos_xt[n, :]))=:.1f}",
    #       end=('\t' if (n+1) % 3 else '\n'))  # operador ternário
    #            # expressão diz que:
    #            # Se a sobra inteira da divisão de n por três  for diferente de zero,
    #            # a mensagem deve terminar com uma tabulação.
    #            # Senão, termina com nova linha.

tend = time.time()

print(f"Complete in {tend - tstart:.6f} seconds.")

fig2, ax = plt.subplots(1, 1)
im = ax.pcolormesh(ts, xm, np.real(cos_xt), cmap='jet')

ax.set_title("Gráfico de cos(kx - ωt)")
ax.set_ylabel("Posição [m]")
ax.set_xlabel("Tempo [s]")
fig2.colorbar(im)

fig2.tight_layout()
fig2.show()

fig3, ax3 = plt.subplots(1, 1)
im3 = ax3.pcolormesh(ts, xm, np.imag(cos_xt), cmap='jet')

ax3.set_title("Gráfico de cos(kx - ωt)")
ax3.set_ylabel("Posição [m]")
ax3.set_xlabel("Tempo [s]")
fig3.colorbar(im3)

fig3.tight_layout()
fig3.show()

input("'Enter' para sair.")


'''This script implements a Bayesian network for the Monty Hall problem.
   See http://staff.utia.cas.cz/vomlel/mh-puzzle.html for a description'''

import numpy as np
from pomegranate import *

# The guests initial door selection is completely random
guest = DiscreteDistribution( { 'A': 1./3, 'B': 1./3, 'C': 1./3 } )

# The door the prize is behind is also completely random
prize = DiscreteDistribution( { 'A': 1./3, 'B': 1./3, 'C': 1./3 } )

    # Monty is dependent on both the guest and the prize.
monty = ConditionalProbabilityTable(
            [[ 'A', 'A', 'A', 0.0 ],
             [ 'A', 'A', 'B', 0.5 ],
             [ 'A', 'A', 'C', 0.5 ],
             [ 'A', 'B', 'A', 0.0 ],
             [ 'A', 'B', 'B', 0.0 ],
             [ 'A', 'B', 'C', 1.0 ],
             [ 'A', 'C', 'A', 0.0 ],
             [ 'A', 'C', 'B', 1.0 ],
             [ 'A', 'C', 'C', 0.0 ],
             [ 'B', 'A', 'A', 0.0 ],
             [ 'B', 'A', 'B', 0.0 ],
             [ 'B', 'A', 'C', 1.0 ],
             [ 'B', 'B', 'A', 0.5 ],
             [ 'B', 'B', 'B', 0.0 ],
             [ 'B', 'B', 'C', 0.5 ],
             [ 'B', 'C', 'A', 1.0 ],
             [ 'B', 'C', 'B', 0.0 ],
             [ 'B', 'C', 'C', 0.0 ],
             [ 'C', 'A', 'A', 0.0 ],
             [ 'C', 'A', 'B', 1.0 ],
             [ 'C', 'A', 'C', 0.0 ],
             [ 'C', 'B', 'A', 1.0 ],
             [ 'C', 'B', 'B', 0.0 ],
             [ 'C', 'B', 'C', 0.0 ],
             [ 'C', 'C', 'A', 0.5 ],
             [ 'C', 'C', 'B', 0.5 ],
             [ 'C', 'C', 'C', 0.0 ]], [guest, prize] )

# State objects hold both the distribution, and a high level name.
s1 = State( guest, name="guest" )
s2 = State( prize, name="prize" )
s3 = State( monty, name="monty" )

# Create the Bayesian network object with a useful name
network = BayesianNetwork( "Monty Hall Problem" )

# Add the three nodes to the network
network.add_nodes( [ s1, s2, s3 ] )

# Add transitions which represent conditional dependencies, where the second node is conditionally dependent on the first node (Monty is dependent on both guest and prize)
network.add_edge( s1, s3 )
network.add_edge( s2, s3 )
network.bake()

observations = { 'guest' : 'A' }

# beliefs will be an array of posterior distributions or clamped values for each state, indexed corresponding to the order
# in self.states.
beliefs = network.forward_backward( observations )

# Convert the beliefs into a more readable format
beliefs = map( str, beliefs )

# Print out the state name and belief for each state on individual lines
print "\n".join( "{}\t{}".format( state.name, belief ) for state, belief in zip( network.states, beliefs ) )

observations = { 'guest' : 'A', 'monty' : 'B' }
beliefs = map( str, network.forward_backward( observations ) )
print "\n".join( "{}\t{}".format( state.name, belief ) for state, belief in zip( network.states, beliefs ) )


"""
Module for doing the training
"""

from __future__ import division
import numpy as np
import plot as plot
from numpy import matrix
from numpy import linalg

def train (train_X, train_Y, learning_rate=1, delay=0.2, type="curve"):
    """
    Trains the linear regression model on training data
    Sets the hyperparameter according to the validation data
    and final accuracy on test data
    """

    Theta = np.matrix([0.0, 0.0]).T
    X_matrix = np.matrix(train_X).T
    Y_matrix = np.matrix(train_Y).T

    X_ones = np.ones((X_matrix.shape[0], 1))
    X_matrix = np.hstack((X_ones, X_matrix))

    # normalisation (approximate)
    X_matrix[:,1] = X_matrix[:,1] / 10

    epoch = 0
    eta = learning_rate
    costData = [] # for plotting real time data
    old_cost = 0
    converged = None
    while (True):
        Theta = SGD(X_matrix, Y_matrix, Theta, eta, 20)
        cost = compute_cost(X_matrix, Y_matrix, Theta)
        # print ('Epoch: %d | Cost: %.8f | Theta: %f, %f' % (epoch, cost, Theta[0,0], Theta[1,0]) )
        epoch = epoch + 1
        # Stopping condition
        if (float(Theta[0]) >= 10000 or float(Theta[1]) >= 10000 or (cost is float('inf')) or (epoch > 6 and cost > 1.5 * old_cost)): # 50 iters for the purpose of plotting
            # Diverged
            print ("The model is diverging :(, please change the learning rate :)")
            converged = False
            break
        if (epoch > 5000):
            # too slow
            print ("The learning rate is too small :(. Stopping since taking >5000 epochs. To train faster use eta close to 1...")
            converged = False
            break

        if (epoch > 20 and cost < 1e-5 and abs(old_cost - cost) / old_cost < 0.0001):
            # Change in cost is less than 0.01% => Stop
            converged = True
            break
        costData.append( (float(cost), float(Theta[0, 0]), float(Theta[1,0]) / 10.0) )
        old_cost = cost

    Theta[1,:] = Theta[1,:] / 10
    X_matrix[:,1] = X_matrix[:,1] * 10

    # Print result
    print("Theta0: %.6f | Theta1: %.6f | #Epochs: %d" % (Theta[0], Theta[1], epoch))

    plot.regressionPlot(train_X, train_Y, Theta[1,0], Theta[0,0], Xlabel="Acidity", Ylabel="Density of Wine", marker="bx", fileName="Q1/plots/regression.png")
    animatedDesent(X_matrix, Y_matrix, np.array(costData), delay, converged=converged)
    return Theta

def animatedDesent (X_matrix, Y_matrix, costData, delay=0.2, converged=True):
    """
    Plots the J(Theta) curve in 3D space and contours
    Shows the real time gradient descent
    """
    theta0s = np.linspace(0.3, 1.7, 100)
    theta1s = np.linspace(-0.080, 0.080, 105)

    if (not converged):
        theta0s = np.linspace(-2000, 2000, 100)
        theta1s = np.linspace(-2000, 2000, 100)

    costMatrix = np.zeros((len(theta1s), len(theta0s)))
    for i in range(len(theta1s)):
        for j in range(len(theta0s)):
            Theta = np.matrix([theta0s[j], theta1s[i]]).T
            # compute cost
            costMatrix[i][j] = compute_cost(X_matrix, Y_matrix, Theta)

    plot.costPlot(theta0s, theta1s, costMatrix, costData, delay=delay, Xlabel="Theta 0", Ylabel="Theta 1", Zlabel="Cost")
    plot.contourPlot(theta0s, theta1s, costMatrix, costData, delay=delay, converged=converged, Xlabel="Theta 0", Ylabel="Theta 1", Zlabel="Cost")

def SGD (X, Y, Theta, eta, batch_size=20):
    """
    Computes one epoch of the batch gradient decent algorithm
    """

    Theta = Theta - eta * compute_gradient(X, Y, Theta)

    return Theta

def compute_gradient (X, Y, Theta):
    """
    Computes the cost gradient
    X = m*n
    Y = m*1
    Theta = n*1
    gradient = (1/m) * X_transpose * (X*Theta - Y)
    """
    (m, n) = X.shape
    return (1.0/m) * (X.T) * (X*Theta - Y)

def compute_cost (X, Y, Theta):
    """
    Computes the J(Theta)
    X = m*n
    Y = m*1
    Theta = n*1
    Cost = (1/2m) * (Y-X*Theta)_tran * (Y-X*Theta)
    """

    (m, n) = X.shape
    error = Y - X*Theta
    return (0.5 / m) * error.T * error


# -*- coding: utf-8 -*-
"""
Created on Tue Nov 17 14:28:30 2015

@author: Hanna
"""
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import scipy.optimize as op

def plotData(data):
    pos = data[data[:,2] == 1]
    neg = data[data[:,2] == 0]

    plt.figure()
    plt.scatter(pos[:,0], pos[:,1], c='k', marker='+', s=40, linewidths=2)
    plt.scatter(neg[:,0], neg[:,1], c='y', marker='o', s=40, linewidths=1)
    plt.legend(['y=1', 'y=0'], loc='upper right', scatterpoints=1)
    plt.xlabel("Microchip test 1")
    plt.ylabel("Microchip test 2")
    plt.xlim([-1, 1.5])
    plt.ylim([-0.8, 1.2])

def plotDecisionBdryNonlin(data,X,theta,lambbda):
    plotData(data)
    u = np.linspace(-1,1.5,50)
    v = np.linspace(-1,1.5,50)
    #print(np.shape(theta))
    z = np.zeros((len(u),len(v)))
    for i in range(0, len(u)):
        for j in range(0, len(v)):
            mapped = mapFeature(u[i],v[j],6)
            #print(np.shape(mapped))
            z[i,j] = np.dot(mapped,theta)
    u, v = np.meshgrid(u,v)
    plt.contour(u, v, z.T, [0.0, 0.0], colors = 'Green')
    plt.annotate('—', xy=(1.02, 0.79), color='Green')
    plt.annotate('Decision bdry', xy=(1.11, 0.79),fontsize=10)
    plt.title("lambda=" + str(lambbda))
    plt.savefig("NonLinDecisionBdry_lambda"+str(lambbda)+".pdf")

def mapFeature(X1,X2,degree):
    #maps features X1,X2 into polynomial of degree 6
    #Returns a new feature array with more features, comprising of
    #X1, X2, X1.^2, X2.^2, X1*X2, X1*X2.^2, etc..
    #adds intercept to a new feature matrix
    out = np.ones((np.shape(X1)))
    for i in range(1,degree+1):
        for j in range(0,i+1):
            out=np.hstack((out,(X1**(i-j))*(X2**j)))

    return out

def sigmoid(z):
    #works elementwise for any array z

    return sp.special.expit(z)  # expit(x) = 1/(1+exp(-x)) elementwise for array x

def hypothesis(theta,X):
    #works for any # of features

    return sigmoid(np.dot(X,theta))

def computeCostReg(theta,X,y,lambbda):  # J(theta) with regularization
    #works for any # of features
    m = len(y)
    h = hypothesis(theta,X)
    thetaReg = theta[1:]  #remove the first row(corresponding to theta0) from matrix theta
    cost = (-np.dot(y.T,sp.log(h))-np.dot((1.0-y).T,sp.log(1.0-h)))/m + lambbda*np.dot(thetaReg.T,thetaReg)/(2.0*m)
    #check for nans: can occur since have log
    #if skip this, precision loss occurs
    if np.isnan(cost):
        return np.inf

    return cost

def computeCostDerivReg(theta,X,y,lambbda):  # partial derivatives of J(theta) with regularization
    #works for any # of features
    n = np.shape(X)[1]  # # of features including itercept; in main n is the # of original features
    m = np.shape(X)[0]
    #minimize routine changes dimensions of theta from matrix to vector,
    #i.e from (3,1) to (3,) in this case
    #so need to reshape to original dimensions
    #since in computeCostDeriv routine it is important that theta is matrix
    #does not matter for computeCost routine
    theta = theta.reshape(n,1)
    h = hypothesis(theta,X)
    #initialize matrix of gradients
    gradient = np.zeros(np.shape(theta))
    #use formula for gradient of regularized cost function
    gradient = np.dot(X.T,h-y)/m + lambbda*theta/m
    #do not need to regularize theta0
    #it's computationally more efficient to compute all elements with regularization
    #and then compensate for theta0
    gradient[0,0] = gradient[0,0] - lambbda*theta[0,0]/m

    return gradient.flatten()  # minimize needs vector of gradients not matrix

def predict(theta,X):
    if hypothesis(theta,X) >= 0.5:
        prediction = 1
    else:
        prediction = 0

    return prediction

if __name__ == '__main__':

    data = np.genfromtxt("ex2data2.txt", delimiter=',')
    m = np.shape(data)[0]  # number of examples in training set
    n = np.shape(data)[1]-1  # number of features
    X, y = data[:,:n], data[:,n:]

    #plot data
    plotData(data)
    plt.savefig("scatterData2.pdf")

    #bdry looks nonlinear so enlarge feature space to degree 6 polynomial
    X = mapFeature(X[:,0:1],X[:,1:2],6)

    #initialize theta
    theta = np.zeros((np.shape(X)[1],1))
    #set regularization parameter
    lambbda = 1.0

    #test cost function on initial theta, should be 0.693
    print("cost function for initial theta = ",computeCostReg(theta,X,y,lambbda),"should be 0.693")  # get [[ 0.69314718]]

    #find minimum of cost function using BFGS
    result = op.minimize(computeCostReg, theta, args=(X,y,lambbda), method='BFGS', jac=computeCostDerivReg, options={'disp': True})
    theta = result.x  # note, result.x is a vector so below theta is a vector ie when passed to plotDecisionBdryNonlin
    cost = result.fun
    print("optimal theta =",theta)
    print("optimal cost funstion =",cost)

    #plot decision bdry
    plotDecisionBdryNonlin(data,X,theta,lambbda)

    #try other values of lambda
    lambbdas = [0.0,0.5,100]
    for lambbda in lambbdas:
        theta = np.zeros((np.shape(X)[1],1))
        #using TNC (truncated Newton) gives decision bdry similar to matlab's fmiunc for lambbda=0;
        #using BFGS gives different boundary then fminunc for lambbda=0 although fminunc uses BFGS;
        #for other tested values of lambda there is no difference between TNC and BFGS
        #result = op.minimize(computeCostReg, theta, args=(X,y,lambbda), method='BFGS', jac=computeCostDerivReg, options={'disp': True})
        result = op.minimize(computeCostReg, theta, args=(X,y,lambbda), method='TNC', jac=computeCostDerivReg, options={'disp': True})
        theta = result.x
        plotDecisionBdryNonlin(data,X,theta,lambbda)

    plt.show()


import numpy as np
import matplotlib.pyplot as plt

def tpr( y_pred, y_actual, threshold):
        """
        y_pred    : numpy array of predicted values between 0 and 1.
        y_actual  : numpy array of actual values, either 0 or 1.
        threshold : value at which roundup begins.

        Returns true positive rate when `y_pred` is rounded up when greater than `threshold` and down otherwise.
        """
        y_rounded = np.array([ pred > threshold for pred in y_pred ])
        num_true_positive = np.logical_and(y_rounded, y_actual).sum()
        num_total_positive = y_actual.sum()
        return num_true_positive / num_total_positive

def fpr( y_pred, y_actual, threshold):
        """
        y_pred    : numpy array of predicted values between 0 and 1.
        y_actual  : numpy array of actual values, either 0 or 1.
        threshold : value at which roundup begins.

        Returns false positive rate when `y_pred` is rounded up when greater than `threshold` and down otherwise.
        """
        y_rounded = np.array([ pred > threshold for pred in y_pred ])
        num_false_positive = np.logical_and(y_rounded, np.logical_not(y_actual)).sum()
        num_total_positive = np.logical_not(y_actual).sum()
        return num_false_positive / num_total_positive

def compute_auc(y_pred, y_actual):
        """
        Approximates the Area Under the Curve of the Receiver Operating Characteristic.

        roc_auc_score from sklearn.metrics is definitely a closer approximation. Will improve here.
        """
        thresholds = np.arange(0,1,0.01)
        fprs = [ fpr(y_pred, y_actual, threshold) for threshold in thresholds]
        tprs = [tpr(y_pred, y_actual, threshold) for threshold in thresholds]
        rectangle_bases = np.array([ np.abs(fprs[i+1] - fprs[i]) for i in range(len(fprs) - 1) ])
        rectangle_heights = tprs[:-1]
        rectangle_areas = rectangle_bases * rectangle_heights
        return rectangle_areas.sum()

def plot_auc(y_pred, y_actual, include_chance=True):
        """
        include_chance : if True, plots the straight line y=x which can be compared to ROC score.

        Uses matplotlib.pyplot to plot the ROC curve.
        """
        thresholds = np.arange(0,1,0.01)
        fprs = [ fpr(y_pred, y_actual, threshold) for threshold in thresholds]
        tprs = [tpr(y_pred, y_actual, threshold) for threshold in thresholds]
        plt.plot(fprs, tprs)
        if include_chance:
                plt.plot([0,1], [0,1], color='orange')
        plt.xlabel('False Positive Rate')
        plt.ylabel('True Positive Rate')
        plt.title('Receiver Operating Characteristic')

# y_actual = np.array([0] * 75 + [1] * 100)
# y_pred = np.concatenate([
#         np.random.uniform(0,   0.7, 75 ),
#         np.random.uniform(0.3, 1.0, 100 )
# ])

# tpr( y_pred, y_actual, 0.5)
# fpr( y_pred, y_actual, 0.5)

# compute_auc(y_pred, y_actual)
# plot_auc(y_pred, y_actual, include_chance=True)


from numpy import abs as abs
from numpy import array as array
from numpy import floor as floor
from numpy import max as max
from numpy import sqrt as sqrt
from numpy import sum as sum
from numpy import zeros as zeros
from scipy.stats import norm as norm

class CumulativeSums:

    @staticmethod
    def cumulative_sums_test(binary_data:str, mode=0, verbose=False):
        """
        from the NIST documentation http://csrc.nist.gov/publications/nistpubs/800-22-rev1a/SP800-22rev1a.pdf

        The focus of this test is the maximal excursion (from zero) of the random walk defined by the cumulative sum of
        adjusted (-1, +1) digits in the sequence. The purpose of the test is to determine whether the cumulative sum of
        the partial sequences occurring in the tested sequence is too large or too small relative to the expected
        behavior of that cumulative sum for random sequences. This cumulative sum may be considered as a random walk.
        For a random sequence, the excursions of the random walk should be near zero. For certain types of non-random
        sequences, the excursions of this random walk from zero will be large.

        :param      binary_data:    a binary string
        :param      mode            A switch for applying the test either forward through the input sequence (mode = 0)
                                    or backward through the sequence (mode = 1).
        :param      verbose         True to display the debug messgae, False to turn off debug message
        :return:    (p_value, bool) A tuple which contain the p_value and result of frequency_test(True or False)

        """

        length_of_binary_data = len(binary_data)
        counts = zeros(length_of_binary_data)

        # Determine whether forward or backward data
        if not mode == 0:
            binary_data = binary_data[::-1]

        counter = 0
        for char in binary_data:
            sub = 1
            if char == '0':
                sub = -1
            if counter > 0:
                counts[counter] = counts[counter -1] + sub
            else:
                counts[counter] = sub

            counter += 1
        # Compute the test statistic z =max1≤k≤n|Sk|, where max1≤k≤n|Sk| is the largest of the
        # absolute values of the partial sums Sk.
        abs_max = max(abs(counts))

        start = int(floor(0.25 * floor(-length_of_binary_data / abs_max) + 1))
        end = int(floor(0.25 * floor(length_of_binary_data / abs_max) - 1))

        terms_one = []
        for k in range(start, end + 1):
            sub = norm.cdf((4 * k - 1) * abs_max / sqrt(length_of_binary_data))
            terms_one.append(norm.cdf((4 * k + 1) * abs_max / sqrt(length_of_binary_data)) - sub)

        start = int(floor(0.25 * floor(-length_of_binary_data / abs_max - 3)))
        end = int(floor(0.25 * floor(length_of_binary_data / abs_max) - 1))

        terms_two = []
        for k in range(start, end + 1):
            sub = norm.cdf((4 * k + 1) * abs_max / sqrt(length_of_binary_data))
            terms_two.append(norm.cdf((4 * k + 3) * abs_max / sqrt(length_of_binary_data)) - sub)

        p_value = 1.0 - sum(array(terms_one))
        p_value += sum(array(terms_two))

        if verbose:
            print('Cumulative Sums Test DEBUG BEGIN:')
            print("\tLength of input:\t", length_of_binary_data)
            print('\tMode:\t\t\t\t', mode)
            print('\tValue of z:\t\t\t', abs_max)
            print('\tP-Value:\t\t\t', p_value)
            print('DEBUG END.')

        return (p_value, (p_value >= 0.01))


import numpy as np
import scipy
import scipy.stats as stats
import scipy.linalg
from scipy.misc import factorial
from scipy.special import erf
from sigvisa.models import Distribution

class Gamma(Distribution):
    def __init__(self, alpha, beta):
        self.alpha = alpha
        self.beta = beta

    def log_p(self, x, **kwargs):
        alpha = self.alpha
        beta = self.beta

        if x < 0.0: return np.log(1e-300)
        # the special case of an exponential distribution is defined even when x==0
        if alpha == 1: return np.log(beta) - beta*x
        if x == 0.0: return np.log(1e-300)
        lp = alpha*np.log(beta) - scipy.special.gammaln(alpha) + (alpha-1)*np.log(x) - beta*x
        if np.isnan(lp):
            lp = np.float("-inf")
        return lp

    def deriv_log_p(self, x):
        alpha = self.alpha
        beta = self.beta
        if x == 0.0: return 1000.0
        return (alpha-1)/x - beta

    def predict(self, **kwargs):
        return self.alpha/self.beta

    def sample(self, **kwargs):
        return stats.gamma.rvs(self.alpha, scale=1.0/self.beta, loc=0., n=1)

class InvGamma(Distribution):
    # mean: beta/(alpha-1)
    # mode: beta/(alpha+1)
    # variance: beta^2 / ( (alpha-1)^2 (alpha-2) )

    def __init__(self, alpha, beta):
        self.alpha = alpha
        self.beta = beta

    def predict(self):
        return self.beta / (self.alpha+1) # return the mode, since the mean isn't always defined

    def log_p(self, x, **kwargs):
        alpha = self.alpha
        beta = self.beta
        if alpha <= 0 or beta <= 0:
            return np.float("-inf")
        if x == 0.0: return np.log(1e-300)
        lp = alpha*np.log(beta) - scipy.special.gammaln(alpha) - (alpha+1)*np.log(x) - beta/x
        if np.isnan(lp):
            lp = np.float("-inf")

        return lp

    def deriv_log_p(self, x):
        alpha = self.alpha
        beta = self.beta
        if x == 0.0: return 1000.0
        return beta/(x**2) - (alpha+1)/x

    def sample(self):
        s = scipy.stats.invgamma.rvs(a=self.alpha, size=1)
        return s * self.beta

    def variance(self):
        assert (self.alpha > 2)
        return self.beta**2 / ((self.alpha-1)**2 * (self.alpha - 2))

class LogNormal(Distribution):
    def __init__(self, mu, sigma):
        self.mu = mu
        self.sigma = sigma

    def log_p(self, x, **kwargs):
        mu = self.mu
        sigma = self.sigma
        if x == 0.0: return np.log(1e-300)
        lp = -1 * np.log(x) - .5 * np.log(2*np.pi) - np.log(sigma) - .5 * (np.log(x) - mu)**2 / sigma**2
        if np.isnan(lp):
            lp = np.float("-inf")
        return lp

    def deriv_log_p(self, x):
        mu = self.mu
        sigma = self.sigma
        if x == 0.0: return 1000.0
        return (-1 -(np.log(x) - mu)/(sigma**2)) / x

    def sample(self):
        return np.exp(np.random.randn() * self.sigma + self.mu)

    def variance(self):
        return (np.exp(self.sigma**2) - 1 ) * ( np.exp(2*self.mu + self.sigma**2))

    def predict(self):
        return np.exp(self.mu)

class Uniform(Distribution):
    def __init__(self, lbound, rbound):
        assert ( lbound < rbound)
        self.lbound = lbound
        self.rbound = rbound

    def log_p(self, x,  **kwargs):
        if self.lbound <= x <= self.rbound:
            return -np.log(self.rbound - self.lbound)
        else:
            return np.float("-inf")

    def predict(self, **kwargs):
        return self.lbound + (self.rbound - self.lbound) / 2

    def sample(self, **kwargs):
        return self.lbound + np.random.rand() * (self.rbound - self.lbound)

class Gaussian(Distribution):
    def __init__(self, mean, std):
        self.mean = mean
        self.std = std
        self.var = std**2

    def log_p(self, x,  **kwargs):
        mu = self.mean
        sigma2 = self.var
        lp = -.5 * np.log(2*np.pi*sigma2) - .5 * (x - mu)**2 / sigma2
        if sigma2==0:
            lp = np.float("-inf")
        return lp

    def deriv_log_p(self, x, **kwargs):
        return -(x - self.mean)/self.var

    def entropy(self):
        return .5 * np.log(2*np.pi*np.e*self.var)

    def predict(self, *args, **kwargs):
        return self.mean

    def variance(self, *args, **kwargs):
        return self.var

    def sample(self, *args, **kwargs):
        return self.mean + np.random.randn() * self.std

    def product(self, other):
        # given two Gaussian distributions, return
        # the Gaussian resulting from normalizing the product
        # N(x; u1, v1) N(x; u2, v2).
        # This corresponds to computing a Bayesian posterior
        # given a Gaussian prior and Gaussian likelihood.

        prec1 = 1.0/self.var
        prec2 = 1.0/other.var
        prec = prec1+prec2

        mean = (prec1*self.mean + prec2*other.mean)/prec
        return Gaussian(mean, 1.0/np.sqrt(prec))

    def __str__(self):
        return "Gaussian(mean=%f, std=%f)" % (self.mean, self.std)

class TruncatedGaussian(Distribution):
    def __init__(self, mean, std, a=-np.inf, b=np.inf, eps=1e-2):
        self.mean = mean
        self.std = std
        self.a=a
        self.b=b
        self.eps = eps

        self.Z = .5 * (erf((self.b-mean)/(std*np.sqrt(2))) -  erf((self.a-mean)/(std*np.sqrt(2))))
        self.logZ = np.log(self.Z)

    def log_p(self, x,  **kwargs):
        eps = self.eps
        if x <= self.a-eps or x >= self.b +eps:
            return -np.inf

        mu = self.mean
        sigma = self.std
        lp = -.5 * np.log(2*np.pi*sigma*sigma) - .5 * (x - mu)**2 / sigma**2 - self.logZ
        if np.isnan(lp):
            lp = np.float("-inf")

        if x < self.a:

            d = ( (self.a-x)/eps ) ** (1/1024.0)
            penalty =  d / (1 - d )
            return lp - penalty
        elif x > self.b:
            # at x=b, we have 0
            # at x=b+eps
            d = ( (x-self.b)/eps ) ** (1/1024.0)
            penalty =  d / (1 - d )
            return lp - penalty

        return lp

    def deriv_log_p(self, x, **kwargs):
        eps=self.eps
        if x <= self.a-eps or x >= self.b +eps:
            return 0.0

        d_lp = -(x - self.mean)/(self.std**2)

        if x < self.a:
            d = ( (self.a-x)/eps ) ** (1/1024.0)
            dd_dx = (1/1024.0) * ( (self.a-x)/eps )**(1/1024.0 - 1.0) * -1.0/eps
            penalty =  d / (1 - d )
            dpenalty_dd = 1.0/(1-d)**2
            dpenalty_dx = dpenalty_dd * dd_dx
            return d_lp - dpenalty_dx
        elif x > self.b:
            # at x=b, we have 0
            # at x=b+eps
            d = ( (x-self.b)/eps ) ** (1/1024.0)
            dd_dx = (1/1024.0) * ( (x-self.b)/eps )**(1/1024.0 - 1.0) * 1.0/eps
            penalty =  d / (1 - d )
            dpenalty_dd = 1.0/(1-d)**2
            dpenalty_dx = dpenalty_dd * dd_dx
            return d_lp - dpenalty_dx

        return d_lp

    def predict(self, **kwargs):
        return self.mean

    def sample(self, **kwargs):

        # just do rejection sampling since in practice I only plan to
        # cut off very unlikely values.
        sample = self.a
        while sample <= self.a or sample >= self.b:
            sample = self.mean + np.random.randn() * self.std
        return sample

    def variance(self, **kwargs):
        return self.std**2

class MultiGaussian(Distribution):
    def __init__(self, mean, cov, pre_inv=False):
        self.mean = mean
        self.n_d = len(mean)
        self.cov = cov
        self.L = scipy.linalg.cholesky(cov, True)

        if pre_inv:
            self.invL = np.linalg.inv(self.L)
        else:
            self.invL = None

    def predict(self, **kwargs):
        return self.mean.copy()

    def log_p(self, x, **kwargs):
        assert(len(x) == self.n_d)
        r = x-self.mean

        if self.invL is not None:
            l = np.dot(self.invL, r)
            rr = np.dot(l.T, l)
        else:
            tmp = scipy.linalg.cho_solve((self.L, True), r)
            rr = np.dot(r.T, tmp)

        logdet2 = np.log(np.diag(self.L)).sum()
        ll =  -.5 * (rr + len(self.mean) * np.log(2*np.pi)) - logdet2
        return ll

    def sample(self):
        n = len(self.mean)
        z = np.random.randn(n)
        return np.dot(self.L, z) + self.mean

class Laplacian(Distribution):
    def __init__(self, center, scale):
        self.center = center
        self.scale = scale

    def log_p(self, x,  **kwargs):
        center = self.center
        scale = self.scale
        lp = -np.log(2*scale) - np.abs(x-center)/scale
        if np.isnan(lp):
            lp = np.float("-inf")
        return lp

    def predict(self, **kwargs):
        return self.center

    def sample(self, **kwargs):
        u = np.random.rand() - .5
        return self.center - self.scale * np.sign(u) * np.log(1-2*np.abs(u))

    def variance(self, **kwargs):
        return 2*self.scale**2

class Exponential(Distribution):
    def __init__(self, rate, min_value=0.0):
        self.rate = float(rate)
        self.min_value = min_value

    def log_p(self, x,  **kwargs):
        rate = self.rate
        x = x - self.min_value
        if x < 0:
            lp = np.float("-inf")
        else:
            lp = np.log(rate) - rate * x

        return lp

    def predict(self, **kwargs):
        return 1.0/self.rate + self.min_value

    def sample(self, **kwargs):
        u = np.random.rand()
        return -np.log(u) / self.rate + self.min_value

class Poisson(Distribution):
    def __init__(self, mu):
        self.mu = mu

    def log_p(self, x, **kwargs):
        return -self.mu  + x * np.log(self.mu) - scipy.special.gammaln(x+1)

    def predict(self, **kwargs):
        return self.mu

    def sample(self, **kwargs):
        return stats.poisson.rvs(self.mu)

class Beta(Distribution):
    def __init__(self, alpha, beta):
        assert(alpha >= 0 and beta >= 0)
        self.alpha = float(alpha)
        self.beta = float(beta)

    def log_p(self, x, **kwargs):
        if x <= 0 or x >= 1:
            return -np.inf
        alpha , beta = self.alpha, self.beta

        lp = (alpha-1)*np.log(x) + (beta-1)*np.log(1-x) - scipy.special.betaln(alpha, beta)
        return lp

    def deriv_log_p(self, x, *args, **kwargs):
        return (self.alpha-1.) / x + (self.beta-1.) / (x-1.)

    def entropy(self):
        alpha, beta = self.alpha, self.beta

        B = scipy.special.betaln(alpha, beta)
        dga = scipy.special.digamma(alpha)
        dgb = scipy.special.digamma(beta)
        dgab = scipy.special.digamma(alpha+beta)

        entropy = B - (alpha-1)*dga - (beta-1)*dgb - (alpha+beta-2)*dgab
        return entropy

    def predict(self, *args, **kwargs):
        return self.alpha/(self.alpha+self.beta)

    def sample(self, *args, **kwargs):
        return scipy.stats.beta(self.alpha, self.beta, loc=0, scale=1).rvs(1)[0]

    def variance(self, **kwargs):
        alpha, beta = self.alpha, self.beta
        return (alpha*beta)/((alpha+beta)**2 * (alpha+beta+1))

class Bernoulli(Distribution):

    def __init__(self, p):
        self.p = p

    def log_p(self, x, **kwargs):
        if x:
            return np.log(self.p)
        else:
            return np.log(1-self.p)

    def predict(self, **kwargs):
        return self.p >= .5

    def sample(self, **kwargs):
        u = np.random.rand()
        return u < self.p

class Negate(Distribution):
    def __init__(self, dist):
        self.dist = dist

    def dim(self, *args, **kwargs):
        return self.dist.dim( *args, **kwargs)

    def predict(self, *args, **kwargs):
        return -1 * self.dist.predict(*args, **kwargs)

    def sample(self, *args, **kwargs):
        return -1 * self.dist.sample(*args, **kwargs)

    def log_p(self, x, *args, **kwargs):
        return self.dist.log_p(-x, *args, **kwargs)

    def deriv_log_p(self, x, *args, **kwargs):
        return self.dist.deriv_log_p(-x, *args, **kwargs)

class PiecewiseLinear(Distribution):
    def __init__(self, xs, lps, mix_dist=None, mix_weight=0.0):
        self.mix_dist = mix_dist
        self.mix_weight = mix_weight
        self.ps = np.exp(lps - np.max(lps))
        self.xs = xs
        self._normalize()

    def _normalize(self):
        pts = len(self.xs)
        areas = np.empty((pts-1,))
        for i in range(pts-1):
            gap = self.xs[i+1]-self.xs[i]
            areas[i] = gap * (self.ps[i+1]+self.ps[i])/2.0
        Z = np.sum(areas)

        if Z == 0 or not np.isfinite(Z):
            import pdb; pdb.set_trace()

        self.areas = areas / Z
        self.ps /= Z

    def log_p(self, x, *args, **kwargs):
        idx = np.searchsorted(self.xs, x)
        if idx == 0:
            p = 0
        elif idx==len(self.xs):
            p = 0
        else:
            p1 = self.ps[idx-1]
            p2 = self.ps[idx]
            z = x-self.xs[idx-1]
            gap = self.xs[idx]-self.xs[idx-1]

            p = (1.0 - z/gap) * p1 + (z/gap)*p2

        if self.mix_weight > 0:
            mix_p = np.exp(self.mix_dist.log_p(x))
            p = p*(1.0-self.mix_weight) + self.mix_weight * mix_p

        lp = np.log(p)
        #assert(np.isfinite(lp))
        return lp

    def sample(self, *args, **kwargs):
        if self.mix_weight > 0:
            u = np.random.rand()
            if u < self.mix_weight:
                return self.mix_dist.sample(*args, **kwargs)

        pts = len(self.xs)
        segment = np.random.choice(np.arange((pts-1),), p=self.areas)
        area = self.areas[segment]
        gap = self.xs[segment+1] - self.xs[segment]
        p1 = self.ps[segment]
        p2 = self.ps[segment+1]

        u = np.random.rand() * area
        if np.abs(p1-p2) < 1e-10:
            z = (u/area) * gap
        else:
            z = (np.sqrt(p1**2 * gap**2 + 2*(p2-p1)*u*gap) - p1*gap) / (p2-p1)

        if np.isnan(z):
            import pdb; pdb.set_trace()

        if z > gap:
            import pdb; pdb.set_trace()

        x =  self.xs[segment] + z
        return x


import os
import numpy as np

# import jax.numpy as jnp
from sklearn.decomposition import TruncatedSVD

def Temporal_basis_POD(K, SAVE_T_POD=False, FOLDER_OUT='./',n_Modes=10):
    """
    This method computes the POD basis. For some theoretical insights, you can find
    the theoretical background of the proper orthogonal decomposition in a nutshell here:

    https://youtu.be/8fhupzhAR_M
    --------------------------------------------------------------------------------------------------------------------
    Parameters:
    ----------

    :param FOLDER_OUT: str
            Folder in which the results will be saved (if SAVE_T_POD=True)
    :param K: np.array
            Temporal correlation matrix
    :param SAVE_T_POD: bool
            A flag deciding whether the results are saved on disk or not. If the MEMORY_SAVING feature is active, it is
            switched True by default.
    :param n_Modes: int
           number of modes that will be computed
    --------------------------------------------------------------------------------------------------------------------
    Returns:
    --------

    :return: Psi_P: np.array
            POD Psis
    :return: Sigma_P: np.array
            POD Sigmas
    """
    # Solver 1: Use the standard SVD
    # Psi_P, Lambda_P, _ = np.linalg.svd(K)
    # Sigma_P = np.sqrt(Lambda_P)

    # Solver 2: Use randomized SVD ############## WARNING #################
    svd = TruncatedSVD(n_Modes)
    svd.fit_transform(K)
    Psi_P = svd.components_.T
    Lambda_P=svd.singular_values_
    Sigma_P=np.sqrt(Lambda_P)

    if SAVE_T_POD:
        os.makedirs(FOLDER_OUT + "/POD/", exist_ok=True)
        print("Saving POD temporal basis")
        np.savez(FOLDER_OUT + '/POD/temporal_basis', Psis=Psi_P, Lambdas=Lambda_P, Sigmas=Sigma_P)

    return Psi_P, Sigma_P


import numpy as np

x=list(map(int,list(input().split(' '))))
w = input()
if w:
    w=list(map(int,list(w.split(' '))))

def average(x,weights=None):
    """
    x is array of integers
    w is array of weights corresponding to the integers
    returns weighted average if weights are provided. else returns simple average
    """
    if weights:
        return sum(i*j for i,j in zip(x,weights)) / sum(weights)
    return sum(x) / len(x)

wm = average(x,weights=w)
print(f"{wm:.1f}")

wm = np.average(x,weights=w)
print(f"{wm:.1f}")


import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return 2*x**2

# np.arange(start, stop, step) to give us smoother line
x = np.arange(0, 5, 1e-3)
y = f(x)

plt.figure()
plt.plot(x, y)

colors = ['k', 'g', 'r', 'b', 'c']

def approximate_tangent_line(x, approximate_derivative):
    return (approximate_derivative*x) + b

for i in range(5):
    p2_delta = 1e-4
    x1 = i
    x2 = x1 + p2_delta
    y1 = f(x1)
    y2 = f(x2)

    print((x1,y1), (x2,y2))
    approximate_derivative = (y2-y1)/(x2-x1)
    b = y2 -  approximate_derivative*x2

    to_plot = [x1-0.5, x1, x1+0.5]

    plt.scatter(x1, y1, c=colors[i])
    plt.plot([point for point in to_plot],
        [approximate_tangent_line(point, approximate_derivative)
        for point in to_plot], c=colors[i])

    print('approximate derivative for f(x)',
        f'where x = {x1} is {approximate_derivative}')

plt.savefig('graph2.png')


import decimal

from mpmath import inf, mp, nsum

def pi_mpmath(n):
    """Calculate PI to the Nth digit.
    I figured using mpmath would work well, but this is not very
    efficient. With n = 1000, it took over a minute on my laptop.
    """
    mp.dps = n
    return str(nsum(lambda k: (4/(8*k+1) - 2/(8*k+4) - 1/(8*k+5) - 1/(8*k+6)) / 16**k, (0, inf)))

def pi_decimal(n):
    """Calculate PI to the Nth digit.
    This one uses the native python Decimal type that allows arbitrary
    precision. With n = 1000, it took less than a second on my laptop.
    """
    D = decimal.Decimal
    decimal.getcontext().prec = n+10
    pi = D(0)
    k = 0
    tail_prev = ''
    while True:
        pi += (D(4)/D(8*k+1) - D(2)/D(8*k+4) - D(1)/D(8*k+5) - D(1)/D(8*k+6)) / D(16)**D(k)
        tail = str(pi)[n+1:-1]
        if tail == tail_prev:
            break
        tail_prev = tail
        k += 1
    decimal.getcontext().prec = n
    return str(pi * D(1))

number_of_places = 1
# Reading the precision in from the decimals file.
with open("/precision/decimals", "r") as decimals_f:
    number_of_places = int(decimals_f.read())

# Dumping the value of pi in the pi file.
with open("/computed/pi", "w") as computed_f:
    computed_f.write(pi_decimal(number_of_places))


# requires scipy, dtw, fastdtw, numpy, matplotlib
# all available by pip install
from dtw import dtw
import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import norm
import math
from scipy.spatial.distance import euclidean
from fastdtw import fastdtw
from scipy.stats.stats import pearsonr

# load the time serie we want to compare
x = np.array([])
# load the time series of known points
y = [np.array([])]

# test time series
x = np.array([1, 1, 1, 1, 2, 4, 2, 1, 2, 1])
y = [np.array([10, 11, 11, 11, 2, 4, 3, 7, 8, 9]),  np.array([1, 1, 1, 2, 2, 2, 2, 3, 2, 1])]

x1 = np.array([1, 1, 1, 3, 6, 13, 25, 22, 7, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
y1 = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 12, 24, 23, 8, 3, 1, 1, 1, 1, 1, 1])

"""

Root Mean Squared Error calculation

"""
def rmse(predictions, targets):
    return np.sqrt(((predictions - targets) ** 2).mean())

print ("RMSE: " + str(rmse(x, y[0])))
print ("RMSE: " + str(rmse(x1,y1)))

"""

Euclidian distance between 2 time series

"""
def euclid_dist(t1,t2):
    return np.sqrt(sum((t1-t2)**2))
print("Euclidian distance: " + str(euclid_dist(x,y[0])))
print ("Euclidian distance: " + str(euclid_dist(x1,y1)))

"""

Log returns, returns, moving average
Pearson's correlation coefficient

"""

x_logreturn = np.log(1 + (x / np.roll(x, -1)))
y_logreturn = np.log(1 + (y[0] / np.roll(y[0], -1)))
x1_logreturn = np.log(1 + (x1 / np.roll(x1, -1)))
y1_logreturn = np.log(1 + (y1 / np.roll(y1, -1)))

print ("Pearson's correlation on log returns: " + str(pearsonr(x_logreturn,y_logreturn)))
print ("Pearson's correlation on log returns: " + str(pearsonr(x1_logreturn,y1_logreturn)))

# DTW implementation 1
def dtw1 (x, y):
    x_reshaped = x.reshape(-1, 1)
    y_reshaped = y.reshape(-1, 1)
    dist, cost, acc, path = dtw(x_reshaped, y_reshaped, dist=lambda x_reshaped, y_reshaped: norm(x_reshaped - y_reshaped, ord=1))
    return dist

# DTW Implementation 2 Ref : https://jeremykun.com/2012/07/25/dynamic-time-warping/
def dtw2(seqA, seqB, d = lambda x,y: abs(x-y)):
    # create the cost matrix
    numRows, numCols = len(seqA), len(seqB)
    cost = [[0 for _ in range(numCols)] for _ in range(numRows)]
    # initialize the first row and column
    cost[0][0] = d(seqA[0], seqB[0])
    for i in range(1, numRows):
        cost[i][0] = cost[i-1][0] + d(seqA[i], seqB[0])
    for j in range(1, numCols):
        cost[0][j] = cost[0][j-1] + d(seqA[0], seqB[j])
    # fill in the rest of the matrix
    for i in range(1, numRows):
        for j in range(1, numCols):
            choices = cost[i-1][j], cost[i][j-1], cost[i-1][j-1]
            cost[i][j] = min(choices) + d(seqA[i], seqB[j])
    return cost[-1][-1]

# DTW Implementation 3 Ref: http://alexminnaar.com/time-series-classification-and-clustering-with-python.html
def dtw3(s1, s2):
    DTW={}
    for i in range(len(s1)):
        DTW[(i, -1)] = float('inf')
    for i in range(len(s2)):
        DTW[(-1, i)] = float('inf')
    DTW[(-1, -1)] = 0
    for i in range(len(s1)):
        for j in range(len(s2)):
            dist= (s1[i]-s2[j])**2
            DTW[(i, j)] = dist + min(DTW[(i-1, j)],DTW[(i, j-1)], DTW[(i-1, j-1)])
    return np.sqrt(DTW[len(s1)-1, len(s2)-1])

"""
#¤ DTW Implementation 4 Ref: https://effectiveml.com/dynamic-time-warping-for-sequence-classification.html
Implementation to fix before using
def dtw4(p,q):
    p = p.reshape(-1, 1)
    q = q.reshape(-1, 1)
    ep = np.sqrt(np.sum(np.square(p),axis=1));
    eq = np.sqrt(np.sum(np.square(q),axis=1));
    D = 1 - np.dot(p,q.T)/np.outer(ep,eq) # work out D all at once
    S = np.zeros_like(D)
    Lp = np.shape(p)[0]
    Lq = np.shape(q)[0]
    N = np.shape(p)[1]
    for i in range(Lp):
        for j in range(Lq):
            if i==0 and j==0:  S[i,j] = D[i,j]
            elif i==0: S[i,j] = S[i,j-1] + D[i,j]
            elif j==0: S[i,j] = S[i-1,j] + D[i,j]
            else: S[i,j] = np.min([S[i-1,j],S[i,j-1],S[i-1,j-1]]) + D[i,j]
    return np.sqrt(S[-1,-1]) # return the bottom right hand corner distance
"""

# DTW Implementation 5 Ref : https://pypi.org/project/fastdtw/0.3.0/
def dtw5 (x, y):
    x_reshaped = x.reshape(-1, 1)
    y_reshaped = y.reshape(-1, 1)
    distance, path = fastdtw(x_reshaped, y_reshaped, dist=euclidean)
    return distance

# iterating over the known points and find the most similar
rmse_result = []
euclid_result = []
dtw1_result = []
dtw2_result = []
dtw3_result = []
dtw5_result = []
for i in range(len(y)):
    rmse_result.append(rmse(x, y[i]))
    euclid_result.append(euclid_dist(x,y[i]))
    dtw1_result.append(dtw1(x, y[i]))
    dtw2_result.append(dtw2(x, y[i]))
    dtw3_result.append(dtw3(x, y[i]))
    dtw5_result.append(dtw5(x, y[i]))

print("")
print(rmse_result)
print(euclid_result)
print(dtw1_result)
print(dtw2_result)
print(dtw3_result)
print(dtw5_result)
print("")

print ("Most similar rmse is point               : " + str(np.argmin(rmse_result)) + " " +str(rmse_result[np.argmin(rmse_result)]))
print ("Most similar euclidian distance is point : " + str(np.argmin(euclid_result)) + " " +str(euclid_result[np.argmin(euclid_result)]))
print ("Most similar dtw1 is point               : " + str(np.argmin(dtw1_result)) + " " +str(dtw1_result[np.argmin(dtw1_result)]))
print ("Most similar dtw2 is point               : " + str(np.argmin(dtw2_result)) + " " +str(dtw2_result[np.argmin(dtw2_result)]))
print ("Most similar dtw3 is point               : " + str(np.argmin(dtw3_result)) + " " +str(dtw3_result[np.argmin(dtw3_result)]))
print ("Most similar dtw5 is point               : " + str(np.argmin(dtw5_result)) + " " +str(dtw5_result[np.argmin(dtw5_result)]))


from nose.tools import *
import numpy as np
from compecon import BasisChebyshev

''' test for size of Diff operator '''
n, a, b = 7, 0, 2
Phi = BasisChebyshev(n, a, b)

def test_Diff():
    assert_equal(Phi._diff(0, 2).shape, (n - 2, n))
    assert_equal(Phi._diff(0, -3).shape, (n + 3, n))

''' test for shape of interpolation matrix '''
nx = 24
x = np.linspace(a, b, nx)

def test_Phi():
    assert_equal(Phi(x).shape, (nx, n))
    assert_equal(Phi().shape, (n, n))


import numpy as np
import cv2

def gradient_map(gray):
    # Image derivatives
    SCALE = 1
    DELTA = 0
    DDEPTH = cv2.CV_16S  ## to avoid overflow

    grad_x = cv2.Sobel(gray, DDEPTH, 1, 0, ksize=3, scale=SCALE, delta=DELTA)
    grad_y = cv2.Sobel(gray, DDEPTH, 0, 1, ksize=3, scale=SCALE, delta=DELTA)

    grad_x = np.float32(grad_x)
    grad_x = grad_x * (1 / 512)
    grad_y = np.float32(grad_y)
    grad_y = grad_y * (1 / 512)

    # Gradient and smoothing
    grad_x2 = cv2.multiply(grad_x, grad_x)
    grad_y2 = cv2.multiply(grad_y, grad_y)

    # Magnitude of the gradient
    Mag = np.sqrt(grad_x2 + grad_y2)

    # Orientation of the gradient
    theta = np.arctan(cv2.divide(grad_y, grad_x + np.finfo(float).eps))

    return theta, Mag

def orientation_map(gray, n):
    # Image derivatives
    SCALE = 1
    DELTA = 0
    DDEPTH = cv2.CV_16S  ## to avoid overflow

    grad_x = cv2.Sobel(gray, DDEPTH, 1, 0, ksize=3, scale=SCALE, delta=DELTA)
    grad_y = cv2.Sobel(gray, DDEPTH, 0, 1, ksize=3, scale=SCALE, delta=DELTA)

    grad_x = np.float32(grad_x)
    grad_x = grad_x * (1 / 512)
    grad_y = np.float32(grad_y)
    grad_y = grad_y * (1 / 512)

    # Gradient and smoothing
    grad_x2 = cv2.multiply(grad_x, grad_x)
    grad_y2 = cv2.multiply(grad_y, grad_y)
    grad_xy = cv2.multiply(grad_x, grad_y)
    g_x2 = cv2.blur(grad_x2, (n, n))
    g_y2 = cv2.blur(grad_y2, (n, n))
    g_xy = cv2.blur(grad_xy, (n, n))

    # Magnitude of the gradient
    Mag = np.sqrt(grad_x2 + grad_y2)
    M = cv2.blur(Mag, (n, n))

    # Gradient local aggregation
    vx = 2 * g_xy
    vy = g_x2 - g_y2
    fi = cv2.divide(vx, vy + np.finfo(float).eps)

    case1 = vy >= 0
    case2 = np.logical_and(vy < 0, vx >= 0)
    values1 = 0.5 * np.arctan(fi)
    values2 = 0.5 * (np.arctan(fi) + np.pi)
    values3 = 0.5 * (np.arctan(fi) - np.pi)
    theta = np.copy(values3)
    theta[case1] = values1[case1]
    theta[case2] = values2[case2]

    return theta, M


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import linregress

def draw_plot():
    # Read data from file
    sea_level = pd.read_csv('epa-sea-level.csv')

    # Create scatter plot
    plt.scatter(sea_level['Year'], sea_level['CSIRO Adjusted Sea Level'], s=5)

    # Create first line of best fit
    line_1 = linregress(sea_level['Year'],
                        sea_level['CSIRO Adjusted Sea Level'])
    x_1 = np.arange(1880, 2051, 1)
    y_1 = line_1.slope * x_1 + line_1.intercept
    plt.plot(x_1, y_1, 'r')

    # Create second line of best fit
    recent_sea_level = sea_level[sea_level['Year'] >= 2000]
    line_2 = linregress(recent_sea_level['Year'],
                        recent_sea_level['CSIRO Adjusted Sea Level'])
    x_2 = np.arange(2000, 2051, 1)
    y_2 = line_2.slope * x_2 + line_2.intercept
    plt.plot(x_2, y_2, 'g')

    # Add labels and title
    plt.xlabel('Year')
    plt.ylabel('Sea Level (inches)')
    plt.title('Rise in Sea Level')

    # Save plot and return data for testing (DO NOT MODIFY)
    plt.savefig('sea_level_plot.png')
    return plt.gca()


import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import linprog

c = [-150, -75]
A = [[10, 4], [3, 2], [2, 5]]
b = [1000, 360, 600]

res = linprog(c, A, b)
print(res)

plt.style.use('seaborn-whitegrid')

fig = plt.figure()
ax = plt.axes()

plt.xlabel("x")
plt.xlim(0, 200)
plt.ylabel("y")
#plt.ylim(-800, 800);

x = np.linspace(0, 200, 1000)

l1 = ax.plot(x, (1000 - 10*x)/4, color='blue', label='10x+4y=1000')
l2 = ax.plot(x, (360 - 3*x)/2, color='red', label='3x+2y=360')
l3 = ax.plot(x, (600 - 2*x)/5, color='green', label='2x+5y=600')
l4 = ax.plot(res.x[0], res.x[1], marker="x")
ax.text(2, 6, "150x+75y->max\nx>=0\ny>=0\n10x+4y<=1000\n3x+2y<=360\n2x+5y<=600\n")

ax.legend()
plt.show()


from numpy import *
# PCA analysis
def pca(X):
    """
    :param X: n-by-d data matrix X. Rows of X correspond to observations and columns correspond to dimensions.
    :return: Y - transformed new coordinate in new space, eig_vec - eigenvectors, eig_value
    """
    X = array(X);
    if (X.ndim != 2) or (X.shape[0]==1):
        raise ValueError('dimension of X should be 2 and X shoud have >1 samples')
    #subtract mean
    avg = mean(X,axis=0)
    avg = tile(avg,(X.shape[0],1))
    X -= avg;#WARNING: INPUT X WILL BE CHANGED
    #covariance matrix
    C = dot(X.transpose(),X)/(X.shape[0]-1)
    eig_values,eig_vecs = linalg.eig(C)
    idx = eig_values.argsort()
    idx = idx[ : :-1]
    eig_values = eig_values[idx]
    eig_vecs = eig_vecs[:,idx]
    #new coordinate in new space
    Y = dot(X,eig_vecs)

    return (Y, eig_vecs, eig_values


import numpy as np
import scipy.stats as st
import cvxpy as cp
import pandas as pd
import matplotlib.pyplot as plt
R = pd.read_csv('asset_return_data.csv', index_col=0)
R = R.asfreq(pd.infer_freq(R.index))
T, N = R.shape
np.random.seed(8888)
BenchmarkIndex = R.dot(np.tile(1.0/N, N)) \
                 + st.norm.rvs(loc=0.0, scale=3.0, size=T)
MovingWindow = 96
BackTesting = T - MovingWindow
V_Tracking = np.zeros(BackTesting)
Weight = cp.Variable(N)
Error = cp.Variable(MovingWindow)
TrackingError = cp.sum_squares(Error)
Asset_srT = R / np.sqrt(T)
Index_srT = BenchmarkIndex / np.sqrt(T)
for Month in range(0, BackTesting):
    Asset = Asset_srT.values[Month:(Month + MovingWindow), :]
    Index = Index_srT.values[Month:(Month + MovingWindow)]
    Min_TrackingError = cp.Problem(cp.Minimize(TrackingError),
                                   [Index - Asset @ Weight == Error,
                                    cp.sum(Weight) == 1.0,
                                    Weight >= 0.0])
    Min_TrackingError.solve(solver=cp.ECOS)
    V_Tracking[Month] = R.values[Month + MovingWindow, :].dot(Weight.value)
fig1 = plt.figure(num=1, facecolor='w')
plt.plot(list(range(1, BackTesting + 1)), BenchmarkIndex[MovingWindow:], 'b-')
plt.plot(list(range(1, BackTesting + 1)), V_Tracking, 'r--')
plt.legend(['benchmark index', 'index fund'], loc='best', frameon=False)
plt.xlabel('year')
plt.ylabel('return (%)')
plt.xticks(list(range(12, BackTesting + 1, 12)),
           pd.date_range(R.index[MovingWindow], periods=BackTesting//12,
                         freq='AS').year)
plt.show()


from numpy import log

def compute_1d_array_entropy(_1d_array):

    probabilities = _1d_array / _1d_array.sum()

    return -(probabilities * log(probabilities)).sum()


from typing import Union

from scipy.stats import geom, rv_discrete

from probability.custom_types.external_custom_types import FloatArray1d
from probability.distributions.mixins.attributes import PFloatDMixin
from probability.distributions.mixins.calculable_mixin import CalculableMixin
from probability.distributions.mixins.rv_discrete_1d_mixin import \
    RVDiscrete1dMixin
from probability.utils import num_format, is_scalar

class Geometric(
    RVDiscrete1dMixin,
    PFloatDMixin,
    CalculableMixin,
    object
):
    """
    The (shifted) geometric distribution gives the probability that the first
    occurrence of success requires k independent trials, each with success
    probability p.

    https://en.wikipedia.org/wiki/Geometric_distribution
    """
    def __init__(self, p: float):
        """
        Create a new shifted geometric distribution.

        :param p: Probability of success in any individual trial.
        """
        self._p: float = p
        self._reset_distribution()

    def _reset_distribution(self):

        self._distribution: rv_discrete = geom(self._p)

    @property
    def lower_bound(self) -> int:
        return 1

    @property
    def upper_bound(self) -> int:
        return int(self.ppf().at(0.99))

    def mode(self) -> int:

        return 1

    @staticmethod
    def fit(data: FloatArray1d, **kwargs) -> 'Geometric':
        """
        Fit a Geometric distribution to the data of one or more experiments
        using the maximum likelihood estimate for p.

        :param data: Iterable of data to fit to. Each result represents the
                     result of a single trial, and should be 0 or 1.
        """
        n = sum(data)  # number of experiments
        k = len(data)  # number of trials
        p = n / k
        return Geometric(p=p)

    @staticmethod
    def fits(data: FloatArray1d, **kwargs) -> 'Geometric':
        """
        Fit a Geometric distribution to the distribution of results of a
        series of experiments using the method of moments.

        https://en.wikipedia.org/wiki/Geometric_distribution
        #Parameter_estimation

        :param data: Iterable of results to fit to. Each value represents the
                     number of trials in an experiment to get 1 success, and
                     should be at least 1.
        """
        n = len(data)  # number of experiments
        k = sum(data)  # number of trials
        p = n / k
        return Geometric(p=p)

    def __str__(self):

        return f'Geometric(p={num_format(self._p, 3)})'

    def __repr__(self):

        return f'Geometric(p={self._p})'

    def __eq__(self, other: Union['Geometric', int, float]):

        if is_scalar(other):
            return self.pmf().at(other)
        else:
            return abs(self._p - other._p) < 1e-10

    def __ne__(
            self, other: Union['Geometric', int, float]
    ) -> Union[bool, float]:

        if is_scalar(other):
            return 1 - self.pmf().at(other)
        else:
            return not self.__eq__(other)


import numpy as np
import matplotlib.pylab as plt

def forward_difference(f, x):
	h = 1e-4 # 0.001
	return (f(x+h) - f(x)) / h

def central_difference(f, x):
	h = 1e-4 # 0.0001
	return (f(x+h) - f(x-h)) / (2*h)

def function_1(x):
	return 0.01*x**2 + 0.1*x

# it returns a tangent line of function f where x-point is x
def tangent_line(f, x):
	d = central_difference(f, x)	# df(x)/dx
	y = f(x) - d*x	# tangent point of y-axis
	return lambda t: d*t + y	# return a tangent line

def main():
	x = np.arange(0.0, 20.0, 0.1)
	y = function_1(x)
	plt.xlabel("x")
	plt.ylabel("f(x)")

	tf = tangent_line(function_1, 5)
	y2 = tf(x)

	plt.plot(x, y)
	plt.plot(x, y2)
	plt.show()

if __name__ == '__main__':
	main()


#----------------------------------------------
#   Name: Roberto Sanchez
#   Date: December 07, 2017
#   Assignement 6 - Markov Chains
#------------Importing packages-----------------
import numpy as np
import matplotlib.pyplot as plt
import random
# MarkovChain Definition
def MarkovChain(N,n):
    S = [0 for i in range(0,n)]
    X = np.chararray((n,N))
    X[:] = 0
    M = np.zeros((n,3))
    prob = {'p11' : 1/3, 'p12' : 1/3, 'p13' : 1/3, 'p21' : 1/2, 'p23' : 1/2, 'p22' : 0, 'p31' : 1/4, 'p32' : 1/4, 'p33' : 1/2}
    dist = {'d01' : 1/4, 'd03' : 1/4, 'd02' : 1/2}
    for j in range(0,N):
        r0 = np.random.random();
        if r0 <= dist['d01']:
            s0 = 'R'
        elif r0>dist['d01'] and r0<=dist['d01']+dist['d02']:
            s0 = 'N'
        elif r0>dist['d01']+dist['d02']:
            s0 = 'S'
        S[0] = s0
#
        for k in range(0,n-1):
            s = S[k]
            r = np.random.random();
            if s == 'R':
                if r<=prob['p11']:
                    S[k+1]='R'
                elif r>prob['p11'] and r<=prob['p11']+prob['p12']:
                    S[k+1]='N'
                elif r>prob['p11']+prob['p12']:
                    S[k+1]='S'
            elif s == 'N':
                if r<=prob['p21']:
                    S[k+1]='R'
                elif r>prob['p21'] and r<=prob['p21']+prob['p22']:
                    S[k+1]='N'
                elif r>prob['p21']+prob['p22']:
                    S[k+1]='S'
            elif s == 'S':
                if r<=prob['p31']:
                    S[k+1]='R'
                elif r>=prob['p31'] and r<=prob['p31']+prob['p32']:
                    S[k+1]='N'
                elif r>prob['p31']+prob['p32']:
                    S[k+1]='S'
        X[:,j]=S
    for j in range(0,n):
        ma=0
        mb=0
        mc=0
        x=X[j,:]
        for i in range(N):
            if str(x[i],'utf-8') == 'R':
                ma += 1
        for p in range(N):
            if str(x[p],'utf-8') == 'N':
                mb += 1
        for q in range(N):
            if str(x[q],'utf-8') == 'S':
                mc += 1
        M[j,:] = [ma/N,mb/N,mc/N]

# ---------------------------------Plot-------------------------------------
    plt.figure(1)
    nv = np.linspace(0,n,num=15)
    plt.plot(nv,M[:,0],color = 'blue',marker='*',markersize=6)
    plt.plot(nv,M[:,1],color = 'green',marker='+',markersize=6)
    plt.plot(nv,M[:,2],color = 'red',marker='^',markersize=6)
    plt.title('Simulation results -- States R,N,S')
    plt.xlabel('Time step (n)')
    plt.ylabel('Prob (State)')
    plt.legend((['State R'],['State N'],['State S']))
    plt.show()
    P = np.matrix([[prob['p11'],prob['p12'],prob['p13']],[prob['p21'],prob['p22'],prob['p23']],[prob['p31'],prob['p32'],prob['p33']]])
    y0 = np.matrix([1/4,1/2,1/4])
    Y = np.zeros((n,3))
    Y[0,:] = y0
    for k in range(0,n-1):
        Y[k+1,:] = np.matmul(Y[k,:],P)
    # Figure 2 Chart
    plt.figure(2)
    plt.plot(nv,Y[:,0],color = 'blue',marker='o',markersize=6)
    plt.plot(nv,Y[:,1],color = 'green',marker='o',markersize=6)
    plt.plot(nv,Y[:,2],color = 'red',marker='o',markersize=6)
    plt.title('Results based on State Transition Matix -- States R,N,S')
    plt.xlabel('Time step(n)')
    plt.ylabel('Prob(State)')
    plt.legend((['State R'],['State N'],['State S']))
    plt.show()
MarkovChain(10000,15)


#########################################################################
#            NUMERICAL DERIVATIVES
#
# This module explore compare the difference between 2-points, 3-points
# and 4-points derivatives, with the difference centered or one-sided.
#
#    Copied from Mike Zingale's, with addition of d2r and d2l.
#    (Marina von Steinkirch, spring 2013)
#
#########################################################################

import math
import numpy
import pylab

""" Functions """

def func(x):
    """ the function to be plotted """
    f = numpy.sin(x)
    return f

def fprime(x):
    """ the analytic derivative of func(x) """
    fp = numpy.cos(x)
    return fp

def d1l(dx, fc, i):
    """ first-order, left-sided derivative at index i """
    D = (fc[i] - fc[i-1])/dx
    return D

def d1r(dx, fc, i):
    """ first-order, right-sided derivative at index i """
    D = (fc[i+1] - fc[i])/dx
    return D

def d2(dx, fc, i):
    """ second-order centered derivative at index i """
    D = fc[i+1] - fc[i-1]
    D = D/(2.0*dx)
    return D

def d2r(dx, fc, i):
    """ second-order right-sided derivative at index i """
    D = -fc[i] + 4.0*fc[i+1] - 3.0*fc[i+2]
    D = D/(2.0*dx)
    return D

def d2l(dx, fc, i):
    """ second-order left-sided derivative at index i """
    D = -fc[i+2] + 4.0*fc[i+1] -3.0*fc[i]
    D = D/(2.0*dx)
    return D

def d4(dx, fc, i):
    """ fourth-order centered derivative at index i """
    D = -fc[i+2] + 8.0*fc[i+1] - 8.0*fc[i-1] + fc[i-2]
    D = D/(12.0*dx)
    return D

def line(x, slope, x0, y0):
    return y0 + slope*(x - x0)

""" Constants """

xl = 0.0
xr = math.pi
coarse_point_chosen = 3     # which for this griding is pi/3

""" Main Program """

# fine and  grid (to show exact function and for differencing)
# linspace(start, stop, number_of_points)
fine = numpy.linspace(xl, xr, 500)      # 500 points, from 0 to pi
coarse = numpy.linspace(xl, xr, 10)     # 10 points, from 0 to pi

# define the analytic function for fine and for coarse griding, and the derivative for coarse
f = func(fine)
c = func(coarse)
analytic = fprime(coarse[coarse_point_chosen])

# equally spaced dx for coarse points
dx = coarse[1] - coarse[0]

# get the derivative approximations
Dl = d1l(dx, c, coarse_point_chosen)
Dr = d1r(dx, c, coarse_point_chosen)
D2 = d2(dx, c, coarse_point_chosen)
D2r = d2r(dx, c, coarse_point_chosen)
D2l = d2l(dx, c, coarse_point_chosen)
D4 = d4(dx, c, coarse_point_chosen)

""" Plotting """
# plot the fine and discrete gridded analytic function
pylab.plot(fine, f, color="0.5", lw=2)
pylab.scatter(coarse, c)

# function and point values
x0 = coarse[coarse_point_chosen]
y0 = func(x0)
xplot = numpy.linspace(coarse[1], coarse[5], 50)

pylab.plot(xplot, line(xplot, Dl, x0, y0), "b--", label="left-sided first-order approx")
pylab.plot(xplot, line(xplot, Dr, x0, y0), "bp", label="right-sided first-order approx")
pylab.plot(xplot, line(xplot, D2, x0, y0), "y", lw=3,  label="centered second-order approx")
pylab.plot(xplot, line(xplot, D2l, x0, y0), "r--", label="left-sized second-order approx")
pylab.plot(xplot, line(xplot, D2r, x0, y0), "rp", label="right-sized second-order approx")
pylab.plot(xplot, line(xplot, D4, x0, y0), "m*", lw=3, label="centered fourth-order approx")
#pylab.plot(xplot, line(xplot, analytic, x0, y0), color="0.5", ls=":", label="analytic")

print "analytic:          ", analytic
print "left-sided O(dx):  ", Dl
print "right-sided O(dx): ", Dr
print "centered O(dx**2): ", D2
print "left-sided O(dx**2): ", D2l
print "right-sided O(dx**2): ", D2r
print "centered O(dx**4): ", D4

leg = pylab.legend(loc=2,labelspacing=0.1)
ltext = leg.get_texts()
pylab.setp(ltext, fontsize='small')
leg.draw_frame(1)

# axes run through 0
# http://matplotlib.org/examples/pylab_examples/spine_placement_demo.html
ax = pylab.gca()
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.spines['left'].set_smart_bounds(True)
ax.spines['bottom'].set_smart_bounds(True)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

pylab.xlabel("x (radians)")
pylab.ylabel("Sin(x)")
pylab.grid(True)
pylab.xlim(0,2.0)

pylab.savefig("fprime.png")

print "\nDone!"


import numpy as np
from scipy.stats import t

def outliers_iqr(x, ret='filtered', coef = 1.5):

    """
    Simple detection of potential outliers based on interquartile range (IQR).

    Data that lie within the lower and upper limits are considered
    non-outliers. The lower limit is the number that lies 1.5 IQRs below
    (coefficient may be changed with an argument, see Parameters)
    the first quartile; the upper limit is the number that lies 1.5 IQRs
    above the third quartile.

    Parameters
    ----------
    x : array_like or np.ndarray, 1d
        An array, any object exposing the array interface, containing
        p values.

    ret : str, optional
        Specifies object to be returned. Available options are:
        'filtered' : return a filtered array (default)
        'outliers' : return outliers
        'indices' : return indices of non-outliers
        'outliers_indices' : return indices of outliers

    coef : float, optional
        Coefficient by which IQR is multiplied. Default is 1.5.

    Returns
    -------
    filtered : np.ndarray
        Filtered array (default).

    indices : np.ndarray, optional
        Array with indices of elements lying within the specified limits.

    outliers : np.ndarray, optional
        Array with outliers.

    outliers_indices : np.ndarray, optional
        Array with indices of outlier elements.

    Examples
    --------
    >>> x = np.array([4, 5, 6, 10, 12, 4, 3, 1, 2, 3, 23, 5, 3])
    >>> outliers_iqr(x, ret = 'outliers')
    array([12, 23])

    """

    arr = np.copy(x)

    q1, q3 = np.percentile(arr, [25, 75])
    iqr = q3 - q1
    ll = q1 - iqr * coef
    ul = q3 + iqr * coef

    if ret == 'indices':
        return np.where((arr > ll) & (arr < ul))[0]
    elif ret == 'outliers':
        return arr[(arr < ll) | (arr > ul)]
    elif ret == 'outliers_indices':
        return np.where((arr < ll) | (arr > ul))[0]
    else:
        return x[(x > ll) & (x < ul)]

def outliers_grubbs(x, hypo = False, alpha = 0.05):

    """
    Grubbs' Test for Outliers [1]_. This is the two-sided version of the test.

    The null hypothesis implies that there are no outliers in the data set.

    Parameters
    ----------
    x : array_like or ndarray, 1d
        An array, any object exposing the array interface, containing
        data to test for an outlier in.

    hypo : bool, optional
        Specifies whether to return a bool value of a hypothesis test result.
        Returns True when we can reject the null hypothesis. Otherwise, False.
        Available options are:
        1) True - return a hypothesis test result
        2) False - return a filtered array without an outlier (default)

    alpha : float, optional
        Significance level for a hypothesis test. Default is 0.05.

    Returns
    -------
    arr : np.ndarray
        Filtered array if alternative hypo is True, otherwise an unfiltered
        array.

    hypo : bool, optional
        Null hypothesis test result.

    Notes
    -----
    .. [1] http://www.itl.nist.gov/div898/handbook/eda/section3/eda35h1.htm

    Examples
    --------

    >>> x = np.array([199.31,199.53,200.19,200.82,201.92,201.95,202.18,245.57])
    >>> ph.outliers_grubbs(x)
    array([ 199.31,  199.53,  200.19,  200.82,  201.92,  201.95,  202.18])
    """

    arr = np.copy(x)
    val = np.max(np.abs(arr - np.mean(arr)))
    ind = np.argmax(np.abs(arr - np.mean(arr)))
    G = val / np.std(arr, ddof=1)
    N = len(arr)
    result = G > (N - 1)/np.sqrt(N) * np.sqrt((t.ppf(1-alpha/(2*N), N-2) ** 2) / (N - 2 + t.ppf(1-alpha/(2*N), N-2) ** 2))

    if hypo:
        return result
    else:
        if result:
            return np.delete(arr, ind)
        else:
            return arr

def outliers_tietjen(x, k, hypo = False, alpha = 0.05):

    """
    Tietjen-Moore test [1]_ to detect multiple outliers in a univariate
    data set that follows an approximately normal distribution.
    The Tietjen-Moore test [2]_ is a generalization of the Grubbs' test to
    the case of multiple outliers. If testing for a single outlier,
    the Tietjen-Moore test is equivalent to the Grubbs' test.

    The null hypothesis implies that there are no outliers in the data set.

    Parameters
    ----------
    x : array_like or np.ndarray, 1d
        An array, any object exposing the array interface, containing
        data to test for an outlier in.

    k : int
        Number of potential outliers to test for. Function tests for
        outliers in both tails.

    hypo : bool, optional
        Specifies whether to return a bool value of a hypothesis test result.
        Returns True when we can reject the null hypothesis. Otherwise, False.
        Available options are:
        1) True - return a hypothesis test result
        2) False - return a filtered array without outliers (default)

    alpha : float, optional
        Significance level for a hypothesis test. Default is 0.05.

    Returns
    -------
    arr : np.ndarray
        Filtered array if alternative hypo is True, otherwise an unfiltered
        array.

    hypo : bool, optional
        Null hypothesis test result.

    Notes
    -----
    .. [1] Tietjen and Moore (August 1972), Some Grubbs-Type Statistics
        for the Detection of Outliers, Technometrics, 14(3), pp. 583-597.
    .. [2] http://www.itl.nist.gov/div898/handbook/eda/section3/eda35h2.htm

    Examples
    --------
    >>> x = np.array([-1.40, -0.44, -0.30, -0.24, -0.22, -0.13, -0.05, 0.06,
    0.10, 0.18, 0.20, 0.39, 0.48, 0.63, 1.01])
    >>> outliers_tietjen(x, 2)
    array([-0.44, -0.3 , -0.24, -0.22, -0.13, -0.05,  0.06,  0.1 ,  0.18,
    0.2 ,  0.39,  0.48,  0.63])

    """

    arr = np.copy(x)
    n = arr.size
    def tietjen(x_, k_):
        x_mean = x_.mean()
        r = np.abs(x_ - x_mean)
        z = x_[r.argsort()]
        E = np.sum((z[:-k_] - z[:-k_].mean()) ** 2) / np.sum((z - x_mean) ** 2)
        return E

    e_x = tietjen(arr, k)
    e_norm = np.zeros(10000)

    for i in np.arange(10000):
        norm = np.random.normal(size=n)
        e_norm[i] = tietjen(norm, k)

    CV = np.percentile(e_norm, alpha * 100)
    result = e_x < CV

    if hypo:
        return result
    else:
        if result:
            ind = np.argpartition(np.abs(arr - arr.mean()), -k)[-k:]
            return np.delete(arr, ind)
        else:
            return arr

def outliers_gesd(x, outliers = 5, hypo = False, report = False, alpha=0.05):

    """
    The generalized (Extreme Studentized Deviate) ESD test is used
    to detect one or more outliers in a univariate data set that follows
    an approximately normal distribution [1]_.

    Parameters
    ----------
    x : array_like or np.ndarray, 1d
        An array, any object exposing the array interface, containing
        data to test for outliers.

    outliers : int, optional
        Number of potential outliers to test for. Test is two-tailed, i.e.
        maximum and minimum values are checked for potential outliers.

    hypo : bool, optional
        Specifies whether to return a bool value of a hypothesis test result.
        Returns True when we can reject the null hypothesis. Otherwise, False.
        Available options are:
        1) True - return a hypothesis test result
        2) False - return a filtered array without an outlier (default)

    report : bool, optional
        Specifies whether to return a summary table of the test.
        Available options are:
        1) True - return a summary table
        2) False - return the array with outliers removed. (default)

    alpha : float, optional
        Significance level for a hypothesis test. Default is 0.05.

    Returns
    -------
    result : np.ndarray
        Filtered array if alternative hypo is True, otherwise an unfiltered
        (input) array.

    report : str, optional
        If `report` argument is True, test report is returned instead of
        the result.

    Notes
    -----
    .. [1] Rosner, Bernard (May 1983), Percentage Points for a Generalized
        ESD Many-Outlier Procedure,Technometrics, 25(2), pp. 165-172.

    Examples
    --------
    >>> data = np.array([-0.25, 0.68, 0.94, 1.15, 1.2, 1.26, 1.26, 1.34,
        1.38, 1.43, 1.49, 1.49, 1.55, 1.56, 1.58, 1.65, 1.69, 1.7, 1.76,
        1.77, 1.81, 1.91, 1.94, 1.96, 1.99, 2.06, 2.09, 2.1, 2.14, 2.15,
        2.23, 2.24, 2.26, 2.35, 2.37, 2.4, 2.47, 2.54, 2.62, 2.64, 2.9,
        2.92, 2.92, 2.93, 3.21, 3.26, 3.3, 3.59, 3.68, 4.3, 4.64, 5.34,
        5.42, 6.01])

    >>> outliers_gesd(data, 5)
    array([-0.25,  0.68,  0.94,  1.15,  1.2 ,  1.26,  1.26,  1.34,  1.38,
            1.43,  1.49,  1.49,  1.55,  1.56,  1.58,  1.65,  1.69,  1.7 ,
            1.76,  1.77,  1.81,  1.91,  1.94,  1.96,  1.99,  2.06,  2.09,
            2.1 ,  2.14,  2.15,  2.23,  2.24,  2.26,  2.35,  2.37,  2.4 ,
            2.47,  2.54,  2.62,  2.64,  2.9 ,  2.92,  2.92,  2.93,  3.21,
            3.26,  3.3 ,  3.59,  3.68,  4.3 ,  4.64])

    >>> outliers_gesd(data, outliers = 5, report = True)
    H0: no outliers in the data
    Ha: up to 5 outliers in the data
    Significance level:  α = 0.05
    Reject H0 if Ri > Critical Value (λi)

    Summary Table for Two-Tailed Test
    ---------------------------------------
          Exact           Test     Critical
      Number of      Statistic    Value, λi
    Outliers, i      Value, Ri          5 %
    ---------------------------------------
              1          3.119        3.159
              2          2.943        3.151
              3          3.179        3.144 *
              4           2.81        3.136
              5          2.816        3.128

    """

    rs, ls = np.zeros(outliers, dtype = float), np.zeros(outliers, dtype = float)
    ms = []

    data_proc = np.copy(x)
    argsort_index = np.argsort(data_proc)
    data = data_proc[argsort_index]
    n = data_proc.size

    for i in np.arange(outliers):

        abs_d = np.abs(data_proc - np.mean(data_proc))

        # R-value calculation
        R = np.max(abs_d) / np.std(data_proc, ddof=1)
        rs[i] = R

        # Masked values
        lms = ms[-1] if len(ms) > 0 else []
        ms.append(lms + np.where(data == data_proc[np.argmax(abs_d)])[0].tolist())

        # Lambdas calculation
        p = 1 - alpha / (2 * (n - i))
        df = n - i - 2
        t_ppr = t.ppf(p, df)
        lambd = ((n - i - 1) * t_ppr) / np.sqrt((n - i - 2 + t_ppr**2) * (n - i))
        ls[i] = lambd

        # Remove the observation that maximizes |xi − xmean|
        data_proc = np.delete(data_proc, np.argmax(abs_d))

    if report:

        report = ["H0: no outliers in the data",
                  "Ha: up to " + str(outliers) + " outliers in the data",
                  "Significance level:  α = " + str(alpha),
                  "Reject H0 if Ri > Critical Value (λi)", "",
                  "Summary Table for Two-Tailed Test",
                  "---------------------------------------",
                  "      Exact           Test     Critical",
                  "  Number of      Statistic    Value, λi",
                  "Outliers, i      Value, Ri          5 %",
                  "---------------------------------------"]

        for i, (r, l) in enumerate(zip(rs, ls)):
            report.append('{: >11s}'.format(str(i+1)) + \
                          '{: >15s}'.format(str(np.round(r, 3))) + \
                          '{: >13s}'.format(str(np.round(l, 3))) + (" *" if r > l else ""))

        return "\n".join(report)

    else:
        # Remove masked values
        # for which the test statistic is greater
        # than the critical value and return the result

        if any(rs > ls):
            if hypo:
                data[:] = False
                data[ms[np.max(np.where(rs > ls))]] = True
                # rearrange data so mask is in same order as incoming data
                data = np.vstack((data, np.arange(0, data.shape[0])[argsort_index]))
                data = data[0, data.argsort()[1,]]
                data = data.astype('bool')
            else:
                data = np.delete(data, ms[np.max(np.where(rs > ls))])

        return data


import numpy as np
import time

def length(point1, point2):
    return np.sqrt((point1.x - point2.x)**2 + (point1.y - point2.y)**2)

def nearesrNeighborHeuristic(nodeCount, points):
    solution = [0]
    unvisited_node = list(range(1, nodeCount)) # from 1 to nodeCount - 1
    while len(unvisited_node) != 0:
        exploring_node = solution[-1] # the current city we are in
        closed_distance = -1
        closed_node = None
        for node in unvisited_node:
            if closed_distance < 0:
                closed_distance = length(points[exploring_node], points[node])
                closed_node = node
            elif length(points[exploring_node], points[node]) < closed_distance:
                closed_distance = length(points[exploring_node], points[node])
                closed_node = node
        next_visit_node = closed_node
        solution.append(next_visit_node)
        unvisited_node.remove(next_visit_node)
    return solution

def objectiveVal(path, points):
    totalDist = 0
    nodeCount = len(path)
    for i in range(nodeCount):
        totalDist += length(points[path[i] % (nodeCount-2)], points[path[i+1] % (nodeCount-2)])
    return totalDist

def two_opt(nodeCount, points, timelimit = None):
    feasible_sol = nearesrNeighborHeuristic(nodeCount, points)
    start_time = time.time()
    def checkCrossArcs(path):
        crossArc = False
        largest_diff = 0
        swap_ix = None
        for pair1 in range(0, len(path)-2):
            for pair2 in range(pair1+1, len(path)-1):
                i, j = path[pair1], path[pair1+1]
                k, l = path[pair2], path[pair2+1]
                d_ij = length(points[i], points[j])
                d_kl = length(points[k], points[l])
                d_ik = length(points[i], points[k])
                d_jl = length(points[j], points[l])
                if d_ij + d_kl > d_ik + d_jl:
                    if (d_ij + d_kl)- (d_ik + d_jl) > largest_diff:
                        largest_diff = (d_ij + d_kl)  - (d_ik + d_jl)
                        swap_ix = pair1, pair1+1, pair2, pair2+1
                        crossArc = True
        return crossArc, swap_ix
    terminal,swap_ix = checkCrossArcs(feasible_sol)
    while terminal:
        i, j, k, l = swap_ix
        improved_sol = feasible_sol[:j] + feasible_sol[j:k+1][::-1] + feasible_sol[k+1:]
        feasible_sol = improved_sol
        terminal, swap_ix = checkCrossArcs(feasible_sol)
        if time.time() - start_time > timelimit:
            return feasible_sol, objectiveVal(feasible_sol, points)
        #print(objectiveVal(feasible_sol, points))
    totalDist = objectiveVal(feasible_sol, points)
    assert len(feasible_sol) == nodeCount, "There are some nodes left unvisited."
    return feasible_sol, totalDist


from numpy import prod, zeros, sqrt
from numpy.random import randn
from scipy.linalg import qr
from sklearn.metrics import mean_squared_error

def godec(X, rank=1, card=None, iterated_power=1, max_iter=100, tol=0.001):
    """
    GoDec - Go Decomposition (Tianyi Zhou and Dacheng Tao, 2011)

    The algorithm estimate the low-rank part L and the sparse part S of a matrix X = L + S + G with noise G.

    Parameters
    ----------
    X : array-like, shape (n_features, n_samples), which will be decomposed into a sparse matrix S
        and a low-rank matrix L.

    rank : int >= 1, optional
        The rank of low-rank matrix. The default is 1.

    card : int >= 0, optional
        The cardinality of the sparse matrix. The default is None (number of array elements in X).

    iterated_power : int >= 1, optional
        Number of iterations for the power method, increasing it lead to better accuracy and more time cost. The default is 1.

    max_iter : int >= 0, optional
        Maximum number of iterations to be run. The default is 100.

    tol : float >= 0, optional
        Tolerance for stopping criteria. The default is 0.001.

    Returns
    -------
    L : array-like, low-rank matrix.

    S : array-like, sparse matrix.

    LS : array-like, reconstruction matrix.

    RMSE : root-mean-square error.

    References
    ----------
    Zhou, T. and Tao, D. "GoDec: Randomized Lo-rank & Sparse Matrix Decomposition in Noisy Case", ICML 2011.
    """
    iter = 1
    RMSE = []
    card = prod(X.shape) if card is None else card

    X = X.T if(X.shape[0] < X.shape[1]) else X
    m, n = X.shape

    # Initialization of L and S
    L = X
    S = zeros(X.shape)
    LS = zeros(X.shape)

    while True:
        # Update of L
        Y2 = randn(n, rank)
        for i in range(iterated_power):
            Y1 = L.dot(Y2)
            Y2 = L.T.dot(Y1)
        Q, R = qr(Y2, mode='economic')
        L_new = (L.dot(Q)).dot(Q.T)

        # Update of S
        T = L - L_new + S
        L = L_new
        T_vec = T.reshape(-1)
        S_vec = S.reshape(-1)
        idx = abs(T_vec).argsort()[::-1]
        S_vec[idx[:card]] = T_vec[idx[:card]]
        S = S_vec.reshape(S.shape)

        # Reconstruction
        LS = L + S

        # Stopping criteria
        error = sqrt(mean_squared_error(X, LS))
        RMSE.append(error)

        print("iter: ", iter, "error: ", error)
        if (error <= tol) or (iter >= max_iter):
            break
        else:
            iter = iter + 1

    return L, S, LS, RMSE


import numpy as np

from metrics import r2_score

class SimpleLinearRegression1:
    """
    模型训练中使用 for 循环
    """

    def __init__(self):
        """初始化简单线性回归模型"""
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        """根据训练数据集训练模型"""
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)

        num = 0.0
        d = 0.0

        for x_i, y_i in zip(x_train, y_train):
            num += (x_i - x_mean) * (y_i - y_mean)
            d += (x_i - x_mean) ** 2

        self.a_ = num / d
        self.b_ = y_mean - self.a_ * x_mean

        return self

    def predict(self, x_predict):
        """根据给定的待测数据集，返回预测的结果向量"""
        return np.array([self._predict(x) for x in x_predict])

    def _predict(self, x_single):
        """预测给定的单个待测数据"""
        return self.a_* x_single + self.b_

    def score(self, x_test, y_test):
        """根据测试数据集确定当前模型的准确度"""
        y_predict = self.predict(x_test)
        return r2_score(y_test, y_predict)

    def __repr__(self):
        return "SimpleLinearRegression1()"

class SimpleLinearRegression2:
    """
    模型训练中使用向量化运算
    """

    def __init__(self):
        """初始化简单线性回归模型"""
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        """根据训练数据集训练模型"""
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)

        num = (x_train - x_mean).dot(y_train - y_mean)
        d = (x_train - x_mean).dot(x_train - x_mean)

        self.a_ = num / d
        self.b_ = y_mean - self.a_ * x_mean

        return self

    def predict(self, x_predict):
        """根据给定的待测数据集，返回预测的结果向量"""
        return np.array([self._predict(x) for x in x_predict])

    def _predict(self, x_single):
        """预测给定的单个待测数据"""
        return self.a_* x_single + self.b_

    def score(self, x_test, y_test):
        """根据测试数据集确定当前模型的准确度"""
        y_predict = self.predict(x_test)
        return r2_score(y_test, y_predict)

    def __repr__(self):
        return "SimpleLinearRegression2()"


import numpy as np
import scipy.linalg as LA

def lqr_gain(A,B,Q,R):
  '''
  Arguments:
    State transition matrices (A,B)
    LQR Costs (Q,R)
  Outputs:
    K: optimal infinite-horizon LQR gain matrix given
  '''

  # solve DARE:
  M=LA.solve_discrete_are(A,B,Q,R)

  # K=(B'MB + R)^(-1)*(B'MA)
  return np.dot(LA.inv(np.dot(np.dot(B.T,M),B)+R),(np.dot(np.dot(B.T,M),A)))

def cost_inf_K(A,B,Q,R,K):
  '''
    Arguments:
      State transition matrices (A,B)
      LQR Costs (Q,R)
      Control Gain K
    Outputs:
      cost: Infinite time horizon LQR cost of static gain K
  '''
  cl_map = A+B.dot(K)
  if np.amax(np.abs(LA.eigvals(cl_map)))<(1.0-1.0e-6):
    cost = np.trace(LA.solve_discrete_lyapunov(cl_map.T,Q+np.dot(K.T,R.dot(K))))
  else:
    cost = float("inf")

  return cost

def cost_finite_model(A_true,B_true,Q,R,x0,T,A_dat,B_dat):
  '''
    Arguments:
      True Model state transition matrices (A_true,B_true)
      LQR Costs (Q,R)
      Initial State x0
      Time Horizon T
      Nominal Model state transition matrices (A_dat,B_dat)
    Outputs:
      cost: finite time horizon LQR cost when control is computed using
      (A_dat,B_dat) but executed on system (A_true,B_true)
  '''
  d,p = B_true.shape

  # Ricatti recursion
  M = np.zeros((d,d,T))
  M[:,:,-1]=Q
  for k in range(T-2,-1,-1):
    AMA = np.dot(A_dat.T,M[:,:,k+1].dot(A_dat))
    AMB = np.dot(A_dat.T,M[:,:,k+1].dot(B_dat))
    BMB = np.dot(B_dat.T,M[:,:,k+1].dot(B_dat))
    M[:,:,k] = Q + AMA - np.dot(AMB,LA.inv(R+BMB).dot(AMB.T))

  # compute contols and costs using these Ricatti iterates
  cost = 0
  x = x0
  for k in range(T):
    AMB = np.dot(A_dat.T,M[:,:,k].dot(B_dat))
    BMB = np.dot(B_dat.T,M[:,:,k].dot(B_dat))
    u = -np.dot(LA.inv(R+BMB),np.dot(AMB.T,x))
    x = A_true.dot(x)+B_true.dot(u)
    cost = cost+np.dot(x.T,Q.dot(x))+np.dot(u.T,R.dot(u))

  return cost.flatten()[0]

def cost_finite_K(A_true,B_true,Q,R,x0,T,K):
  '''
    Arguments:
      True Model state transition matrices (A_true,B_true)
      LQR Costs (Q,R)
      Initial State x0
      Time Horizon T
      Static Control Gain K
    Outputs:
      cost: finite time horizon LQR cost when control is static gain K on
      system (A_true,B_true)
  '''

  d,p = B_true.shape

  cost = 0
  x = x0
  for k in range(T):
    u = np.dot(K,x)
    x = A_true.dot(x)+B_true.dot(u)
    cost = cost+np.dot(x.T,Q.dot(x))+np.dot(u.T,R.dot(u))

  return cost.flatten()

def lsqr_estimator(A,B,Q,R,x0,eq_err,N,T):
  '''
    Arguments:
      state transition matrices (A,B)
      LQR Costs (Q,R)
      Initial State x0
      magnitude of noise in dynamics eq_err
      Number of rollouts N
      Time Horizon T
    Outputs:
      Estimated State Transition Matrices (A_nom,B_nom) from least squares
  '''

  d,p = B.shape

  # storage matrices
  X_store = np.zeros((d,N,T+1))
  U_store = np.zeros((p,N,T))

  # simulate
  for k in range(N):
    x = x0
    X_store[:,k,0] = x0.flatten()
    for t in range(T):
      u = np.random.randn(p,1)
      x = A.dot(x)+B.dot(u)+eq_err*np.random.randn(d,1)
      X_store[:,k,t+1] = x.flatten()
      U_store[:,k,t] = u.flatten()

  ### Solve for nominal model
  tmp = np.linalg.lstsq(np.vstack((X_store[:,:,0:T].reshape(d,N*T),
                                U_store.reshape(p,N*T))).T,
                    X_store[:,:,1:(T+1)].reshape(d,N*T).T)[0]
  A_nom = tmp[0:d,:].T
  B_nom = tmp[d:(d+p),:].T
  return (A_nom,B_nom)

def random_search_linear_policy(A,B,Q,R,x0,eq_err,N,T,
    explore_mag = 4e-2, step_size = 5e-1, batch_size = 4):
  '''
    Arguments:
      state transition matrices (A,B)
      LQR Costs (Q,R)
      Initial State x0
      magnitude of noise in dynamics eq_err
      Number of rollouts N
      Time Horizon T

      hyperparameters:
        explore_mag = magnitude of the noise to explore
        step_size
        batch_size = number of directions per minibatches
        safeguard: maximum absolute value of entries of controller gain

    Outputs:
      Static Control Gain K optimized on LQR cost by random search
  '''

  d,p = B.shape

  # initial condition for K
  K0 = 1e-3*np.random.randn(p,d)
  ###

  #### ALGORITHM
  K = K0
  for k in range(N):
    reward_store = []
    mini_batch = np.zeros((p,d))
    for j in range(batch_size):
      V = explore_mag*np.random.randn(p,d)
      for sign in [-1,1]:
        x = x0
        reward = 0
        for t in range(T):
          u = np.dot(K+sign*V,x)
          x = A.dot(x)+B.dot(u)+eq_err*np.random.randn(d,1)
          reward += -np.dot(x.T,Q.dot(x))-np.dot(u.T,R.dot(u))
        mini_batch += (reward*sign)*V
        reward_store.append(reward)
    K += (step_size/np.std(reward_store)/batch_size)*mini_batch

  return K

def uniform_random_linear_policy(A,B,Q,R,x0,eq_err,N,T,linf_norm=3):
  '''
    Arguments:
      state transition matrices (A,B)
      LQR Costs (Q,R)
      Initial State x0
      magnitude of noise in dynamics eq_err
      Number of rollouts N
      Time Horizon T

      hyperparameters
          linf_norm = maximum absolute value of entries of controller gain

    Outputs:
      Static Control Gain K optimized on LQR cost by uniformly sampling policies
      in bounded region
  '''

  d,p = B.shape

  #### "ALGORITHM"
  best_K = np.empty((p,d))
  best_reward = -float("inf")
  for k in range(N):
    K = np.random.uniform(-linf_norm,linf_norm,(p,d))
    x = x0
    reward = 0
    for t in range(T):
      u = np.dot(K,x)
      x = A.dot(x)+B.dot(u)+eq_err*np.random.randn(d,1)
      reward += -np.dot(x.T,Q.dot(x))-np.dot(u.T,R.dot(u))
    if reward>best_reward:
        best_reward = reward
        best_K = K

  return best_K

def policy_gradient_linear_policy(A,B,Q,R,x0,eq_err,N,T,
  explore_mag = 5e-2,step_size = 2, batch_size = 40, safeguard = 2):
  '''
    Arguments:
      state transition matrices (A,B)
      LQR Costs (Q,R)
      Initial State x0
      magnitude of noise in dynamics eq_err
      Number of rollouts N
      Time Horizon T

      hyperparameters
         explore_mag magnitude of the noise to explore
         step_size
         batch_size: number of stochastic gradients per minibatch
         safeguard: maximum absolute value of entries of controller gain

    Outputs:
      Static Control Gain K optimized on LQR cost by Policy Gradient
  '''

  d,p = B.shape

  # initial condition for K
  K0 = 1e-3*np.random.randn(p,d)
  ###

  X_store = np.zeros((d,T))
  V_store = np.zeros((p,T))

  #### ALGORITHM
  K = K0
  baseline = 0
  for k in range(N):
    new_baseline = 0
    mini_batch = np.zeros((p,d))
    for j in range(batch_size):
      x = x0
      reward = 0
      for t in range(T):
        v = explore_mag*np.random.randn(p,1)
        X_store[:,t] = x.flatten()
        V_store[:,t] = v.flatten()
        u = np.dot(K,x)+v
        x = A.dot(x)+B.dot(u)+eq_err*np.random.randn(d,1)
        reward += -np.dot(x.T,Q.dot(x))-np.dot(u.T,R.dot(u))
      mini_batch += ((reward-baseline)/batch_size)*np.dot(V_store,X_store.T)
      new_baseline += reward/batch_size
    K += step_size*mini_batch
    K = np.minimum(np.maximum(K,-safeguard),safeguard)
    baseline = new_baseline
  return K