# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import scipy
from scipy.optimize import curve_fit
from scipy.optimize import differential_evolution
from scipy.optimize import least_squares
import warnings
import matplotlib.pyplot as plt

x = np.loadtxt('time-open-zeroed.txt', unpack=True)
y = np.loadtxt('fluorescence-open.txt', unpack=True)

def func(x, F, a, k, b, m):
    return F + a*(1-np.exp(-k*x)) + b*(1-np.exp(-m*x))

def sumOfSquaredError(parameterTuple):
    warnings.filterwarnings("ignore") #do not print wranings
    val = func(x, *parameterTuple)
    return np.sum((y - val)**2.0)

def generate_Initial_Parameters():
    # min and max used for bounds

    parameterBounds = [(0,100), (-100, 2), (0, 100), (-0.01, 2), (0, 1)]

    #"seed" the numpy random number generator for repeatable results
    result = differential_evolution(sumOfSquaredError, parameterBounds, seed=5)
    return result.x

#generate initial parameters values
geneticParameters = generate_Initial_Parameters()
#curve fit the test data
fittedParameters, pcov = curve_fit(func, x, y, geneticParameters)
print('Parameters', fittedParameters)
modelPredictions = func(x, *fittedParameters)
absError = modelPredictions - y
SE = np.square(absError) #square errors
MSE = np.mean(SE) #mean square errors
RMSE = np.sqrt(MSE) #root mean squared error, RMSE
Rsquared = 1.0 - (np.var(absError)/np.var(y))
print('RMSE:', RMSE)
print('R-squared:', Rsquared)

print()

def compareplt(data1,data2):

     #Plot latência e jitter
      plt.rcParams['font.size']=12
      plt.rcParams['figure.figsize']=[18,6]
      lat = plt.plot(data1, data2, color='blue',label='data')

      plt.legend(loc='best')
      #plt.title('')
      plt.xlabel('Time(s)')
      plt.ylabel('Normalized Fluorescence')
      plt.show(block=False)

#graphics output section
def ModelAndScatterPlot(graphWidth, graphHeight):
    f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
    axes = f.add_subplot(111)

    # first the raw data as a scatter plot
    axes.plot(x, y,  '.')

    # create data for the fitted equation plot
    xModel = np.linspace(min(x), max(x))
    yModel = func(xModel, *fittedParameters)

    # now the model as a line plot
    axes.plot(xModel, yModel)

    axes.set_xlabel('Time(s)') # X axis data label
    axes.set_ylabel('Normalized Fluorescence') # Y axis data label

    plt.show()
    plt.close('all') # clean up after using pyplot

graphWidth = 1000
graphHeight = 600
ModelAndScatterPlot(graphWidth, graphHeight)


#Developer : Vinay Venkatesh
#Date : 2/20/2021

import matplotlib.pyplot as plt
import numpy as np

def trigsin(z, b):

  '''
  In mathematics, the trigonometric functions are real functions which relate
  an angle of a right-angled triangle to ratios of two side lengths.

  Learn More: https://www.mathsisfun.com/sine-cosine-tangent.html
  '''

  x = np.linspace(-np.pi,np.pi,100)

  # the function, which is y = sin(x) here
  y = z * np.sin(b * x)
  yint = z * np.sin(b * 0)

  # setting the axes at the centre
  fig = plt.figure()
  ax = fig.add_subplot(1, 1, 1)
  ax.spines['left'].set_position('center')
  ax.spines['bottom'].set_position('center')
  ax.spines['right'].set_color('none')
  ax.spines['top'].set_color('none')
  ax.xaxis.set_ticks_position('bottom')
  ax.yaxis.set_ticks_position('left')
  if z < 0:
    plt.ylim((z*1.5,-z*1.5))
  else:
    plt.ylim((-z*1.5,z*1.5))
  # plot the functions
  plt.plot(x,y, 'b', label=f'y={z}sin({b}x)')
  plt.title('Sine Graph')
  plt.legend(loc='upper left')

  # show the plot
  plt.show()

def trigcos(z, b):

  '''
  In mathematics, the trigonometric functions are real functions which relate
  an angle of a right-angled triangle to ratios of two side lengths.

  Learn More: https://www.mathsisfun.com/sine-cosine-tangent.html
  '''

  x = np.linspace(-np.pi,np.pi,100)

  # the function, which is y = sin(x) here
  y = z * np.cos(b * x)

  # setting the axes at the centre
  fig = plt.figure()
  ax = fig.add_subplot(1, 1, 1)
  ax.spines['left'].set_position('center')
  ax.spines['bottom'].set_position('center')
  ax.spines['right'].set_color('none')
  ax.spines['top'].set_color('none')
  ax.xaxis.set_ticks_position('bottom')
  ax.yaxis.set_ticks_position('left')
  if z < 0:
    plt.ylim((z*1.5,-z*1.5))
  else:
    plt.ylim((-z*1.5,z*1.5))
  # plot the functions
  plt.plot(x,y, 'b', label=f'y={z}cos({b}x)')
  plt.title('Cosine Graph')
  plt.legend(loc='upper left')

  # show the plot
  plt.show()

def trigtan(z, b):

  '''
  In mathematics, the trigonometric functions are real functions which relate
  an angle of a right-angled triangle to ratios of two side lengths.

  Learn More: https://www.mathsisfun.com/sine-cosine-tangent.html
  '''

  x = np.linspace(-np.pi,np.pi,100)

  # the function, which is y = sin(x) here
  y = z * np.tan(b * x)

  # setting the axes at the centre
  fig = plt.figure()
  ax = fig.add_subplot(1, 1, 1)
  ax.spines['left'].set_position('center')
  ax.spines['bottom'].set_position('center')
  ax.spines['right'].set_color('none')
  ax.spines['top'].set_color('none')
  ax.xaxis.set_ticks_position('bottom')
  ax.yaxis.set_ticks_position('left')
  if z < 0:
    plt.ylim((z*1.5,-z*1.5))
  else:
    plt.ylim((-z*1.5,z*1.5))
  # plot the functions
  plt.plot(x,y, 'b', label=f'y={z}tan({b}x)')
  plt.title('Tangent Graph')
  plt.legend(loc='upper left')

  # show the plot
  plt.show()


import numpy as np

def softmax(z):
    '''

    :param z:
    :return:

    '''
    z -= np.max(z, axis=1).reshape(-1, 1)
    s = (np.exp(z) / np.sum(np.exp(z), axis=1).reshape(-1, 1))
    return s

def initialize(X, y):
    '''

    :param X: features
    :param y: labels
    :return: weights, base

    '''
    weights = np.zeros((X.shape[1], y.shape[1]))
    base = np.zeros((1, y.shape[1]))
    return weights, base

def propagate(weights, base, X, y):
    '''

    :param weights:
    :param base:
    :param X: features
    :param y: labels
    :return: cost, gradient_weights, gradient_base

    '''
    m = X.shape[0]
    h = softmax(np.dot(X, weights) + base)
    cost = (-1/m) * np.sum(y * np.log(h) + (1 - y) * np.log(1 - h))
    grad_w = (1/m) * np.dot(X.T, (h - y))
    grad_b = (1/m) * np.sum((h-y), axis=0)
    return cost, grad_w, grad_b

def predict(X, weights, base):
    '''

    :param X: features
    :param weights:
    :param base:
    :return: predicted labels

    '''
    h = softmax(np.dot(X, weights) + base)
    return h

def evaluate(X, y, weights, base):
    '''

    :param X: features
    :param y: labels
    :param weights:
    :param base:
    :return: accuracy

    '''
    h = softmax(np.dot(X, weights) + base)
    h_argmax = np.argmax(h, axis=1)
    y_argmax = np.argmax(y, axis=1)
    accuracy = sum(h_argmax == y_argmax)/(float(len(y)))
    return accuracy

def model(train_x, train_y, test_x, test_y, iters, alpha, print_cost=True):
    '''

    :param train_x: training features
    :param train_y: training labels
    :param test_x: test features
    :param test_y: test labels
    :param iters: no. of iterations
    :param alpha: learning rate
    :param print_cost: printing the cost
    :return: weights, base

    '''
    # reshaping (28, 28) data int 784
    train_x = np.reshape(train_x, (-1, 784))
    test_x = np.reshape(test_x, (-1, 784))

    # initializing weights and bias
    weights, base = initialize(train_x, train_y)
    print("\nTraining multiclass Logistic Regression on MNIST data...")
    for i in range(iters):
        # getting the cost, weight gradient and base gradient
        cost, grad_w, grad_b = propagate(weights, base, train_x, train_y)
        weights = weights - alpha * grad_w
        base = base - alpha * grad_b
        if print_cost and i % 100 == 0:
            print('cost after iteration {} : {}'.format(i, cost))
    print(f'Cost after iteration {i+1} : {cost}')

    # calculating train and test accuracy
    train_accuracy = evaluate(train_x, train_y, weights, base)
    test_accuracy = evaluate(test_x, test_y, weights, base)
    train_size = len(train_y)
    print(f'Logistic Regression Train accuracy : {train_accuracy}%')
    print(f'Logistic Regression Test accuracy : {test_accuracy}%')
    print(f'Training size : {train_size}, alpha : {alpha}, iterations : {iters}\n\n')
    LR_params = {'weights': weights, 'base': base, 'train_accuracy': train_accuracy,
                 'test_accuracy': test_accuracy, 'train_size': train_size, 'alpha': alpha, 'iters': iters}
    return LR_params


##@file flp.py
#@brief model for solving the capacitated facility location problem
"""
minimize the total (weighted) travel cost from n customers
to some facilities with fixed costs and capacities.

Copyright (c) by Joao Pedro PEDROSO and Mikio KUBO, 2012
"""
from pyscipopt import Model, quicksum, multidict

def flp(I,J,d,M,f,c):
    """flp -- model for the capacitated facility location problem
    Parameters:
        - I: set of customers
        - J: set of facilities
        - d[i]: demand for customer i
        - M[j]: capacity of facility j
        - f[j]: fixed cost for using a facility in point j
        - c[i,j]: unit cost of servicing demand point i from facility j
    Returns a model, ready to be solved.
    """

    model = Model("flp")

    x,y = {},{}
    for j in J:
        y[j] = model.addVar(vtype="B", name="y(%s)"%j)
        for i in I:
            x[i,j] = model.addVar(vtype="C", name="x(%s,%s)"%(i,j))

    for i in I:
        model.addCons(quicksum(x[i,j] for j in J) == d[i], "Demand(%s)"%i)

    for j in M:
        model.addCons(quicksum(x[i,j] for i in I) <= M[j]*y[j], "Capacity(%s)"%i)

    for (i,j) in x:
        model.addCons(x[i,j] <= d[i]*y[j], "Strong(%s,%s)"%(i,j))

    model.setObjective(
        quicksum(f[j]*y[j] for j in J) +
        quicksum(c[i,j]*x[i,j] for i in I for j in J),
        "minimize")
    model.data = x,y

    return model

def make_data():
    """creates example data set"""
    I,d = multidict({1:80, 2:270, 3:250, 4:160, 5:180})            # demand
    J,M,f = multidict({1:[500,1000], 2:[500,1000], 3:[500,1000]}) # capacity, fixed costs
    c = {(1,1):4,  (1,2):6,  (1,3):9,    # transportation costs
         (2,1):5,  (2,2):4,  (2,3):7,
         (3,1):6,  (3,2):3,  (3,3):4,
         (4,1):8,  (4,2):5,  (4,3):3,
         (5,1):10, (5,2):8,  (5,3):4,
         }
    return I,J,d,M,f,c

if __name__ == "__main__":
    I,J,d,M,f,c = make_data()
    model = flp(I,J,d,M,f,c)
    model.optimize()

    EPS = 1.e-6
    x,y = model.data
    edges = [(i,j) for (i,j) in x if model.getVal(x[i,j]) > EPS]
    facilities = [j for j in y if model.getVal(y[j]) > EPS]

    print("Optimal value:", model.getObjVal())
    print("Facilities at nodes:", facilities)
    print("Edges:", edges)

    try: # plot the result using networkx and matplotlib
        import networkx as NX
        import matplotlib.pyplot as P
        P.clf()
        G = NX.Graph()

        other = [j for j in y if j not in facilities]
        customers = ["c%s"%i for i in d]
        G.add_nodes_from(facilities)
        G.add_nodes_from(other)
        G.add_nodes_from(customers)
        for (i,j) in edges:
            G.add_edge("c%s"%i,j)

        position = NX.drawing.layout.spring_layout(G)
        NX.draw(G,position,node_color="y",nodelist=facilities)
        NX.draw(G,position,node_color="g",nodelist=other)
        NX.draw(G,position,node_color="b",nodelist=customers)
        P.show()
    except ImportError:
        print("install 'networkx' and 'matplotlib' for plotting")


import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as stats
import math
import numpy as np

np.random.seed(3)

mu = 0.0
var = 1.0
sigma = math.sqrt(var)

x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
plt.title(f"Distribución normal, $\mu$={mu}, $\sigma$={sigma}")
plt.plot(x, stats.norm.pdf(x, mu, sigma))
plt.show()

# N = 50
# x = np.random.normal(mu, sigma, N)
# y = np.random.normal(mu, sigma, N)
# plt.scatter(x, y, edgecolors='b')
# plt.show()

# lam_n = 30
# n_lambdas = 30
# lambdas = np.linspace(0, lam_n, n_lambdas)
# x = np.linspace(0, 1, 100)

# for lam in lambdas:
#     plt.plot(x, stats.expon.pdf(x, scale=1/lam))

# plt.title(f"Distribución exponencial, $\lambda$=0-{lam_n}, paso={lam_n/n_lambdas}")
# plt.show()


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

# PReLU:
def PReLU(x,a=.01):
    x1=[]
    for i in x:
        if i<0:
            x1.append(i*a)
        else:
            x1.append(i)
    return x1

# PReLU derivative:
def PReLU_deriv(x):
    x1=[]
    for i in x:
        if i<0:
            x1.append(i)
        else:
            x1.append(1)
    return x1

x = np.linspace(-10, 10)

plt.plot(x, PReLU(x))
plt.axis('tight')
plt.title('Activation Function :PReLU')
plt.show()

Tensorflow Basic Exercises/Deep Dive into TF Activation Functions/PReLU.py


import warnings

import numpy as np

def newtons_method(f, df, x0, e=1E-10, tol=1E-10):
    """
    Semantics:
        newton method for finding the root of f given its derivative.
    Args:
        f (callable):  function for finding its roots.
        df (callable):  derivative of f as a function
        x0:  initial gues.
        e (error for the root):
        tol (tol for step):

    Returns:

    """
    number_of_step_crash = 0
    step = 1
    while f(x0) > e or abs(step) > tol:
        if abs(x0) == np.inf or number_of_step_crash > 1E3:  # function too flat.
            raise ValueError("Is the function flat enough ?")
        number_of_step_crash += 1
        step = f(x0) / df(x0)
        x0 -= step
    return x0

def newtons_method_multi(f, df, x0, e=1E-10, tol=1E-10):
    """
    Semantics:
        newton method for finding the root of f given its derivative.
        f is a multi dim function R^n -> R.
    Args:
        f (callable):  function for finding its roots.
        df (callable):  derivative of f as a function, gradient.
        x0:  initial gues.
        e (error for the root):
        tol (tol for step):

    Returns:

    """
    number_of_step_crash = 0
    step = 1
    # TODO step > tol is not supposed to work. comparing vector and float. use something like any
    while np.linalg.norm(df(x0), 2) > e or abs(step) > tol:  # I use norm 2 as criterea
        if number_of_step_crash > 1E4:
            raise Exception("Is the function flat enough ?")
        number_of_step_crash += 1

        A = np.linalg.inv(df(x0))
        B = f(x0)
        step = np.matmul(A, B)
        x0 -= step
    return x0

def newtons_method_vectorised(f, df, x0, e=1E-7, tol=1E-7, silent=True):
    """
    Semantics:
        vectorised newton method for finding the root of f given its derivative.
        the vectorisation means that one can give a function that is in R^d.
        All the inputs are optimised independently.
        Each needs to reach the desired precision.
        If some inputs did not converged (step reached infinity), replace the value by nans.
    Args:
        f (callable):  function for finding its roots.
        Takes two parameters, an array, and a list of indices to slice the array.
        df (callable):  derivative of f as a function.
        Takes two parameters, an array, and a list of indices to slice the array.
        x0:  initial guess. Is changed over iterations.
        e (error for the root):
        tol (tol for step):
        silent (bool): verbose.

    Returns:
        void. x0 contains the optimised values.

    """
    nb_step = 0
    arr_flags_iter = np.full(len(x0), True)

    f_eval = f(x0, arr_flags_iter)
    df_eval = df(x0, arr_flags_iter)

    arr_flags_iter = (np.abs(f_eval / df_eval) > tol) & \
                     (np.abs(f_eval) > e)

    step = np.zeros(len(x0))  # initialization
    while np.any(arr_flags_iter):  # test that they all converged, tol for step and error
        if not nb_step < 10000:
            # test if any step is infinity
            raise Exception("Is the function flat enough ?")

        # Iterate on the indices that haven't yet converged
        f_eval = f(x0, arr_flags_iter)
        step[arr_flags_iter] = f_eval / df(x0, arr_flags_iter)
        step[(step == np.inf)] = np.NaN
        x0[arr_flags_iter] = x0[arr_flags_iter] - step[arr_flags_iter]
        arr_flags_iter[arr_flags_iter] = (np.abs(step[arr_flags_iter]) > tol) & \
                                         (np.abs(f_eval) > e)

        nb_step += 1
    if not silent:
        print('converged in {it} iterations'.format(it=nb_step))
    if np.any(x0 == np.NaN):
        warnings.warn("Nans")

    return


# -*- coding: utf-8 -*-
"""
Created on Thu Aug 19 21:06:25 2021
AI Nano degree Vector Lab
Adding two vectors in 2D
@author: Loulou
"""
# import NumPy and Matplotlib
import numpy as np
import matplotlib.pyplot as plt

# Define vectors
firstVector = np.array([1,1])
secondVector = np.array([-2,2])

# Add the above two vectors
sumVecors = firstVector + secondVector

# Plot vector v as blue arrow with red dot at origin(0,0) using Matplotlib
ax = plt.axes()

# plot red dot at origin(0,0)
ax.plot(0,0,'or')

# plot first vector as blue arrow starting at origin 0,0
ax.arrow(0,0, *firstVector, color='blue', linewidth=2.5,
         head_width=0.30, head_length=0.35)

# plot the second vector of cyan color
ax.arrow(0,0, *secondVector, color='cyan', linewidth=2.5,
         head_width=0.30, head_length=0.35)

# plot the second vector as dotted vector parallel to the original vector
ax.arrow(1,1, *secondVector, color='cyan', linewidth=2.5,
         linestyle='dotted', head_width=0.30, head_length=0.35)

# plot the vector sum as dotted vector of red color
ax.arrow(0,0, *sumVecors, color='red', linewidth=2.5,
         head_width=0.30, head_length=0.35)

# format X-axis
# Set limits for plot for X-axis
ax.set_xlim(-3,3)

# set major ticks for x-axis
major_xticks = np.arange(-3,3)
ax.set_xticks(major_xticks)

# Set limits for plot for Y-axis
ax.set_ylim(-1,5)

# set major ticks for y-axis
major_yticks = np.arange(-1,5)
ax.set_yticks(major_yticks)

# create gridlines for only major tick marks
plt.grid(b=True, which='major')

# Display final plot
plt.show()


#!/usr/bin/env python
# coding: utf-8

# ## Questionário 41 (Q41)

# Orientações:
#
# - Registre suas respostas no questionário de mesmo nome no SIGAA.
# - O tempo de registro das respostas no questionário será de 10 minutos. Portanto, resolva primeiro as questões e depois registre-as.
# - Haverá apenas 1 (uma) tentativa de resposta.
# - Submeta seu arquivo-fonte (utilizado para resolver as questões) em formato _.ipynb_ pelo SIGAA anexando-o à Tarefa denominada "Envio de arquivo" correspondente ao questionário.
#
# *Nota:* o arquivo-fonte será utilizado apenas como prova de execução da tarefa. Nenhuma avaliação será feita quanto ao estilo de programação.
#
#

# **Questão 1.** No _dataset_ [enem2019.xlsx](https://github.com/gcpeixoto/ICD/blob/main/database/enem2019.xlsx), estão disponíveis as notas médias por estado obtidas nas provas do ENEM 2019. A partir da série que contém a média das notas da prova de Ciências Humanas, converta os valores para inteiro, faça uma distribuição de frequências e calcule a amplitude _h_ dos intervalos de classe, se divididos uniformemente. Marque a alternativa que corresponde ao valor correto de _h_ e à classe cuja frequência é 3.
#
# A. _h_ = 8 e [499,509)
#
# B. _h_ = 10 e [499,509)
#
# C. _h_ = 9 e [509,519)
#
# D. _h_ = 10 e [509,519)

#

#
# ## Gabarito
#
# Alternativa **B**

# In[2]:

import pandas as pd
import numpy as np

# In[4]:

df = pd.read_excel("../database/enem2019.xlsx")
df = df.set_index("Estado")
df.head()

# In[27]:

# Coluna a ser avaliada
dados = df['Média da nota da prova de Ciências Humanas'].apply(lambda x: int(x))
dados.sort_values().head()

# In[14]:

# binning usando np.ceil
def binning(d,rule='standard'):

    if isinstance(d,list): d = np.array(d)
    n = len(d)

    if rule == 'standard':
        if n <= 25: K = 5
        else: K = int(np.ceil(np.sqrt(n)))

    if rule == 'sturges':
        K = int(np.ceil(1 + 3.22*np.log10(n)))

    return K

# In[15]:

K1,K2 = binning(dados,rule='standard'), binning(dados,rule='sturges');
K1,K2

# In[16]:

R = np.max(dados) - np.min(dados)
h = np.ceil(R/K1);R,h

# In[17]:

bin_ = [np.min(dados) + i*h.astype('int') for i in range(K1+1)];bin_

# In[21]:

f_r = pd.cut(dados, bins=bin_, right=False)
f = f_r.value_counts()

for a in f.items():
    if a[1] == 3:
        interval = (a[0])

f'Resposta esperada: h = {h} // {interval}'

#

#
# **Questão 2.** Considerando a série que contém a média das notas da prova de Matemática apenas para os estados nordestinos, assinale a alternativa que corresponde ao valor médio aproximado dessas médias, a mediana e a moda, se houver.
#
# A. 504.27, 502.84, unimodal
#
# B. 505.27, 502.84, 9
#
# C. 504.27, 502.84, amodal
#
# D. 504.27, 503.84, 8

#

#
# ## Gabarito
#
# **Alternativa C**

# In[76]:

nordeste = ["AL","BA","CE","MA","PB","PE","PI","RN","SE"]

dados2 = df.loc[nordeste,'Média da nota da prova de Matemática']
dados2 = dados2.sort_values()

if len(dados2.mode()) > 1:
    Mo = 'amodal'
else:
    Mo = np.round(dados2.mode(),2)

f'Resposta esperada: {np.round(dados2.mean(),2)}, {np.round(dados2.median(),2)}, {Mo}'

#

#
# **Questão 3.** Levando em conta a série que contém as médias das notas da prova de Redação apenas para os estados nordestinos, assinale a alternativa correta quanto ao quartil em que o estado da Paraíba se encontrou nesta prova.
#
# A. 4-quartil
#
# B. 3-quartil
#
# C. 2-quartil
#
# D. 1-quartil
#

#

#
# ## Gabarito
# Alternativa **B**

# In[86]:

def quartil(a):
    for a in dados3.quantile([0.0,0.25,0.50,0.75,1]).items():
        if a[1] == dados3.PB:

            if a[0] <= 0.25:
                print("Está no primeiro quartil")

            elif a[0] <= 0.50:
                print("Está no segundo quartil")

            elif a[0] <= 0.75:
                print("Está no terceiro quartil")

            else:
                print("Está no quarto quartil")

# In[87]:

dados3 = df.loc[nordeste,'Média da nota da prova de redação']
dados3 = dados3.sort_values()
quartil(dados3)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: ashutosh

This is a simple program to compute factorial of a given number

"""
import numpy

# This is a recursive function

def factorial(num):
    """
    This function calculates factorial of a number recursively.

    n! = n*(n-1)*(n-2)*...*2*1

    Parameters
    ----------
    num : uint64
        Input positive integer to calcuate factorial.

    Returns
    -------
    uint64
        Factorial of input positive integer.

    """

    if num == 1:
        return num
    else:
        return num * factorial(num - 1)

def main():
    """
    The main function to execute upon call.

    Returns
    -------
    int
        returns integer 0 for safe executions.

    """

    print("Program to calculate factorial of an input positive number")

    num = numpy.uint64(input("Enter a number: "))

    if num < 0:
        print("Factorial cannot be found for negative numbers")
    elif num == 0:
        print("Factorial of 0 is 1")
    else:
        print("Factorial of", num, "is", factorial(num))

    return 0

if __name__ == "__main__":
    main()


"""
Functions for simulating data from a log-linear model.

"""
import numpy as np

def shuffle_same(X, y):
    """Shuffle a data matrix and a label matrix in the same order."""
    assert X.shape[1] == y.shape[0]
    p = np.random.permutation(X.shape[1])
    return X[:, p], y[p]

def simulate_ll(n, p, uncorr_frac, duplicate_features=0, seed=1, verbose=False):
    """Simulate data from a log-linear model.

    See, for instance: https://stats.stackexchange.com/a/46525

    Labels are generated from a subset of the features (thus some of
    the features are uncorrelated with the label).

    Parameters
    ----------
    n: int
        number of samples

    p: int
        number of features

    uncorr_frac: float
        Fraction of features to be uncorrelated with outcome (between 0 and 1)

    duplicate_features: int
        Number of features to add that are duplicates of other features

    seed: int
        Seed for random number generator

    verbose: bool
        Whether to print verbose output or not

    Returns
    -------
    X: array_like, (n, p)
        Simulated features/samples

    y: array_like, (n, 1)
        Simulated labels in {0, 1}

    pis: array_like, (n, 1)
        Bernoulli parameters used to generate labels

    is_correlated: array_like, (p, 1)
        Whether or not each feature is correlated with the label

    """
    np.random.seed(seed)

    p_uncorr = int(uncorr_frac * p)
    p_corr = p - p_uncorr

    if verbose:
        print('Number of informative features: {}'.format(p_corr))
        print('Number of uninformative features: {}'.format(p_uncorr))

    # start by drawing features independently from N(0, 1)
    # TODO: could add an option for discrete data/counts in the future?
    X_corr = np.random.randn(n, p_corr)
    X_uncorr = np.random.randn(n, p_uncorr)
    X = np.concatenate((X_corr, X_uncorr), axis=1)

    if duplicate_features > 0:
        # sample duplicate_features columns with replacement
        # and add to end of current data matrix (will be shuffled later)
        dup_cols = np.concatenate((range(X.shape[1]),
                                   np.random.randint(0, X.shape[1], (duplicate_features,))))
        X = X[:, dup_cols]

    is_correlated = np.zeros(X.shape[1]).astype('bool')
    is_correlated[:p_corr] = True

    # shuffle data and is_correlated indicators in same order, so we know
    # which features are correlated/not correlated with outcome
    X, is_correlated = shuffle_same(X, is_correlated)

    # draw regression coefficients (betas) from N(0, 1)
    B = np.random.randn(p_corr+1)

    # calculate Bernoulli parameter pi(x_i) for each sample x_i
    linsum = B[0] + (X_corr @ B[1:, np.newaxis])
    pis = 1 / (1 + np.exp(-linsum))

    y = np.random.binomial(1, pis.flatten())

    return (X, y, pis, is_correlated)

def split_train_test(n, train_frac, seed=1, verbose=False):
    """Split n samples into train and test indices.

    Gives floor(n * train_frac) indices for training samples (the rest should
    be used for testing).
    """
    np.random.seed(seed)

    n_train = int(train_frac * n)
    n_test = n - n_train

    if verbose:
        print('Train samples: {}, test samples: {}'.format(n_train, n_test))

    train_ixs = np.zeros(n).astype('bool')
    train_ixs[:n_train] = True
    np.random.shuffle(train_ixs)

    return train_ixs


"""Kernel herding.

Implementation of the kernel herding algorithm of
  Yutian Chen, Max Welling, and Alex Smola.
  Super-Samples from Kernel Herding.
  https://arxiv.org/pdf/1203.3472.pdf
"""

import numpy as np

def herding(X, m, kernel, unique=False):
    """
    Returns herding coreset of size n/2^m as row indices into X

    Args:
      X: Input sequence of sample points with shape (n, d)
      m: Thinning factor; output size is n/2^m
      kernel: Kernel function; kernel(y,X) returns array of kernel evaluations
        between y and each row of X
      unique: If True, constrains herding updates to never select the same
        row index more than once
    """
    n = X.shape[0]
    coreset_size = int(n/2**m)
    # print(X.shape, n, m, coreset_size)

    # Allocate memory for the coreset; important to assign dtype
    coreset = np.empty(coreset_size, dtype=int)

    # Initialize meanK vector with meanK[ii] = PnK(X[ii]) where Pn denotes
    # distibution of X
    meanK = np.empty(n)
    for ii in range(n):
        meanK[ii] = np.mean(kernel(X[ii, np.newaxis], X))

    # Our objective = PnK(x) - QK(x) where x denotes a candidate point in X,
    # and Q denotes the coreset; and we are maximizing objective
    # since Q is initialized to 0, starting objective is simply meanK
    objective = meanK.copy()

    # At each step we add x_t = argmax_{x in X} PnK(x) - Q k(x) to Q, i.e.,
    # and update Q to (t+1) / (t+2) * Q   + 1 / (t+2) * dirac_{x_t}
    # where we use t+1 because of Python indexing
    for t in range(coreset_size):
        # Add argmax of the objective to coreset
        coreset[t] =  np.argmax(objective)
        # x_{t} := X[coreset[t]]

        # We can write next step objective as
        # = PnK - Qnew K = PnK - (t+1) / (t+2) * Qk   + 1 / (t+2) * K(x_t, .)
        # = (t+1) / (t+2) * (PnK - Qk)    + 1 / (t+2) * ( PnK -  K(x_t, .) )
        # = (t+1) / (t+2) * objective + 1 / (t+2) * ( meanK - K(x_t, X) )
        # since we always consider points only in X
        objective = objective * (t+1) / (t+2) + (meanK - kernel( X[coreset[t], np.newaxis], X)) / (t+2)

        if unique:
            # If requested, ensure the same row index is not selected again
            objective[coreset[t]] = -np.inf
    return(coreset)


import numpy as np
from scipy.linalg import lu, inv
import scipy.linalg
import numpy
import time

def gausselim(A,B):

    pl, u = lu(A, permute_l=True)

    y = np.zeros(B.size)
    for m, b in enumerate(B.flatten()):
        y[m] = b
        if m:
            for n in xrange(m):
                y[m] -= y[n] * pl[m,n]
        y[m] /= pl[m, m]

    x = np.zeros(B.size)
    lastidx = B.size - 1  # last index
    for midx in xrange(B.size):
        m = B.size - 1 - midx  # backwards index
        x[m] = y[m]
        if midx:
            for nidx in xrange(midx):
                n = B.size - 1  - nidx
                x[m] -= x[n] * u[m,n]
        x[m] /= u[m, m]
    return x

if __name__ == '__main__':
    A = np.array([[1.,1+0.5e-15,3.],
                  [2.,2.,20.],
                  [3.,6.,4.],
                  ])
    b = np.array([1,6,13])
    x = gausselim(A, b)
    print x

    print '\n\nresidual', scipy.linalg.norm(numpy.dot(A, x) - b)/scipy.linalg.norm(A)
    tic = time.clock()
    toc = time.clock()
    print "Processing time is : %f" %(toc - tic)


import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate

def interpolated_intersection(x_1, y_1, x_2, y_2, acc=1000, spline='linear'):
	x_1_dx_avg = (np.amax(x_1) - np.amin(x_1)) / len(x_1)
	x_2_dx_avg = (np.amax(x_2) - np.amin(x_2)) / len(x_2)
	dx = np.amin((x_1_dx_avg, x_2_dx_avg))
	# interpolation resolution
	# minimal step size of input arrays is reduced
	step = dx / 2
	# concatenated arrays to determine new range min and max
	x_intersect_min = np.amax((np.amin(x_1), np.amin(x_2)))
	x_intersect_max = np.amin((np.amax(x_1), np.amax(x_2)))
	# domain for interpolation with resolution 'step'
	x_ip = np.arange(x_intersect_min, x_intersect_max, step)

	# create interpolation functions with given arrays
	f = interpolate.interp1d(x_1, y_1, kind=spline)
	g = interpolate.interp1d(x_2, y_2, kind=spline)

	#interpolation function on new interpolation domain with resoltion res
	f_ip = f(x_ip)
	g_ip = g(x_ip)

	# indices (or domain values) of the intersection points
	idx = np.argwhere(np.diff(np.sign(f_ip - g_ip))).flatten()

	# increased precision for localisation of intersection
	# new interpolation in vicinity of intersection points with accuracy 'acc'
	res_res = acc
	p = np.array([])
	q = np.array([])
	for i in idx:
		k = interpolate.interp1d([x_ip[i], x_ip[i+1]], [f_ip[i], f_ip[i+1]])
		l = interpolate.interp1d([x_ip[i], x_ip[i+1]], [g_ip[i], g_ip[i+1]])

		z_ip = np.linspace(x_ip[i], x_ip[i+1], res_res)

		k_ip = k(z_ip)
		l_ip = l(z_ip)

		idx_idx = np.argwhere(np.diff(np.sign(k_ip - l_ip))).flatten()

		p = np.append(p, [z_ip[idx_idx]])
		# k_ip and l_ip return the same solution as it is the intersection value
		q = np.append(q, [k_ip[idx_idx]])

	return np.concatenate((p, q))

# demonstration and testing

# two intersecting functions with different domain step sizes and domain limits
x_f = np.linspace(0, 12, 500)
f = np.sin(x_f)

x_g = np.linspace(2, 15, 900)
g = np.cos(x_g)

# applying defined function for intersection points and storing in (x, y)
x, y = np.split(interpolated_intersection(x_f, f, x_g, g), 2)

# plot functions
plt.plot(x_f, f)
plt.plot(x_g, g)

# plot intersection points
plt.plot(x, y, 'ro')

plt.show()


from math import pi
import numpy as np
from scipy import optimize
import matplotlib.pyplot as plt

#############
# 1. budget #
#############

def budgetset(ax,p1,p2,I,**kwargs):

    x = [0,0,I/p1]
    y = [0,I/p2,0]

    ax.fill(x,y,color="firebrick",lw=2,alpha=0.5,**kwargs)

def budgetline(ax,p1,p2,I,**kwargs):

    if 'color' not in kwargs:
        kwargs['color'] = 'black'
    if 'lw' not in kwargs:
        kwargs['lw'] = 2

    x = [0,I/p1]
    y = [I/p2,0]

    ax.plot(x,y,**kwargs)

def budgetline_slope(ax,p1,p2,I,scalex=1.03,scaley=1.03,**kwargs):

    x = (I/p1)/2*scalex
    y = (I/p2)/2*scaley

    ax.text(x,y,f'slope = -{p1/p2:3.2f}',**kwargs)

def endowment(ax,e1,e2,scalex=1.03,scaley=1.03,**kwargs):

    ax.scatter(e1,e2,color='black',**kwargs)
    ax.text(e1*scalex,e2*scaley,'endowment')

def budgetline_with_kink(ax,p1_A,p1_B,p2,I,xbar,**kwargs):

    x = [0,xbar,xbar+(I-p1_A*xbar)/p1_B]
    y = [I/p2,(I-p1_A*xbar)/p2,0]

    ax.plot(x,y,color='black',lw=2,**kwargs)

def budgetset_with_kink(ax,p1_A,p1_B,p2,I,xbar,**kwargs):

    x = [0,0,xbar,xbar+(I-p1_A*xbar)/p1_B]
    y = [0,I/p2,(I-p1_A*xbar)/p2,0]

    ax.fill(x,y,color="firebrick",lw=2,alpha=0.5,**kwargs)

##############
# 2. utility #
##############

def utility_functions(par,uname,v=None):

    par.uname = uname
    par.g_inv = None
    if par.uname == 'cobb_douglas':
        par.u = lambda x1,x2,alpha,beta: x1**alpha*x2**beta
        par.g = lambda u,x1,alpha,beta: (u/x1**alpha)**(1/beta)
    elif par.uname == 'ces':
        def u(x1,x2,alpha,beta):
            if beta == 0:
                return  x1**alpha*x2**(1-alpha)
            else:
                return (alpha*x1**(-beta)+(1-alpha)*x2**(-beta))**(-1.0/beta)
        par.u = u
        def g(u,x1,alpha,beta):
            if beta == 0:
                return (u/x1**alpha)**(1/(1-alpha))
            else:
                return ((u**(-beta)-alpha*x1**(-beta))/(1-alpha))**(-1.0/beta)
        par.g = g
        def g_inv(u,x2,alpha,beta):
            if beta == 0:
                return (u/x2**alpha)**(1/(1-alpha))
            else:
                return ((u**(-beta)-(1-alpha)*x2**(-beta))/alpha)**(-1.0/beta)
        par.g_inv = g_inv
    elif par.uname == 'perfect_substitutes':
        par.u = lambda x1,x2,alpha,beta: par.alpha*x1+par.beta*x2
        par.g = lambda u,x1,alpha,beta: (u-par.alpha*x1)/par.beta
    elif par.uname == 'leontief':
        par.u = lambda x1,x2,alpha,beta: np.fmin(par.alpha*x1,par.beta*x2)
        par.g = ''
    elif par.uname ==  'quasi_linear':
        assert callable(v), 'v is not callable'
        par.u = lambda x1,x2,alpha,beta: alpha*v(x1)+beta*x2
        par.g = lambda u,x1,alpha,beta: (u-alpha*v(x1))/beta
    elif par.uname == 'concave':
        par.u = lambda x1,x2,alpha,beta: alpha*x1**2+beta*x2**2
        par.g = lambda u,x1,alpha,beta: np.sqrt((u-alpha*x1**2)/beta)
        par.g_inv = lambda u,x2,alpha,beta: np.sqrt((u-beta*x2**2)/alpha)
    elif par.uname == 'quasi_quasi_linear':
        par.u = lambda x1,x2,alpha,beta: x1**alpha*(x2+beta)
        par.g = lambda u,x1,alpha,beta: (u/x1**alpha-beta)
    elif par.uname == 'saturated':
        par.u = lambda x1,x2,alpha,beta: -(x1-alpha)**2-(x2-beta)**2
        par.g = 'saturated'
    else:
        raise ValueError('unknown utility function')

def find_indifference_curve(u,par):

    if callable(par.g_inv):

        # given x1
        x1_x1 = np.linspace(0,par.x1_max,par.N)
        with np.errstate(divide='ignore',invalid='ignore'):
            x2_x1 = par.g(u,x1_x1,par.alpha,par.beta)

        # given x2
        x2_x2 = np.linspace(0,par.x2_max,par.N)
        with np.errstate(divide='ignore',invalid='ignore'):
            x1_x2 = par.g_inv(u,x2_x2,par.alpha,par.beta)

        x1 = np.hstack([x1_x1,x1_x2])
        x2 = np.hstack([x2_x1,x2_x2])
        I = np.argsort(x1)
        x1 = x1[I]
        x2 = x2[I]

    elif callable(par.g):

        x1 = np.linspace(0,par.x1_max,par.N)
        with np.errstate(divide='ignore',invalid='ignore'):
            x2 = par.g(u,x1,par.alpha,par.beta)

    else: # arbitrary utility function

        x1 = []
        x2 = []

        x1_vec = np.linspace(par.eps,par.x1_max,par.N)
        for x1_now in x1_vec:

            def target_for_x2(x2):
                return par.u(x1_now,np.fmax(x2,par.eps),par.alpha,par.beta)-u

            x_A,_infodict_A,ier_A,_mesg_A = optimize.fsolve(target_for_x2, 0, full_output=True)
            x_B,_infodict_B,ier_B,_mesg_B = optimize.fsolve(target_for_x2, par.x2_max, full_output=True)

            if ier_A == 1:
                x1.append(x1_now)
                x2.append(x_A[0])
            else:
                x1.append(np.nan)
                x2.append(np.nan)

            if ier_B == 1 and np.abs(x_A[0]-x_B[0]) > 0.01:
                x1.append(x1_now)
                x2.append(x_B[0])
            else:
                x1.append(np.nan)
                x2.append(np.nan)

        # e. fixed x2
        x2_vec = np.linspace(par.eps,par.x2_max,par.N)
        for x2_now in x2_vec:

            def target_for_x1(x1):
                return par.u(np.fmax(x1,par.eps),x2_now,par.alpha,par.beta)-u

            x_A,_infodict_A,ier_A,_mesg_A = optimize.fsolve(target_for_x1, 0, full_output=True)
            x_B,_infodict_B,ier_B,_mesg_B = optimize.fsolve(target_for_x1, par.x1_max, full_output=True)

            if ier_A == 1:
                x1.append(x_A[0])
                x2.append(x2_now)
            else:
                x1.append(np.nan)
                x2.append(np.nan)

            if ier_B == 1 and np.abs(x_A[0]-x_B[0]) > 0.01:
                x1.append(x_B[0])
                x2.append(x2_now)
            else:
                x1.append(np.nan)
                x2.append(np.nan)

        # f. sort
        x1 = np.array(x1)
        x2 = np.array(x2)
        I = np.argsort(x1)
        x1 = x1[I]
        x2 = x2[I]

    # clean
    with np.errstate(divide='ignore',invalid='ignore'):
        u_curve = par.u(x1,x2,par.alpha,par.beta)
        I = (u-u_curve)**2 > 1e-4
    x2[I] = np.nan

    return x1,x2

def indifference_curve(ax,u,par,inv=False,**kwargs):

    if 'color' not in kwargs:
        kwargs['color'] = 'navy'
    if 'lw' not in kwargs:
        kwargs['lw'] = 2

    if par.uname == 'leontief':

        corner_x1 = u/par.alpha
        x1 = [corner_x1,corner_x1,par.x1_max]

        corner_x2 = u/par.beta
        x2 = [par.x2_max,corner_x2,corner_x2]

        if inv:
            ax.plot(1-np.array(x1),1-np.array(x2),**kwargs)
        else:
            ax.plot(x1,x2,**kwargs)

    elif par.uname == 'saturated':

        radius = np.sqrt(-u)
        if inv:
            circle = plt.Circle((1-par.alpha,1-par.beta),radius,fill=False,**kwargs)
        else:
            circle = plt.Circle((par.alpha,par.beta),radius,fill=False,**kwargs)
        ax.add_artist(circle)

    else:

        x1,x2 = find_indifference_curve(u,par)

        if inv:
            ax.plot(1-x1,1-x2,**kwargs)
        else:
            ax.plot(x1,x2,**kwargs)

def monotonicity(ax,par,x1,x2,text='north-east'):

    polygon = plt.Polygon([[x1, x2],[par.x1_max, x2],[par.x1_max, par.x2_max],[x1, par.x2_max],[x1, x2]],
        color='black',alpha=0.10)
    ax.add_patch(polygon)
    ax.text(x1*1.05,0.95*par.x2_max,text)

def convex_combination(ax,par,x1,x2,u,text='mix'):

    diff = 5

    if par.uname == 'leontief':

        x1 = u/par.alpha
        x2 = u/par.beta

        x1_low = x1
        x2_low = x2 + diff

        x1_high = x1 + diff
        x2_high = x2

    elif par.uname == 'saturated':

        diff_circle = 35

        radius = np.sqrt(-u)

        low = 45 + diff_circle
        x1_low = par.alpha - radius*np.cos(low/180*pi)
        x2_low = par.beta - radius*np.sin(low/180*pi)

        high = 45 - diff_circle
        x1_high = par.alpha - radius*np.cos(high/180*pi)
        x2_high = par.beta - radius*np.sin(high/180*pi)

    else:

        x1, x2 = find_indifference_curve(u,par)

        I = (np.isnan(x1) == False) & (np.isnan(x2) == False)
        J = (x1[I] > 0) & (x2[I] > 0) & (x1[I] < par.x1_max) & (x2[I] < par.x2_max)

        x1 = x1[I][J]
        x2 = x2[I][J]
        N = x1.size
        i_low = np.int(N/3)
        i_high = np.int(N*2/3)

        x1_low = x1[i_low]
        x2_low = x2[i_low]

        x1_high = x1[i_high]
        x2_high = x2[i_high]

    ax.plot([x1_low,x1_high],[x2_low,x2_high],ls='--',marker='o',markerfacecolor='none',color='black')

    x1 = 0.05*x1_low + 0.95*x1_high
    x2 = 0.05*x2_low + 0.95*x2_high
    ax.text(x1,x2*1.05,text)

###################
# 3. optimization #
###################

def maximization(par):

    if par.monotone:

        # a. target
        def x2_func(x1):
            return (par.I - par.p1*x1)/par.p2
        def target(x1):
            x2 = x2_func(x1)
            return -par.u(x1,x2,par.alpha,par.beta)

        # b. solve
        xopt = optimize.fminbound(target, 0, par.I/par.p1)

        # c. save
        x1 = xopt
        x2 = x2_func(x1)

    else:

        # a. target
        def target_2d(x):
            excess_spending = par.p1*x[0]+par.p2*x[1]-par.I
            return -par.u(x[0],x[1],par.alpha,par.beta) + 1000*np.max([excess_spending,-x[0],-x[1],0])

        # b. solve
        x0 = np.array([par.I/par.p1,par.I/par.p2])/2
        res = optimize.minimize(target_2d,x0,method='Nelder-Mead')

        # c. save
        x1 = res.x[0]
        x2 = res.x[1]

    u = par.u(x1,x2,par.alpha,par.beta)
    return x1,x2,u

def costminimization(par,u):

    # a. target
    def target_2d(x):
        x1 = x[0]
        x2 = x[1]
        udiff = (par.u(x1,x2,par.alpha,par.beta)-u)**2

        return par.p1*x1+par.p2*x2 + 1000*udiff + 1000*np.max([-x[0],-x[1],0])

    # b. solve
    x0 = np.array([par.I/par.p1,par.I/par.p2])/2
    res = optimize.minimize(target_2d,x0,method='Nelder-Mead')

    # c. save
    x1 = res.x[0]
    x2 = res.x[1]

    return x1,x2


"""
@Author: tushushu
@Date: 2019-01-04 15:35:11
@Last Modified by: tushushu
@Last Modified time: 2019-05-03 09:13:34
"""
import heapq

from numpy import ndarray
from numpy.linalg import eig

class PCA:
    """Principal component analysis (PCA)

    Arguments:
        n_components {int} -- Number of components to keep.
        eigen_vectors {ndarray} -- The eigen vectors according to
        top n_components large eigen values.
    """

    def __init__(self):
        self.n_components = None
        self.eigen_vectors = None
        self.avg = None

    @staticmethod
    def _normalize(data: ndarray):
        """Normalize the data by mean subtraction.

        Arguments:
            data {ndarray} -- Training data.

        Returns:
            ndarray -- Normalized data with shape(n_rows, n_cols)
            ndarray -- Mean of data with shape(1, n_cols)
        """

        avg = data.mean(axis=0)
        return data - avg, avg

    @staticmethod
    def _get_covariance(data: ndarray) -> ndarray:
        """Calculate the covariance matrix of data.

        Arguments:
            data {ndarray} -- Training data.

        Returns:
            ndarray -- covariance matrix with shape(n_cols, n_cols)
        """

        n_rows = data.shape[0]
        return data.T.dot(data) / (n_rows - 1)

    @staticmethod
    def _get_top_eigen_vectors(data: ndarray, n_components: int) -> ndarray:
        """The eigen vectors according to top n_components large eigen values.

        Arguments:
            data {ndarray} -- Training data.
            n_components {int} -- Number of components to keep.

        Returns:
            ndarray -- eigen vectors with shape(n_cols, n_components).
        """

        # Calculate eigen values and eigen vectors of covariance matrix.
        eigen_values, eigen_vectors = eig(data)
        # The indexes of top n_components large eigen values.
        _indexes = heapq.nlargest(n_components, enumerate(eigen_values),
                                  key=lambda x: x[1])
        indexes = [x[0] for x in _indexes]
        return eigen_vectors[:, indexes]

    def fit(self, data: ndarray, n_components: int):
        """Fit the model with data.

        Arguments:
            data {ndarray} -- Training data.
            n_components {int} -- Number of components to keep.
        """

        data_norm, self.avg = self._normalize(data)
        data_cov = self._get_covariance(data_norm)
        self.n_components = n_components
        self.eigen_vectors = self._get_top_eigen_vectors(
            data_cov, n_components)

    def transform(self, data: ndarray) -> ndarray:
        """Apply the dimensionality reduction on X.

        Arguments:
            data {ndarray} -- Training data.

        Returns:
            ndarray -- with shape(n_cols, n_components).
        """

        return (data - self.avg).dot(self.eigen_vectors)

    def fit_trasform(self, data: ndarray, n_components: int) -> ndarray:
        """Fit the model with data and apply the dimensionality reduction on data.

        Arguments:
            data {ndarray} -- Training data.
            n_components {int} -- Number of components to keep.

        Returns:
            ndarray -- with shape(n_cols, n_components).
        """

        self.fit(data, n_components)
        return self.transform(data)


# _*_coding:utf-8_*_
"""
@author:
@license: (C) Copyright 2020-,
@file: criterion_functions.py
@date: 10/12/2020 8:27 pm
@IDE:
@desc:
"""
import math
from abc import ABCMeta, abstractmethod

import numpy as np

# =============================================================================
# Functions for Classification
# =============================================================================

# # For non-fuzzy decision trees
# def calculate_entropy(y):
#     """
#     Calculate the entropy of y.
#     """
#     entropy = 0
#
#     log2 = lambda x: math.log(x) / math.log(2)
#
#     unique_labels = np.unique(y)
#     for label in unique_labels:
#         count = len(y[y == label])
#         p = count / len(y)
#         entropy += -p * log2(p)
#
#     return entropy
#
#
# # For non-fuzzy decision trees
# def calculate_gini_index(y):
#     """
#     Calculate the Gini index of y.
#     """
#     diffsum = 0
#     for i, yi in enumerate(y[:-1], 1):
#         diffsum += np.sum(np.abs(yi - y[i:]))
#     return diffsum / (len(y) ** 2 * np.mean(y))
#
#
# # For non-fuzzy decision trees
# def calculate_gini(y):
#     """
#     Calculate the Gini impurity of y.
#     """
#     # Implementation based on the 1st Formula:
#     # diff = 0
#     # unique_labels = np.unique(y)
#     # for label in unique_labels:
#     #     count = len(y[y == label])
#     #     p = count / len(y)
#     #     diff += p * p
#     #
#     # return 1 - diff
#
#     # Implementation based on the 2nd Formula:
#     gini = 0
#     unique_labels = np.unique(y)
#     for label in unique_labels:
#         count = len(y[y == label])
#         p = count / len(y)
#         gini += p * (1 - p)
#
#     return gini

# For fuzzy decision trees
def calculate_entropy(y, dm=None):
    """
    Calculate the entropy of y.
    """
    entropy = 0

    log2 = lambda x: math.log(x) / math.log(2)

    unique_labels = np.unique(y)
    for label in unique_labels:
        if dm is not None:
            # print("****####  ", dm.shape)
            # print("****####  ", dm[np.where(y == label)[0], :].shape)
            sum_sub_dm = np.sum(dm[np.where(y == label)[0], :])
            p = sum_sub_dm / np.sum(dm)
            entropy += -p * log2(p)
        else:
            count = len(y[y == label])
            p = count / len(y)
            entropy += -p * log2(p)

    return entropy

# For fuzzy decision trees
def calculate_gini(y, dm=None):
    """
    Calculate the Gini impurity of y.
    """
    # Implementation based on the 1st Formula:
    # diff = 0
    # unique_labels = np.unique(y)
    # for label in unique_labels:
    #     count = len(y[y == label])
    #     p = count / len(y)
    #     diff += p * p
    #
    # return 1 - diff

    # Implementation based on the 2nd Formula:
    gini = 0
    unique_labels = np.unique(y)
    for label in unique_labels:
        if dm is not None:
            # print("****####  ", dm.shape)
            # print("****####  ", dm[np.where(y == label)[0], :].shape)
            sum_sub_dm = np.sum(dm[np.where(y == label)[0], :])
            p = sum_sub_dm / np.sum(dm)
            gini += p * (1 - p)
        else:
            count = len(y[y == label])
            p = count / len(y)
            gini += p * (1 - p)

    return gini

def calculate_impurity_gain(y, sub_y_1, sub_y_2, criterion_func, p_subset_true_dm=None, p_subset_false_dm=None):
    """
    Calculate the impurity gain, which is equal to the
    impurity of y minus the entropy of sub_y_1 and sub_y_2.
    """
    impurity = criterion_func(y)

    if p_subset_true_dm is not None and p_subset_false_dm is not None:
        information_gain = impurity - (p_subset_true_dm * criterion_func(sub_y_1[:, -1], sub_y_1[:, :-1])) - (p_subset_false_dm * criterion_func(sub_y_2[:, -1], sub_y_2[:, :-1]))
    else:
        p_1 = len(sub_y_1) / len(y)
        p_2 = len(sub_y_2) / len(y)
        information_gain = impurity - (p_1 * criterion_func(sub_y_1)) - (p_2 * criterion_func(sub_y_2))

    return information_gain

def calculate_impurity_gain_ratio(y, sub_y_1, sub_y_2, X_sub, criterion_func, p_subset_true_dm=None, p_subset_false_dm=None):
    """
    Calculate the impurity gain ratio.
    """
    information_gain = calculate_impurity_gain(y=y, sub_y_1=sub_y_1, sub_y_2=sub_y_2, criterion_func=criterion_func, p_subset_true_dm=p_subset_true_dm, p_subset_false_dm=p_subset_false_dm)
    intrinsic_value = criterion_func(X_sub)
    information_gain_ratio = information_gain / intrinsic_value

    return information_gain_ratio

def calculate_value_by_majority_vote(y):
    """
    Calculate value by majority vote.

    NB: Used in classification decision tree.
    """
    majority_value = None

    max_count = 0
    unique_labels = np.unique(y)
    for label in unique_labels:
        count = len(y[y == label])
        if count > max_count:
            majority_value = label
            max_count = count

    return majority_value

# =============================================================================
# Functions for Regression
# =============================================================================

def calculate_mse(y_true, y_pred):
    """
    Calculate the Mean Squared Error between y_true and y_pred.
    """
    mse = np.mean(np.power(y_true - y_pred, 2))
    return mse

def calculate_mae(y_true, y_pred):
    """
    Calculate the Mean Absolute Error between y_true and y_pred.
    """
    mae = np.mean(abs(y_true - y_pred))
    return mae

def calculate_variance(y):
    """
    Calculate the variance of y.
    """
    mean = np.ones(np.shape(y)) * y.mean(0)
    n_samples = np.shape(y)[0]
    variance = (1 / n_samples) * np.diag((y - mean).T.dot(y - mean))  # T means transposing a matrix.

    return variance

def calculate_standard_deviation(y):
    """
    Calculate the standard deviation of y.
    """
    std_dev = np.sqrt(calculate_variance(y))

    return std_dev

def calculate_variance_reduction(y, sub_y_1, sub_y_2, criterion_func, p_subset_true_dm=None, p_subset_false_dm=None):
    """
    Calculate the variance reduction, which is equal to the
    impurity of y minus the entropy of sub_y_1 and sub_y_2.
    """
    var = criterion_func(y)
    var_1 = criterion_func(np.expand_dims(sub_y_1[:, -1], axis=1))
    var_2 = criterion_func(np.expand_dims(sub_y_2[:, -1], axis=1))

    if p_subset_true_dm is not None and p_subset_false_dm is not None:
        p_1 = p_subset_true_dm
        p_2 = p_subset_false_dm
    else:
        p_1 = len(sub_y_1) / len(y)
        p_2 = len(sub_y_2) / len(y)

    # Calculate the variance reduction
    variance_reduction = var - (p_1 * var_1 + p_2 * var_2)

    return sum(variance_reduction)

def calculate_mean_value(y):
    """
    Calculate the mean of y.

    Parameters
    ----------
    y: array-like of shape (n_samples, n_labels)

    Returns
    -------
    value: array-like of the shape reduced by one dimension,
           at least a 0-d float number
        The mean values.
    """
    value = np.mean(y, axis=0)

    return value if len(value) > 1 else value[0]

# =============================================================================
# Statistical functions
# =============================================================================

def calculate_proba(y):
    """
    Calculate the probabilities of each element in the set.

    NB: Before counting, the elements will be reordered from smallest to largest.

    Parameters
    ----------
    y: array-like of shape (n_samples,)
    """
    prob_list = []

    label_values = np.unique(y)
    for label in label_values:
        prob_list.append(np.sum(y == label) / np.shape(y)[0])

    # If the number of dimensions of y is greater than 1,
    # the following method may cause a ValueError: object too deep for desired array.
    # if len(np.shape(y)) > 1:
    #     y = np.squeeze(y)
    # dist = np.bincount(y)
    # for count in dist:
    #     print(count / np.shape(y)[0])

    return prob_list

# =============================================================================
# Loss functions
# =============================================================================

class LossFunction(metaclass=ABCMeta):
    """
    Base loss function class that encapsulates all
    base functions to be inherited by all derived
    function classes.

    Warning: This class should not be used directly.
    Use derived classes instead.
    """

    @abstractmethod
    def loss(self, y, y_pred):
        pass

    @abstractmethod
    def gradient(self, y, y_pred):
        pass

class LeastSquaresFunction(LossFunction):
    """
    Function class used in a gradient boosting regressor
    (Friedman et al., 1998; Friedman 2001).
    """

    def loss(self, y, y_pred):
        """Lost function is a Least-square equation: L(y, F) = (y - F) ^ 2 / 2"""
        return 0.5 * np.power((y - y_pred), 2)

    def gradient(self, y, y_pred):
        return -(y - y_pred)

class SoftLeastSquaresFunction(LossFunction):
    """
    Function class used in a gradient boosting classifier
    (Friedman et al., 1998; Friedman 2001).
    """

    def loss(self, y, y_pred):
        """
        Lost function (Least-square equation: L(y, F) = (y - F) ^ 2 / 2)
        is not applicable in classification.
        """
        pass

    def gradient(self, y, proba):
        return y - proba

# =============================================================================
# Functions for Bagging Ensembles
# =============================================================================

def majority_vote(y_preds):
    """
    Get the the final classification result by majority voting method.

    Parameters
    ----------
    y_preds: array-like of shape (n_samples, n_estimators)
        NB: The input array needs to be of integer dtype, otherwise a
        TypeError is raised.

    Returns
    -------
    y_pred: array-like of shape (n_samples, )
    """
    y_pred = []
    for y_p in y_preds:
        y_pred.append(np.bincount(y_p.astype("int")).argmax())
        # np.bincount(): Count number of occurrences of each value in array of non-negative ints.
        # np.argmax(): Return indices of the maximum values along the given axis.

    return y_pred

def mean_value(y_preds):
    """
    Get the final regression result by averaging method.

    Parameters
    ----------
    y_preds: array-like of shape (n_samples, n_estimators, n_labels)

    Returns
    -------
    y_pred: array-like of the shape (n_samples, n_labels) reduced by one dimension,
           at least array-like of shape (n_samples, )
    """
    y_pred = []
    for y_p in y_preds:
        y_pred.append(calculate_mean_value(y_p))

    return np.array(y_pred)

if __name__ == '__main__':
    y = [[1, 1, 2],
         [2, 2, 1],
         [2, 1, 2]]
    # y = [[[0, 1], [0, 1], [1, 0]],
    #      [[0, 1], [1, 0], [0, 1]],
    #      [[1, 0], [0, 1], [1, 0]]]
    # y = [["yes", "yes", "no"],
    #      ["yes", "no", "yes"],
    #      ["no", "yes", "no"]]
    # y = [[1], [1], [0]]
    y = np.array(y)

    # print("y's shape:", y.shape)
    # print(y)
    # print("y's mean value is:", np.mean(y, axis=0))

    if len(np.shape(y)) == 1:
        y = np.expand_dims(y, axis=1)
        print("After increasing dimensionality, y's shape:", y.shape)
    print(y)

    y = majority_vote(y)
    print("Final classification results are:\n", y)

    # # y = y.T
    # # print("After transposition, y's shape:", y.shape)
    # # print(y)
    #
    # print("Mean value of y is:", calculate_mean_value(y))
    # # print("y's mean value is:", np.mean(y, axis=0))
    # # print(len(np.mean(y, axis=0)))

    # y = [[[2], [3], [2]],
    #      [[2], [5], [4]],
    #      [[5], [5], [2]]]
    y = [[[2, 5], [3, 5], [2, 6]],
         [[2, 5], [2, 5], [2, 4]],
         [[2, 5], [4, 5], [2, 5]]]
    y = np.array(y)
    y = mean_value(y)
    print("Final regression results are:\n", y)

    # # ======================================================================================================
    # # Test the speed of my one_hot_encode() and that of sklearn in comparison.
    # import time
    #
    # y = [1, 1, 0]
    # y = np.array(y)
    # time_start = time.time()
    # from fuzzytrees.util_data_processing_funcs import one_hot_encode
    # y = one_hot_encode(y)
    # print(y)
    # print("Elapsed time: {:.5}s".format(time.time() - time_start))
    #
    # y = [1, 1, 0]
    # y = np.array(y)
    # y = np.expand_dims(y, axis=1)
    # time_start = time.time()
    # from sklearn.preprocessing import OneHotEncoder
    # transformer = OneHotEncoder(handle_unknown='ignore')
    # y = transformer.fit_transform(y).toarray()
    # print(y)
    # print("Elapsed time: {:.5}s".format(time.time() - time_start))
    # # ======================================================================================================


import numpy as np
from scipy.io import loadmat
from scipy.linalg import eig
import matplotlib.pyplot as plt

class PCA:
    def __init__(self, n_components):
        self.n_components = n_components
        self.pc_ = []
        self.__mean = 0
        # self.reconstruction_error = np.inf

    def fit(self, x, svd=True):
        x = x.astype('float64')[:, :]
        n_samples, n_feats = x.shape
        self.__mean = np.mean(x, axis=0, keepdims=True)
        x_tilde = x - self.__mean
        if not svd:
            C = np.dot(x_tilde.T, x_tilde) / (n_samples - 1)
            _, vectors = eig(C)
        else:
            u, s, v = np.linalg.svd(x_tilde.T)
            vectors = u
        self.pc_ = vectors[:, :self.n_components]
        return self

    def transform(self, x):
        x_prime = np.dot(x, self.pc_)
        return self.__mean + np.dot(self.pc_, x_prime.T).T

    def fit_transform(self, x):
        self.fit(x)
        return self.transform(x)

def load_split_data(file_name, ratio=0.7):
    mat = loadmat(file_name)['faces'].T
    l = int(ratio * mat.shape[0])
    return mat[:l], mat[l:]

def show_image(before, after, proc="train"):
    columns = 7
    rows = 10
    per_fig = columns * rows
    for i, a in zip(range(before.shape[0] // per_fig), range(after.shape[0] // per_fig)):
        fig = plt.figure(figsize=(100, 100))
        fig.suptitle("{} Images {}-{} Before PCA".format(proc, i *
                                                         per_fig + 1, (i + 1) * per_fig))
        for j in range(1, per_fig + 1):
            if i * per_fig + j - 1 >= before.shape[0]:
                break
            fig.add_subplot(rows, columns, j)
            plt.imshow(before[i * per_fig + j - 1].reshape((64, 64)).T)
        # fig.savefig("{} Images {}-{} Before PCA.png".format(proc, i *
        #                                                     per_fig + 1, (i + 1) * per_fig))
        plt.show()

        fig = plt.figure(figsize=(100, 100))
        fig.suptitle("{} Images {}-{} After PCA".format(proc, a *
                                                        per_fig + 1, (a + 1) * per_fig))
        for j in range(1, per_fig + 1):
            if a * per_fig + j - 1 >= after.shape[0]:
                break
            fig.add_subplot(rows, columns, j)
            plt.imshow(after[a * per_fig + j - 1].reshape((64, 64)).T)
        # fig.savefig("{} Images {}-{} After PCA.png".format(proc, a *
        #                                                    per_fig + 1, (a + 1) * per_fig))
        plt.show()

def __main__():
    train, test = load_split_data("faces.mat")
    n = int(input("Enter number of components:"))
    print("NUMBER OF COMPONENTS =", n)
    pca = PCA(n)
    train_imgs = pca.fit_transform(train)
    test_imgs = pca.transform(test)
    print("TRAIN IMAGES:")
    show_image(train, train_imgs)
    print("TEST IMAGES:")
    show_image(test, test_imgs)

__main__()


import numpy as np

def gramschmidt(A):
	_, k = A.shape
	Q = A[:, [0]] / np.linalg.norm(A[:, 0])
	for j in range(1, k):
		q = A[:, j] - np.dot(Q, np.dot(Q.T, A[:, j]))
		nq = np.linalg.norm(q)
		if nq < 1e-9 * np.linalg.norm(A[:, j]):
			break
		Q = np.column_stack([Q, q / nq])
	return Q
A= np.random.random((5,5))
print (A)
Q=gramschmidt(A)
print (Q*np.transpose(Q))


import numpy as np

# THIS FILE CONTAINS A SCRATCH IMPLEMENTATION FOR MOST COMMONLY USED ACTIVATION FUNCTIONS
"""
    Compute the activation(whichever activation you wants to use) of x
    Arguments:
    x -- A scalar or numpy array of any size.
    Return:
    s -- activation(x)
"""
"""
Function Used
np.exp(){visit}:- https://docs.scipy.org/doc/numpy/reference/generated/numpy.exp.html
np.tanh(){visit}:- https://docs.scipy.org/doc/numpy/reference/generated/numpy.tanh.html

"""

def sigmoid(x):
    #Normally used to find the probability i.e. used in output layer
    s = 1/(1+np.exp(-x))
    return s

def relu(x):
    # Most widely used and is used in hidden layers
    # it resticts the value to be greater than or equal to zero
    s = np.maximum(0,x)

    return s
"""
A RELU Activation can sometimes cause a neuron to die in other words,
causes a neuron to never activate again.
"""
def Leaky_RELU(x):
    #Leaky RELU activation helps in aiding the dying problem of relu,increasing the threshold for x.
    #This causes x to be significantly more than 0.
    s = max(x*0.01, x)
    return s

def Tanh(x):
    # It squashes x to the range [-1, 1]. Its output is Zero Centered.
    s = (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
    #         or
    #s = np.tanh(x)
    return s

def HardTanh(x):
    #while tanh might output a value more than 1 or less than -1.
    #HardTanh Activation forces the value to be in range[-1,1].
    if x > 1:
        x = 1
    elif x < -1:
        x = -1
    else:
        x = x
    return x

def ELU(x):
    # A good alternative to relu, cost convergence to zero is faster.
    # ELU can produce negative output
    alpha = 1.0
    s = max(0,x) + min(0, alpha *(np.exp(x) - 1))
    return s

def Softmax(x):
    #Softmax normalizes input into a probability distribution consisting of K probabilities.
    # K probabilities sums up to 1
    s = np.exp(x)/np.sum(np.exp(x))
    return s


def cells():
    '''
    # Section 3.1 RREF exercises
    '''

    '''
    '''

    from sympy import *
    init_printing()

    %matplotlib notebook
    import matplotlib.pyplot as mpl
    from util.plot_helpers import plot_augmat # helper function

    '''
    '''

    '''
    ## RREF
    '''

    '''
    '''

    '''
    ### E3.1
    '''

    '''
    '''

    AUG = Matrix([
      [3,      3, 6],
      [2, S(3)/2, 5]])
    AUG

    '''
    '''

    AUG.rref()
    # solution is x=4, y=-2

    '''
    '''

    '''
    ### Verify the solution geometrically
    '''

    '''
    '''

    AUG = Matrix([
      [3,      3,  6],
      [2, S(3)/2,  5]])

    fig = mpl.figure()
    plot_augmat(AUG)
    # the solution (4,-2) is where the two lines intersect

    '''
    '''

    '''
    ### E3.2
    '''

    '''
    '''

    A = Matrix([
             [3,       3,  6],
             [2,  S(3)/2,  5]])
    A

    '''
    '''

    # First row operation:  R1  <-- 1/3*R1
    A[0,:] = A[0,:]/3
    A

    '''
    '''

    # Second row operation:  R2  <-- R2 - 2*R1
    A[1,:] = A[1,:] - 2*A[0,:]
    A

    '''
    '''

    # Third row operation:  R2  <-- -2*R2
    A[1,:] = -2*A[1,:]
    A

    '''
    '''

    # Fourth row operation:  R1  <-- R1 - R2
    A[0,:] = A[0,:] - A[1,:]
    A

    '''
    '''

    '''
    ### E3.3
    '''

    '''
    '''

    AUGA = Matrix([
     [3, 3,  6],
     [1, 1,  5]])
    AUGA.rref()
    # no solutions since second row   0x+0y == 1  is impossible

    '''
    '''

    # verify geomtetrically
    AUGA = Matrix([
     [3, 3,  6],
     [1, 1,  5]])

    fig = mpl.figure()
    plot_augmat(AUGA)
    # no solution since lines two lines are parallel

    '''
    '''

    '''
    '''

    AUGB = Matrix([
      [3,     3,  6],
      [2, S(3)/2, 3]])
    AUGB.rref()
    # one solution x=0, y=2

    '''
    '''

    # verify geomtetrically
    AUGB = Matrix([
      [3,     3,  6],
      [2, S(3)/2, 3]])

    fig = mpl.figure()
    plot_augmat(AUGB)
    # the solution (0,2) is where the two lines intersect

    '''
    '''

    AUGC = Matrix([
      [3, 3,  6],
      [1, 1,  2]])
    AUGC.rref()
    # infinitely many soln's of the form  point + s*dir, for s in \mathbb{R}

    '''
    '''

    # to complete the solution,
    # observe the second column is a free varible y = s
    # and thus we have these equations:
    #   x +  s = 2
    #  0x + 0s = 0   (trivial eqn.)
    #        y = s   (def'n of free variable)
    # thus solution is:
    #      [x,y]  =  [2-s,s]  =  [2,0] + s*[-1,1]     for s in \mathbb{R}

    '''
    '''

    # verify geomtetrically
    AUGC = Matrix([
      [3, 3,  6],
      [1, 1,  2]])

    fig = mpl.figure()
    plot_augmat(AUGC)
    # the solution is infinite since two lines are the same

    '''
    '''

    '''
    '''

    '''
    '''

    '''
    ## Matrix equations
    '''

    '''
    '''

    '''
    '''

    '''
    '''

    '''
    '''

    '''
    '''

    '''
    ## Matrix product
    '''

    '''
    '''

    '''
    ### E3.5

    Compute the following matrix products:
    $$
    P =
    \begin{bmatrix} 	1&2 \\   3&4  \end{bmatrix}
    \begin{bmatrix} 	5&6 \\   7&8  \end{bmatrix}
    \quad
    \textrm{and}
    \quad
    Q =
    \begin{bmatrix}
    3& 1 &  2&  2 \\ 0 & 2 & -2 & 1
    \end{bmatrix}\!\!		%
    \begin{bmatrix}
        -2 &  3 \\
        \ \ 1 &  0 \\
        -2 & \!\!-2 \\
        \ \ 2 &  2
      \end{bmatrix}\!.
    $$
    '''

    '''
    '''

    # define matrices
    P1 = Matrix([
        [1, 2],
        [3, 4]])
    P2 = Matrix([
        [5, 6],
        [7, 8]])

    P = P1*P2
    P

    '''
    '''

    # define matrices
    Q1 = Matrix([[3, 1,  2, 2],
                 [0, 2, -2, 1]])
    Q2 = Matrix([[-2,  3],
                 [ 1,  0],
                 [-2, -2],
                 [ 2,  2]])

    '''
    '''

    '''
    ## Determinants
    '''

    '''
    '''

    '''
    '''

    '''
    '''

    '''
    '''

    '''
    ## Matrix inverse
    '''

    '''
    '''

    '''
    '''


"""

https://en.wikipedia.org/wiki/Bessel_polynomials
https://en.wikipedia.org/wiki/Bessel_filter

"""

from sympy import *
from sympy.abc import *
import sys
import os

def memoize(f):
    memo = {}
    def helper(x):
        if x not in memo:
            memo[x] = expand(simplify(f(x)))
        return memo[x]
    return helper

def pbessel(n):
    if n < 0:
        return 0
    if n == 0:
        return 1
    if n == 1:
        return x+1
    return (2*n-1)*x*pbessel(n-1) + pbessel(n-2)

def prbessel(n):
    if n < 2:
        return pbessel(n)
    return (2*n-1)*prbessel(n-1) + x*x*prbessel(n-2)

pbessel = memoize(pbessel)
prbessel = memoize(prbessel)

if len(sys.argv) < 2:
    print("usage: order ...")
    sys.exit()

for i in range(len(sys.argv)-1):
    n = int(sys.argv[i+1])
    print("Order {}".format(n))
    print("Bessel")
    print(pbessel(n))
    print("Reversed Bessel")
    print(prbessel(n))
    print()


import numpy as np
import scipy.sparse as sps

def findifcoef(sten, d):
    """
    Finite difference coeficients for a given stencil and derivative order. It solves A*x = b to find
    coefficient where A and b are generated from provided stencil and order.

    Parameters
    ----------
    sten : list
        Finite difference stencil.
    d : integer
        Derivatrive order.

    Returns
    -------
    fdcoeff : float
        Finite difference coefficients.

    Examples
    --------
    2nd order center finite difference coefficients for [0, 1, 2]:

    >>> findifcoef([-1, 0, 1], 2)
        [ 1. -2.  1.]
    """

    assert d < len(sten), "Order of derivative should be smaller than stencil's length"

    # size of the stecil
    n = np.arange(len(sten))

    # left hand side matrix
    A = sten**n.reshape((n.shape[0], 1))

    # right hand side matrix
    b = np.zeros(n.shape)
    # b[d] = 1
    b[d] = np.arange(1, d+1).prod()

    # solve A*x = b
    coef = np.linalg.solve(A, b)
    # coef = np.linalg.inv(A) @ b
    coef[np.abs(coef) < 1e-10] = 0

    return coef

def findifder(fun, d, p, h, axis):
    """
    Finite difference derivative for a given n-dimensional array. It uses centeral fd for interior points
    and forward and backward for points at the boundary, assuming a uniform grid.

    Parameters
    ----------
    fun : array
        Input n-dimensional function.
    d, p : integer
        Derivatrive order and accuracy respectively.
    h : float
        Grid spacing.
    axis : integer
        Derivative is taken along this axis.

    Returns
    -------
    derfun : array
        dth order derivative of input function.
    """

    # Initialize
    fact = np.arange(1, d+1).prod()/h**d    # d!/h**d
    ind = fun.shape[axis]   # grid size along derivative axis
    smax = (d + p - 1)//2   # maximum index of the stencil
    derfun = np.zeros_like(fun)

    # Move derivative axis to 0
    fun = np.swapaxes(fun, axis, 0)

    # [smax:-smax] points centeral findif with [-(d+p-1)/2, ..., (d+p-1)/2] stencil
    sten = range(-smax, smax+1)
    coef = findifcoef(sten, d)
    for s, c in zip(sten, coef):
        derfun[smax:-smax] += c * fun[smax+s:ind-smax+s]

    # [0:smax] points forward findif with [0, 1, ..., (d+p-1)] stencil
    sten = range(d + p)
    coef = findifcoef(sten, d)
    for s, c in zip(sten, coef):
        derfun[:smax] += c * fun[s:s+smax]

    # [-smax:] points backward findif with [0, -1, ..., -(d+p-1)] stencil
    sten = range(0, -(d + p), -1)
    coef = findifcoef(sten, d)
    for s, c in zip(sten, coef):
        derfun[-smax:] += c * fun[-smax+s:ind+s]

    # Multiply the factor and move the derivative axis to its original position
    # return fact * np.swapaxes(derfun, 0, axis)
    return np.swapaxes(derfun, 0, axis) / h**d

def genderoper(d, p, h, axis):
    """
    Generate function helper for dth order derivative with pth order accuracy, assuming a
    uniform grid with spacing h. Once generated it can be applied to any n-dimensional array.
    Parameters
    ----------
    d, p : integer
        Derivatrive order and accuracy respectively.
    h : float
        Grid spacing.
    axis : integer
        Derivative is taken along this axis.

    Returns
    -------
    derfun : function helper
        dth order derivative function helper.
    """

    return lambda fun: findifder(fun, d, p, h, axis)

def findifmat(ngrid, d, p, h, axis):
    """
    Finite difference matrix for a given n-dimensional array. It uses centeral fd for interior points
    and forward and backward for points at the boundary, assuming a uniform grid. It assumes a row-major
    indexing for grid points.

    Parameters
    ----------
    ngrid : tuple
        Grid dimension.
    d, p : integer
        Derivatrive order and accuracy respectively.
    h : float
        Grid spacing.
    axis : integer
        Derivative is taken along this axis.

    Returns
    -------
    dermat : array
        Matrix for dth order derivative.
    """

    # Initialize
    fact  = np.arange(1, d+1).prod()/h**d    # d!/h**d
    smax  = (d + p - 1)//2                   # maximum index of the stencil
    nmat  = np.prod(ngrid)                   # total number of grid points
    npts  = ngrid[axis]                      # size of grid along derivative axis
    igrid = np.arange(nmat).reshape(ngrid)   # row-major indexing for grid points
    igrid = np.swapaxes(igrid, axis, 0)      # move the derivative axis to 0
    fdmat = np.zeros((nmat, nmat))

    # [smax:-smax] points centeral findif with [-(d+p-1)/2, ..., (d+p-1)/2] stencil
    sten = range(-smax, smax+1)
    coef = findifcoef(sten, d)
    row  = igrid[smax:npts-smax].flatten()
    for ss, cc in zip(sten, coef):
        col = igrid[smax+ss:npts-smax+ss].flatten()
        fdmat[row, col] = cc

    # [0:smax] points forward findif with [0, 1, ..., (d+p-1)] stencil
    sten = range(d + p)
    coef = findifcoef(sten, d)
    row  = igrid[0:smax].flatten()
    for ss, cc in zip(sten, coef):
        col = igrid[ss:smax+ss].flatten()
        fdmat[row, col] = cc

    # [-smax:] points backward findif with [0, -1, ..., -(d+p-1)] stencil
    sten = range(0, -(d + p), -1)
    coef = findifcoef(sten, d)
    row  = igrid[npts-smax:npts].flatten()
    for ss, cc in zip(sten, coef):
        col = igrid[npts-smax+ss:npts+ss].flatten()
        fdmat[row, col] = cc

    # return fact * fdmat
    return fdmat / h**d

def findifmatsp(ngrid, d, p, h, axis):
    """
    Finite difference matrix for a given n-dimensional array. It uses centeral fd for interior points
    and forward and backward for points at the boundary, assuming a uniform grid. It assumes a row-major
    indexing for grid points.

    Parameters
    ----------
    ngrid : tuple
        Grid dimension.
    d, p : integer
        Derivatrive order and accuracy respectively.
    h : float
        Grid spacing.
    axis : integer
        Derivative is taken along this axis.

    Returns
    -------
    dermat : sparse lil_matrix
        Matrix for dth order derivative.
    """

    # Initialize
    fact  = np.arange(1, d+1).prod()/h**d    # d!/h**d
    smax  = (d + p - 1)//2                   # maximum index of the stencil
    nmat  = np.prod(ngrid)                   # total number of grid points
    npts  = ngrid[axis]                      # size of grid along derivative axis
    igrid = np.arange(nmat).reshape(ngrid)   # row-major indexing for grid points
    igrid = np.swapaxes(igrid, axis, 0)      # move the derivative axis to 0
    fdmat = sps.lil_matrix((nmat, nmat), dtype=np.float64)

    # [smax:-smax] points centeral findif with [-(d+p-1)/2, ..., (d+p-1)/2] stencil
    sten = range(-smax, smax+1)
    coef = findifcoef(sten, d)
    row  = igrid[smax:npts-smax].flatten()
    for ss, cc in zip(sten, coef):
        col = igrid[smax+ss:npts-smax+ss].flatten()
        fdmat[row, col] = cc

    # [0:smax] points forward findif with [0, 1, ..., (d+p-1)] stencil
    sten = range(d + p)
    coef = findifcoef(sten, d)
    row  = igrid[0:smax].flatten()
    for ss, cc in zip(sten, coef):
        col = igrid[ss:smax+ss].flatten()
        fdmat[row, col] = cc

    # [-smax:] points backward findif with [0, -1, ..., -(d+p-1)] stencil
    sten = range(0, -(d + p), -1)
    coef = findifcoef(sten, d)
    row  = igrid[npts-smax:npts].flatten()
    for ss, cc in zip(sten, coef):
        col = igrid[npts-smax+ss:npts+ss].flatten()
        fdmat[row, col] = cc

    # return fact * fdmat
    return fdmat / h**d


"""
Use symbolic math to derive expressions for rotation matrices
based on various parameterizations
"""
import sympy
import sympy.vector as vector

from sympy.matrices import eye
from sympy import cos, sin
from sympy import matrices

def skew_matrix(a):

    return sympy.Matrix([[0, -a[2], a[1]],
                         [a[2], 0, -a[0]],
                         [-a[1], a[0], 0]])

def dyadic_product(a,b):

    return sympy.Matrix([[a[0]*b[0],a[0]*b[1],a[0]*b[2]],
                         [a[1]*b[0],a[1]*b[1],a[1]*b[2]],
                         [a[2]*b[0],a[2]*b[1],a[2]*b[2]]])

theta, phi, alpha = sympy.symbols('theta phi alpha')

xyz = vector.CoordSysCartesian('xyz')

a1, a2, a3 = sympy.symbols('a1 a2 a3')
b1, b2, b3 = sympy.symbols('b1 b2 b3')

a = sympy.Matrix([a1, a2, a3])
b = sympy.Matrix([b1, b2, b3])

from sympy.abc import phi, theta, alpha

axis = sympy.Matrix([cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta)])

R = cos(alpha) * eye(3) + sin(alpha) * skew_matrix(axis) + \
    (1-cos(alpha)) * dyadic_product(axis,axis)

R = sympy.simplify(R)

R2 = sympy.lambdify([theta, phi, alpha], R, "numpy")

import spin

rot = spin.AxisAngle(spin.random_rotation())

print rot.matrix
print R2(*rot.dofs)

RR = matrices.exp(skew_matrix(a))

dR_theta = sympy.Matrix([[sympy.diff(R[i,j], theta) for j in range(3)] for i in range(3)])
#dR_theta = sympy.simplify(dR_theta)

dR_phi = sympy.Matrix([[sympy.diff(R[i,j], phi) for j in range(3)] for i in range(3)])
#dR_phi = sympy.simplify(dR_phi)

dR_alpha = sympy.Matrix([[sympy.diff(R[i,j], alpha) for j in range(3)] for i in range(3)])
#dR_alpha = sympy.simplify(dR_alpha)

## cython code

replacements = [('cos(theta)','ca'),
                ('sin(theta)','sa'),
                ('cos(phi)','cb'),
                ('sin(phi)','sb'),
                ('cos(alpha)','cc'),
                ('sin(alpha)','sc')]

for i in range(3):
    for j in range(3):
        row = str(R[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'R[{0},{1}] = {2}'.format(i,j,row)

for i in range(3):
    for j in range(3):
        row = str(dR_theta[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'A[{0},{1}] = {2}'.format(i,j,row)

for i in range(3):
    for j in range(3):
        row = str(dR_phi[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'B[{0},{1}] = {2}'.format(i,j,row)

for i in range(3):
    for j in range(3):
        row = str(dR_alpha[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'C[{0},{1}] = {2}'.format(i,j,row)

from sympy.abc import w, x, y, z

q = sympy.Matrix([w, x, y, z])
r = w**2 + x**2 + y**2 + z**2
R = sympy.Matrix([[q[0]**2+q[1]**2-q[2]**2-q[3]**2,
                   2*q[1]*q[2]-2*q[0]*q[3],
                   2*q[1]*q[3]+2*q[0]*q[2]],
                  [2*q[1]*q[2]+2*q[0]*q[3],
                   q[0]**2-q[1]**2+q[2]**2-q[3]**2,
                   2*q[2]*q[3]-2*q[0]*q[1]],
                  [2*q[1]*q[3]-2*q[0]*q[2],
                   2*q[2]*q[3]+2*q[0]*q[1],
                   q[0]**2-q[1]**2-q[2]**2+q[3]**2]]) / r

dR_w = sympy.Matrix([[sympy.diff(R[i,j], w) for j in range(3)] for i in range(3)])
dR_x = sympy.Matrix([[sympy.diff(R[i,j], x) for j in range(3)] for i in range(3)])
dR_y = sympy.Matrix([[sympy.diff(R[i,j], y) for j in range(3)] for i in range(3)])
dR_z = sympy.Matrix([[sympy.diff(R[i,j], z) for j in range(3)] for i in range(3)])

dR_w = sympy.simplify(dR_w)

replacements = [('w','q[0]'),
                ('x','q[1]'),
                ('y','q[2]'),
                ('z','q[3]')]

replacements = [('w','w'),
                ('x','x'),
                ('y','y'),
                ('z','z'),
                ('(w**2 + x**2 + y**2 + z**2)','r')]

for i in range(3):
    for j in range(3):
        row = str(dR_w[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'A[{0},{1}] = {2}'.format(i,j,row)

print
for i in range(3):
    for j in range(3):
        row = str(dR_x[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'B[{0},{1}] = {2}'.format(i,j,row)

print
for i in range(3):
    for j in range(3):
        row = str(dR_y[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'C[{0},{1}] = {2}'.format(i,j,row)

print
for i in range(3):
    for j in range(3):
        row = str(dR_z[i,j])
        for a, b in replacements: row=row.replace(a,b)
        print 'D[{0},{1}] = {2}'.format(i,j,row)


# -*- coding:utf-8 -*-
"""
Project   : numpy
File Name : 5_9_to_5_10
Author    : Focus
Date      : 8/21/2021 10:14 PM
Keywords  : Moore Penrose pseudo inverse
Abstract  :
Param     :
Usage     : py 5_9_to_5_10
Reference :
"""
import numpy as np
A = np.mat("4 11 14; 8 7 -2")
print("A: \n", A)
p_inv0 = np.linalg.pinv(A)
print("Checking:-------")
print(A * p_inv0)


# -*- coding: utf-8 -*-
"""
Created on Mon Aug 31 05:51:34 2020

@author: Castellano
"""

class Bisection_Method(object):
    """Bisection Method for Finding Roots of a function.

    Parameters
    -------------
    function :

        A function for which the root will be found

    a : int

        The beginning of an interval where we believe the root recides.

    b : int

        The end of an interval where we believe the root recides.

    """

    def __init__(self, function, a=int, b=int):
        self.f = function
        self.a = a
        self.b = b

    def bisect(self, timed=False, verbose=False, tol=.001):
        """Bisect For Finding The Root of a function.

        verbose : Boolean

            Should results be printed on each iteration.

        timed : Boolean

            Should the execution time be displayed.

        tol : float

            The minimum tolerance to which the root should be found.

        Returns
        ---------
        root : float

            Approximate solution for the roof of function f.

        """

        import numpy as np
        from time import time

        start_time = time()

        if np.sign(self.f(self.a))*np.sign(self.f(self.b)) >= 0:

            raise Exception('Provide an initial interval [a,b] such that f(a)*f(b)<0. ')

        fa = self.f(self.a)
        fb = self.f(self.b)

        if verbose == True:

            s = "{} {} {} {} {} {} {}".format('|  k  ',
                                              '|    ak    ',
                                              '|  f(ak)  ',
                                              '|    ck    ',
                                              '|  f(ck)  ',
                                              '|    bk    ',
                                              '|  f(bk)  ')
            print(s)

        k = 0

        while (self.b-self.a)/2 > tol:
            k += 1
            c = (self.a + self.b)/2
            fc = self.f(c)
            if fc == 0:
                break
            if np.sign(fc)*np.sign(fa) < 0:
                self.b , fb = c, fc
            else:
                self.a , fa = c, fc
                if verbose == True:

                    s = "{0:4d} {1:12f} {2:7d} {3:15f} {4:6d} {5:14f} {6:7d}".format(int(k),
                                                                                self.a,
                                                                                int(np.sign(fa)),
                                                                                c,
                                                                                int(np.sign(fc)),
                                                                                self.b,
                                                                                int(np.sign(fb)))
                    print(s)

            xc = (self.a + self.b)/2

        s = "{} {:6f}".format('The best estimate of the root is', xc)
        print(s)

        if timed == True:
            print(" Execution Took %s seconds ---" % (time() - start_time))

        root = xc
        return root

    def n_iter(self, tol=.001):
        """Calculates number of iteration for Bisection Method.

        Parameters
        -------------

        tol : float

            The minimum tolerance to which the root should be found.

        Returns
        ---------
        n : float

            Approximate number of iterations required to find the root of function.

        """

        from math import log

        n = (log((self.b-self.a)/abs(tol))/log(2))

        return print(n, "Iterations \n")


import numpy as np
import math
from scipy.stats.stats import pearsonr

#ax+by=c
#px+qy=r
A = np.array([[8,-10],[40,-18]])
B = np.array([-66,214])
X = np.linalg.solve(A,B)

mean_x = X[0]
mean_y = X[1]

print("mean_x : ",mean_x)
print("mean_y : ",mean_y)

# Equations : (x - x_mean) = bxy(y - y_mean) , (y - y_mean) = byx(x - x_mean)

# case : 1 => 8x = 10y - 66 , 18y = 40x + 214
bxy = 10/8
byx = 40/18
r = math.sqrt(bxy*byx)
print("case 1 : ",r)

# case : 2 => 10y = 8x + 66 , 40x = 18y - 214
bxy = 18/40
byx = 8/10
r = math.sqrt(bxy*byx)
print("case 2 : ",r)

# selecting r such a way that r<=1 && r>=1
# if byx and bxy are -ve then r is also -ve
# for -ve numbers math.sqrt(-ve) gives "domain error"


import numpy as np
import scipy.linalg

def pca(*series):
    d = np.array(np.column_stack(series),dtype='float')
    print 'input data:'
    print d

    # compute the mean by variating the first axis (i.e. across columns)
    mean = np.mean(d, axis=0)

    # make the data 0-mean
    d -= mean

    print 'zero-mean input data:'
    print d

    # compute SVD of d
    (U, S, V) = np.linalg.svd(d, full_matrices=False)

    # get principal component
    v1 = V[0,][:,np.newaxis]

    # project each data point onto subspace of v1
    d = d.dot(v1)

    return (mean, v1, d)

def pca_revert(mean, v1, d):
    # expand the components
    d = d.dot(v1.T)

    # add back the mean
    d += mean

    return d

if __name__ == '__main__':
    # 4 time-series observed for 2 time instances
    (mean, v1, d) = pca([2400, 1300], [5500, 4800], [4100, 3900], [14500, 10600])
    print 'means:'
    print mean
    print 'principal component:'
    print v1
    print 'reduced version of data:'
    print d
    print 'guess:'
    print pca_revert(mean, v1, d)


import numpy as np

def jacobi(A, b, ITERATION_LIMIT = 1000):
    """
        https://en.wikipedia.org/wiki/Jacobi_method
    """
    x = np.zeros_like(b)
    for it_count in range(ITERATION_LIMIT):
        x_new = np.zeros_like(x)

        for i in range(A.shape[0]):
            s1 = np.dot(A[i, :i], x[:i])
            s2 = np.dot(A[i, i + 1:], x[i + 1:])
            x_new[i] = (b[i] - s1 - s2) / A[i, i]

        if np.allclose(x, x_new, atol=1e-10, rtol=0.):
            break

        x = x_new
    # error = np.dot(A, x) - b
    return x


from math import sqrt
from numpy import array, linalg

def det(matrix):
    return linalg.det(array(matrix))

class Vec3:
    def __init__(self, *args):
        if len(args) == 1:
            self.x = args[0][0]
            self.y = args[0][1]
            self.z = args[0][2]
        elif len(args) == 3:
            self.x = args[0]
            self.y = args[1]
            self.z = args[2]
        else:
            raise ValueError("Invalid Quantity of input: " + str(len(args)))

    def __add__(self, other):
        if type(other) == Vec3:
            return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
        elif type(other) in [list, tuple]:
            return Vec3(self.x + other[0], self.y + other[1], self.z + other[2])
        else:
            raise TypeError("Vec3 can only add with Vec3, list, tuple")

    def __radd__(self, other):
        if type(other) == Vec3:
            return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
        elif type(other) in [list, tuple]:
            return [self.x + other[0], self.y + other[1], self.z + other[2]]
        else:
            raise TypeError("Vec3 can only add with Vec3, list, tuple")

    def __sub__(self, other):
        if type(other) == Vec3:
            return Vec3(self.x - other.x, self.y - other.y, self.z - other.z)
        elif type(other) in [list, tuple]:
            return Vec3(self.x - other[0], self.y - other[1], self.z - other[2])
        else:
            raise TypeError("Vec3 can only subtract with Vec3, list, tuple")

    def __rsub__(self, other):
        if type(other) == Vec3:
            return Vec3(other.x - self.x, other.y - self.y, other.z - self.z)
        elif type(other) in [list, tuple]:
            return [other[0] - self.x, other[1] - self.y, other[2] - self.z]
        else:
            raise TypeError("Vec3 can only subtract with Vec3, list, tuple")

    def __mul__(self, other):
        if type(other) in [int, float]:
            return Vec3(self.x * other, self.y * other, self.z * other)
        if type(other) == Vec3:
            return self.x * other.x + self.y * other.y + self.z * other.z
        elif type(other) in [list, tuple]:
            return self.x * other[0] + self.y * other[1] + self.z * other[2]
        else:
            raise TypeError(f"Vec3 can only multiply with Vec3, list, tuple, int, float")

    def __rmul__(self, other):
        return self.__mul__(other)

    def __truediv__(self, other):
        if type(other) in [int, float]:
            return self.__mul__(1 / other)
        else:
            raise TypeError(f"Vec3 can only divide with int, float")

    def __abs__(self):
        return sqrt(self.x * self.x + self.y * self.y + self.z * self.z)

    def __neg__(self):
        return Vec3(-self.x, -self.y, -self.z)

    def __str__(self):
        return f"Vec3({self.x}, {self.y}, {self.z})"

    def dist_sq(self):
        return self.x * self.x + self.y * self.y + self.z * self.z

    def cross(self, other):
        return Vec3(
            det([[self.y, self.z], [other.y, other.z]]),
            -det([[self.x, self.z], [other.x, other.z]]),
            det([[self.x, self.y], [other.x, other.y]]),
        )

    def to_list(self):
        return [self.x, self.y, self.z]


import numpy as np
import math

''' Misc of activation functions
    for the neural network
'''

def get_activation(name):
    return eval(name+"_activation")

def sigmoid_activation(x=None,deriv=False):
    ''' Sigmoid function (used for hidden neurons)
    '''
    if deriv == True:
        return sigmoid(x)*(1-sigmoid(x))
    return 1/(1+np.exp(-x))

def tansig_activation(x=None,deriv=False):
    ''' Tangent Sigmoid function
    '''
    return ( np.exp(x)-np.exp(-x) ) / ( np.exp(x)+np.exp(-x) )

def purelin_activation(x=None,deriv=False):
    ''' Linear (usually used in output neurons)
    '''
    if deriv == True:
        return 1
    return x

def tanh_activation(z):
    z = max(-60.0, min(60.0, 2.5 * z))
    return math.tanh(z)

def sin_activation(z):
    z = max(-60.0, min(60.0, 5.0 * z))
    return math.sin(z)

def gauss_activation(z):
    z = max(-3.4, min(3.4, z))
    return math.exp(-5.0 * z**2)

def relu_activation(z):
    return z if z > 0.0 else 0.0

def softplus_activation(z):
    z = max(-60.0, min(60.0, 5.0 * z))
    return 0.2 * math.log(1 + math.exp(z))

def identityn_activation(z):
    return z

def clamped_activation(z):
    return max(-1.0, min(1.0, z))

def inverse_activation(z):
    if z == 0:
        return 0.0

    return 1.0 / z

def logarithmic_activation(z):
    z = max(1e-7, z)
    return math.log(z)

def exponential_activation(z):
    z = max(-60.0, min(60.0, z))
    return math.exp(z)

def absolute_activation(z):
    return abs(z)

def hat_activation(z):
    return max(0.0, 1 - abs(z))

def square_activation(z):
    return z ** 2

def cube_activation(z):
    return z ** 3


import numpy as np
from scipy.optimize import linprog

"""
Wasserstein距离也被形象地称之为“推土机距离”（Earth Mover's Distance，EMD），因为它可以用一个“推土”的例子来通俗地表达它的含义。

假设在位置i=1,2,…,n处我们分布有p1,p2,…,pn那么多的土，简单起见我们设土的总数量为1，即p1+p2+⋯+pn=1，现在要将土推到位置j=1,2,…,n′上，每处的量为q1,q2,…,qn′，而从i推到j的成本为di,j，求成本最低的方案以及对应的最低成本。
"""
def wasserstein_distance(p, q, D):
    """通过线性规划求Wasserstein距离
    p.shape=[m], q.shape=[n], D.shape=[m, n]
    p.sum()=1, q.sum()=1, p∈[0,1], q∈[0,1]
    """
    A_eq = []
    for i in range(len(p)):
        A = np.zeros_like(D)
        A[i, :] = 1
        A_eq.append(A.reshape(-1))
    for i in range(len(q)):
        A = np.zeros_like(D)
        A[:, i] = 1
        A_eq.append(A.reshape(-1))
    A_eq = np.array(A_eq)
    b_eq = np.concatenate([p, q])
    D = D.reshape(-1)
    result = linprog(D, A_eq=A_eq[:-1], b_eq=b_eq[:-1])
    return result.fun


import numpy as np

def std_PCA(W,d):
    '''
    Given a n x n matrix (this is equal to A^T A for an m x n data matrix A), output the top d eigenvectors of W as numpy n x d matrix.
    '''
    [eigenValues,eigenVectors] = np.linalg.eig(W)

    #sort eigenvalues and eigenvectors in decending orders
    idx = eigenValues.argsort()[::-1]
    eigenValues = eigenValues[idx]
    eigenVectors = eigenVectors[:,idx]

    #take the first d vectors. Obtained the solution
    return eigenVectors[:,:d]


# Whitening: Normalization of Correlated Multivariate Data
# Following function is created with reference to the page 253-259 of text book "Neural Networks for Applied Sciences and Engineering" by Sandhya Samarasinghe

import numpy as np

def whitening(data_matrix):
    """
    Whitening - Normalization of Correlated Multivariate Data

    :param data_matrix: '(the number of data, the number of variables) size' data matrix
    :return: '(the number of data, the number of variables) size' whitened data matrix
    """
    # whitening the data

    matrix_mean = data_matrix.mean(axis=0)  # '(the number of data, the number of variables) size' data matrix
    num_data = data_matrix.shape[0]  # the number of data
    dim_data = data_matrix.shape[1]  # the number of variables

    matrix_cov = np.zeros((dim_data, dim_data))  # Covariance matrix (the covariance between the two variables)
    for i in range(num_data):
        matrix_cov = matrix_cov + np.dot((data_matrix[i, :].reshape([1, dim_data]) - matrix_mean[:].reshape([1, dim_data])).transpose(),
                                         (data_matrix[i, :].reshape([1, dim_data]) - matrix_mean[:].reshape([1, dim_data]))) / (num_data - 1.0)

    """The Covariance matrix can be transformed into a new matrix that corresponds to a set of new rescaled variables
    that have unit variance and are independent of one another. Therefore, covariance between two new variables is zero.
    This is accomplished by the well-known eigenvalue decomposition method or principal component analysis (PCA)."""

    eig_w, eig_v = np.linalg.eig(matrix_cov)
    """Each eigenvector (eig_v) defines the direction of a new axis for the rescaled variable called a principal component
    so that all new axes are perpendicular to each other.
    Thus, this process essentially decorrelates the original input variables."""

    # To obtain the transformed variables, the original variables are multiplied by the weights (eigenvector)
    # Prior to this, weights are normalized by dividing the corresponding standart deviation (square root of eigenvalue)
    eig_v_norm = np.zeros((dim_data, dim_data))
    for i in range(data_matrix.shape[1]):
        eig_v_norm[:, i] = eig_v[:, i]/abs(eig_w[i]) ** 0.5

    # To transform the original variables to zero mean,
    # simply subtract the corresponding mean value from the values of each of the original variables.
    matrix_whitened = np.dot((data_matrix - np.dot(np.ones((num_data, 1)).reshape([num_data, 1]), matrix_mean[:].reshape([1, dim_data]))), eig_v_norm)

    return matrix_whitened


import numpy as np
from fractions import Fraction
# import networkx as nx
# import matplotlib.pyplot as plt
#
# G=nx.barabasi_albert_graph(10,4)
# nx.draw(G, with_labels=True)
# plt.show()

def float_format(vector, decimal):
    return np.round((vector).astype(np.float), decimals=decimal)

in_pr = Fraction(1, 5)

adj_mat = np.matrix([[0, 0, 0, 0, 1],
              [0.5, 0, 0, 0, 0],
              [0.5, 0, 0, 0, 0],
              [0, 1, 0.5, 0, 0],
              [0, 0, 0.5, 1, 0]])

x = np.zeros((5, 5))
x[:] = in_pr

damping = 0.85

formula = damping * adj_mat + ((1 - damping) * x)

pr = np.matrix([in_pr, in_pr, in_pr, in_pr, in_pr])
pr = np.transpose(pr)

prev_rank = pr
for it in range(1,100):
    pr = formula * pr
    print (float_format(pr, 3))
    #checking for convergence
    if (prev_rank == pr).all():
        break
    prev_rank = pr

print ("Final:\n", float_format(pr, 3))
print ("sum", np.sum(pr))


import math

import numpy as np

from ..entities.camera import Camera

EYE_3 = np.eye(3)
EYE_4 = np.eye(4)

def create_rotation_matrix(rot_x: float, rot_y: float, rot_z: float) -> np.ndarray:
    """
    Creates rotation matrix fromEuler angles.

    Args:
        (float) rot_x: Rotation angle for x-axis
        (float) rot_y: Rotation angle for y-axis
        (float) rot_z: Rotation angle for z-axis

    Returns:
         (np.ndarray): Rotation matrix
    """
    sx, sy, sz = math.sin(rot_x), math.sin(rot_y), math.sin(rot_z)
    cx, cy, cz = math.cos(rot_x), math.cos(rot_y), math.cos(rot_z)

    cc, cs = cx * cz, cx * sz
    sc, ss = sx * cz, sx * sz

    # matrix = np.eye(3)
    matrix = EYE_3.copy()

    matrix[0, 0] = cy * cz
    matrix[0, 1] = sy * sc - cs
    matrix[0, 2] = sy * cc + ss

    matrix[1, 0] = cy * sz
    matrix[1, 1] = sy * ss + cc
    matrix[1, 2] = sy * cs - sc

    matrix[2, 0] = -sy
    matrix[2, 1] = cy * sx
    matrix[2, 2] = cy * cx

    return matrix

def create_transformation_matrix(position: np.ndarray, rotation: np.ndarray, scale: np.ndarray) -> np.ndarray:
    """
    Compose transformation matrix (translation, rotation, scale)

    Args:
        (np.ndarray) position: numpy array of shape (N, ). Order: x, y, z
        (np.ndarray) rotation: numpy array of shape (N, ). Euler angles in degrees, order: x, y, z
        (np.ndarray) scale: numpy array of shape (N, )

    Returns:
        (np.ndarray) transformation matrix, shape (n+1, n+1) where n is the number of axis (usually 3 - 3D case)
    """
    n = len(position)

    # matrix = np.eye(n + 1)
    matrix = EYE_4.copy()

    rotation_matrix = create_rotation_matrix(rotation[0], rotation[1], rotation[2])

    scale_diag = EYE_3.copy()
    scale_diag[0, 0] = scale[0]
    scale_diag[1, 1] = scale[1]
    scale_diag[2, 2] = scale[2]

    matrix[:n, :n] = np.dot(rotation_matrix, scale_diag)
    matrix[:n, n] = position[:]

    return matrix

def create_view_matrix(camera: Camera):
    n = 3
    matrix = np.eye(n + 1)

    rotation_matrix = create_rotation_matrix(-1 * camera.rot_x, -1 * camera.rot_y, -1 * camera.rot_z)

    matrix[:n, :n] = rotation_matrix
    matrix[:n, n] = np.dot(rotation_matrix, -1 * camera.position)

    return matrix


from math import log, sqrt, exp, erf
import numpy as np
invsqrt = lambda x: 1.0/sqrt(x)

def black_scholes_python ( nopt, price, strike, t, rate, vol, call, put ):
    mr = -rate
    sig_sig_two = vol * vol * 2

    for i in range(nopt):
        P = float( price [i] )
        S = strike [i]
        T = t [i]

        a = log(P / S)
        b = T * mr

        z = T * sig_sig_two
        c = 0.25 * z
        y = invsqrt(z)

        w1 = (a - b + c) * y
        w2 = (a - b - c) * y

        d1 = 0.5 + 0.5 * erf(w1)
        d2 = 0.5 + 0.5 * erf(w2)

        Se = exp(b) * S

        call [i] = P * d1 - Se * d2
        put [i] = call [i] - P + Se