##################################################################
### This file is used to generate Figures & Tables in Chapter7 ###
##################################################################

import os
import time
import numpy as np
import tensorflow as tf
from tensorflow.random import set_seed
from math import factorial
from scipy.stats import norm
from scipy.integrate import odeint
import numpy.polynomial.hermite_e as H
from sklearn.preprocessing import StandardScaler
import dolfin as fn
from numpy.polynomial.legendre import leggauss
import matplotlib.pyplot as plt

####### Plot Formatting ######
plt.rc('lines', linewidth = 4)
plt.rc('xtick', labelsize = 13)
plt.rc('ytick', labelsize = 13)
plt.rc('legend',fontsize=14)
plt.rcParams["font.family"] = "serif"
plt.rcParams['axes.labelsize'] = 18
plt.rcParams['axes.titlesize'] = 15
plt.rcParams['lines.markersize'] = 8
plt.rcParams['figure.figsize'] = (7.0, 5.0)

#### To make it cleaner, create Directory "images" to store all the figures ####
imagepath = os.path.join(os.getcwd(),"images")
os.makedirs(imagepath,exist_ok=True)

##################################################
##############        PCE vs MC     ##############
##################################################

############## PCE ###############
start_def = time.time()
def Phi(n):
    #define H_n
    coeffs = [0]*(n+1)
    coeffs[n] = 1
    return coeffs

def inner2_herm(n):       ###return the denominator when computing $k_i$
    return factorial(n)

def product3_herm(i,j,l):
    #compute \Phi_i*\Phi_j*\Phi_l
    return lambda x: H.hermeval(x, H.hermemul(H.hermemul(Phi(i),Phi(j)),Phi(l)))

def inner3_herm(P,i,j,l):
    #compute <\Phi_i\Phi_j\Phi_l>
    #Set up Gauss-Hermite quadrature, weighting function is exp^{-x^2}
    m=(P+1)**2
    x, w=H.hermegauss(m)
    inner=sum([product3_herm(i,j,l)(x[idx]) * w[idx] for idx in range(m)])               return inner/np.sqrt(2*np.pi)   #because of the weight
time_def = time.time() - start_def

start_prep = time.time()
P=4
ki_herm = [0,1]+[0]*(P-1)
Inner3_herm = np.zeros((P+1,P+1,P+1)) #store all inner3_herm values
Inner2_herm = np.zeros(P+1)
for i in range(P+1):
    for j in range(P+1):
        for l in range(P+1):
            Inner3_herm[i,j,l] = inner3_herm(P,i,j,l)
for i in range(P+1):
    Inner2_herm[i] = inner2_herm(i)
time_prep = time.time() - start_prep

start_ode = time.time()
def ode_system_herm(y, t, P):
    #P indicates the highest degree
    dydt = np.zeros(P+1)
    for l in range(len(dydt)):
        dydt[l] = -(sum(sum(Inner3_herm[i,j,l]*ki_herm[i]*y[j] for j in range(P+1)) for i in range(P+1)))/Inner2_herm[l]
    return dydt
time_ode = time.time() - start_ode

start_solveode = time.time()
sol_herm = odeint(ode_system_herm, [1.0]+[0.0]*P, np.linspace(0,1,101), args=(P, ))
time_solveode = time.time() - start_solveode

time_all = time_def + time_prep + time_ode + time_solveode

############## MC ###############
start_ode_mc = time.time()
def ode(y,t,nsample,k):
    '''
    Build the ode system
    '''
    dydt = np.zeros(nsample)
    for i in range(nsample):
        dydt[i] = -k[i]*y[i]
    return dydt
time_def_mc = time.time() - start_ode_mc

nsample = np.array([10, 100, 1000, 10000, 100000])
time_solveode_mc = np.zeros(len(nsample))
start_solveode_mc = np.zeros(len(nsample))
mean_mc_1 = np.zeros(len(nsample))
mean_mc_05 = np.zeros(len(nsample))
for i in range(len(nsample)):
    k = norm.rvs(loc=0, scale=1, size=nsample[i], random_state=12345)
    start_solveode_mc[i] = time.time()
    sol_mc = odeint(ode, [1.0]*nsample[i], np.linspace(0,1,101),args=(nsample[i],k))  #t:np.linspace(0,1,101)
    mean_mc_1[i] = np.mean(sol_mc[100,:])
    mean_mc_05[i] = np.mean(sol_mc[50,:])
    time_solveode_mc[i] = time.time() - start_solveode_mc[i]

time_all_mc = time_def_mc + time_solveode_mc

############## Comparison ###############
#### Table 7.2, row 1 ####
### PCE
print(time_solveode)
### MC
print(time_solveode_mc)

## t = 0.5
mean_pc_05 = sol_herm[:,0][50]   #mean value using pc at t=0.5
mean_exact_05 = np.e**(1/8)
## t = 1
mean_pc_1 = sol_herm[:,0][100]   #mean value using pc at t=1
mean_exact_1 = np.e**(1/2)

#### Table 7.2, row 2 ####
print(mean_pc_05)
print(mean_mc_05)
print(mean_exact_05)

print()

#### Table 7.2, row 3 ####
print(mean_pc_1)
print(mean_mc_1)
print(mean_exact_1)

##################################################
##############       NN vs Poly     ##############
##################################################

############## NN ###############
#Define the activation function
def rbf(x):
    return tf.math.exp(-x**2)
def d_rbf(x):
    return tf.gradients(rbf,x)
def rbf_grad(op, grad):
    x = op.inputs[0]
    n_gr = d_rbf(x)    #defining the gradient.
    return grad * n_gr
def py_func(func, inp, Tout, stateful=True, name=None, grad=None):
    # Need to generate a unique name to avoid duplicates:
    rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+2))
    tf.RegisterGradient(rnd_name)(grad)
    g = tf.get_default_graph()
    with g.gradient_override_map({"PyFunc": rnd_name, "PyFuncStateless": rnd_name}):
        return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
def tf_rbf(x,name=None):
    with tf.name_scope(name, "rbf", [x]) as name:
        y = py_func(rbf,   #forward pass function
                    [x],
                    [tf.float32],
                    name=name,
                    grad= rbf_grad) #the function that overrides gradient
        y[0].set_shape(x.get_shape())     #when using with the code, it is used to specify the rank of the input.
    return y[0]

np.random.seed(12345)
size = 100
delta_t = 0.01
n = int(0.5/delta_t)
### Original data ###
lam_in = np.random.normal(0, 1, size)
y_exact = np.array([np.exp(-i*0.5) for i in lam_in])
y_out = np.array([(1-i*delta_t)**n for i in lam_in])
### After feature scaling ###
scaler = StandardScaler()
data_trans = scaler.fit_transform(lam_in.reshape(-1,1))

num_neuron = 5
tf.random.set_seed(12345)
model_ode = tf.keras.Sequential()
model_ode.add(tf.keras.layers.Dense(num_neuron,activation=rbf))
model_ode.add(tf.keras.layers.Dense(1))
model_ode.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.01))
model_ode.fit(data_trans[:,0],y_out, epochs=1500, verbose=0)

preds_ode = []
for j in data_trans[:,0]:
    preds_ode.append(model_ode.predict([j]))
preds_ode_shaped = tf.reshape(tf.constant(np.array(preds_ode)),len(preds_ode))
mse_fd_nn = tf.keras.losses.MSE(y_exact,preds_ode_shaped).numpy()

fig = plt.figure()
plt.xlabel("$\lambda$")
plt.ylabel("$q$")
plt.title("MSE=%.5f"%(mse_fd_nn))
plt.scatter(lam_in, y_out, label='Obs')
plt.scatter(lam_in, preds_ode_shaped, label='NN')
plt.legend()
plt.show();
# fig.savefig("images/comp_fd_nn.png")

############## Polynomial Regression ###############
mymodel3 = np.poly1d(np.polyfit(data_trans[:,0], y_out, 3))
preds_fd_pr3 = mymodel3(data_trans[:,0])
mse_fd_pr3 = tf.keras.losses.MSE(y_exact,preds_fd_pr3).numpy()

fig = plt.figure()
plt.xlabel("$\lambda$")
plt.ylabel("$q$")
plt.title("MSE=%.5f"%(mse_fd_pr3))
plt.scatter(lam_in, y_out, label='Obs')
plt.scatter(lam_in, preds_fd_pr3, label='PR (deg=3)')
plt.legend()
plt.show();
# fig.savefig("images/comp_fd_pr3.png")

####################################################
########  Stochastic collocation method   ##########
####################################################
def QoI_FEM(x0,y0,lam1,lam2,gridx,gridy,p):
    mesh = fn.UnitSquareMesh(gridx, gridy)
    V = fn.FunctionSpace(mesh, "Lagrange", p)

    # Define diffusion tensor (here, just a scalar function) and parameters
    A = fn.Expression((('exp(lam1)','a'),
                ('a','exp(lam2)')), a = fn.Constant(0.0), lam1 = lam1, lam2 = lam2, degree=3)

    u_exact = fn.Expression("sin(lam1*pi*x[0])*cos(lam2*pi*x[1])", lam1 = lam1, lam2 = lam2, degree=2+p)

    # Define the mix of Neumann and Dirichlet BCs
    class LeftBoundary(fn.SubDomain):
        def inside(self, x, on_boundary):
            return (x[0] < fn.DOLFIN_EPS)
    class RightBoundary(fn.SubDomain):
        def inside(self, x, on_boundary):
            return (x[0] > 1.0 - fn.DOLFIN_EPS)
    class TopBoundary(fn.SubDomain):
        def inside(self, x, on_boundary):
            return (x[1] > 1.0 - fn.DOLFIN_EPS)
    class BottomBoundary(fn.SubDomain):
        def inside(self, x, on_boundary):
            return (x[1] < fn.DOLFIN_EPS)

    # Create a mesh function (mf) assigning an unsigned integer ('uint')
    # to each edge (which is a "Facet" in 2D)
    mf = fn.MeshFunction('size_t', mesh, 1)
    mf.set_all(0) # initialize the function to be zero
    # Setup the boundary classes that use Neumann boundary conditions
    NTB = TopBoundary() # instatiate
    NTB.mark(mf, 1) # set all values of the mf to be 1 on this boundary
    NBB = BottomBoundary()
    NBB.mark(mf, 2) # set all values of the mf to be 2 on this boundary
    NRB = RightBoundary()
    NRB.mark(mf, 3)

    # Define Dirichlet boundary conditions
    Gamma_0 = fn.DirichletBC(V, u_exact, LeftBoundary())
    bcs = [Gamma_0]

    # Define data necessary to approximate exact solution
    f = ( fn.exp(lam1)*(lam1*fn.pi)**2 + fn.exp(lam2)*(lam2*fn.pi)**2 ) * u_exact
    g1 = fn.Expression("-exp(lam2)*lam2*pi*sin(lam1*pi*x[0])*sin(lam2*pi*x[1])", lam1=lam1, lam2=lam2, degree=2+p)    #pointing outward unit normal vector, pointing upaward (0,1)
    g2 = fn.Expression("exp(lam2)*lam2*pi*sin(lam1*pi*x[0])*sin(lam2*pi*x[1])", lam1=lam1, lam2=lam2, degree=2+p)     #pointing downward (0,1)
    g3 = fn.Expression("exp(lam1)*lam1*pi*cos(lam1*pi*x[0])*cos(lam2*pi*x[1])", lam1=lam1, lam2=lam2, degree=2+p)

    fn.ds = fn.ds(subdomain_data=mf)
    # Define variational problem
    u = fn.TrialFunction(V)
    v = fn.TestFunction(V)
    a = fn.inner(A*fn.grad(u), fn.grad(v))*fn.dx
    L = f*v*fn.dx + g1*v*fn.ds(1) + g2*v*fn.ds(2) + g3*v*fn.ds(3)  #note the 1, 2 and 3 correspond to the mf

    # Compute solution
    u = fn.Function(V)
    fn.solve(a == L, u, bcs)

    return u(x0,y0)

def exactQ(x,y):
    return (1-np.cos(np.pi*x))*np.sin(np.pi*y)/(np.pi**2*x*y)

x0 = [0.2, 0.2, 0.2, 0.3, 0.5, 0.5]
y0 = [0.3, 0.5, 0.8, 0.2, 0.2, 0.5]
M, N = 5, 5
x1,w1 = leggauss(M)
x2,w2 = leggauss(N)
tab = np.zeros((len(x0),2))
for k in range(len(x0)):
    #### Stochastic Collocation Mean at x0, y0 ####
    uij = np.zeros((M,N))
    for i in range(M):
        for j in range(N):
            uij[i,j] = QoI_FEM(x0[k],y0[k],(1+x1[i])/2,(1+x2[j])/2,10,10,2)

    sol = 0
    for i in range(M):
        for j in range(N):
            sol += w1[i]*w2[j]*uij[i,j]
    sol /= 4
    tab[k,0] = sol
    #### Exact Mean at x0, y0 ####
    tab[k,1] = exactQ(x0[k],y0[k])

print(tab)

##################################################
##############       Discussion     ##############
##################################################
def model(x):
    if x<=1:
        return 15*x+10
    elif x<=7:
        return x**3-12*x**2+36*x
    elif x<=10:
        return 15/np.pi*np.sin(np.pi*(x-7))+7
    else:
        return -30*np.sqrt(x-9)+37

np.random.seed(12345)
x_syn = np.random.uniform(0,15,100)
y_exact = np.array([model(i) for i in x_syn])
y_syn = y_exact+np.random.normal(0,1,len(x_syn))

scaler_syn = StandardScaler()
syndata_trans = scaler_syn.fit_transform(x_syn.reshape(-1,1))

num_neuron = 5
tf.random.set_seed(12345)
model_syn_all = tf.keras.Sequential()
model_syn_all.add(tf.keras.layers.Dense(num_neuron,activation=rbf))
model_syn_all.add(tf.keras.layers.Dense(num_neuron,activation=rbf))
# model_syn_all.add(tf.keras.layers.Dense(num_neuron,activation=rbf))
# model_syn_all.add(tf.keras.layers.Dense(num_neuron,activation=rbf))
model_syn_all.add(tf.keras.layers.Dense(1))
model_syn_all.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.01))
model_syn_all.fit(syndata_trans[:,0],y_syn, epochs=1000, verbose=0)

fig = plt.figure()
plt.xlabel("$x$")
plt.ylabel("$y$")
y_pred = []
for j in syndata_trans[:,0]:
    y_pred.append(model_syn_all.predict([j]))
y_pred_shaped = tf.reshape(tf.constant(np.array(y_pred)),len(y_pred))
error0 = tf.keras.losses.MSE(y_syn,y_pred_shaped).numpy()
plt.title("MSE=%.5f"%(error0))
plt.scatter(x_syn, y_syn, label='Obs')
plt.scatter(x_syn, y_pred_shaped, color='red',label="NN")
plt.legend()
plt.show();
# fig.savefig("images/comp_nn_1step.png")

## Step 1
num_neuron = 5
tf.random.set_seed(12345)
model_nn1 = tf.keras.Sequential()
model_nn1.add(tf.keras.layers.Dense(num_neuron,activation=rbf))
model_nn1.add(tf.keras.layers.Dense(1))
model_nn1.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.01))
model_nn1.fit(syndata_trans[:,0],y_syn, epochs=1000, verbose=0)

fig = plt.figure(figsize=(13,4))
plt.subplot(121)
plt.xlabel("$x$")
plt.ylabel("$y$")
y_pred1 = []
for j in syndata_trans[:,0]:
    y_pred1.append(model_nn1.predict([j]))
y_pred1_shaped = tf.reshape(tf.constant(np.array(y_pred1)),len(y_pred1))
plt.title("Overall Fit")
plt.scatter(x_syn, y_syn, label='Obs')
plt.scatter(x_syn, y_pred1_shaped, color='red',label="NN")
plt.legend();
plt.subplot(122)
plt.xlabel("$x$")
plt.ylabel("Residual")
mse1 = tf.keras.losses.MSE(y_syn,y_pred1_shaped).numpy()
plt.title("MSE=%.5f"%(mse1))
plt.scatter(x_syn, y_syn-y_pred1_shaped)
plt.show();
# fig.savefig("images/comp_nn_step1.png");

## Step 2
tf.random.set_seed(12345)
model_nn2 = tf.keras.Sequential()
model_nn2.add(tf.keras.layers.Dense(5,activation=rbf))
model_nn2.add(tf.keras.layers.Dense(1))
error1 = y_syn - y_pred1_shaped
scaler_syn2 = StandardScaler()
model_nn2.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.01))
model_nn2.fit(syndata_trans[:,0],error1, epochs=1000, verbose=0)

fig = plt.figure(figsize=(15,4))
plt.subplot(121)
plt.xlabel("$x$")
plt.ylabel("$y$")
y_pred2 = []
for j in syndata_trans[:,0]:
    y_pred2.append(model_nn2.predict([j]))
y_pred2_shaped = tf.reshape(tf.constant(np.array(y_pred2)),len(y_pred2))
plt.title("Overall Fit")
plt.scatter(x_syn, y_syn, label='Obs')
plt.scatter(x_syn, y_pred1_shaped+y_pred2_shaped, color='red',label="NN")
plt.legend();
plt.subplot(122)
plt.xlabel("$x$")
plt.ylabel("Residual")
mse2 = tf.keras.losses.MSE(y_syn,y_pred1_shaped+y_pred2_shaped).numpy()
plt.title("MSE=%.5f"%(mse2))
plt.scatter(x_syn, y_syn-y_pred1_shaped-y_pred2_shaped)
plt.show();
# fig.savefig("images/comp_nn_step2.png");

## Step 3
tf.random.set_seed(12345)
model_nn3 = tf.keras.Sequential()
model_nn3.add(tf.keras.layers.Dense(5,activation=rbf))
model_nn3.add(tf.keras.layers.Dense(1))
error2 = y_syn - y_pred1_shaped - y_pred2_shaped
scaler_syn3 = StandardScaler()
model_nn3.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.01))
model_nn3.fit(syndata_trans[:,0],error2, epochs=1000, verbose=0)

fig = plt.figure(figsize=(13,4))
plt.subplot(121)
plt.xlabel("$x$")
plt.ylabel("$y$")
y_pred3 = []
for j in syndata_trans[:,0]:
    y_pred3.append(model_nn3.predict([j]))
y_pred3_shaped = tf.reshape(tf.constant(np.array(y_pred3)),len(y_pred3))
plt.title("Overall Fit")
plt.scatter(x_syn, y_syn, label='Obs')
plt.scatter(x_syn, y_pred1_shaped+y_pred2_shaped+y_pred3_shaped, color='red',label="NN")
plt.legend();
plt.subplot(122)
plt.xlabel("$x$")
plt.ylabel("Residual")
mse3 = tf.keras.losses.MSE(y_syn,y_pred1_shaped+y_pred2_shaped+y_pred3_shaped).numpy()
plt.title("MSE=%.5f"%(mse3))
plt.scatter(x_syn, y_syn-y_pred1_shaped-y_pred2_shaped-y_pred3_shaped);
plt.show();
# fig.savefig("images/comp_nn_step3.png");

## all in one
num_neuron = 15
tf.random.set_seed(12345)
model_nn11 = tf.keras.Sequential()
model_nn11.add(tf.keras.layers.Dense(num_neuron,activation=rbf))
model_nn11.add(tf.keras.layers.Dense(1))
model_nn11.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.01))
model_nn11.fit(syndata_trans[:,0],y_syn, epochs=5000, verbose=0)

fig = plt.figure(figsize=(13,4))
plt.subplot(121)
plt.xlabel("$x$")
plt.ylabel("$y$")
y_pred11 = []
for j in syndata_trans[:,0]:
    y_pred11.append(model_nn11.predict([j]))
y_pred11_shaped = tf.reshape(tf.constant(np.array(y_pred11)),len(y_pred11))
plt.title("Overall Fit")
plt.scatter(x_syn, y_syn, label='Obs')
plt.scatter(x_syn, y_pred11_shaped, color='red', label="NN")
plt.legend();
plt.subplot(122)
plt.xlabel("$x$")
plt.ylabel("Residual")
mse11 = tf.keras.losses.MSE(y_syn,y_pred11_shaped).numpy()
plt.title("MSE=%.5f"%(mse11))
plt.scatter(x_syn, y_syn-y_pred11_shaped)
plt.show();
# fig.savefig("images/comp_nn_step11.png");


import numpy as np
import matplotlib.pyplot as plt
import pickle

##############################

data_file = 'data.pickle'

def data_load():
    with open(data_file, 'rb') as f:
        return pickle.load(f)

data = data_load()

def print_plots_names():
    for pl in data['plots']:
        print(pl['name'])

def plot_plot(p,lines=None,predict=None, save_as=None):
    fig = plt.figure()
    ax = fig.add_subplot(111)

    if p['ylim']:
        plt.ylim(0, p['ylim'])

    if not(lines):
        lines = list(range(p["no_lines"]))
    for line in lines:
        vals = p['lines'][line]
        if p['axis']=='progressive':
            x_vals = np.sqrt(np.prod(vals[:,0:6],axis=1)/10000)
        else:
            x_vals = vals[:,p['axis']]
        y_vals = vals[:, 6]
        ax.plot(x_vals, y_vals)
        if predict:
            p_vals = predict(vals)
            ax.plot(x_vals, p_vals,"k--")
    for (xs,ys,s) in p['text']:
        plt.text(xs,ys,s)
    ax.set_xlabel(p['x_axis_name'])
    ax.set_ylabel('Milliseconds')
    if save_as:
        plt.savefig(save_as, bbox_inches='tight')
    plt.show()

################## alpha flops ######################

# The function mypredict compute the alpha-flops correction accoridng to the formula given in the article
# "Dissecting FLOPs along input dimensions for GreenAI cost estimations" accepted for presentation at the
# the 7th International Online & Onsite Conference on Machine Learning, Optimization, and Data Science –
# October 4 – 8, 2021 – Grasmere, Lake District, England – UK

# we distinguish only two cases for K, namely K=1 and K>1.
# if K=1, beta is 0.02 and gamma is .99
# if K>1, then beta is 0.001 and gamma is .56
# This values have been obtained by regression over the dataset

def beta_gamma(K):
    Kis1 = K == 1
    beta = Kis1 * 0.02 + (1 - Kis1) * 0.001
    gamma = Kis1 * .99 + (1 - Kis1) * .56
    return beta,gamma

final = 0.0375

def mypredict(vals,print_prediction=False):
    D = np.prod(vals[:,0:2],axis=1)
    K = np.prod(vals[:,4:6],axis=1)
    C = np.prod(vals[:,2:4],axis=1)
    beta,gamma = beta_gamma(K)
    FLOPS = C * K * D / 1000000
    #logK = tf.math.log(K) + 1
    logK = np.log(K) +1
    x = beta * (D - logK)
    x = (logK + x) / D
    #x = tf.math.log(x)
    x = np.log(x)
    x = gamma * x
    #x = final * tf.math.exp(x)
    x = final * np.exp(x)
    Ypred = x * FLOPS
    if print_prediction:
        for i in range(0,Ypred.shape[0]):
            print("predicted = {}; actual = {}".format(Ypred[i],vals[i,6]))
    return(Ypred)

#################################################################
# Actual plotting.
# Predictions are plotted with dashed lines

plots = data["plots"]

plot_plot(plots[0],predict=mypredict) #av,se_as="PLOTS/plot1")
plot_plot(plots[1],predict=mypredict) #,save_as="PLOTS/plot2")
plot_plot(plots[2],predict=mypredict) #,save_as="PLOTS/plot3")
plot_plot(plots[3],predict=mypredict) #,save_as="PLOTS/plot4")  #K=1
plot_plot(plots[4],predict=mypredict) #,save_as="PLOTS/plot5")
plot_plot(plots[5],predict=mypredict) #,save_as="PLOTS/plot6_K1") #K=1
plot_plot(plots[6],predict=mypredict) #,save_as="PLOTS/plot11")
plot_plot(plots[7],predict=mypredict) #,save_as="PLOTS/dense_vs_batch") #K = 1


"""
author: Boris Shishov
"""

import numpy as np
from scipy.spatial import distance

EPSILON = 1e-10

def _error(actual: np.ndarray, predicted: np.ndarray):
    """ Simple error """
    return actual - predicted

def _percentage_error(actual: np.ndarray, predicted: np.ndarray):
    """
    Percentage error
    Note: result is NOT multiplied by 100
    """
    return _error(actual, predicted) / (actual + EPSILON)

def _naive_forecasting(actual: np.ndarray, seasonality: int = 1):
    """ Naive forecasting method which just repeats previous samples """
    return actual[:-seasonality]

def _relative_error(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Relative Error """
    if benchmark is None or isinstance(benchmark, int):
        # If no benchmark prediction provided - use naive forecasting
        if not isinstance(benchmark, int):
            seasonality = 1
        else:
            seasonality = benchmark
        return _error(actual[seasonality:], predicted[seasonality:]) /\
               (_error(actual[seasonality:], _naive_forecasting(actual, seasonality)) + EPSILON)

    return _error(actual, predicted) / (_error(actual, benchmark) + EPSILON)

def _bounded_relative_error(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Bounded Relative Error """
    if benchmark is None or isinstance(benchmark, int):
        # If no benchmark prediction provided - use naive forecasting
        if not isinstance(benchmark, int):
            seasonality = 1
        else:
            seasonality = benchmark

        abs_err = np.abs(_error(actual[seasonality:], predicted[seasonality:]))
        abs_err_bench = np.abs(_error(actual[seasonality:], _naive_forecasting(actual, seasonality)))
    else:
        abs_err = np.abs(_error(actual, predicted))
        abs_err_bench = np.abs(_error(actual, benchmark))

    return abs_err / (abs_err + abs_err_bench + EPSILON)

def _geometric_mean(a, axis=0, dtype=None):
    """ Geometric mean """
    if not isinstance(a, np.ndarray):  # if not an ndarray object attempt to convert it
        log_a = np.log(np.array(a, dtype=dtype))
    elif dtype:  # Must change the default dtype allowing array type
        if isinstance(a, np.ma.MaskedArray):
            log_a = np.log(np.ma.asarray(a, dtype=dtype))
        else:
            log_a = np.log(np.asarray(a, dtype=dtype))
    else:
        log_a = np.log(a)
    return np.exp(log_a.mean(axis=axis))

def mse(actual: np.ndarray, predicted: np.ndarray):
    """ Mean Squared Error """
    return np.mean(np.square(_error(actual, predicted)))

def rmse(actual: np.ndarray, predicted: np.ndarray):
    """ Root Mean Squared Error """
    return np.sqrt(mse(actual, predicted))

def nrmse(actual: np.ndarray, predicted: np.ndarray):
    """ Normalized Root Mean Squared Error """
    return rmse(actual, predicted) / (actual.max() - actual.min())

def me(actual: np.ndarray, predicted: np.ndarray):
    """ Mean Error """
    return np.mean(_error(actual, predicted))

def mae(actual: np.ndarray, predicted: np.ndarray):
    """ Mean Absolute Error """
    return np.mean(np.abs(_error(actual, predicted)))

mad = mae  # Mean Absolute Deviation (it is the same as MAE)

def gmae(actual: np.ndarray, predicted: np.ndarray):
    """ Geometric Mean Absolute Error """
    return _geometric_mean(np.abs(_error(actual, predicted)))

def mdae(actual: np.ndarray, predicted: np.ndarray):
    """ Median Absolute Error """
    return np.median(np.abs(_error(actual, predicted)))

def mpe(actual: np.ndarray, predicted: np.ndarray):
    """ Mean Percentage Error """
    return np.mean(_percentage_error(actual, predicted))

def mape(actual: np.ndarray, predicted: np.ndarray):
    """
    Mean Absolute Percentage Error
    Properties:
        + Easy to interpret
        + Scale independent
        - Biased, not symmetric
        - Undefined when actual[t] == 0
    Note: result is NOT multiplied by 100
    """
    return np.mean(np.abs(_percentage_error(actual, predicted)))

def mdape(actual: np.ndarray, predicted: np.ndarray):
    """
    Median Absolute Percentage Error
    Note: result is NOT multiplied by 100
    """
    return np.median(np.abs(_percentage_error(actual, predicted)))

def smape(actual: np.ndarray, predicted: np.ndarray):
    """
    Symmetric Mean Absolute Percentage Error
    Note: result is NOT multiplied by 100
    """
    return np.mean(2.0 * np.abs(actual - predicted) / ((np.abs(actual) + np.abs(predicted)) + EPSILON))

def smdape(actual: np.ndarray, predicted: np.ndarray):
    """
    Symmetric Median Absolute Percentage Error
    Note: result is NOT multiplied by 100
    """
    return np.median(2.0 * np.abs(actual - predicted) / ((np.abs(actual) + np.abs(predicted)) + EPSILON))

def maape(actual: np.ndarray, predicted: np.ndarray):
    """
    Mean Arctangent Absolute Percentage Error
    Note: result is NOT multiplied by 100
    """
    return np.mean(np.arctan(np.abs((actual - predicted) / (actual + EPSILON))))

def mase(actual: np.ndarray, predicted: np.ndarray, seasonality: int = 1):
    """
    Mean Absolute Scaled Error
    Baseline (benchmark) is computed with naive forecasting (shifted by @seasonality)
    """
    return mae(actual, predicted) / mae(actual[seasonality:], _naive_forecasting(actual, seasonality))

def std_ae(actual: np.ndarray, predicted: np.ndarray):
    """ Normalized Absolute Error """
    __mae = mae(actual, predicted)
    return np.sqrt(np.sum(np.square(_error(actual, predicted) - __mae))/(len(actual) - 1))

def std_ape(actual: np.ndarray, predicted: np.ndarray):
    """ Normalized Absolute Percentage Error """
    __mape = mape(actual, predicted)
    return np.sqrt(np.sum(np.square(_percentage_error(actual, predicted) - __mape))/(len(actual) - 1))

def rmspe(actual: np.ndarray, predicted: np.ndarray):
    """
    Root Mean Squared Percentage Error
    Note: result is NOT multiplied by 100
    """
    return np.sqrt(np.mean(np.square(_percentage_error(actual, predicted))))

def rmdspe(actual: np.ndarray, predicted: np.ndarray):
    """
    Root Median Squared Percentage Error
    Note: result is NOT multiplied by 100
    """
    return np.sqrt(np.median(np.square(_percentage_error(actual, predicted))))

def rmsse(actual: np.ndarray, predicted: np.ndarray, seasonality: int = 1):
    """ Root Mean Squared Scaled Error """
    q = np.abs(_error(actual, predicted)) / mae(actual[seasonality:], _naive_forecasting(actual, seasonality))
    return np.sqrt(np.mean(np.square(q)))

def inrse(actual: np.ndarray, predicted: np.ndarray):
    """ Integral Normalized Root Squared Error """
    return np.sqrt(np.sum(np.square(_error(actual, predicted))) / np.sum(np.square(actual - np.mean(actual))))

def rrse(actual: np.ndarray, predicted: np.ndarray):
    """ Root Relative Squared Error """
    return np.sqrt(np.sum(np.square(actual - predicted)) / np.sum(np.square(actual - np.mean(actual))))

def mre(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Mean Relative Error """
    return np.mean(_relative_error(actual, predicted, benchmark))

def rae(actual: np.ndarray, predicted: np.ndarray):
    """ Relative Absolute Error (aka Approximation Error) """
    return np.sum(np.abs(actual - predicted)) / (np.sum(np.abs(actual - np.mean(actual))) + EPSILON)

def mrae(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Mean Relative Absolute Error """
    return np.mean(np.abs(_relative_error(actual, predicted, benchmark)))

def mdrae(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Median Relative Absolute Error """
    return np.median(np.abs(_relative_error(actual, predicted, benchmark)))

def gmrae(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Geometric Mean Relative Absolute Error """
    return _geometric_mean(np.abs(_relative_error(actual, predicted, benchmark)))

def mbrae(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Mean Bounded Relative Absolute Error """
    return np.mean(_bounded_relative_error(actual, predicted, benchmark))

def umbrae(actual: np.ndarray, predicted: np.ndarray, benchmark: np.ndarray = None):
    """ Unscaled Mean Bounded Relative Absolute Error """
    __mbrae = mbrae(actual, predicted, benchmark)
    return __mbrae / (1 - __mbrae)

def mda(actual: np.ndarray, predicted: np.ndarray):
    """ Mean Directional Accuracy """
    return np.mean((np.sign(actual[1:] - actual[:-1]) == np.sign(predicted[1:] - predicted[:-1])).astype(int))

def jensenshannon(actual: np.ndarray, predicted: np.ndarray):
    actual_dis, bin_edges_actual = np.histogram(actual, bins=100)
    predict_dis, bin_edges_predict = np.histogram(predicted, bins=bin_edges_actual)
    return distance.jensenshannon(actual_dis, predict_dis)

METRICS = {
    'mse': mse,
    'rmse': rmse,
    'nrmse': nrmse,
    'me': me,
    'mae': mae,
    'mad': mad,
    'gmae': gmae,
    'mdae': mdae,
    'mpe': mpe,
    'mape': mape,
    'mdape': mdape,
    'smape': smape,
    'smdape': smdape,
    'maape': maape,
    'mase': mase,
    'std_ae': std_ae,
    'std_ape': std_ape,
    'rmspe': rmspe,
    'rmdspe': rmdspe,
    'rmsse': rmsse,
    'inrse': inrse,
    'rrse': rrse,
    'mre': mre,
    'rae': rae,
    'mrae': mrae,
    'mdrae': mdrae,
    'gmrae': gmrae,
    'mbrae': mbrae,
    'umbrae': umbrae,
    'mda': mda,
    "jsd": jensenshannon,
}

def evaluate(actual: np.ndarray, predicted: np.ndarray, metrics=('mae', 'rmse', 'mse', 'smape')):
    results = {}
    for name in metrics:
        try:
            results[name] = round(METRICS[name](actual, predicted), 7)
        except Exception as err:
            results[name] = np.nan
            print('Unable to compute metric {0}: {1}'.format(name, err))
    return results

def evaluate_all(actual: np.ndarray, predicted: np.ndarray):
    return evaluate(actual, predicted, metrics=set(METRICS.keys()))


from sympy import *
x, y, z, k, n = symbols('x y z k n')
init_printing(use_unicode=True)

def verify_base_case(formula, valid_from_n, base_case):
    computed_base_case = (sympify(formula)).subs(n, valid_from_n)
    base_case_satisfied = computed_base_case == base_case
    return base_case_satisfied

def expand_induction_hypothesis_k_plus_1(formula, next_expression):
    # inductive hypothesis
    inductive_step = formula.replace('n', 'k') + '+' + next_expression.replace('n', 'k')
    return expand(inductive_step)

def expand_formula_k_plus_1(formula):
    return expand(formula.replace('n', '(k+1)'))

def prove_arithmetic_series_formula(formula, valid_from_n, base_case, next_expression):
    # verify base case
    base_case_satisfied = verify_base_case(formula, valid_from_n, base_case)

    # Inductive step
    inductive_hypothesis = expand_induction_hypothesis_k_plus_1(formula, next_expression)
    formula_next_term = expand_formula_k_plus_1(formula)

    # If the inductive hypothesis matches the formula for the next term
    # then we have proved the formula
    return {
        'base_case_satisfied': base_case_satisfied,
        'inductive_hypothesis': inductive_hypothesis,
        'formula_next_term': formula_next_term,
        'proved': base_case_satisfied and inductive_hypothesis == formula_next_term
    }

# Sum of all even numbers
INPUT_FORMULA = 'n*(n+1)'
INPUT_VALID_FROM_N = 1
INPUT_BASE_CASE = 2
INPUT_NEXT_STEP = '2*(n+1)'

print prove_arithmetic_series_formula(
    INPUT_FORMULA,
    INPUT_VALID_FROM_N,
    INPUT_BASE_CASE,
    INPUT_NEXT_STEP
    )


import math
#from sympy import *
from scipy.misc import derivative
import numpy as np

__all__ = ['calc_sigmoide']

def calc_sigmoide(x):
    return 1/(1+np.exp(-x))

def derivative_sigmoid(x):
    return derivative(calc_sigmoide,x,dx=1e-9)

'''
if __name__ == '__main__':
    q = calc_sigmoid(np.array([[1,2,3],[4,5,6]]))
    s = derivative_sigmoid(np.array([[1,2,3],[4,5,6]]))
    print(q)
    print(s)

'''


import numpy as np

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

def optimize(f, a: float, b: float, eps: float = 1e-8):
    optimize.n_it = 0
    x, y, z = (a + b) / 2, (a + b) / 2, (a + b) / 2  # топ3 приближения минимума
    orac = f(x)
    fx, fy, fz = orac[0], orac[0], orac[0]
    dfx, dfy, dfz = orac[1], orac[1], orac[1]
    while b - a > eps:
        optimize.n_it += 1
        candidates = []
        if abs(x - y) >= eps and abs(dfx - dfy) > 0:
            u = (x * dfy - y * dfx) / (dfy - dfx)  # метод секущей поиска f'(x) = 0
            if (u > a) and (u < b):
                candidates.append(u)
        if abs(x - z) >= eps and abs(dfx - dfy) > 0:
            u = (x * dfz - z * dfx) / (dfz - dfx)
            if (u > a) and (u < b):
                candidates.append(u)
        if len(candidates):
            u = min(candidates, key=lambda v: abs(v - x))
        elif dfx > 0:  # бинпоиск нуля производной
            u = (a + x) / 2
        elif dfx < 0:
            u = (x + b) / 2
        else:
            return np.array(x)
        if (abs(a - x) < eps / 2) and (abs(x - u) < eps / 2):
            u = x + eps / 2
        elif (abs(b - x) < eps / 2) and (abs(x - u) < eps / 2):
            u = x - eps / 2
        fu, dfu = f(u)
        if fu <= fx:  # приближение u лучше, чем x
            if u > x:
                a = x
            else:
                b = x
            x, y, z = u, x, y
            fx, fy, fz = fu, fx, fy
            dfx, dfy, dfz = dfu, dfx, dfy
        else:
            if u > x:
                b = u
            else:
                a = u
            if fu <= fy or abs(y - x) < eps:  # u хуже x но лучше y
                y, z = u, y
                fy, fz = fu, fy
                dfy, dfz = dfu, dfy
            elif fu < fz or abs(z - x) < eps or abs(z - y) < eps:  # u хуже x, y, но лучше z
                z = u
                fz = fu
                dfz = dfu
    return np.array(u)


%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

# Uniformly distrubited, equal chance of any value occurring
#
# Equal distribution between -10.0 and 10.0 as the variable
# Plotted with 10,000 data points
values = np.random.uniform(-10.0, 10.0, 100000)
plt.hist(values, 50)
plt.show()

# Visualizing a normal distribution
# The normal distribution is also known as a Gaussian distribution
x = np.arange(-3, 3, 0.001)
plt.plot(x, norm.pdf(x))

# Generate a custom normal distribution
# With certain parameters
#
# mu    -> mean
# sigma -> stddev
#
mu = 5.0
sigma = 2.0
num_datapoints = 10000
num_bins = 1000
values = np.random.normal(mu, sigma, num_datapoints)
plt.hist(values, num_bins)
plt.show()

# Exponential fall off probability density function
#
step = 0.001
l = 3
x = np.arange(0, l, step)
plt.plot(x, expon.pdf(x))

# Binomial
# Probability mass function
# i.e. for discrete data
#
from scipy.stats import binom

# n -> number of samples
# p -> probability of each outcome
n, p = 10, 0.5
step = 0.001
x = np.arange(0, 10, step)
plt.plot(x, binom.pmf(x, n, p))

# Poisson
# Can be skewed!
# Not the same as normal distribution
from scipy.stats import poisson
import matplotlib.pyplot as plt

# Mean
mu = 450
step = 0.5
end = 600
x = np.arange(400, end, step)
plt.plot(x, poisson.pmf(x, mu))

# The equivalent of a PDF for using discrete data is:
#
# A probability mass function


import numpy as np
import sympy as sy
from sympy import init_printing
from sympy import pprint
init_printing()

__author__='SatoshiTerasaki<terasakisatoshi.math@gmail.com>'
__version__='1.0.0'
__date__='2017/02/25'

def calc_with_sympy(A):
    print("calc with sympy")
    print("A="),pprint(A)
    for eigen_value,multi,eigen_vect in A.eigenvects():
        print("eigen_value",eigen_value,"its multiplocity is",multi)
        print("eigen_vect corresponds the eigen_value is")
        pprint(eigen_vect)

def calc_with_numpy(A):
    print("calc with numpy")
    eigen_vals,eigen_vects=np.linalg.eig(A)
    for idx,val in enumerate(eigen_vals):
        print("eigen vector corresponds {} is {}".format(val,eigen_vects[:,idx]))

def main():
    A=[[1,-1,2],
       [0,-1,3],
       [0,3,-1]]
    calc_with_sympy(sy.Matrix(A))
    calc_with_numpy(np.array(A))

if __name__=='__main__':
    main()


import pandas as pd
import numpy as np

def get_most_volatile(prices):
    """Return the ticker symbol for the most volatile stock.

    Parameters
    ----------
    prices : pandas.DataFrame
        a pandas.DataFrame object with columns: ['ticker', 'date', 'price']

    Returns
    -------
    ticker : string
        ticker symbol for the most volatile stock
    """

    prices = prices.set_index('date')

    stock_return_volatility = []

    for ticker in prices.ticker.unique():
        prices_for_ticker = prices[prices['ticker'] == ticker]['price']
        log_return = np.log(prices_for_ticker) - np.log(prices_for_ticker.shift(1))
        stock_return_volatility.append(log_return.std())

    volatility_series = pd.Series(stock_return_volatility, index=prices.ticker.unique())

    return volatility_series.idxmax()

def test_run(filename='prices.csv'):
    """Test run get_most_volatile() with stock prices from a file."""
    prices = pd.read_csv(filename, parse_dates=['date'])
    print("Most volatile stock: {}".format(get_most_volatile(prices)))

if __name__ == '__main__':
    test_run()


import math
from typing import List, Tuple
import numpy

''' All data utilities are here'''

def generate_data_part_1() -> Tuple[List[List[float]], List[float]]:
    features = [[i / 10.] for i in range(0, 10)]
    values = [2 * (x[0] ** 1.2) + 1 for x in features]
    return features, values

def generate_data_part_2() -> Tuple[List[List[float]], List[float]]:
    features = [[i / 10.0] for i in range(-10, 20)]
    values = [math.exp(x[0]) for x in features]
    return features, values

def generate_data_part_3() -> Tuple[List[List[float]], List[float]]:
    from sklearn.datasets import load_iris
    features, labels = load_iris(return_X_y=True)
    features = features.astype(float).tolist()
    labels = labels.astype(int).tolist()
    return features, labels

def generate_data_cancer() -> Tuple[List[List[float]], List[int]]:
    from sklearn.datasets import load_breast_cancer
    features, labels = load_breast_cancer(return_X_y=True)
    features = features.astype(float).tolist()
    labels = labels.astype(int).tolist()
    return features, labels

def generate_data_perceptron(nb_features=2, seperation=2) -> Tuple[List[List[float]], List[int]]:
    ''' Generates data for perceptron problem'''
    '''
        nb_features = 2, seperation=2 generates linearly seperable data
        nb_features = 2, seperation=1 generates linearly seperable data

        Also note that it appends 1 to feature vector to account for bias term

    '''
    from sklearn.datasets import make_classification
    x, y = make_classification(n_samples=100, n_features=nb_features, n_informative=2, n_redundant=0, n_classes=2, n_clusters_per_class=2,
                               weights=None, flip_y=0.00, class_sep=seperation, hypercube=True, shift=0.0, scale=1.0, shuffle=True, random_state=500)
    y = 2 * y - 1
    x = numpy.insert(x, 0, 1, axis=1)

    features = x.astype(float).tolist()
    labels = y.astype(int).tolist()
    return features, labels


import numpy as np
import math

def mat2euler(M, cy_thresh=None):
    ''' Discover Euler angle vector from 3x3 matrix

    Uses the conventions above.

    Parameters
    ----------
    M : array-like, shape (3,3)
    cy_thresh : None or scalar, optional
       threshold below which to give up on straightforward arctan for
       estimating x rotation.  If None (default), estimate from
       precision of input.

    Returns
    -------
    z : scalar
    y : scalar
    x : scalar
       Rotations in radians around z, y, x axes, respectively

    Notes
    -----
    If there was no numerical error, the routine could be derived using
    Sympy expression for z then y then x rotation matrix, which is::

      [                       cos(y)*cos(z),                       -cos(y)*sin(z),         sin(y)],
      [cos(x)*sin(z) + cos(z)*sin(x)*sin(y), cos(x)*cos(z) - sin(x)*sin(y)*sin(z), -cos(y)*sin(x)],
      [sin(x)*sin(z) - cos(x)*cos(z)*sin(y), cos(z)*sin(x) + cos(x)*sin(y)*sin(z),  cos(x)*cos(y)]

    with the obvious derivations for z, y, and x

       z = atan2(-r12, r11)
       y = asin(r13)
       x = atan2(-r23, r33)

    Problems arise when cos(y) is close to zero, because both of::

       z = atan2(cos(y)*sin(z), cos(y)*cos(z))
       x = atan2(cos(y)*sin(x), cos(x)*cos(y))

    will be close to atan2(0, 0), and highly unstable.

    The ``cy`` fix for numerical instability below is from: *Graphics
    Gems IV*, Paul Heckbert (editor), Academic Press, 1994, ISBN:
    0123361559.  Specifically it comes from EulerAngles.c by Ken
    Shoemake, and deals with the case where cos(y) is close to zero:

    See: http://www.graphicsgems.org/

    The code appears to be licensed (from the website) as "can be used
    without restrictions".
    '''
    _FLOAT_EPS_4 = np.finfo(float).eps * 4.0
    M = np.asarray(M)
    if cy_thresh is None:
        try:
            cy_thresh = np.finfo(M.dtype).eps * 4
        except ValueError:
            cy_thresh = _FLOAT_EPS_4
    r11, r12, r13, r21, r22, r23, r31, r32, r33 = M.flat
    # cy: sqrt((cos(y)*cos(z))**2 + (cos(x)*cos(y))**2)
    cy = math.sqrt(r33*r33 + r23*r23)
    if cy > cy_thresh: # cos(y) not close to zero, standard form
        z = math.atan2(-r12,  r11) # atan2(cos(y)*sin(z), cos(y)*cos(z))
        y = math.atan2(r13,  cy) # atan2(sin(y), cy)
        x = math.atan2(-r23, r33) # atan2(cos(y)*sin(x), cos(x)*cos(y))
    else: # cos(y) (close to) zero, so x -> 0.0 (see above)
        # so r21 -> sin(z), r22 -> cos(z) and
        z = math.atan2(r21,  r22)
        y = math.atan2(r13,  cy) # atan2(sin(y), cy)
        x = 0.0
    return z, y, x


# This file is part of PWLQ repository.
# Copyright (c) Samsung Semiconductor, Inc.
# All rights reserved.

import torch
import numpy as np

##########################################################################################
####  Uniform quantization
##########################################################################################

# References:
#   https://arxiv.org/abs/1806.08342
#   https://arxiv.org/abs/1712.05877
def uniform_symmetric_quantizer(x, bits=8.0, minv=None, maxv=None, signed=True,
                                scale_bits=0.0, num_levels=None, scale=None, simulated=True):
    if minv is None:
        maxv = torch.max(torch.abs(x))
        minv = - maxv if signed else 0

    if signed:
        maxv = np.max([-float(minv), float(maxv)])
        minv = - maxv
    else:
        minv = 0

    if num_levels is None:
        num_levels = 2 ** bits

    if scale is None:
        scale = (maxv - minv) / (num_levels - 1)

    if scale_bits > 0:
        scale_levels = 2 ** scale_bits
        scale = torch.round(torch.mul(scale, scale_levels)) / scale_levels

    ## clamp
    x = torch.clamp(x, min=float(minv), max=float(maxv))

    x_int = torch.round(x / scale)

    if signed:
        x_quant = torch.clamp(x_int, min=-num_levels/2, max=num_levels/2 - 1)
        assert(minv == - maxv)
    else:
        x_quant = torch.clamp(x_int, min=0, max=num_levels - 1)
        assert(minv == 0 and maxv > 0)

    x_dequant = x_quant * scale

    return x_dequant if simulated else x_quant

def uniform_affine_quantizer(x, bits=8.0, minv=None, maxv=None, offset=None, include_zero=False,
                            scale_bits=0.0, num_levels=None, scale=None, simulated=True):
    if minv is None:
        maxv = torch.max(x)
        minv = torch.min(x)
        if include_zero:
            if minv > 0:
                minv = 0
            elif maxv < 0:
                maxv = 0

    if num_levels is None:
        num_levels = 2 ** bits

    if not scale:
        scale = (maxv - minv) / (num_levels - 1)

    if not offset:
        offset =  minv

    if scale_bits > 0:
        scale_levels = 2 ** scale_bits
        scale = torch.round(torch.mul(scale, scale_levels)) / scale_levels
        offset = torch.round(torch.mul(offset, scale_levels)) / scale_levels

    ## clamp
    x = torch.clamp(x, min=float(minv), max=float(maxv))

    x_int = torch.round((x - offset) / scale)

    x_quant = torch.clamp(x_int, min=0, max=num_levels - 1)

    x_dequant = x_quant * scale + offset

    return x_dequant if simulated else x_quant


"""
Demo gradient descent
"""
import numpy as np
import pylab as pl

x_min, x_max = -0.6, 1.1
y_min, y_max = -0.1, 1.1

x0, y0 = 3., 2.
epsilon = .1

for index, epsilon in enumerate((1, .01)):
    # s_x, s_y = 1.5, .01
    #def f(x, y):
    #    return -s_x*np.cos(x - x0) - s_y*np.cos(y - y0)

    #def f_prime(x, y):
    #    return s_x*np.sin(x - x0), s_y*np.sin(y - y0)

    def rosenbrock(x, y):
        return epsilon*(1 - x)**2 + (y - x**2)**2

    def rosenbrock_prime(x, y):
        return (-epsilon*2*(1 - x) - 4*x*(y - x**2),
                2*(y - x**2))

    f = rosenbrock
    f_prime = rosenbrock_prime

    x, y = np.mgrid[x_min:x_max:100j, y_min:y_max:100j]
    x = x.T
    y = y.T

    pl.figure(index, figsize=(3, 2.5))
    pl.clf()
    #pl.axes([0, 0, 1, 1])

    contours = pl.contour(f(x, y),
                        extent=[x_min, x_max, y_min, y_max],
                        cmap=pl.cm.gnuplot, origin='lower')
    pl.clabel(contours,
            inline=1,
            fmt='%1.1f',
            fontsize=14)

    x_i, y_i = 0, 0
    all_x_i = list()
    all_y_i = list()

    for i in range(10):
        all_x_i.append(x_i)
        all_y_i.append(y_i)
        dx_i, dy_i = f_prime(x_i, y_i)
        x_i += -dx_i
        y_i += -dy_i

    pl.plot(all_x_i, all_y_i, 'b-')
    pl.plot(all_x_i, all_y_i, 'k+')

    pl.plot([x0], [y0], 'rx')


# -*- coding: utf-8 -*-
"""
Created on Fri Jun  5 11:56:32 2020
Some functions to do Logistic Regression
@author: Ji-Ping Dai
"""
import numpy as np
import matplotlib.pyplot as plt
plt.rc('text',usetex=True)
plt.rc('font',family='Times New Roman')

def plotdata(X,y,ax):
    '''PLOTDATA Plots the data points x and y into a new figure'''
    plt.xticks(fontsize=20)
    plt.yticks(fontsize=20)
    ax.plot(X[(y==1).flatten(),0], X[(y==1).flatten(),1], 'kx')
    ax.plot(X[(y==0).flatten(),0], X[(y==0).flatten(),1], 'yo')
    return

def sigmoid(z):
    '''sigmoid function, output between 0-1'''
    sigmoid = 1/(1+np.exp(-z))
    return sigmoid

def costfunc(theta,x,y):
    '''Compute cost for Logistic Regression'''
    m = len(y)
    theta = theta.reshape(-1,1)
    z = x@theta
    J = -1/m*(y.T@np.log(sigmoid(z))+(1-y).T@np.log(1-sigmoid(z)))
    return J

def costfuncReg(theta,x,y,lam):
    '''Compute cost for Logistic Regression'''
    m = len(y)
    theta = theta.reshape(-1,1)
    J=np.zeros([len(theta),1])
    z = x@theta
    J = -1/m*(y.T@np.log(sigmoid(z))+(1-y).T@np.log(1-sigmoid(z)))+lam/2/m*theta.T[:,1:]@theta[1:,:]
    return J

def grid(theta,x,y):
    '''Compute gradient for Logistic Regression'''
    m = len(y)
    theta = theta.reshape(-1,1)
    z = x@theta
    grid = 1/m*(x.T@(sigmoid(z)-y))
    return grid.flatten()

def gridReg(theta,x,y,lam):
    '''Compute gradient for Logistic Regression'''
    m = len(y)
    theta = theta.reshape(-1,1)
    grid=np.zeros([len(theta),1])
    z = x@theta
    grid[0,:] = 1/m*(x.T@(sigmoid(z)-y))[0,:]
    grid[1:,:] = 1/m*(x.T@(sigmoid(z)-y))[1:,:] + lam/m*theta[1:,:]
    return grid.flatten()

def gradientDescent(x,y,theta,iterations,alpha):
    '''Performs gradient descent to learn theta'''
    m = len(y)
    cost = np.zeros(iterations)
    for i in range(iterations):
        z = x@theta
        theta = theta-1/m*alpha*x.T@(sigmoid(z)-y)
        cost[i] = costfunc(theta,x,y)
    return theta, cost

def plotboundary(X,y,theta,ax):
    '''Plots the Decision Boundary'''
    plotdata(X,y,ax)
    if len(theta)<=3:
        px=np.linspace(np.min(X[:,0])-2,np.max(X[:,0])+2,100)
        py=(-theta[0]-theta[1]*px)/theta[2]
        ax.plot(px,py,ls='--',color='b')
    else:
        px=np.linspace(-1,1.5,100)
        py=np.linspace(-1,1.5,100)
        cost=np.zeros([100,100])
        for i in range(len(px)):
            for j in range(len(py)):
                cost[i,j]=mapX(px[i],py[j])@theta
        cost=cost.T
        PX,PY=np.meshgrid(px,py)
        ax.contour(PX,PY,cost,[0],colors='k')
    return

def predict(x,theta):
    '''Predict whether the label is 0 or 1 using learned logistic '''
    p = sigmoid(x@theta.reshape(-1,1))
    p[p>=0.5]=1
    p[p<0.5]=0
    return p

def mapX(x1,x2):
    '''Feature mapping function to polynomial features'''
    order = 6
    X = np.ones([x1.size,1])
    order=6
    for i in range(1,order+1):
        for j in range(i+1):
            newcol = (x1**(i-j)*x2**(j)).reshape(-1,1)
            X = np.concatenate([X,newcol],axis=1)
    return X


#!/usr/bin/env python

''' Método de Newton: encontrar o mínimo dessa função '''

from sympy import lambdify, diff, cos, sin, exp
from sympy.abc import x

from Error import *
from Log import *

MAX = 50
PATH = 'log/newton-opt/'
TOLERANCE = 0.00000001 # 10**(-8)

def newton_optimization(fn, cx, tol, nmax) :
    l = Log()
    e = Error()
    previous = 0

    dx = fn.diff(x)
    dx2 = dx.diff(x)

    dx = lambdify(x, dx)
    dx2 = lambdify(x, dx2)

    for n in range(nmax) :
        if (dx2(cx) == 0) :
            return "Error 27: derivative less than zero"
            breakpoint
        cx = cx - (dx(cx) / dx2(cx) )
        e.absolute(cx, previous)
        l.append([cx, e._absolute, dx(cx), dx2(cx)])
        if (e._absolute < tol) :
            l.set_header(['x', 'absolute_error', 'function', 'derivative'])
            l.list2file((PATH+str(fn)))
            return cx
            breakpoint
        previous = cx
    return False

def run_test(function, a, TOLERANCE, MAX):
    m = newton_optimization(function, a, TOLERANCE, MAX)
    print('f(x) =',function, '-> newton optimization =', m)
    return m

if __name__ == "__main__":

    ''' Tests
        https://en.wikipedia.org/wiki/Newton%27s_method_in_optimization
    '''

    log = []
    a = .0000005
    fx = [(cos(x) - x**3), (x**2 - 612), ((x**3)-(2*x)+2), (x**6 - x - 1), (x**3-6*x**2+4*x+2)]

    euler = exp(-( ( ((x-1)**2)/(2*(0.75**2)) ) + ( ((x-2)**2)/(2*(0.5**2)) )  ))
    fx = [1 - euler + ( 0.04 * (((x-1)**2) + ((x-2)**2)) )]

    for f in fx:
        run_test(f, a, TOLERANCE, MAX)


"""
brownian() implements one dimensional Brownian motion (i.e. the Wiener process).
"""

# File: brownian.py
# From SciPy examples: http://scipy-cookbook.readthedocs.io/items/BrownianMotion.html

from math import sqrt
from scipy.stats import norm
import numpy as np

def brownian(x0, n:int, dt, delta, out=None):
    """
    Generate an instance of Brownian motion (i.e. the Wiener process):

        X(t) = X(0) + N(0, delta**2 * t; 0, t)

    where N(a,b; t0, t1) is a normally distributed random variable with mean a and
    variance b.  The parameters t0 and t1 make explicit the statistical
    independence of N on different time intervals; that is, if [t0, t1) and
    [t2, t3) are disjoint intervals, then N(a, b; t0, t1) and N(a, b; t2, t3)
    are independent.

    Written as an iteration scheme,

        X(t + dt) = X(t) + N(0, delta**2 * dt; t, t+dt)

    If `x0` is an array (or array-like), each value in `x0` is treated as
    an initial condition, and the value returned is a numpy array with one
    more dimension than `x0`.

    x0 : float or numpy array (or something that can be converted to a numpy array
         using numpy.asarray(x0)).
        The initial condition(s) (i.e. position(s)) of the Brownian motion.
    n : int
        The number of steps to take.
    dt : float
        The time step.
    delta : float
        delta determines the "speed" of the Brownian motion.  The random variable
        of the position at time t, X(t), has a normal distribution whose mean is
        the position at time t=0 and whose variance is delta**2*t.
    out : numpy array or None
        If `out` is not None, it specifies the array in which to put the
        result.  If `out` is None, a new numpy array is created and returned.

    A numpy array of floats with shape `x0.shape + (n,)`.

    Note that the initial value `x0` is not included in the returned array.
    """

    x0 = np.asarray(x0)

    # For each element of x0, generate a sample of n numbers from a
    # normal distribution.
    r = norm.rvs(size=x0.shape + (n,), scale=delta*sqrt(dt))

    # If `out` was not given, create an output array.
    if out is None:
        out = np.empty(r.shape)

    # This computes the Brownian motion by forming the cumulative sum of
    # the random samples.
    np.cumsum(r, axis=-1, out=out)

    # Add the initial condition.
    out += np.expand_dims(x0, axis=-1)

    return out

# Adapted from the NumPy Geometric Brownian Motion function by Yves Hilpisch:
# https://www.wakari.io/sharing/bundle/yves/Yves_Hilpisch_Python_in_Finance_Talk_NYC?has_login=False
def geometric_brownian(S0, mu, sigma, dt, num_paths: int, num_steps: int):
    """
    :param S0: the initial value
    :param mu: the percentage drift
    :param sigma: the percentage volatility
    :param dt: the time-step (fraction of a year)
    :param num_paths: the number of paths to generate
    :param num_steps: the number of steps to generate
    :return: an array with the paths
    """
    S = S0 * np.exp(np.cumsum((mu - 0.5 * sigma ** 2) * dt
                + sigma * np.sqrt(dt) * np.random.standard_normal((num_steps, num_paths)), axis=0))
    return S.transpose()


#
# Copyright (c) 2017 Intel Corporation
# SPDX-License-Identifier: BSD-2-Clause
#

# This code was ported from a Julia implementation as part of the
# ParallelAccelerator Julia package which in turn was ported from a
# MATLAB implementation available at
# https://www.piso.at/julius/programming/octave-2d-wave-equation
# with permission of the author.
# Original MATLAB implementation is copyright (c) 2014 Julius Piso.

from __future__ import print_function

import sys
import numpy as np
from numba import njit, stencil
try:
    import matplotlib.pyplot as plt
    from matplotlib.animation import FuncAnimation
except ImportError:
    raise RuntimeError("matplotlib is needed to run this example. Try 'conda install matplotlib'")

@stencil()
def rws_kernel(p, c, r):
    return 2 * c[0, 0] - p[0, 0] + r * r * (c[-1, 0] + c[1, 0] + c[0, -1] + c[0, 1] - 4*c[0, 0])

@njit(parallel=True)
def runWaveStencil(p, c, f, r, t, n, s2, s4, s):
    rws_kernel(p, c, r, out=f)

    # Dynamic source
    f[s2+s4-2:s2+s4+1, 0:2] = 1.5 * np.sin(t*n)
    f[s2-s4-2:s2-s4+1, 0:2] = 1.5 * np.sin(t*n)
    f[1:s-1, 0:2] = 1.0

    # Transparent boundary handling
    f[1:s-1, 0]   = (2.0 * c[1:s-1, 0]   + (r-1.0) * p[1:s-1, 0]   + 2.0*r*r*(c[1:s-1, 1]   + c[2:s, 0]   + c[0:s-2, 0]   - 3.0 * c[1:s-1, 0]))   / (1.0+r) # Y:1
    f[1:s-1, s-1] = (2.0 * c[1:s-1, s-1] + (r-1.0) * p[1:s-1, s-1] + 2.0*r*r*(c[1:s-1, s-2] + c[2:s, s-1] + c[0:s-2, s-1] - 3.0 * c[1:s-1, s-1])) / (1.0+r) # Y:s
    f[0, 1:s-1]   = (2.0 * c[0, 1:s-1]   + (r-1.0) * p[0, 1:s-1]   + 2.0*r*r*(c[1, 1:s-1]   + c[0, 2:s]   + c[0, 0:s-2]   - 3.0 * c[0, 1:s-1]))   / (1.0+r) # X:1
    f[s-1, 1:s-1] = (2.0 * c[s-1, 1:s-1] + (r-1.0) * p[s-1, 1:s-1] + 2.0*r*r*(c[s-2, 1:s-1] + c[s-1, 2:s] + c[s-1, 0:s-2] - 3.0 * c[s-1, 1:s-1])) / (1.0+r) # Y:s

class State(object):
    def __init__(self, speed, s):
        self.speed = speed
        self.s = s

        self.t = 0.0

        self.s = s
        self.s2  = self.s // 2
        self.s4  = self.s // 4
        self.s8  = self.s // 8
        self.s16 = self.s // 16

        self.p = np.zeros((self.s, self.s)) # past
        self.c = np.zeros((self.s, self.s)) # current
        self.f = np.zeros((self.s, self.s)) # future

        self.dt = 0.0001     # Time resolution of the simulation
        self.dx = 0.01       # Distance between elements
        self.r = self.speed * self.dt / self.dx

        self.n = 300
        self.last = -1

        for i in range(self.s2 - self.s16 - 1, self.s2 + self.s16):
            # Initial conditions
            self.c[i, self.s2 - self.s16 - 1 : self.s2 + self.s16 ] = - 2 * np.cos(0.5 * 2 * np.pi / (self.s8) * np.arange(self.s2 - self.s16 , self.s2 + self.s16 + 1)) * np.cos(0.5 * 2 * np.pi / (self.s8) * i)
            self.p[i, 0:self.s] = self.c[i, 0:self.s]

        self.im = plt.imshow(self.c, animated=True)

    def step(self):
        # Wave equation
        runWaveStencil(self.p, self.c, self.f, self.r, self.t, self.n, self.s2, self.s4, self.s)

        # Transparent corner handling
        self.f[0, 0] =     (2 * self.c[0, 0]     + (self.r-1) * self.p[0, 0]     + 2*self.r*self.r* (self.c[1, 0]       + self.c[0, 1]       - 2*self.c[0, 0]))     / (1+self.r) # X:1; Y:1
        self.f[self.s-1, self.s-1] = (2 * self.c[self.s-1, self.s-1] + (self.r-1) * self.p[self.s-1, self.s-1] + 2*self.r*self.r* (self.c[self.s-2, self.s-1] + self.c[self.s-1, self.s-2] - 2*self.c[self.s-1, self.s-1])) / (1+self.r) # X:s; Y:s
        self.f[0, self.s-1] =   (2 * self.c[0, self.s-1]   + (self.r-1) * self.p[0, self.s-1]   + 2*self.r*self.r* (self.c[1, self.s-1]     + self.c[0, self.s-2]   - 2*self.c[0, self.s-1]))   / (1+self.r) # X:1; Y:s
        self.f[self.s-1, 0] =   (2 * self.c[self.s-1, 0]   + (self.r-1) * self.p[self.s-1, 0]   + 2*self.r*self.r* (self.c[self.s-2, 0]   + self.c[self.s-1, 1]     - 2*self.c[self.s-1, 0]))   / (1+self.r) # X:s; Y:1

        # Rotate buffers for next iteration
        tmp = self.p
        self.p = self.c
        self.c = self.f
        self.f = tmp

        self.t += self.dt
        self.im.set_array(self.c)

    def plot_step(self, x):
        if x > self.last:
            print("plot_step", x)
            self.step()
            self.last = x

def wave2d():
    speed = 10      # Propagation speed
    s = 512         # Array size (spatial resolution of the simulation)

    fig = plt.figure()
    state = State(speed, s)
    ani = FuncAnimation(fig, state.plot_step)
    plt.show()

    return True

def main(*args):
    wave2d()

if __name__ == "__main__":
    main(*sys.argv[1:])


import matplotlib.pyplot as plt
import numpy as np
from sigmoid_module import logit, sigmoid
import os.path as p
def target_file_abs_path(target_file_relative_path):
    return p.join(p.dirname(p.realpath(__file__)), target_file_relative_path)

print(logit(0.5))
print(sigmoid(0.5))

z = np.arange(-7, 7, 0.1)
phi_z = sigmoid(z)

plt.plot(z, phi_z)
plt.axvline(0.0, color='k')
plt.ylim(-0.1, 1.1)
plt.xlabel('z')
plt.ylabel("$\phi (z)$")
plt.yticks([0.0, 0.5, 1.0])

ax = plt.gca()
ax.yaxis.grid(True)

plt.savefig(target_file_abs_path('./sigmoid_curve.png'))


# Run the blending process
# Martha Grover, July 6, 2017 (MATLAB)
# John Hedengren, July 14, 2017 (Python)

import numpy as np
from scipy.integrate import odeint

# Here is the playlist for the accompanying screencasts:
# https://www.youtube.com/playlist?list=PL4xAk5aclnUhb0tM6nypIATyxPRk0fB3L

# Following on the first screencast (Blending Process: Dynamic Simulation),
# here you can simulate the nonlinear coupled set of differential equations.
# As in the second screencast (Blending Process: Steady States),
# observe here how the mass fraction in the tank
# approaches the steady state value of xbar as the system approaches long
# time.  The volume does not have a unique steady state.  Since filling a
# tank is a integrating process, it may increase or decrease without bound,
# based on the difference between the inlet and outlet mass flow rates.

# Parameters
rho = 1000   # Density [kg/m^3]

# Here we will consider x1 and x2 to remain as constants
x1 = 0.1
x2 = 0

#######################################################################
############### Define the Nonlinear Model  ###########################
#######################################################################
# Nominal inputs:
# x1: Mass fraction of Species A in Stream 1 (unitless)
# w1: Mass flow rate in Stream 1 [kg/s]
# x2: Mass fraction of Species A in Stream 2 (unitless)
# w2: Mass flow rate in Stream 2 [kg/s]
# w:  Outlet mass flow [kg/s]

def blending(z,t,u):
    # Dynamic model of the blending process
    # State variables passed in as vector z:
    V = z[0]   # Volume [m3]
    x = z[1]   # Mass fraction of Species A in the tank (unitless)
    # Inputs passed in as vector u:
    w1 = u[0]  # Mass flow rate in Stream 1 [kg/s]
    w2 = u[1]  # Mass flow rate in Stream 2 [kg/s]
    w = u[2]   # Here we set the outlet flow equal to the total inlet flow

    # Dynamic equations
    dVdt = (1.0/rho)*(w1+w2-w)                     # Change in volume
    dxdt = (1.0/(rho*V))*(w1*(x1-x)+w2*(x2-x))     # Change in mass fraction

    # Assemble the two time derivatives back into a vector to pass back
    dzdt = [dVdt,dxdt]
    return dzdt

#######################################################################
############# Dynamic Simulation of the Nonlinear System ##############
#######################################################################

# Initial conditions
V0 = 10        # Initial volume in the tank [m^3]
x0 = 0.025     # Initial mass fraction of Species A in the tank (unitless)
# Note: these are currently set at their nominal steady-state values...
# But you can try changing them to other values.
z0 = [V0,x0]  # Initial condition vector for the system

# The flow rates will be the variables in u that may change over time
w1 = 1         # w1: Mass flow rate in Stream 1 [kg/s]
w2 = 3         # w2: Mass flow rate in Stream 2 [kg/s]
w = w1 + w2    # w:  Outlet mass flow [kg/s]
u = [w1,w2,w]  # Assemble these together in a column vector u

tf = 3600      # Final simulation time [s]
t = np.linspace(0,tf,100) # points to report solution

# Simulate the blending process
z = odeint(blending,z0,t,args=(u,))

# plotting results
import matplotlib.pyplot as plt

# Plot the blending process under steady operation
plt.figure(1)
plt.subplot(2,1,1)
plt.plot(t,z[:,0])
plt.xlabel('time t [s]')
plt.ylabel('V [m^3]')
plt.title('Blending process under constant inputs')
plt.subplot(2,1,2)
plt.plot(t,z[:,1])
plt.xlabel('time t [s]')
plt.ylabel('x')

# Calculate the steady-state value for x
xbar = (w1*x1 + w2*x2)/(w1+w2)
# Check to see if this matches the long-term value of x on the plot
# Since V does not have a unique steady state, specify a desired operating value
# Here it is set equal to the initial volume
Vbar = V0  # volume [m^3]

# Define ubar as the set of inputs to achieve this steady state
ubar = u

# Next simulate the system for the higher value of w1 = 1.1 (0.1 higher)
dw1 = 0.1
u[0] = ubar[0] + dw1

zs = odeint(blending,z0,t,args=(u,))

# Plot the blending process under a step change in w1
plt.figure(2)
plt.subplot(2,1,1)
plt.plot(t,zs[:,0])
plt.xlabel('time t [s]')
plt.ylabel('V [m^3]')
plt.title('Blending process under a step input to w_1')
plt.subplot(2,1,2)
plt.plot(t,zs[:,1])
plt.xlabel('time t [s]')
plt.ylabel('x')

# show plots
plt.show()


######################################################################
#
# Functions to calculate integration points and weights for Gaussian
# quadrature
#
# x,w = gaussxw(N) returns integration points x and integration
#           weights w such that sum_i w[i]*f(x[i]) is the Nth-order
#           Gaussian approximation to the integral int_{-1}^1 f(x) dx
# x,w = gaussxwab(N,a,b) returns integration points and weights
#           mapped to the interval [a,b], so that sum_i w[i]*f(x[i])
#           is the Nth-order Gaussian approximation to the integral
#           int_a^b f(x) dx
#
# This code finds the zeros of the nth Legendre polynomial using
# Newton's method, starting from the approximation given in Abramowitz
# and Stegun 22.16.6.  The Legendre polynomial itself is evaluated
# using the recurrence relation given in Abramowitz and Stegun
# 22.7.10.  The function has been checked against other sources for
# values of N up to 1000.  It is compatible with version 2 and version
# 3 of Python.
#
# Written by Mark Newman <mejn@umich.edu>, June 4, 2011
# You may use, share, or modify this file freely
#
######################################################################

from numpy import ones,copy,cos,tan,pi,linspace

def gaussxw(N):

    # Initial approximation to roots of the Legendre polynomial
    a = linspace(3,4*N-1,N)/(4*N+2)
    x = cos(pi*a+1/(8*N*N*tan(a)))

    # Find roots using Newton's method
    epsilon = 1e-15
    delta = 1.0
    while delta>epsilon:
        p0 = ones(N,float)
        p1 = copy(x)
        for k in range(1,N):
            p0,p1 = p1,((2*k+1)*x*p1-k*p0)/(k+1)
        dp = (N+1)*(p0-x*p1)/(1-x*x)
        dx = p1/dp
        x -= dx
        delta = max(abs(dx))

    # Calculate the weights
    w = 2*(N+1)*(N+1)/(N*N*(1-x*x)*dp*dp)

    return x,w

def gaussxwab(N,a,b):
    x,w = gaussxw(N)
    return 0.5*(b-a)*x+0.5*(b+a),0.5*(b-a)*w


from __future__ import division
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from problem_6a import construct_A
from problem_6b import gen_vectors
from matplotlib import rc

def generate_four_tuples(A, b_all):

	tuples = []

	for i in range(10):

		b = b_all[i]

		x = np.linalg.solve(A, b)

		for j in range(10):
			# print(i, j)
			b_db = b_all[(i+1) * 10 + j]
			x_dx = np.linalg.solve(A, b_db)

			db = b_db - b
			dx = x_dx - x

			tuples.append((b, db, x, dx))

	return np.array(tuples)

def generate_plot(cno_A, tuples):

	points_x = []
	points_y = []

	for i in range(len(tuples)):

		db_norm = np.linalg.norm(tuples[i][1], ord=2)
		b_norm = np.linalg.norm(tuples[i][0], ord=2)
		dx_norm = np.linalg.norm(tuples[i][3], ord=2)
		x_norm = np.linalg.norm(tuples[i][2], ord=2)

		x = cno_A * (db_norm / b_norm)
		y = dx_norm / x_norm

		points_x.append(x)
		points_y.append(y)

	points_x = np.array(points_x, dtype=np.float128)
	points_y = np.array(points_y, dtype=np.float128)

	plt.figure()
	plt.xlabel(u"cond(A) * (||\delta b|| / ||b||)")
	plt.ylabel(u"||\delta x|| / ||x||")
	plt.plot(points_x, points_y, "ko")
	plt.savefig("problem_6c.png")
	# Uncomment this line to see the plot
	# plt.show()

def main():

	A, cno_A = construct_A(512)
	b_all = gen_vectors()
	tuples = generate_four_tuples(A, b_all)
	generate_plot(cno_A, tuples)

if __name__ == '__main__':
	main()


#Nabin Chapagain
#1001551151

#k_means(<data_file>, <K>, <initialization>)

# Importing all needed libraries
import numpy as np
import math
import sys
import random
import matplotlib.pyplot as plt

fname = sys.argv[1]
k = int(sys.argv[2])
initialization = sys.argv[3]

if(initialization == "round_robin" or initialization == "random"):
    k = k
else:
    print("wrong input for initialization!!! Try again with round_robin or random")
    exit(0)

file_mat_raw = np.loadtxt(fname)
dim = file_mat_raw.ndim
no_row = len(file_mat_raw)
no_col = 1
if(dim != 1):
    no_col =len(file_mat_raw[0])

b = np.random.randint(1,k+1, size = no_row )

if(initialization == 'round_robin'):
    for i in range(no_row):
        if((i+1)%k == 0):
            b[i] = k
        else:
            b[i] = (i+1)%k

file_mat = np.column_stack((file_mat_raw,b))

#now I have read the file and assigned a column to store the value of assigned cluster, I will proceed to compute the means
#It might be better to use recursion for this case

poss_clusters = np.arange(1,k+1)

centers = np.zeros([k, no_col])
dist = np.zeros([k, 1])

counter = 1
while(counter > 0):
    counter = 0
    for i in range(k):
        dummy_var = np.mean(file_mat[:][file_mat[:,-1]==i+1], axis=0)
        centers[i] = dummy_var[0:no_col]

    #now need to calculate euclidean distance for each point in individual rows from each of the centers
    for i in range(no_row):
        for j in range(k):
            dist[j] = np.linalg.norm(file_mat_raw[i] - centers[j])

        supposed_cluster = np.argmin(dist)+1
        if(file_mat[i,-1] != supposed_cluster):
            file_mat[i,-1] = supposed_cluster
            counter += 1

if(no_col == 1):
    for i in range(no_row):
        print('%10.4f --> cluster %d\n'% (file_mat[i,0], file_mat[i,-1]))
if(no_col == 2):
    for i in range(no_row):
        print('(%10.4f, %10.4f) --> cluster %d\n'% (file_mat[i,0], file_mat[i,1], file_mat[i,-1]))

#colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
if(no_col == 2):
    fig = plt.figure( figsize=(3, 3) \
                    , dpi= 100 \
                    , facecolor='w' \
                    , edgecolor='w' \
                    ) # create figure object

for i in range(k):
    choice = file_mat_raw[:][file_mat[:,-1] == i+1]
    if(no_col == 2):
        plt.scatter(choice[:,0],choice[:,1])

        plt.scatter(centers[:,0],centers[:,1], c= 'k')
if(no_col == 2):
    plt.show()


import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

N=5000 # nb of points
K=4 # nb of clusters
d=3 # dimension EITHER 2 or 3

mu=np.random.randint(-10,10,(3,K))
sigma=np.random.rand(K)+1
points=np.zeros((3,N))

for n in range(N):
    k=np.random.randint(0,K)
    points[:,n]=mu[:,k]+sigma[k]*np.random.rand(3) # d = 3 (even for d = 2)

if d==2:
    points[2,:] = 0 # set third dimension to 0 (d = 2)

if d==2:
    plt.figure()
    plt.plot(points[0,:],points[1,:],'o')
    plt.show()

if d==3:
    fig = plt.figure()
    ax = fig.add_subplot(111,projection='3d')
    ax.scatter(points[0,:],points[1,:],points[2,:])
    plt.show()

file=open("dataset_N{}_K{}_D{}.txt".format(N,K,d),"w")
file.write("{} \n".format(N))
for n in range(N):
    for i in range(3): # even for d = 2
        file.write("{} ".format(points[i,n]))
    file.write("\n")
file.close()


# -*- coding: utf-8 -*-
"""
Create the Farey FInite Fractal as a sampling pattern for MRI

All figures and code pertaining to the display, saving and generation of fractals,
are covered under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0
International Public License: http://creativecommons.org/licenses/by-nc-sa/4.0/.
For publication and commercial use of this content, please obtain a suitable license
from Shekhar S. Chandra.
"""
from __future__ import print_function    # (at top of module)
import _libpath #add custom libs
import finitetransform.numbertheory as nt #local modules
import finitetransform.mojette as mojette
import finitetransform.radon as radon
import finitetransform.imageio as imageio #local module
import finitetransform.farey as farey #local module
import numpy as np

#parameters
N = 16
M = 2*N
K = 1
twoQuads = True
print("N:", N, "M:", M)
#p = nt.nearestPrime(M)
#print("p:", p)
#pDash = nt.nearestPrime(N)
#print("p':", pDash)
#angles = mojette.angleSet_Finite(pDash, 2)
angles, lengths = mojette.angleSet_Symmetric(N,N,1,True,K) #here
#getProjectionCoordinates
perpAngle = farey.farey(1,0)
angles.append(perpAngle)
print("Number of Angles:", len(angles))
print("angles:", angles)

#powerSpect = np.zeros((p,p))
powerSpect = np.zeros((M,M))

#np.set_printoptions(threshold=np.nan)

#compute lines
print("Computing Finite lines...")
centered = True
lines = []
mValues = []
pValues = []
qValues = []
for angle in angles:
    #m, inv = farey.toFinite(angle, p)
    #u, v = radon.getSliceCoordinates2(m, powerSpect, centered, p)
    m, p, q, inv = farey.toFinite(angle, M)
    u, v = radon.getSliceCoordinates2(m, powerSpect, centered, M)
    lines.append((u,v))
    mValues.append(m)
    pValues.append(p)
    qValues.append(q)

    #second quadrant
    if twoQuads:
        #if m != 0 and m != p: #dont repeat these
        if m != 0 and m != M: #dont repeat these
            #m = p-m
            #u, v = radon.getSliceCoordinates2(m, powerSpect, centered, p)
            m = M-m
            z = M-2*z
            u, v = radon.getSliceCoordinates2(m, powerSpect, centered, M)
            lines.append((u,v))
            w, y = radon.getSliceCoordinates2(z, powerSpect, centered, 1024)
            lines.append((w,y))
            mValues.append(m)

mu = len(lines)
print("Number of lines:", len(lines))
#print("Proportion of p:", len(lines)/float(p))
#print("Proportion of 2D space:", 2.0-len(lines)/float(p))
print("Proportion of M:", len(lines)/float(M))
print("Proportion of 2D space:", 2.0-len(lines)/float(M))
print(mValues)
print(pValues)
print(qValues)

#plot slices responsible for reconstruction
import matplotlib.pyplot as plt
from matplotlib.pyplot import cm

fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16, 8))

plt.gray()
plt.tight_layout()

maxLines = len(lines)
#maxLines = 12
ax[0].imshow(powerSpect)
ax[1].imshow(powerSpect)
#color=iter(cm.rainbow(np.linspace(0,1,len(lines))))
color=iter(cm.jet(np.linspace(0,1,maxLines+1)))
fareyImage = np.zeros_like(powerSpect)
for i, line in enumerate(lines):
    u, v = line
    c=next(color)
    ax[0].plot(u, v, '.', c=c)
    ax[1].plot(u, v, '.r',markersize=1)
    fareyImage[u,v] = 255
    if i == maxLines:
        break
#ax[0].set_title('Sampling (colour per line) for prime size:'+str(p))
#ax[1].set_title('Sampling (same colour per line) for prime size:'+str(p))
ax[0].set_title('Sampling (colour per line) for dyadic size:'+str(M))
ax[1].set_title('Sampling (same colour per line) for dyadic size:'+str(M))
#ax[0].set_xlim([0,M])
#ax[0].set_ylim([0,M])
#ax[1].set_xlim([0,M])
#ax[1].set_ylim([0,M])

#imageio.imsave("farey_image_"+str(p)+"_"+str(K)+".png", fareyImage)
imageio.imsave("farey_image_"+str(M)+"_"+str(K)+".png", fareyImage)

plt.show()

fig,
plt.plot(pValues, qValues, 'ro')
plt.show()


import numpy as np

def accuracy_score(y_true, y_pred):
    """
    Classification performance metric that computes the accuracy of y_true
    and y_pred.
    :param numpy.array y_true: array-like of shape (n_samples,) Ground truth correct labels.
    :param numpy.array y_pred: array-like of shape (n_samples,) Estimated target values.
    :returns: C (float) Accuracy score.
    """
    correct = 0
    for true, pred in zip(y_true, y_pred):
        if true == pred:
            correct += 1
    accuracy = correct / len(y_true)
    return accuracy

def mse(y_true, y_pred, squared=True):
    """
    Mean squared error regression loss function.
    Parameters
    :param numpy.array y_true: array-like of shape (n_samples,)
        Ground truth (correct) target values.
    :param numpy.array y_pred: array-like of shape (n_samples,)
        Estimated target values.
    :param bool squared: If True returns MSE, if False returns RMSE. Default=True
    :returns: loss (float) A non-negative floating point value (the best value is 0.0).
    """
    y_true = np.array(y_true)
    y_pred = np.array(y_pred)
    errors = np.average((y_true - y_pred) ** 2, axis=0)
    if not squared:
        errors = np.sqrt(errors)
    return np.average(errors)

def r2_score(y_true, y_pred):
    """
    R^2 regression score function.
        R^2 = 1 - SS_res / SS_tot
    where SS_res is the residual sum of squares and SS_tot is the total
    sum of squares.
    :param numpy.array y_true : array-like of shape (n_samples,) Ground truth (correct) target values.
    :param numpy.array y_pred : array-like of shape (n_samples,) Estimated target values.
    :returns: score (float) R^2 score.
    """
    # Residual sum of squares.
    numerator = ((y_true - y_pred) ** 2).sum(axis=0)
    # Total sum of squares.
    denominator = ((y_true - np.average(y_true, axis=0)) ** 2).sum(axis=0)
    # R^2.
    score = 1 - numerator / denominator
    return score

def mse_prime(y_true, y_pred):
    return 2*(y_pred-y_true)/y_true.size

def cross_entropy(y_true, y_pred):
    return -(y_true * np.log(y_pred)).sum()

def cross_entropy_prime(y_true, y_pred):
    return y_pred - y_true


# --------------
# Importing header files
import numpy as np
import warnings

warnings.filterwarnings('ignore')

#New record
new_record=[[50,  9,  4,  1,  0,  0, 40,  0]]

#Reading file
data = np.genfromtxt(path, delimiter=",", skip_header=1)
#Code starts here
census=np.concatenate([data,new_record])
#print(data.shape)
#print(census.shape)

age=np.array(census[:,0])
#print(age.shape)
max_age=max(age)
min_age=min(age)
#print(max_age)
#print(min_age)
age_mean=age.mean().round(2)
#print(age_mean)
age_std=age.std().round(2)
#print(age_std)
race_0=np.array(census[:,2][census[:,2]==0])

race_1=np.array(census[:,2][census[:,2]==1])
race_2=np.array(census[:,2][census[:,2]==2])
race_3=np.array(census[:,2][census[:,2]==3])
race_4=np.array(census[:,2][census[:,2]==4])
#print(race_4.shape)

len_0=len(race_0)
len_1=len(race_1)
len_2=len(race_2)
len_3=len(race_3)
len_4=len(race_4)

if(min(len_0,len_1,len_2,len_3,len_4)==len_0):
    minority_race=0
elif(min(len_0,len_1,len_2,len_3,len_4)==len_1):
    minority_race=1
elif(min(len_0,len_1,len_2,len_3,len_4)==len_2):
    minority_race=2
elif(min(len_0,len_1,len_2,len_3,len_4)==len_3):
    minority_race=3
else:
    minority_race=4
#print(minority_race)
senior_citizens=np.array(census[census[:,0]>60])
working_hours_sum=np.sum(senior_citizens[:,6])
print(working_hours_sum)
senior_citizens_len=len(senior_citizens)
avg_working_hours=working_hours_sum/senior_citizens_len
print(avg_working_hours.round(2))
high=np.array(census[census[:,1]>10])
low=np.array(census[census[:,1]<=10])
avg_pay_high=(np.mean(high[:,7])).round(2)
avg_pay_low=(np.mean(low[:,7])).round(2)
print(avg_pay_high)
print(avg_pay_low)


'''

'''
import numpy as np

def check_orientation(origin, points):
    '''
    *origin* is a point inside a (convex) shape
    Meaning of orientation:
    - look from origin to the triangle plane
    - return True if the triangle points are oriented counter-clockwise, returns True (orientation is suitable for FBEM)
    :origin: a reference point to check orinetation
    :points: coordinates of a triangle: array of 3 points, each is a 3D point
    '''
    origin = np.array(origin)
    [p1, p2, p3] = [np.array(point) for point in points]
    v12 = p1 - p2
    v32 = p3 - p2
    normal = np.cross(v12, v32)
    orientation = p1 + p2 + p3 - 3 * origin
    sign = np.dot(orientation, normal)
    if sign > 0:
        return True
    elif sign < 0:
        return False
    else:
        raise ValueError("Origin is in the triagnle plane")

def orientate(origin, points, triangle):
    """
    Check orientation, fix it if it is wrong.
    """
    if not check_orientation(origin, points):
        triangle = (triangle[0], triangle[2], triangle[1])
    return triangle

def orientateTriangulation(origin, points, triangulation):
    '''
    Fix orientation in triangles in a triangulation array (array of triangle indices).
    '''
    triangulationH = []
    for tri in triangulation:
        triH = orientate(origin, [points[tri[0]], points[tri[1]], points[tri[2]]], tri)
        triangulationH.append(triH)
    return triangulationH

if __name__ == '__main__':
    # Tests

    origin = np.array([0,0,1])
    points = np.array([[1,0,0], [0,1,0], [0,0,0]])
    print(check_orientation(origin, points)) # OK: True


import math
from math import ceil
import numpy as np

def cartesian_product(*arrays) -> np.ndarray:
    """
    Computes the cartesian product of given arrays fast.

    :param arrays: arrays to compute the cartesian product of.

    :return: the cartesian product of the given arrays.
    :rtype: numpy.ndarray
    """
    la = len(arrays)
    dtype = np.result_type(*arrays)
    arr = np.empty([len(a) for a in arrays] + [la], dtype=dtype)
    for i, a in enumerate(np.ix_(*arrays)):
        arr[..., i] = a
    return arr.reshape(-1, la)

def multiply_point(point: tuple[float, ...], coef: float) -> tuple[float, ...]:
    """
    Multiples each value in a given tuple by a coefficient.

    :param point: the point to multiply.
    :type point: tuple[float, ...]

    :param coef: the coefficient to multiply the points by.
    :type coef: float

    :return: the tuple, where each element is multiplied by the coefficient.
    :rtype: tuple[float]
    """

    return tuple(p * coef for p in point)

def add_points(points: list[tuple[float, ...]], coefs=None) -> tuple[float, ...]:
    """
    Adds values in tuples (for adding coordinates).

    :param points: list of tuples to add together.
    :type points: list[tuple[float, ...]]

    :param coefs: coefficients before the tuples (all 1's by default).
    :type coefs: list[float]

    :raises:
        AssertionError: if the number of tuples and coefficients are not equal.
    :raises:
        AssertionError: if the number of values is not equal in all tuples.

    :return: the sum of tuples.
    :rtype: tuple[float, ...]
    """

    if coefs != None:
        assert len(points) == len(coefs), "Number of points and number of coefficients must be equal."
    else:
        coefs = [1] * len(points)

    tuple_length = len(points[0])
    assert all(len(p) == tuple_length for p in points), "Number of values should be equal for all points."

    points_t = [
        tuple([points[p][i] * coefs[p] for p in range(len(points))]) for i in range(tuple_length)
    ]
    return tuple(map(sum, points_t))

def point_ceil(p: tuple[float, ...]) -> tuple[int, ...]:
    """
    Computes the ceiling of a tuple.

    :param p: a tuple.
    :type p: tuple[float, ...]

    :return: tuple of ceilings of all values in the given tuple.
    :rtype: tuple[int, ...]
    """

    return tuple(ceil(i) for i in p)

def euclidian_dist(p1: tuple[float, float], p2=(0, 0)) -> float:
    """
    Calculates the Euclidian distance between two points.

    :param p1: coordinates of point 1.
    :type p1: tuple[float, float]

    :param p2: coordinates of point 2.
    :type p2: tuple[float, float]

    :return: the Euclidean distance between two 2D points.
    :rtype: float
    """

    return math.sqrt(
        pow(p1[0] - p2[0], 2) + pow(p1[1] - p2[1], 2)
    )


# -*- coding: utf-8 -*-
"""
Title: Iris Dataset exploration using Linear Regressio
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import math
import scipy
import scipy.stats

from matplotlib import style
import matplotlib.patches as mpatches
from sklearn import preprocessing, cross_validation, svm
from sklearn.preprocessing import StandardScaler
from sklearn.utils import shuffle
from sklearn.cluster import KMeans

style.use('ggplot')

FILE_NAME = "res/iris_missing.csv"

def covarience_matrix(X):
    #standardizing data
    X_std = StandardScaler().fit_transform(X)

    #sample means of feature columns' of dataset
    mean_vec = np.mean(X_std, axis=0)
    #covariance matrix
    cov_mat = (X_std - mean_vec).T.dot((X_std - mean_vec)) / (X_std.shape[0]-1)
    #if right handside is ( Xstd - mean(Xstd) )^T . ( Xstd - mean(Xstd) )
    #simplyfying X^T.X / ( n - 1 )
    cov_mat = np.cov(X_std.T)
    return cov_mat

def max_min_bi_corel(X):
    a = covarience_matrix(X)
    a[a>=1] = 0
    maxcor = np.argwhere(a.max() == a)[0] # reverse 1

    b = covarience_matrix(X)
    mincor = np.argwhere(b.min() == b)[0] # reverse 1

    return maxcor,mincor

def main():
    ## loading the data
    data = pd.read_csv(FILE_NAME, header=None, index_col=0, names = ["sepal_width", "sepal_length", "petal_width", "petal_length", "Class"] )
    #data.reset_index(inplace=True)

    # Create an array of three colours, one for each species.
    colors = np.array(['red', 'green', 'blue','yellow','violet'])
    labelss = np.array(['Setosa', 'Versicolor', 'Virginica','W','Y'])

    #0,1,2 labels for selecting color by index
    data.loc[ data['Class']=='Iris-setosa', 'Class'] = 0
    data.loc[ data['Class']=='Iris-versicolor', 'Class'] = 1
    data.loc[ data['Class']=='Iris-virginica', 'Class'] = 2

    #def handle_missing_values()
    #data.fillna(0, inplace=True)
    #data = data.apply(lambda x: x.fillna(x.mean()),axis=0)
    data = data.apply(lambda x: x.fillna(x.median()),axis=0)

    ## Rounding label column to nearest integer
    data['Class'].round(0)
    ## Eliminating 000 after decimal from modified label column
    data.Class = data.Class.astype(int)

    #data = shuffle(data)

    x = data.iloc[:,:-1]
    y = data['Class']

    print("Covariance Matrix =")
    print(covarience_matrix(x))

    maxcor,mincor = max_min_bi_corel(x)
    print("Most Colinearity %s"%maxcor)
    print("Least Colinearity %s"%mincor)

    #12x7 unit plot
    plt.figure('Unsupervised Clustering - KMeans',figsize=(12,7))

    #nrows=1, ncols=2, plot_number=1
    plt.subplot(2, 2, 1)
    plt.scatter(x[data.columns[mincor[0]]], x[data.columns[mincor[1]]], c=colors[y], s=40)
    plt.title('%s vs %s[Lowest Colinear]'%(data.columns[mincor[0]],data.columns[mincor[1]]))

    #nrows=1, ncols=2, plot_number=2
    plt.subplot(2, 2, 2)
    plt.scatter(x[data.columns[maxcor[0]]], x[data.columns[maxcor[1]]], c=colors[y], s=40)
    plt.title('%s vs %s[Highest Colinear]'%(data.columns[maxcor[0]],data.columns[maxcor[1]]))

    clu = KMeans(n_clusters=3)
    clu.fit(x)

    print("For actual labels,where")
    count=0
    for c in labelss:
        print("Label=%s -> Species = %s"%(count,c))
        count+=1

    print("Actual labels %s" % y.tolist())

    # The fudge to reorder the cluster ids.
    #predictedY = np.choose(clu.labels_, [1, 0, 2]).astype(np.int64)
    predictedY = clu.labels_
    print("Clustered groups %s" % predictedY)

    # Plot the classifications that we saw earlier between Petal Length and Petal Width
    plt.subplot(2, 2, 3)
    plt.scatter(x['petal_length'], x['petal_width'], label = labelss[y], c=colors[y], s=40) #colormap
    plt.title('Actual Classes')

    color_patch = []
    for c in range(len(colors)):
        color_patch.append(mpatches.Patch(color=colors[c], label=labelss[c]))
        plt.legend(handles=color_patch)

    # Plot the classifications according to the model
    plt.subplot(2, 2, 4)
    plt.scatter(x['petal_length'], x['petal_width'], c=colors[predictedY], s=40) #colormap
    plt.title("Model's predicted classes[Clusters without label]")

    plt.tight_layout()
    plt.show()

    '''
    accuracy = clf.score(X_test, y_test)
    print("Test Score %s" %accuracy)

    predict = clf.predict(XP)
    print(yP,np.round( np.array(predict)))
    prediction_score = ( sum( yP==np.round( np.array(predict) ) ) / len(yP) ) * 100
    print("Prediction score %s" %prediction_score)
    '''

if __name__ == '__main__':
    main()


import random
import numpy as np
import matplotlib.pylab as plt

def RandomListGen(listSize, randomSumNum):
    L = []
    for i in range(listSize):
        randomNum = 0
        for j in range(randomSumNum):
            randomNum += random.random()
        L.append(randomNum)
    return L

def plotRandomList(list, randomSumNum):
    plt.clf()
    plt.plot(list, np.arange(0, randomSumNum, randomSumNum/len(list)))
    plt.show()

def PDFCalc(list, randomSumNum, gap):
    sortedList = sorted(list)
    PDF = {"0":0}
    guess = 0
    for j in sortedList:
        if (j > guess + gap):
            guess += gap
            PDF[str(guess)] = 0
        PDF[str(guess)] += 1
    return PDF

def PDFPlot(PDF):
    plt.clf()
    plt.ylim(0, max(PDF.values())*1.2)
    plt.plot(*zip(*PDF.items()))
    plt.show()

# plotRandomList(RandomListGen(10000000, 1), 1)
PDF = PDFCalc(RandomListGen(100000, 50), 50, 0.01)
PDFPlot(PDF)


import numpy as np
import math

a = np.arange(12).reshape(3,4)
print a

# sum over the first axis (rows), so this gives the sum in each column
print a.sum(axis=0)

# sum over all elements
print a.sum()

# find the minimum and maximum element
print a.min(), a.max()

print " "

# universal functions
b = a*math.pi/12.0
print b

c = np.cos(b)
print c

print " "

# add two arrays
d = b + c
print d


import numpy as np
import scipy.misc
import matplotlib.pyplot as plt

plt.rc("font", size=16, family="serif", serif="Computer Sans")
plt.rc("text", usetex=True)

N = 5
x = np.arange(0, N + 1)

theta = np.array([0.3, 0.5, 0.8])
colors = ['b', 'r', 'g']

i = 0
for th in theta:
	p = scipy.misc.comb(N, x)*th**x*(1. - th)**(N - x)
	p /= p.sum()
	plt.plot(x, p, 'o-', color=colors[i], markersize=10,
		label='$\\theta = {val}$'.format(val=th))
	i += 1

plt.xlabel('Possible Data $x$')
plt.ylabel('Probability')
plt.ylim([-0.1, 1.])
plt.xlim([-0.5, 5.5])
plt.legend(numpoints=1, loc='upper center')
plt.savefig('binomial.pdf', bbox_inches='tight')
#plt.show()

x = 2
theta = np.linspace(0., 1., 1001)
p = theta**x*(1. - theta)**(N - x)
p /= np.trapz(p, x=theta)
plt.plot(theta, np.ones(p.shape), 'g--', linewidth=2, label='Prior $p(\\theta)$')
plt.plot(theta, p, 'b', linewidth=2, label='Posterior $p(\\theta|x)$')
plt.xlabel('Possible Values $\\theta$')
plt.ylabel('Probability Density')
plt.legend()
plt.savefig('bus_inference.pdf', bbox_inches='tight')
#plt.show()

prior1 = np.ones(theta.shape)
prior2 = (theta + 0.001)**(-0.5)*(1. - theta + 0.001)**(-0.5); prior2 /= np.trapz(prior2, x=theta)
prior3 = theta**100*(1. - theta)**100; prior3 /= np.trapz(prior3, x=theta)
post1 = prior1*theta**x*(1. - theta)**(N - x); post1 /= np.trapz(post1, x=theta)
post2 = prior2*theta**x*(1. - theta)**(N - x); post2 /= np.trapz(post2, x=theta)
post3 = prior3*theta**x*(1. - theta)**(N - x); post3 /= np.trapz(post3, x=theta)
plt.plot(theta, prior1, 'b--', linewidth=2, label='Prior 1')
plt.plot(theta, prior2, 'r--', linewidth=2, label='Prior 2')
plt.plot(theta, prior3, 'g--', linewidth=2, label='Prior 3')
plt.plot(theta, post1, 'b', linewidth=2)
plt.plot(theta, post2, 'r', linewidth=2)
plt.plot(theta, post3, 'g', linewidth=2)
plt.legend()
plt.xlabel('Possible Values $\\theta$')
plt.title('Three Priors, Three Posteriors')
plt.ylabel('Probability Density')
plt.savefig('three_priors.pdf', bbox_inches='tight')
#plt.show()

N = 1000
x = 500
prior1 = np.ones(theta.shape)
prior2 = (theta + 0.001)**(-0.5)*(1. - theta + 0.001)**(-0.5); prior2 /= np.trapz(prior2, x=theta)
prior3 = theta**100*(1. - theta)**100; prior3 /= np.trapz(prior3, x=theta)
post1 = prior1*theta**x*(1. - theta)**(N - x); post1 /= np.trapz(post1, x=theta)
post2 = prior2*theta**x*(1. - theta)**(N - x); post2 /= np.trapz(post2, x=theta)
post3 = prior3*theta**x*(1. - theta)**(N - x); post3 /= np.trapz(post3, x=theta)
plt.plot(theta, prior1, 'b--', linewidth=2, label='Prior 1')
plt.plot(theta, prior2, 'r--', linewidth=2, label='Prior 2')
plt.plot(theta, prior3, 'g--', linewidth=2, label='Prior 3')
plt.plot(theta, post1, 'b', linewidth=2, alpha=0.5)
plt.plot(theta, post2, 'r', linewidth=2, alpha=0.5)
plt.plot(theta, post3, 'g', linewidth=2, alpha=0.5)
plt.xlabel('Possible Values $\\theta$')
plt.ylabel('Probability Density')
plt.title('Lots of Data')
plt.xlim([0.4, 0.6])
plt.legend()
plt.savefig('lots_of_data.pdf', bbox_inches='tight')
#plt.show()


#!/usr/bin/python
# encoding: utf-8

"""
@author: Ian
@contact:yongguiluo@hotmail.com
@file: permutation_combination.py
@time: 2019/3/23 13:27
排列组合
"""
from scipy.special import comb, perm
from itertools import combinations, permutations

def permutation(n, m):
    """
    n中选择m个数进行排列
    先总结出递推公式
    :param n:
    :param m:
    :return:
    """
    return 1 if m == 0 else permutation(n, m - 1) * (n - m + 1)

if __name__ == "__main__":
    print(permutation(5, 4))#120
    print(perm(5, 4))
    print(comb(5, 4))
    #调用 itertools 获取排列组合的全部情况数
    print(list(permutations([1, 2, 3], 2)))
    print(list(combinations([1, 2, 3], 2)))


import math
import sympy as sym

print("BOUNDING PHASE METHOD")
x = sym.Symbol('x')

### Function ###

f = x**2 - 5*x + x**2

################

def substitute(k):
    return (f.subs(x,k))

while(1):
    delta = float(input("Enter the delta value : "))
    x_o = 0.6 #initial guess
    x_minus_delta = x_o - delta
    x_plus_delta = x_o + delta

    f_minus_delta = substitute(x_minus_delta)
    f_plus_delta = substitute(x_plus_delta)
    f_o = substitute(x_o)
    print("x_minus_delta = {}  x = {}  x_plus_delta = {}".format(x_minus_delta,x_o,x_plus_delta))
    print("f(x-$) = {}  f(x) = {}  f(x+$) = {}".format(f_minus_delta,f_o,f_plus_delta))

    if(f_minus_delta>=f_o and f_o>=f_plus_delta):
        delta = delta
        break
    elif(f_minus_delta<=f_o and f_o<=f_plus_delta):
        delta = -delta
        break
    else:
        continue

a = []
a.append(x_o)
k = 0
f_o_plus_1 = f_o - 1
while(f_o_plus_1 < f_o):
    x_o_plus_1 = x_o + (2**k)*delta
    a.append(x_o_plus_1)
    k = k + 1
    f_o_plus_1 = substitute(x_o_plus_1)
    f_o = substitute(x_o)
    print("step :", k)
    print("x_o = {} , x_o_plus_1 = {}".format(x_o,x_o_plus_1))
    print("f_o = {}  f_o_plus_1 = {}".format(f_o,f_o_plus_1))
    x_o = x_o_plus_1

print("( {} , {}  )".format(a[-3],x_o_plus_1))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Oct  5 17:33:27 2018

@author: shivam
"""

"""
Numpy contd
Datatypes
"""

import numpy as np

x = np.array([1, 2])   # Let numpy choose the datatype
print(x.dtype)         # Prints "int64"

x = np.array([1.0, 2.0])   # Let numpy choose the datatype
print(x.dtype)             # Prints "float64"

x = np.array([1, 2], dtype=np.int64)   # Force a particular datatype
print(x.dtype, x.shape)       # Prints "int64"

"""

Array Math
    Element wise operations.
"""
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)

# Elementwise sum; both produce the array
# [[ 6.0  8.0]
#  [10.0 12.0]]
print(x + y)
print(np.add(x, y))

# Elementwise difference; both produce the array
# [[-4.0 -4.0]
#  [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))

# Elementwise product; both produce the array
# [[ 5.0 12.0]
#  [21.0 32.0]]
print(x * y)
print(np.multiply(x, y))

# Elementwise division; both produce the array
# [[ 0.2         0.33333333]
#  [ 0.42857143  0.5       ]]
print(x / y)
print(np.divide(x, y))

# Elementwise square root; produces the array
# [[ 1.          1.41421356]
#  [ 1.73205081  2.        ]]
print(np.sqrt(x))

"""
dot is available both as a function in the numpy module and as an instance method of array objects
"""

x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

v = np.array([9,10])
w = np.array([11, 12])

# Inner product of vectors; both produce 219
print(v.dot(w))
print(np.dot(v, w))

# Matrix / vector product; both produce the rank 1 array [29 67]
print(x.dot(v))
print(np.dot(x, v))

# Matrix / matrix product; both produce the rank 2 array
# [[19 22]
#  [43 50]]
print(x.dot(y))
print(np.dot(x, y))

"""
Numpy provides many useful functions for performing computations on arrays; one of the most useful is sum
"""
x = np.array([[1,2],[3,4]])

print(np.sum(x))  # Compute sum of all elements; prints "10"
print(np.sum(x, axis=0))  # Compute sum of each column; prints "[4 6]"
print(np.sum(x, axis=1))  # Compute sum of each row; prints "[3 7]"

"""
Transpose of the matrix
"""
x = np.array([[1,2], [3,4]])
print(x)    # Prints "[[1 2]
            #          [3 4]]"
print(x.T)  # Prints "[[1 3]
            #          [2 4]]"

# Note that taking the transpose of a rank 1 array does nothing:
v = np.array([1,2,3])
print(v)    # Prints "[1 2 3]"
print(v.T)  # Prints "[1 2 3]"


# coding: utf-8
# Released under the MIT licence https://opensource.org/licenses/mit-license.php
# Copyright © 2021 Kazuki Akimoto. All right reserved.

import numpy as np

# もとの行列を表示
def desplay_matrix(mat):
	print('行列は')
	print(mat)
	print('________________')

# 転置行列
def transpose_matrix(mat):
	print('転置行列は')
	print(mat.T)
	print('________________')

# 逆行列
def inverse_matrix(mat):
	print('逆行列は')
	try:
		print(np.linalg.inv(mat))
	except np.linalg.LinAlgError:
		print('エラー：この行列には逆行列が存在しません')
	print('________________')

#行列式
def determinant(mat):
	print('行列式は')
	print(np.linalg.det(mat))
	print('________________')

#固有値、固有ベクトル
def eigenvalue(mat):
	print('固有値・固有ベクトルは')
	w, v = np.linalg.eig(mat)
	print('固有値 :{}, 固有ベクトル:{}'.format(w[0],v[0]))
	print('固有値 :{}, 固有ベクトル:{}'.format(w[1],v[1]))
	print('________________')


from skimage import io, data
import numpy as np
from matplotlib import pyplot as plt

im = data.camera()
im = im.astype('float')

lin, col = im.shape

#im2 = im.copy()
im2 = np.zeros((lin,col))

filtro = np.array([[1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9],
                   [1/9, 1/9, 1/9]])

filtro = np.array([[1, 0, -1],
                   [1, 0, -1],
                   [1, 0, -1]]) / 6

for i in range(1, lin-1):
    for j in range(1, col-1):
#        soma = im[i-1,j-1]+im[i-1,j]+im[i-1,j+1]
#        soma = soma + im[i,j-1]+im[i,j]+im[i,j+1]
#        soma = soma + im[i+1,j-1]+im[i+1,j]+im[i+1,j+1]
#        media = soma / 9

        sub_im = im[i-1:i+2, j-1:j+2]

#        media = sub_im.mean()
#        media = (sub_im * (1/9)).sum()

        mult = sub_im * filtro
        media = mult.sum()

        im2[i,j] = media

plt.figure()
plt.subplot(121)
plt.imshow(im.astype('uint8'), cmap='gray')
plt.subplot(122)
plt.imshow(im2.astype('uint8'), cmap='gray')


import numpy as np

def build_sine_table(f_sine, samp_freq, data_type):
    """
    :param f_sine: Modulate frequency for voice effect in Hz.
    :param samp_freq: Sampling frequency in Hz
    :param data_type: Data type of sinusoid table. Must be signed integer type.
    :return:
    """

    if data_type is np.int16 or np.int32:
        MAX_SINE = np.iinfo(data_type).max
    else:
        raise ValueError("Data type must be signed integer.")

    # periods
    samp_per = 1./samp_freq
    sine_per = 1./f_sine

    # compute time instances
    t_vals = np.arange(0, sine_per, samp_per)
    LOOKUP_SIZE = len(t_vals)
    n_vals = np.arange(LOOKUP_SIZE)

    # compute the sine table
    w_mod = 2*np.pi*f_sine/samp_freq
    SINE_TABLE = np.sin(w_mod*n_vals) * MAX_SINE

    return SINE_TABLE, MAX_SINE, LOOKUP_SIZE


import jax.numpy as jnp
from jax import custom_jvp,jit
from jax.scipy.stats import norm,t
from jax.scipy.special import ndtri

### Functions for Clayton copula ###
#Calculate bivariate normal copula log H_uv and log c_uv
@jit
def clayton_logdistribution_logdensity(u,v,a):
    #clip to prevent 0s and 1s in CDF
    eps = 1e-6
    u = jnp.clip(u,eps,1-eps)
    v = jnp.clip(v,eps,1-eps)

    #initialize useful terms
    u_ = 1-u
    v_ = 1-v
    k = (a+1)/a
    denom = u_**(-1/a) + v_**(-1/a)-1

    #compute log cop density and conditional cdf
    logcop_dens = jnp.log(k) - k*(jnp.log(u_) + jnp.log(v_)) -(a+2)*jnp.log(denom)
    log1cop_dist = jnp.clip(-k*jnp.log(v_) - (a+1)*jnp.log(denom),jnp.log(eps),jnp.log(1-eps))
    logcop_dist = jnp.log1p(-jnp.exp(log1cop_dist))

    return logcop_dist,logcop_dens
### ###

### Functions for Gaussian Copula ###
@custom_jvp #forward diff (define jvp for faster derivatives)
def ndtri_(u):
    return ndtri(u)
@ndtri_.defjvp
def f_jvp(primals, tangents):
    u, = primals
    u_dot, = tangents
    primal_out = ndtri_(u)
    tangent_out = (1/norm.pdf(primal_out))*u_dot
    return primal_out, tangent_out
ndtri_ = jit(ndtri_)

@custom_jvp #forward diff (define jvp for faster derivatives)
def norm_logcdf(z):
    return norm.logcdf(z)
@norm_logcdf.defjvp
def f_jvp(primals, tangents):
    z, = primals
    z_dot, = tangents
    primal_out = norm_logcdf(z)
    tangent_out = jnp.exp(norm.logpdf(z)-primal_out)*z_dot
    return primal_out, tangent_out
norm_logcdf = jit(norm_logcdf)

@jit #Calculate normal copula cdf and logpdf for f32
def norm_copula_logdistribution_logdensity(u,v,rho):
    #clip to prevent 0s and 1s in CDF, needed for numerical stability in high d.
    eps = 1e-6
    u = jnp.clip(u,eps,1-eps)
    v = jnp.clip(v,eps,1-eps)

    #for reverse mode
    pu = ndtri_(u)
    pv = ndtri_(v)
    z = (pu - rho*pv)/jnp.sqrt(1- rho**2)

    logcop_dist = norm_logcdf(z)
    logcop_dist = jnp.clip(logcop_dist,jnp.log(eps),jnp.log(1-eps))
    logcop_dens = -0.5*jnp.log(1-rho**2) + (0.5/(1-rho**2))*(-(rho**2)*(pu**2 + pv**2)+ 2*rho*pu*pv)

    return logcop_dist,logcop_dens