from math import cos, pi, sqrt
import numpy as np

def dct_2d(image, numberCoefficients=0):

    nc = numberCoefficients # passando para NC para melhorar a visibilidade da formula
    height = image.shape[0]
    width = image.shape[1]
    imageRow = np.zeros_like(image).astype(float)
    imageCol = np.zeros_like(image).astype(float)

    for h in range(height):
        imageRow[h, :] = dct_1d(image[h, :], nc) # aplicando IDCT na linhas
    for w in range(width):
        imageCol[:, w] = dct_1d(imageRow[:, w], nc) # aplicando IDCT nas colunas

    return imageCol

def dct_1d(image, numberCoefficients=0):

    nc = numberCoefficients
    n = len(image)
    newImage= np.zeros_like(image).astype(float)

    for k in range(n):
        sum = 0
        for i in range(n):
            sum += image[i] * cos(2 * pi * k / (2.0 * n) * i + (k * pi) / (2.0 * n))
        ck = sqrt(0.5) if k == 0 else 1
        newImage[k] = sqrt(2.0 / n) * ck * sum

    # salvando os N maiores numeros e zerandos todos os outros
    if nc > 0:
        newImage.sort()
        for i in range(nc, n):
            newImage[i] = 0

    return newImage # retorno de um VETOR

def idct_2d(image):

    height = image.shape[0]
    width =  image.shape[1]
    imageRow = np.zeros_like(image).astype(float)
    imageCol = np.zeros_like(image).astype(float)

    for h in range(height):
        imageRow[h, :] = idct_1d(image[h, :]) # aplicando IDCT na linhas
    for w in range(width):
        imageCol[:, w] = idct_1d(imageRow[:, w]) # aplicando IDCT nas colunas

    return imageCol

def idct_1d(image):

    n = len(image)
    newImage = np.zeros_like(image).astype(float)

    for i in range(n):
        sum = 0
        for k in range(n):
            ck = sqrt(0.5) if k == 0 else 1 # operador tenario para verificar o valor do CK
            sum += ck * image[k] * cos(2 * pi * k / (2.0 * n) * i + (k * pi) / (2.0 * n))

        newImage[i] = sqrt(2.0 / n) * sum

    return newImage


from FileReader import readCSV
from scipy.stats import t
import numpy
import math

dataSet = readCSV('CSV_files/test.csv')

#1 Population Me an
def populationMean(dataSet):
    mean = sum(dataSet) / len(dataSet)
    return mean

# print("Population mean: ", str(populationMean(dataSet)))

#2 Median
def median(dataSet):
    listLength = len(dataSet)
    sortedList = sorted(dataSet)
    index = (listLength - 1) // 2
    if (listLength % 2):
        return sortedList[index]
    else:
        return (sortedList[index] + sortedList[index + 1])/2.0

# print('Mode: ', str(median(dataSet)))

#3 Mode
def mode(dataSet):
    n = len(dataSet)
    getMode = {}

    for l in dataSet:
        getMode[l] = getMode.get(l,0) + 1

    maxValue = max(list(getMode.values()))
    modeValue = [a for a, v in getMode.items() if v == maxValue]

    if len(modeValue) == n:
        return("No mode within given dataset")
    else:
        return("Mode is / are: " + ', '.join(map(str, modeValue)))

# print(str(mode(dataSet)))

#4 Population Standard Deviation
def populationStandardDeviation(dataSet):
    # CSVlues are supposed to be the values that are given
    u = 0
    #This is the Mean
    Top = 0
    # This is the top half of the equation
    Set = 0
    # This the bottom half of the equation
    Ans = 0
    # This is the Answer
    u = sum(dataSet)/len(dataSet)

    for i in dataSet:
        Top +=(i-u)**2

    Set = Top/len(dataSet)

    Ans = math.sqrt(Set)

    return Ans

#5 Variance of population proportion
def variancePopulationProportion(dataSet):
    mean = sum(dataSet) / len(dataSet)
    populationProportion = 1 / len(dataSet)
    print('populationProportion: ', populationProportion)
    if populationProportion != 0:
        variance = sum((xi - mean) ** 2 for xi in dataSet) / populationProportion
    else:
        variance = 0

    return variance

# print('Variance of Population Proportion: ', str(variancePopulationProportion(dataSet)))

#6 Z-Score
def zScore(dataSet):
    mean = sum(dataSet) / len(dataSet)
    std = math.sqrt(sum([(val - mean)**2 for val in dataSet])/(len(dataSet) - 1))
    scores = []
    for num in dataSet:
        # calculates the z-score of each number in the dataset
        zScore = (num - mean)/std
        scores.append(zScore)
    return scores

# zScore(dataSet)
#7 Standardized Score
def standardizedScore(dataSet):
    mean = sum(dataSet) / len(dataSet)
    std = math.sqrt(sum((val - mean) ** 2 for val in dataSet))/(len(dataSet))

    scores = []

    for num in dataSet:
        standardizedScore = (num - mean)/std
        scores.append(standardizedScore)
    return scores

#    print("Standardized Scores of dataset:", standardizedScore(dataSet))

#8 Population Correlation Coefficient
def populationCorrelationCoefficient(dataSet):

    dataSet.pop()
    dataSetX = dataSet[9:18]
    dataSetY = dataSet[0:9]

    Ex = sum(dataSetX)
    Ey = sum(dataSetY)
    Exy = 0
    Ex2 = 0
    Ey2 = 0
    n = len(dataSetX)

    if n != len(dataSetY):
        cake ='The two data sets that you have entered do not have the same number of numbers.'
        return cake
    else:
        for i in range(len(dataSetX)):
            Exy += dataSetX[i]* dataSetY[i]
            Ex2 += dataSetX[i] ** 2
            Ey2 += dataSetY[i] ** 2

        Top = 0
        Top = (n*Exy) - (Ex*Ey)
        Bottom = 0
        Bottom = math.sqrt((n*Ex2-Ex**2)* (n*Ey2-Ey**2))
        ans = Top/Bottom
        return ans

#9 Confidence Interval
def confidenceInterval(dataSet):
    confidence = .95
    n = len(dataSet)
    m = sum(dataSet) / n
    std = math.sqrt(sum([(val - m)**2 for val in dataSet])/(len(dataSet) - 1))
    std_err = std / math.sqrt(n)
    t = m / std_err
    h = std_err * t * float(1 + confidence) / float(2., n - 1)

    start = m + h
    end = m - h

    return start, end

# print ("Confidence Interval:", confidenceInterval(dataSet))

#10 Population Variance
def variance(dataSet):
    mean = sum(dataSet) / len(dataSet)

    variance = sum((xi - mean) ** 2 for xi in dataSet) / len(dataSet)
    return variance

# print('Population Variance: ', str(variance(dataSet)))

#11 P Value
def pValue(dataSet):
    set1 = dataSet[0:9]
    set2 = dataSet[9:18]

    mean_1 = sum(set1)/len(set1)
    mean_2 = sum(set2)/len(set2)

    n1 = len(set1) - 1
    std_err_1 = (math.sqrt(sum([(val - mean_1) ** 2 for val in set1]))/(n1)) / math.sqrt(len(set1))

    n2 = len(set2) - 1
    std_err_2 = (math.sqrt(sum([(val - mean_2) ** 2 for val in set2]))/(n2)) / math.sqrt(len(set2))

    std_err_diff = math.sqrt(std_err_1 ** 2 + std_err_2 ** 2)

    t_statistic = (mean_1 - mean_2) / (std_err_diff)

    deg_of_freedom = len(set1) + len(set2) - 2

    alpha = 0.05

    critical_value = t.ppf(1.0 - alpha, deg_of_freedom)

    pValue = (1 - t.cdf(abs(t_statistic), deg_of_freedom)) * 2

    if pValue > alpha:
        return("p-value is less than alpha. Null hypothesis accepted: means are equal.")
    else:
        return("p-value is greater than alpha. Null hypothesis rejected: means are not equal.")

#12 Proportion
def proportion(dataSet):
    try:
        ans = []
        total = sum(dataSet)

        for i in dataSet:
            temp = i/total
            ans.append('{:.4f}'.format(temp))
        return ans

    except:
        return "Pay attion, also I can not divide by zero :("

#13 Sample Mean
def sampleMean(dataSet):
    shortendDataSet = dataSet[0:5]
    smean = sum(dataSet) / len(dataSet)

    return smean
# print ("Sample Mean:", sampleMean(dataSet))

#14 Sample Standard Deviation
def standardDeviation(dataSet):
    mean = sum(dataSet) / len(dataSet)
    std = math.sqrt(sum([(val - mean)**2 for val in dataSet])/(len(dataSet) - 1))

    return std
#15 Variance of sample proportion
def varianceSampleProportion(dataSet):
    mean = sum(dataSet) / len(dataSet)
    varianceSampleProportion = sum((xi - mean) ** 2 for xi in dataSet) / (len(dataSet) - 1)

    return varianceSampleProportion

    print("Variance of Sample Proportion is:", varianceSampleProportion)


import numpy as np
import warnings
warnings.filterwarnings('ignore')
import sys
import csv

# Command to display all the columns of a numpy array
np.set_printoptions(threshold=sys.maxsize)
# Load the data. Data is already given to you in variable `path`
with open(path) as f:
    read_data=csv.reader(f,delimiter =",")
    read_data=list(read_data)
#remove the header

read_data.remove(read_data[0])
# Convert the data into a numpy array and store it in sales_data
sales_data=np.array(read_data)

# How many unique ad campaigns (xyz_campaign_id) does this data contain ? And for how many times was each campaign run ?
from collections import Counter
unique_add_campaign=print(np.unique(sales_data[:,1]))
print(Counter(sales_data[:,1]))

# What are the age groups that were targeted through these ad campaigns?
age_groups=np.unique(sales_data[:,3])
print("Age groups that were targeted",age_groups)

# What was the average, minimum and maximum amount spent on the ads?
Min_Amt=sales_data[:,8].astype(float).min()
Max_Amt=sales_data[:,8].astype(float).max()
Average_Amt=sales_data[:,8].astype(float).mean()
print("average, minimum and maximum amount spent on the ads",Average_Amt,Min_Amt,Max_Amt,"respectively")
print(sales_data[:,8].astype(float))

# What is the id of the ad having the maximum number of clicks ?
max_clicks_idadd=sales_data[:,7].astype(float).max()
print(max_clicks_idadd)
mask=(sales_data[:,7].astype(float)==max_clicks_idadd)
ad_id_max_clicks=sales_data[:,0][mask]
print('id of the ad having the maximum number of clicks',ad_id_max_clicks)

# How many people bought the product after seeing the ad with most clicks? Is that the maximum number of purchases in this dataset?
mask_1=(sales_data[:,0]==ad_id_max_clicks)
people_bought=sales_data[:,10][mask_1]
print("people bought the product after seeing the ad with most clicks",people_bought)

# So the ad with the most clicks didn't fetch the maximum number of purchases. Let's find the details of the product having maximum number of purchases
max_purchases=sales_data[:,-1].astype(int).max()
print(sales_data[:,-1].astype(int).max()==max_purchases)
print("product having maximum number of purchases",max_purchases)

# Create a new feature `Click Through Rate`  (CTR) and then concatenate it to the original numpy array

# Create a new numpy array to calculate CTR
CTR = np.array((sales_data[:,7].astype(float)/sales_data[:,6].astype(float))*100)

# Note the shapes of CTR and the original array are different
print(sales_data.shape)
print('The original shape of CTR is ',CTR.shape)

# Convert CTR to the same shape as that of the original array
CTR = CTR.reshape(-1,1)
print('New shape of CTR is ',CTR.shape)

# Concatenate CTR to the original array
sales_data = np.concatenate((sales_data, CTR),axis=1)
sales_data

# Create a new column that represents Cost Per Mille (CPM)

# Create a new numpy array to calculate CPM
CPM = (sales_data[:,8].astype(float)/sales_data[:,6].astype(float))*1000

# Note the shapes of CPM and the original array are different
print(sales_data.shape)
print('The original shape of CPM is ',CPM.shape)

# Convert CTR to the same shape as that of the original array
CPM = CPM.reshape(-1,1)
print('New shape of CTR is ',CPM.shape)

# Concatenate CTR to the original array
sales_data = np.concatenate((sales_data, CPM),axis=1)
print(sales_data)


import numpy as np

from abstractclasses import solver, solver_model

"""
Matrix multiplcation solves for the distance between two points in 2 or 3
dimensional space.
"""

# ————————————————————————————————————————————————
# MATRIX MULTIPLICATION SOLVER CLASS
# ————————————————————————————————————————————————

class matrix_multiplication_solver(solver):
    def prompt_inputs(self) -> None:
        sx0_arg = self.prompt_integer(
            "Please enter the width of the first matrix. (This will also be "
            + "the height of the second matrix.) > "
        )
        sy0_arg = self.prompt_integer(
            "Please enter the height of the first matrix. > "
        )
        sx1_arg = self.prompt_integer(
            "Please enter the width of the second matrix. > "
        )
        sy1_arg = sx0_arg

        mat0 = [[0] * sx0_arg for _ in range(sy0_arg)]
        mat1 = [[0] * sx1_arg for _ in range(sy1_arg)]

        for x in range(sx0_arg):
            for y in range(sy0_arg):
                mat0[y][x] = self.prompt_float(
                    "Enter the value at {}".format(x)
                    + ", {}".format(y)
                    + " of the first matrix.\n"
                )

        for i in range(sx1_arg):
            for j in range(sy1_arg):
                mat1[j][i] = self.prompt_float(
                    "Enter the value at {}".format(i)
                    + ", {}".format(j)
                    + " of the second matrix.\n"
                )

        # Set inputs
        self.inputs["sx0_arg"] = sx0_arg
        self.inputs["sy0_arg"] = sy0_arg
        self.inputs["sx1_arg"] = sx1_arg
        self.inputs["sy1_arg"] = sy1_arg
        self.inputs["mat0"] = mat0
        self.inputs["mat1"] = mat1

# ————————————————————————————————————————————————
# MATRIX MULTIPLICATION MODEL CLASS
# ————————————————————————————————————————————————

class matrix_multiplication_model(solver_model):
    def solve(self) -> None:
        sx0 = self.inputs["sx0_arg"]
        sy0 = self.inputs["sy0_arg"]
        sx1 = self.inputs["sx1_arg"]
        sy1 = self.inputs["sy1_arg"]
        mat0 = self.inputs["mat0"]
        mat1 = self.inputs["mat1"]
        self.ans = np.matmul(mat0, mat1)
        self.work = self.matrix_multiplicationwork(
            sx0, sy0, sx1, sy1, "", mat0, mat1
        )

    def matrix_multiplicationwork(
        self, sx0: int, sy0: int, sx1: int, sy1: int, v: str, mat0=[], mat1=[]
    ) -> str:
        v += "With matrices of size: {}".format(sx0) + ", {}".format(sy0)
        v += " and size: {}".format(sx1) + ", {}".format(sy1) + "\n"
        v += (
            "our resulting matrix will be size: {}".format(sx1)
            + ", {}.".format(sy0)
            + "\n"
        )
        v += "Multiply {}".format(mat0) + "\n"
        v += "with {}.".format(mat1) + "\n"
        v += "We get the " + "answer: {}".format(np.matmul(mat0, mat1)) + "\n"
        return v


# %%
import scipy as sci
import numpy as np
from matplotlib import pyplot as plt
from scipy import optimize
# %%

# function to find the closest point in an array to match up two arrays
def find_nearest(array, value):
    array = np.asarray(array)
    idx = (np.abs(array - value)).argmin()
    return array[idx]

# calculates the effective potential to be plotted on the graph
def gravitational_potential(mass, positions, xx, yy):

    """Initialises the mass and positions"""
    m1 = mass[0]
    m2 = mass[1]

    m1 = mass[0]/(mass[0]+mass[1])
    m2 = mass[1]/(mass[0]+mass[1])

    r_m1 = positions[0]
    r_m2 = positions[1]

    G = 1

    total_PE = G*(m1/np.sqrt((xx - r_m1[0])**2 + (yy - r_m1[1])**2)
                  + m2/np.sqrt((xx - r_m2[0])**2 + (yy - r_m2[1])**2))

    rotational_PE = 1/2*(xx**2 + yy**2)

    effective_PE = total_PE + rotational_PE

    return effective_PE

top = 1
limit = 3

x = np.linspace(-limit, limit, 70)
y = np.linspace(-limit, limit, 70)

xx, yy = np.meshgrid(x, y)

mass = np.array([1.989e30, 1.989e30/(3)])
m = mass[1]/(mass[0]+mass[1])
positions = np.array([[-1+m, 0], [m, 0]])
positions_x = np.array([positions[0][0], positions[1][0]])
distance_between = abs(positions[0]-positions[1])

# The follwing functions calculate the first three Lagrange points

def L1_function(r,m):
    m=m
    r0 = 3*m**2 - 3*m + 1
    r1 = 1*m**4 - 2*m**3 + 1*m**2 - 4*m + 2
    r2 = -4*m**3 + 6*m**2 - 2*m + 1
    r3 = 6*m**2 - 6*m + 1
    r4 = -4*m + 2
    r5 = 1

    return r5*r**5 + r4*r**4 + r3*r**3 + r2*r**2 + r1*r + r0

def L2_function(r,m):
    m=m
    r0 = -2*m**3 + 3*m**2 - 3*m + 1
    r1 = 1*m**4 - 2*m**3 + 5*m**2 - 4*m + 2
    r2 = -4*m**3 + 6*m**2 - 4*m + 1
    r3 = 6*m**2 - 6*m + 1
    r4 = -4*m + 2
    r5 = 1

    return r5*r**5 + r4*r**4 + r3*r**3 + r2*r**2 + r1*r + r0

def L3_function(r,m):
    r0 = -3*m**2 + 3*m - 1
    r1 = 1*m**4 - 2*m**3 + 1*m**2 + 4*m - 2
    r2 = -4*m**3 + 6*m**2 - 2*m - 1
    r3 = 6*m**2 - 6*m + 1
    r4 = -4*m + 2
    r5 = 1

    return r5*r**5 + r4*r**4 + r3*r**3 + r2*r**2 + r1*r + r0

# Uses the mesh grid of xx & yy to create a contour graph for the PE
z = gravitational_potential(mass, positions, xx, yy)

# prints the positions of the Lagrange points
print("L1:",sci.optimize.bisect(L1_function, -limit, limit, args=m))
print("L2:",sci.optimize.bisect(L2_function, -limit, limit, args=m))
print("L3:",sci.optimize.bisect(L3_function, -2, 2, args=m))

"""Calculating and plotting the Lagrange Points"""
L1 = sci.optimize.bisect(L1_function, -limit, limit, args=m)
L2 = sci.optimize.bisect(L2_function, -limit, limit, args=m)
L3 = sci.optimize.bisect(L3_function, -limit, limit, args=m)
L4 = np.average(positions_x)
L5 = np.average(positions_x)

L1_x = find_nearest(x, L1)
L2_x = find_nearest(x, L2)
L3_x = find_nearest(x, L3)
L4_x = find_nearest(x, L4)
L5_x = find_nearest(x, L5)

L4_y =  (np.sqrt(3)*distance_between[0])/2
L5_y = -(np.sqrt(3)*distance_between[0])/2

L1_z = z[np.where(x == L1_x), np.where(x == L1_x)]
L2_z = z[np.where(x == L2_x), np.where(x == L2_x)]
L3_z = z[np.where(x == L3_x), np.where(x == L3_x)]
L4_z = z[np.where(y == L4_x), np.where(x == L4_x)]
L5_z = z[np.where(y == L5_x), np.where(x == L5_x)]

# Plots the results on a 3D contour graph

fig = plt.figure()
ax = plt.axes(projection='3d')
ax.contour3D(x, y, -z, 50)
ax.invert_xaxis()
ax.set_xlabel(r'$x$', fontsize=15)
ax.set_ylabel(r'$y$', fontsize=15)

ax.scatter3D(2*L4-L1, 0, -L1_z, label="L1", s=65)
ax.scatter3D(-L4+L2, 0, -L2_z, label="L2", s=65)
ax.scatter3D(L4-L3, 0, -L3_z, label="L3", s=65)
ax.scatter3D(L4, L4_y, -L4_z, label="L4", s=65)
ax.scatter3D(L5, L5_y, -L5_z, label="L5", s=65)
ax.legend(loc="lower left")

if top == 1:
    ax.view_init(elev=90., azim=90)
    ax.w_zaxis.line.set_lw(0.)
    ax.set_zticks([])
    ax.dist = 7
else:
    ax.set_zlabel(r'$z$', fontsize=15)
ax.set_title('Plot of the Effective Potential for $\mu$ = %.2f' %
             (m,), fontsize=16)
plt.savefig("Lagrange points for \mu = %.2f.svg" %(m,), dpi=600)
plt.show()


import sympy as sym
import numpy
import matplotlib.pyplot as plt
import mpmath

def lagrange_series(x, N):
    psi = []
    #  h = Rational(1, N)
    h = 1.0/N
    points = [i*h for i in range(N+1)]
    for i in range(len(points)):
        p = 1
        for k in range(len(points)):
            if k != i:
                p *= (x - points[k])/(points[i] - points[k])
        psi.append(p)
    psi = psi[1:-1]
    return psi

def analytical():
    eps_values = [1.0, 0.1, 0.01, 0.001]
    for eps in eps_values:
      x = numpy.arange(Omega[0], Omega[1], 1/((N+1)*100.0))
      ue =  (numpy.exp(-x/eps) - 1)/ (numpy.exp(-1/eps) - 1)
      print((len(x), len(ue)))
      plt.plot(x, ue)
    plt.legend(["$\epsilon$=%.1e" % eps for eps in eps_values],
               loc="lower right")
    plt.title("Analytical Solution")
    plt.show()

def bernstein_series(x, N):
    # FIXME: check if a normalization constant is common in the definition
    # advantage is that the basis is always positive
    psi = []
    # for k in range(0,N+1):
    for k in range(1,N):  # bc elsewhere
        psi_k = x**k*(1-x)**(N-k)
        psi.append(psi_k)
    return psi

def sin_series(x, N):
    # FIXME: do not satisfy bc
    psi = []
    for k in range(1,N):
        psi_k = sym.sin(sym.pi*k*x)
        psi.append(psi_k)
    return psi

def series(x, series_type, N):
    if series_type=="sin"  : return sin_series(x, N)
    elif series_type=="Bernstein"  : return bernstein_series(x, N)
    elif series_type=="Lagrange"  : return lagrange_series(x, N)
    else: print("series type unknown ") # sys.exit(0)

def epsilon_experiment(N, series_type, Omega,
                       eps_values = [1.0, 0.1, 0.01, 0.001]):
    # x is global, symbol or array
    psi = series(x, series_type, N)
    f = 1
    for eps in eps_values:
        A = sym.zeros(N-1, N-1)
        b = sym.zeros(N-1)

        for i in range(0, N-1):
            integrand = f*psi[i]
            integrand = sym.lambdify([x], integrand, 'mpmath')
            b[i,0] = mpmath.quad(integrand, [Omega[0], Omega[1]])
            for j in range(0, N-1):
                integrand = eps*sym.diff(psi[i], x)*\
                  sym.diff(psi[j], x) - sym.diff(psi[i], x)*psi[j]
                integrand = sym.lambdify([x], integrand, 'mpmath')
                A[i,j] = mpmath.quad(integrand, [Omega[0], Omega[1]])

        c = A.LUsolve(b)
        u = sum(c[r,0]*psi[r] for r in range(N-1)) + x

        U = sym.lambdify([x], u, modules='numpy')
        x_ = numpy.arange(Omega[0], Omega[1], 1/((N+1)*100.0))
        U_ = U(x_)
        plt.plot(x_, U_)
    plt.legend(["$\epsilon$=%.1e" % eps for eps in eps_values],
               loc="upper left")
    plt.title(series_type)
    plt.show()

if __name__ == '__main__':
    import sys
    if len(sys.argv) > 1:
        series_type = sys.argv[1]
    else:
        series_type = "Bernstein"
    if len(sys.argv) > 2:
        N = int(sys.argv[2])
    else:
        N = 8
    #series_type = "sin"
    #series_type = "Lagrange"

    Omega = [0, 1]
    x = sym.Symbol("x")

    analytical()
    epsilon_experiment(N, series_type, Omega)


'''
Common methods for beamtools package

Created Fri May 12

@author: cpkmanchee
'''

import numpy as np

__all__ = ['normalize','gaussian','sech2','lorentzian','gaussian2D','rk4','alias_dict']

class Func:
    def __init__(self, value=None, index=None):
        self.val = value
        self.ind = index

    def at(self,x):
        return np.interp(x, self.ind, self.val)

    def diff(self):
        self.gradient = np.gradient(self.val)/np.gradient(self.ind)

    def diff_at(self,x):
        return np.interp(x,self.ind,self.gradient)

def normalize(f, offset=0):
    '''Normalize array of data. Optional offset.
    '''
    return (f-f.min())/(f.max()-f.min()) + offset

def gaussian(x,sigma,amp=1,x0=0,const=0):
    '''Gaussian distribution.
    x = independent variable
    sigma = sd (width parameter)
    x0 = centre position
    amp = amplitude
    const = y-offset
    '''
    return amp*np.exp(-(x-x0)**2/(2*sigma**2)) + const

def sech2(x,sigma,amp=1,x0=0,const=0):
    '''Hyperbolic secant-squared distribution.
    x = independent variable
    sigma = width parameter
    x0 = centre position
    amp = amplitude
    const = y-offset
    '''
    return amp*(1/np.cosh((x-x0)/sigma))**2 + const

def lorentzian(x,sigma,amp=1,x0=0,const=0):
    '''Lorentzian distribution.
    x = independent variable
    sigma = width parameter
    x0 = centre position
    amp = amplitude
    const = y-offset
    '''
    return amp*(sigma**2/((x-x0)**2+sigma**2)) + const

def gaussian2D(xy_meshgrid,x0,y0,sigx,sigy,amp,const,theta=0):
    '''Generates a 2D gaussian surface of size (n x m).

    Inputs:
        xy_meshgrid = [x,y]
        x = meshgrid of x array
        y = meshgrid of y array

    where x and y are of size (n x m)
    n = y.shape[0] (or x.) = number of rows
    m = x.shape[1] (or y.) = number of columns

        x0,y0 = peak location
        sig_ = standard deviation in x and y, gaussian 1/e radius
        amp = amplitude
        const = offset (constant)
        theta = rotation parameter, 0 by default

    Output:
        g.ravel() = flattened array of gaussian amplitude data

    where g is the 2D array of gaussian amplitudes of size (n x m)
    '''
    x = xy_meshgrid[0]
    y = xy_meshgrid[1]

    a = np.cos(theta)**2/(2*sigx**2) + np.sin(theta)**2/(2*sigy**2)
    b = -np.sin(2*theta)/(4*sigx**2) + np.sin(2*theta)/(4*sigy**2)
    c = np.sin(theta)**2/(2*sigx**2) + np.cos(theta)**2/(2*sigy**2)

    g = amp*np.exp(-(a*(x-x0)**2 -b*(x-x0)*(y-y0) + c*(y-y0)**2)) + const

    return g.ravel()

def rk4(f, x, y0, const_args=[], abs_x=False):
    '''
    functional form
    y'(x) = f(x,y,constants)

    f must be function, f(x,y,const_args)
    x = array
    y0 = initial condition,
    cont_args = additional constants required for f

    returns y, integrated array
    '''

    N = np.size(x)
    y = np.zeros(np.shape(x))
    y[0] = y0
    dx = np.gradient(x)

    if abs_x:
        dx = np.abs(dx)

    for i in range(N-1):
        k1 = f(x[i], y[i], *const_args)
        k2 = f(x[i] + dx[i]/2, y[i] + k1*dx[i]/2, *const_args)
        k3 = f(x[i] + dx[i]/2, y[i] + k2*dx[i]/2, *const_args)
        k4 = f(x[i] + dx[i], y[i] + k3*dx[i], *const_args)

        y[i+1] = y[i] + (k1 + 2*k2 + 2*k3 + k4)*dx[i]/6

    return y

alias_dict = {
        'gaus': ('gaus','gaussian','g'),
        'sech2': ('sech2','secant squared','hyperbolic secant squared','s'),
        'GausFit': ('GausFit','gaus','gaussian'),
        'Sech2Fit': ('Sech2Fit', 'sech2','secant squared','hyperbolic secant squared'),
        'constant': ('constant','const','c'),
        'linear': ('linear','lin','l'),
        'quadratic': ('quadratic', 'quad', 'q'),
        'symmetric': ('symmetric','sym','s'),
        'asymmetric': ('asymmetric','asym','a')
        }


from sympy import *
from tait_bryan_R_utils import *
from rodrigues_R_utils import *
from quaternion_R_utils import *

xsl, ysl, zsl = symbols('xsl ysl zsl')
xtg, ytg, ztg = symbols('xtg ytg ztg')
px, py, pz = symbols('px py pz')
om, fi, ka = symbols('om fi ka')
#sx, sy, sz = symbols('sx sy sz')
#q0, q1, q2, q3 = symbols('q0 q1 q2 q3')
vzx, vzy, vzz = symbols('vzx vzy vzz')

position_symbols = [px, py, pz]
orientation_symbols = [om, fi, ka]
#orientation_symbols = [sx, sy, sz]
#orientation_symbols = [q0, q1, q2, q3]
all_symbols = position_symbols + orientation_symbols

point_source_local = Matrix([xsl, ysl, zsl,1]).vec()
RT_wc = matrix44FromTaitBryan(px, py, pz, om, fi, ka)[:-1,:]
#RT_wc = matrix44FromRodrigues(px, py, pz, sx, sy, sz)[:-1,:]
#RT_wc = matrix44FromQuaternion(px, py, pz, q0, q1, q2, q3)[:-1,:]
point_source_global = RT_wc * point_source_local
point_on_plane_target_global = Matrix([xtg, ytg, ztg])

vzt = Matrix([[vzx, vzy, vzz]]).transpose()

target_value = Matrix([0]).vec()
model_function = Matrix([vzt.dot(point_source_global - point_on_plane_target_global)]).vec()
delta = target_value - model_function
delta_jacobian=delta.jacobian(all_symbols)

print(delta)
print(delta_jacobian)

with open("point_to_plane_tait_bryan_wc_jacobian.h",'w') as f_cpp:
    f_cpp.write("inline void point_to_plane_tait_bryan_wc(Eigen::Matrix<double, 1, 1> &delta, double px, double py, double pz, double om, double fi, double ka, double xsl, double ysl, double zsl, double xtg, double ytg, double ztg, double vzx, double vzy, double vzz)\n")
    f_cpp.write("{")
    f_cpp.write("delta.coeffRef(0,0) = %s;\n"%(ccode(delta[0,0])))
    f_cpp.write("}")
    f_cpp.write("\n")
    f_cpp.write("inline void point_to_plane_tait_bryan_wc_jacobian(Eigen::Matrix<double, 1, 6> &j, double px, double py, double pz, double om, double fi, double ka, double xsl, double ysl, double zsl, double xtg, double ytg, double ztg, double vzx, double vzy, double vzz)\n")
    f_cpp.write("{")
    for i in range (1):
        for j in range (6):
            f_cpp.write("j.coeffRef(%d,%d) = %s;\n"%(i,j, ccode(delta_jacobian[i,j])))
    f_cpp.write("}")


import numpy as np

from nnn.core import _Module

class Activation(_Module):
    pass

class Sigmoid(Activation):
    name = 'sigmoid'

    def forward(self, X: np.ndarray, grad: bool = True) -> np.ndarray:
        super(Sigmoid, self).forward(X, grad)

        return 1. / (1. + np.exp(-X))

    def backward(self, grad: np.ndarray) -> np.ndarray:
        last = super(Sigmoid, self).backward(grad)

        result = self.forward(last, grad=False)

        return grad * result * (1. - result)

class ReLU(Activation):
    name = 'relu'

    def forward(self, X: np.ndarray, grad: bool = True) -> np.ndarray:
        super(ReLU, self).forward(X, grad)

        return np.maximum(0, X)

    def backward(self, grad: np.ndarray) -> np.ndarray:
        last = super(ReLU, self).backward(grad)

        grad = grad.copy()
        grad[last <= 0] = 0

        return grad


from numpy import random, pi
import matplotlib.pyplot as plt

N = 10_000  # number of required points
Ntrials, Nhits = 0, 0
acc_x, acc_y = [], []  # accepted x, y
rej_x, rej_y = [], []  # rejected x, y

# Rejection Sampling
while Nhits < N:
    Ntrials += 1
    x, y = random.uniform(-1, 1, 2)
    if (x**2 + y**2)**2 <= 2*abs(x*y):
        acc_x.append(x)
        acc_y.append(y)
        Nhits += 1
    else:
        rej_x.append(x)
        rej_y.append(y)

print("Total number of samples drawn S = %d" % Ntrials)
print("Number of samples in the disk N = %d" % N)

ig, ax = plt.subplots()

plt.scatter(acc_x, acc_y, color = 'green', s = 1) # parameter s determines the size of each dot in the scatter plot
plt.scatter(rej_x, rej_y, color = 'red', s = 1)

ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
ax.set_aspect('equal')  # set aspect ratio 1:1

plt.show()


# -*- coding: utf-8 -*-
"""
Created on Sun Jan 07 07:52:52 2018

@author: MVGrigoriev

@task: kNN method
"""

import pandas
import numpy as np
from sklearn.neighbors import KNeighborsClassifier   # Import class from scikit-learn
from sklearn.model_selection import KFold   # Import KFold function
from sklearn.model_selection import cross_val_score   # Import metrics for cross validation
from sklearn.preprocessing import scale   # Import Scale function
data = pandas.read_csv('wine.data', header=None)  # Import data
target = data[0]   # Extract target
features = data.drop(0, axis=1)   # Extract features
kf = KFold(n_splits=5, shuffle=True, random_state=42)

# At what k is the maximum quality obtained without normalization of characteristics?
#
# What is the maximum quality without the normalization of characteristics (the number in the scale from 0 to 1)?
#
listOfAccuracy = []
for i in range(1, 51):
    neigh = KNeighborsClassifier(n_neighbors=i)
    neigh.fit(features, target)
    cvs = cross_val_score(neigh, features, target, cv=kf, scoring='accuracy')
    cvsValue = np.mean(cvs)
    listOfAccuracy.append(cvsValue)
optValue = max(listOfAccuracy)
optIndex = listOfAccuracy.index(optValue)
with open('2_1.txt', 'w') as f1:
    print(optIndex+1, file=f1, end='')
with open('2_2.txt', 'w') as f2:
    print(round(optValue, 2), file=f2, end='')

# Which optimal K is obtained after the normalization of the characteristics?
#
# What is the maximum quality after the normalization of characteristics (a number in the range from 0 to 1)?
#
features = scale(features)
listOfAccuracy = []
for i in range(1, 51):
    neigh = KNeighborsClassifier(n_neighbors=i)
    neigh.fit(features, target)
    cvs = cross_val_score(neigh, features, target, cv=kf, scoring='accuracy')
    cvsValue = np.mean(cvs)
    listOfAccuracy.append(cvsValue)
optValue = max(listOfAccuracy)
optIndex = listOfAccuracy.index(optValue)
with open('2_3.txt', 'w') as f3:
    print(optIndex+1, file=f3, end='')
with open('2_4.txt', 'w') as f4:
    print(round(optValue, 2), file=f4, end='')


import numpy as np
import logging
from benchmarker import benchmark

logger = logging.getLogger('exp11_blocked_matrices')

@benchmark
def blocked_solve_naive(A1, A2, B, C):
    C = np.linalg.solve(np.concatenate(
        (np.concatenate((A1, np.zeros((A1.shape[0], A1.shape[1]), dtype=np.float64)), axis=1),
         np.concatenate((np.zeros((A2.shape[0], A2.shape[1]), dtype=np.float64), A2), axis=1)), axis=0), B)
    return C

@benchmark
def blocked_solve_recommended(A1, A2, B, C):
    b1 = B[0:A1.shape[0], 0:B.shape[1]]
    b2 = B[A1.shape[0]:, 0:B.shape[1]]
    C = np.concatenate((np.linalg.solve(A1, b1), np.linalg.solve(A2, b2)), axis=0)
    return C

def exp11_blocked_matrices(b, n):
    bm_n = int(n / 2)
    A1 = np.random.randn(bm_n, bm_n)
    A2 = np.random.randn(bm_n, bm_n)
    B = np.random.randn(2 * bm_n, 2 * bm_n)
    C = np.zeros((2 * bm_n, 2 * bm_n), dtype=np.float64)

    res1 = b.benchmark("compact", blocked_solve_naive, A1, A2, B, C)
    res2 = b.benchmark("blocked", blocked_solve_recommended, A1, A2, B, C)
    logger.info('PartitionedMatrices correctness: {}'.format(np.allclose(res1, res2)))


import matplotlib
matplotlib.rcParams = matplotlib.rc_params_from_file('../../matplotlibrc')

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

from web_solution import simulate_convergence

#Create plot of 2-arm convergence
def two_arm_plot():
    pvec = np.array([.04, .05])
    priors, weights, champ_ind, days = simulate_convergence(pvec)
    weights = np.array(weights)/50.
    plt.plot(weights)
    plt.plot([0, days], [.95, .95], '--k')
    plt.plot([0, days], [.05, .05], '--k')
    plt.savefig('weights1.pdf')
    plt.clf()

#Create plots for 6-arm convergence
def six_arm_plot():
    pvec = np.array([.04, .02, .03, .035, .045, .05])
    priors, weights, champ_ind, days = simulate_convergence(pvec)
    weights = np.array(weights)/50.
    plt.plot(weights)
    plt.plot([0, days], [.95, .95], '--k')
    plt.plot([0, days], [.05, .05], '--k')
    plt.savefig('weights2.pdf')
    plt.clf()

def priors_plot():
    x = np.linspace(0,1,1000)
    y2 = beta.pdf(x,1,2)
    y3 = beta.pdf(x,10,20)
    y4 = beta.pdf(x,100,200)

    plt.plot(x,y2, label = r'$\alpha = 1, \beta = 2$')
    plt.plot(x,y3, label = r'$\alpha = 10, \beta = 20$')
    plt.plot(x,y4, label = r'$\alpha = 100, \beta = 200$')
    plt.legend()
    plt.savefig('priors.pdf')

if __name__ == "__main__":
    two_arm_plot()
    six_arm_plot()
    priors_plot()


## create a 3-D transformation matrix

import math
import array
import numpy as np
import vpython as vp # pip install vpython

v1 = vp.vector(1,0,0) # creates a vector of floating points [1.0,0.0,0.0]
# # print(v1)
# # print(type(v1)) # class 'vpython.cyvector.vector'
# # print(v1.x, v1.y, v1.z) # returns each component
#
# # ROTATE
# degrees_from_vertical = 20.0
degrees_rotate = 90.0
theta = math.radians(degrees_rotate) # theta is radians of measured degrees
v2 = vp.rotate(v1,angle=theta,axis=vp.vector(0,1,0))
print("vp rotate: {}".format(v2))
# print(type(v2))
# print(v2) # outputs a rotation of v1 about the y-axis by theta radians
#
# # making own CS transform of 20 deg from vertical = 110 deg roration
# A_jake = np.array([[math.cos(math.radians(110)),math.cos(math.radians(0.0)),math.cos(math.radians(200.0))],
#                 [0,math.cos(math.radians(0)),0],
#                 [math.cos(math.radians(20)),0,math.cos(math.radians(110))]])
# # coordiate rotation matrix of 110 deg counter clockwise about y axis
# # print(A_jake)
# v_prime_jake = np.array([1,0,0]) # vector in prime CS aligned with x' axis
# v_jake = np.matmul(A_jake,v_prime_jake)
# print("v_jake rotate: {}".format(v_jake))

# theta will be dip of wall (from horizontal)
def CoordinateRotation_3D(x,y,z,theta,alpha):
    v1 = vp.vector(x,y,z)
    # Rotate about y'-axis for x' to x and z' to z
    theta_radians = math.radians(theta) # theta is radians of measured degrees
    v_abouty = vp.rotate(v1,angle=theta_radians,axis=vp.vector(0,1,0))

    # Rotate about x-axis for y' to y and z' to z
    alpha_radians = math.radians(alpha)
    v_aboutx = vp.rotate(v_abouty,angle=alpha_radians,axis=vp.vector(1,0,0))
    return v_aboutx

# FL = CoordinateRotation_3D(1,0,0,theta = 70.0,alpha = 0.0)
# print("FL: {}".format(FL))
CL = CoordinateRotation_3D(1,0,0,theta=90.0,alpha=0.0)
print("CL: {}".format(CL))
# CT = CoordinateRotation_3D(1,0,0,theta=0.0,alpha=0.0)
# print("CT: {}".format(CT))
# CR = CoordinateRotation_3D(1,0,0,theta=90.0,alpha=180.0)
# print("CR: {}".format(CR))
# FR = CoordinateRotation_3D(1,0,0,theta=110.0,alpha=180.0)
# print("FR: {}".format(FR))

# A = np.array([[0,0,0],[0,1,0],[-1,0,0]])
# v_prime = np.array([1,0,0])
# v_new = np.matmul(A,v_prime)
# print("v matrix: {}".format(v_new))

def Rotate_3D_TimeSeries(x,y,z,theta,alpha):
    nptsx=len(x)
    nptsy=len(y)
    nptsz=len(z)
    if nptsx != nptsy:
        print("Mismatch npts",nptsx,nptsy)
        return
    xprime=[]
    yprime=[]
    zprime=[]
    i=0
    while i < nptsx:
        [xp, yp, zp]=CoordinateRotation_3D(x[i],y[i],z[i],theta,alpha)
        xprime.append(xp)
        yprime.append(yp)
        zprime.append(zp)
        i=i+1
    return [xprime, yprime, zprime]


# -*- coding: utf-8 -*-
#利用numpy模块构造幻方
import numpy as np

#列表循环向左移offset位
def shift_left(lst, offset):
    return [lst[(i+offset)%len(lst)] for i in range(len(lst))]

#列表循环向右移offset位
def shift_right(lst, offset):
    return [lst[i-offset] for i in range(len(lst))]

#构造奇数阶幻方函数
def magic_of_odd_order(n):
    p = (int)((n-1)/2)

    #创建矩阵1
    initial_lst1 = list(range(p+1,n))+list(range(p+1))
    initial_mat1 = []
    for i in range(n):
        initial_mat1.append(shift_left(initial_lst1, i))
    mat1 = np.array(initial_mat1)

    #创建矩阵2
    initial_lst2 = list(range(p,-1,-1))+list(range(2*p,p,-1))
    initial_mat2 = []
    for i in range(n):
        initial_mat2.append(shift_right(initial_lst2, i))
    mat2 = np.array(initial_mat2)

    #创建矩阵3,即元素全为1的矩阵
    mat3= np.ones((n,n),dtype=np.int)

    #构造幻方
    magic = n*mat2+mat1+mat3
    return magic

#构造4n阶幻方函数
def magic_of_4n_order(n):
    mat = np.array(range(1,n*n+1)).reshape(n,n)
    for i in range((int)(n/4)):
        for j in range((int)(n/4)):
            for k in range(4): #将每个4*4小方块的对角线换成互补元素
                mat[k+4*j][k+4*i] = n*n+1-mat[k+4*j][k+4*i]
                mat[k+4*j][3-k+4*i] = n*n+1-mat[k+4*j][3-k+4*i]

    return mat

#构造4n+2阶幻方函数
def magic_of_4n2_order(n):
    p = (int)(n/2)
    matA = magic_of_odd_order(p)
    matD = matA+p**2
    matB = matD+p**2
    matC = matB+p**2

    #交换矩阵块A与矩阵块C中特定元素的位置
    row = (int)((p-1)/2)
    for i in range(p):
        if i != row:
            for k in range((int)((n-2)/4)):
                matA[i][k],matC[i][k] = matC[i][k],matA[i][k]
        else:
            for k in range((int)((n-2)/4)):
                matA[i][row+k],matC[i][row+k] = matC[i][row+k],matA[i][row+k]

    #交换矩阵块B与矩阵块D中特定元素的位置
    col = (int)((p-1)/2)
    for j in range(col+2-(int)((n-2)/4),col+1):
        for i in range(p):
            matB[i][j],matD[i][j] = matD[i][j],matB[i][j]

    #合并矩阵块A,B,C,D组成幻方
    magic = np.row_stack((np.column_stack((matA,matB)),np.column_stack((matC,matD))))
    return magic

def fun():
    order = eval(input('Enter the order of magic square(>=3): '))

    if order%2 ==1:
        magic = magic_of_odd_order(order)
    elif order%4 == 0:
        magic = magic_of_4n_order(order)
    else:
        magic = magic_of_4n2_order(order)
    print('Generating magic square of %d order......'%order)

    for row in magic:
        for col in row:
            print(col, end='\t')
        print()

    #验证生成的magic是否为幻方
    val = input(("Do you want to validate?[Y|N]"))
    if val == 'Y' or val == 'y':
        print('每行的和:', np.sum(magic, axis=0))
        print('每列的和:', np.sum(magic, axis=1))
        print('主对角线的和:', sum([magic[i][i] for i in range(order)]))
        print('副对角线的和:', sum([magic[i][order-1-i] for i in range(order)]))
    print('It\'s Done!')

fun()


import numpy as np
import utils

'''
There is a lot of information and assumptions that need to be hardcorded based on domain knowledge.
Such information is;
Transition probabilities, = T
Observation probabilities,= O
Initial state probabilities = X0
Initial backward probabilities = B0 = the algorithm specifies this to be 1's
'''

# Step 0
'''
We need to know the Evidence values
in other words, we need to know what we observe.

In our example we observe if an person has an umbrella or not,
thus our evidence values is True or False

In our example we have observed
day 1 = True, Day 2 = True,
day 3 = False
day 4 = True, day 5 = True
'''
evidences = [True, True, False, True, True]
#evidences = [True]

# Step 1
'''
Find and create transition Probabililties, and create a SxS transition probability Matrix
Our example has one 2 states. Rain and not Rain., This gives us a 2x2 Transition matrix

T =     R       NR
      R[RR      RNR]
     NR[NR-R  NR-NR]

Thus you can read it as From Rain to RAIN (RR), From Rain to Not RAIN RNR, etc.

Row = FROM, Column = TO

Our transition probability is that there is a .7 probability for same wether as today, tomorrow.
Giving R - R = RR = 0.7

This gives us the information that the probability of not the same wether tomorrow is 1 - probSameWether
R-NR AND NR - R = 1 - 0.7 = 0.3
'''

T = np.matrix("0.7, 0.3; 0.3,0.7")

# Step 2
'''
Find and create observation matrix

In our case we can observe that the person brings the umbrella when;
it rains, brings umbrella, we know that this has a probability of .9
it rains, forgets umbrella, we know ...........................of 1 - prob(rain * brings U)  = 1 - 0.9 = 1

it does not rain, brings umbrella, we know taht this has a probability of .2
it does not rain, does not bring umbrella, we know .................... of 1 - prob(R * U) = 1 - .2 = .8

we can create the Observation matrix by specifying the evidence variable-value as rows
and the state-variable values (rain, not rain) or think of it as the possible values for the evidence variables(true, false) as columns

O =     T   F   =  R  -R  =
       U          U         [0.9  0.1]
      -U         -U         [0.2  0.8]
'''
O = np.matrix("0.9, 0.1; 0.2, 0.8")

# Step 3
'''

Convert \ create diagonal-matrices for specific observation evidence matrices for each evidence value.
We need to do this and can do this just because of simplification in calculation
AND math alows us to! (Don't know why, though).

We do this by just converting the O columns into diagonal matrixes (all elements that are not in the main diagonal = 0)
So for the specific evidence = True = U
U = [.9 0]   AND -U = [.1 0]
    [0 .2]            [0 .8]

For programming ease we put these into an array, so we have easy acces.
'''
u_true = np.matrix(".9, 0; 0, .2")
u_false = np.matrix(".1, 0; 0, .8")

u_specifics = [u_true, u_false]

# Step 4
'''
Init the prior state probabilities, because we do not have observation for this day
we just make up some probabilities based on domain knowledge.

Our example has 2 states, and we say that there is a 50-50% chance it rained or not
'''
print("instatiation f", 0, ":", 0)
x0 = np.matrix(".5; .5")

# step 5
'''
Forward Part of the Forward-backward algorithm
This use an algorithm\method called filtering from probability theory.
We also want to keep track of all the forward-messages, so we can use them when smoothing

The first message is equal to the prior state probability. so we can just append it to the list of messages
We do this becaus we need it in the computation.

The number of observations / evidence we have collect corresponds with 't' in the algorithm from P.Norvig and Russels book
'''
f_msgs = [x0]

for i in range(1, len(evidences)+1):
    print("Calculationg f", 0, ":", i)
    # find out what specific evidence matrix to use, based on evidence
    if evidences[i-1]: # uses i-1, because evidences start at t=1 and not t = 0,
        o = u_specifics[0]
    else:
        o = u_specifics[1]

    # now we can calcualte the message
    f_msg = o * T.T * f_msgs[i-1]

    #now we just normalize the message
    normalizer = f_msg.sum()
    f_msg = f_msg / normalizer

    # add the message to the list of messages
    f_msgs.append(f_msg)

# Just prints out the forward messages in a nice way so we can double check that we have implemented
# the forward part successfully
utils.pretty_print_matrix(f_msgs)

# Step 6
'''
Init backward state (is actually last message = bt:t)
The algorithm states that this is going to be a vector of 1's
One 1 for each possible state. We have two states, Rain and not Rain
'''
print("instatiation b", len(evidences), ":", len(evidences))
B0 = np.matrix("1; 1")

# Step 7
'''
Backwards part
'''

# since we know that we are going pass t (num evidence) message, and that B0 actually is the last
# for programming ease, lets just create the list now
# we are going to get number of evidences + 1(B0) backward messages. This because of our assumption of last message is 1's
b_msgs = [None for x in range(0, len(evidences))]
b_msgs.append(B0)

# print to check values
#print(b_msgs)
#print(evidences)

# calcualt bi:t, since B0 = bt:t
for i in range(len(evidences)-1, -1, -1): # if |evidences| = 5 ==> i = 4,3,2,1,0..
    print("Calculationg b", i, ":", len(evidences))
    if evidences[i]:
        o = u_specifics[0]
    else:
        o = u_specifics[1]

    # calculate the backward message
    print(o, b_msgs[i+1])
    b_msg = T * o * b_msgs[i+1]

    # normalize the message
    normalizer = b_msg.sum()
    b_msg = b_msg / normalizer

    # Track the message
    b_msgs[i] = b_msg

utils.pretty_print_matrix(b_msgs)

# Step 8
'''
Finally the smoothing step
'''
smoothed_values = []
for i in range(0, len(evidences)):
    # Now we are trying to multiply 2x1  * 2x1 matrixes. This is not allowed, we need pointwise / elementwise mult.
    smoothed = np.matrix(f_msgs[i].A * b_msgs[i].A)

    normalizer = smoothed.sum()
    smoothed = smoothed / normalizer

    smoothed_values.append(smoothed)

utils.pretty_print_matrix(smoothed_values)


import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error
from math import sqrt
import matplotlib.pyplot as plt

# 读取数据
prices_data0 = pd.read_csv('prices.csv')
X = [prices_data0['area'], prices_data0['rooms']]
y = prices_data0['price']
Xdata = np.array(X)
ydata = np.array(y)
Xdata_mine = np.r_[Xdata, np.ones([1, len(Xdata[0])])].T
# np.r_是按列连接两个矩阵，就是把两矩阵上下相加，要求列数相等。
# 依据给定形状和类型(shape[, dtype, order])返回一个新的元素全部为1的数组
# .T是装置

weightX = np.array([1.0, 1.0, 1.0], )
epsilon = 0.001
alpha = 1e-7
diff = [0, 0]
max_itor = 1000
error = []
cnt = 0
m = len(Xdata)
# 梯度下降gradient descent
while True:
    cnt += 1
    # iterations
    for i in range(m):
        #  y = weightX[0]* x[0] +  weightX[1] * x[1] +weightX[2]
        # residual
        diff[0] = (weightX[0] * Xdata_mine[i][0] + weightX[1] * Xdata_mine[i][1] + weightX[2]) - ydata[i]
        # gradient = diff[0] * x[i][j]
        weightX[0] -= alpha * diff[0] * Xdata_mine[i][0]
        weightX[1] -= alpha * diff[0] * Xdata_mine[i][1]
        weightX[2] -= alpha * diff[0] * Xdata_mine[i][2]
    # RMSE错误函数
    # the error function
    Y_pred = np.dot(Xdata_mine, weightX)
    error1 = sqrt(mean_squared_error(y, Y_pred))
    error.append(error1)
    if cnt > 1:
        if abs(error[cnt - 1] - error[cnt - 2]) < epsilon:
            break
        else:
            pass

print('=================no pre-processed data=============')
plt.plot(list(range(0, cnt)), error)  # cnt是迭代次数
plt.xlabel('the number of iterations')
plt.ylabel('the error function ')
plt.show()

# print ('the number of iterations : ', cnt)
# print ('Done: anser of mine :',  weightX)
print('min error of mine:', min(error))

# 和SciKit库中的线性回归结果进行比较
linreg = LinearRegression()
linreg.fit(Xdata.T, ydata)
# print (linreg.intercept_)
# print ('anser of sklearn:',linreg.coef_)

skerror = linreg.predict(Xdata.T)
print('error of sklearn:', sqrt(mean_squared_error(ydata, skerror)))

# plt.plot(Xdata[0], ydata, '.')
# plt.plot(Xdata[0], np.dot(Xdata_mine,weightX),'-',color='r')
# plt.plot(Xdata[0], linreg.coef_[0]*Xdata[0]+linreg.coef_[1]*Xdata[1]+linreg.intercept_, '-',color='g')
# plt.show()

print('================= min-max scaled data=============')
scaler0 = MinMaxScaler()
scaler0.fit(Xdata[0].reshape(-1, 1))
MinMaxScaler(copy=True, feature_range=(0, 1))

scaler1 = MinMaxScaler()
scaler1.fit(Xdata[1].reshape(-1, 1))
MinMaxScaler(copy=True, feature_range=(0, 1))
Xdata_2_1 = scaler0.transform(Xdata[0].reshape(-1, 1))
Xdata_2_2 = scaler1.transform(Xdata[1].reshape(-1, 1))
Xdata2 = np.c_[Xdata_2_1, Xdata_2_1].T
Xdata_mine2 = np.r_[Xdata2, np.ones([1, len(Xdata2[0])])].T

alpha = 1e-3
diff = [0, 0]
max_itor = 1000
error = []

cnt = 0
m = len(Xdata2)
while True:
    cnt += 1
    # iterations
    for i in range(m):
        #  y = weightX[0]* x[0] +  weightX[1] * x[1] +weightX[2]
        # residual
        diff[0] = (weightX[0] * Xdata_mine2[i][0] + weightX[1] * Xdata_mine2[i][1] + weightX[2]) - ydata[i]
        # gradient = diff[0] * x[i][j]
        weightX[0] -= alpha * diff[0] * Xdata_mine2[i][0]
        weightX[1] -= alpha * diff[0] * Xdata_mine2[i][1]
        weightX[2] -= alpha * diff[0] * Xdata_mine2[i][2]

    # the error function
    Y_pred = np.dot(Xdata_mine2, weightX)
    error1 = sqrt(mean_squared_error(y, Y_pred))

    error.append(error1);
    if cnt > 1:
        if abs(error[cnt - 1] - error[cnt - 2]) < epsilon:
            break
        else:
            pass

#    print ' theta0 : %f, theta1 : %f, theta2 : %f, error1 : %f' % (theta0, theta1, theta2, error1)

plt.plot(list(range(0, cnt)), error)
plt.xlabel('the number of iterations')
plt.ylabel('the error function ')
plt.show()

# print ('the number of iterations : ', cnt)
# print ('Done: anser of mine :',  weightX)
print('min error of mine:', min(error))

linreg = LinearRegression()
linreg.fit(Xdata2.T, ydata)
# print (linreg.intercept_)
# print ('anser of sklearn:',linreg.coef_)
skerror = linreg.predict(Xdata2.T)
print('error of sklearn:', sqrt(mean_squared_error(ydata, skerror)))

# plt.plot(Xdata2[0], ydata, '.')
# plt.plot(Xdata2[0], np.dot(Xdata_mine2,weightX),'-',color='r')
# plt.plot(Xdata2[0], linreg.coef_[0]*Xdata2[0]+linreg.coef_[1]*Xdata2[1]+linreg.intercept_, '-',color='g')
# plt.show()

print('=================standardized scaled data=============')
scaler0 = StandardScaler()
scaler0.fit(Xdata[0].reshape(-1, 1))
StandardScaler(copy=True, with_mean=True, with_std=True)

scaler1 = StandardScaler()
scaler1.fit(Xdata[1].reshape(-1, 1))
StandardScaler(copy=True, with_mean=True, with_std=True)
Xdata_3_1 = scaler0.transform(Xdata[0].reshape(-1, 1))
Xdata_3_2 = scaler1.transform(Xdata[1].reshape(-1, 1))
Xdata3 = np.c_[Xdata_2_1, Xdata_2_1].T
Xdata_mine3 = np.r_[Xdata2, np.ones([1, len(Xdata2[0])])].T

alpha = 1e-2
diff = [0, 0]
max_itor = 1000
error = []

cnt = 0
m = len(Xdata3)
while True:
    cnt += 1

    # iterations

    for i in range(m):
        #  y = weightX[0]* x[0] +  weightX[1] * x[1] +weightX[2]
        # residual
        diff[0] = (weightX[0] * Xdata_mine3[i][0] + weightX[1] * Xdata_mine3[i][1] + weightX[2]) - ydata[i]

        # gradient = diff[0] * x[i][j]
        weightX[0] -= alpha * diff[0] * Xdata_mine3[i][0]
        weightX[1] -= alpha * diff[0] * Xdata_mine3[i][1]
        weightX[2] -= alpha * diff[0] * Xdata_mine3[i][2]

    # the error function
    Y_pred = np.dot(Xdata_mine3, weightX)
    error1 = sqrt(mean_squared_error(y, Y_pred))

    error.append(error1);
    if cnt > 1:
        if abs(error[cnt - 1] - error[cnt - 2]) < epsilon:
            break
        else:
            pass

#    print ' theta0 : %f, theta1 : %f, theta2 : %f, error1 : %f' % (theta0, theta1, theta2, error1)

plt.plot(list(range(0, cnt)), error)
plt.xlabel('the number of iterations')
plt.ylabel('the error function ')
plt.show()

# print ('the number of iterations : ', cnt)
# print ('Done: anser of mine :',  weightX)
print('min error of mine:', min(error))

linreg3 = LinearRegression()
linreg3.fit(Xdata3.T, ydata)
# print (linreg.intercept_)
# print ('anser of sklearn:',linreg.coef_)
skerror3 = linreg3.predict(Xdata3.T)
print('error of sklearn:', sqrt(mean_squared_error(ydata, skerror3)))

# plt.plot(Xdata3[0], ydata, '.')
# plt.plot(Xdata3[0], np.dot(Xdata_mine3,weightX),'-',color='r')
# plt.plot(Xdata3[0], linreg.coef_[0]*Xdata3[0]+linreg.coef_[1]*Xdata3[1]+linreg.intercept_, '-',color='g')
# plt.show()


# -*- coding: utf-8 -*-
import numpy as np

a= np.array([0.3,2.9,4.0])

exp_a = np.exp(a) #exponential function
print(exp_a)

sum_exp_a = np.sum(exp_a)
print(sum_exp_a)

def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y


import numpy as np

class LogLinearOG:
    """
    Log linear optimal growth model, with log utility, CD production and
    multiplicative lognormal shock, so that

        y = f(k, z) = z k^alpha

    with z ~ LN(mu, s).

    The class holds parameters and true value and policy functions.
    """

    def __init__(self, alpha=0.4, beta=0.96, mu=0, s=0.1):

        self.alpha, self.beta, self.mu, self.s = alpha, beta, mu, s

        # == Some useful constants == #
        self.ab = alpha * beta
        self.c1 = np.log(1 - self.ab) / (1 - beta)
        self.c2 = (mu + alpha * np.log(self.ab)) / (1 - alpha)
        self.c3 = 1 / (1 - beta)
        self.c4 = 1 / (1 - self.ab)

    def u(self, c):
        " Utility "
        return np.log(c)

    def u_prime(self, c):
        return 1 / c

    def f(self, k):
        " Deterministic part of production function.  "
        return k**self.alpha

    def f_prime(self, k):
        return self.alpha * k**(self.alpha - 1)

    def c_star(self, y):
        " True optimal policy.  "
        return (1 - self.alpha * self.beta) * y

    def v_star(self, y):
        " True value function. "
        return self.c1 + self.c2 * (self.c3 - self.c4) + self.c4 * np.log(y)


import numpy as np

# Scales dataset to be values between [-1, 1]
def unit_scale(dataset):
    scalevals = 1 / np.max(np.abs(dataset), axis=0)
    return dataset * scalevals, scalevals


# Option Pricing in Python using the Black-Scholes-Merton Model (BSM) - Nov 2018. Author: Shen Lim.
# Copyright 2018, Shen Lim, All Rights Reserved.
import numpy as np
import scipy.stats as si

'''
Black-Scholes-Merton Model for European Options

S: Spot stock price
K: Strike price
T: Time to maturity
r: Risk-free rate of interest (in decimals)
sigma: Stock volatility
q: Dividend rate (in decimals)
'''

def bs():
    S = float(input("Spot stock price? "))
    K = float(input("Strike price? "))
    T = float(input("Time to maturity (years)? "))
    r = float(input("Risk-free rate (decimals)? "))
    sigma = float(input("Volatility (decimals)? "))
    call = input("Call or put? ")
    q = float(input("Dividends? Enter 0 if none. "))

    if (q == 0): # No dividends.

        d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
        d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
        N1 = si.norm.cdf(d1, 0.0, 1.0) # N(.) is the cumulative distribution function of the standard normal distribution.
        N2 = si.norm.cdf(d2, 0.0, 1.0)
        n1 = si.norm.cdf(-d1, 0.0, 1.0)
        n2 = si.norm.cdf(-d2, 0.0, 1.0)
        nPrime = np.exp((n1 ** 2)/2) / np.sqrt(2 * np.pi) # Standard normal probability density function.

        gamma = nPrime / (S * sigma * np.sqrt(T))
        vega = nPrime * S * np.sqrt(T)

        if (call.lower() == "c") or (call.lower() == "call"):
            call = (S * N1 - K * np.exp(-r * T) * N2)
            cDelta = N1
            cTheta = -((S * nPrime * sigma)/(2 * np.sqrt(T))) - (r * K * np.exp(-r * T) * N2)
            cRho = K * T * np.exp(-r * T) * N2

            print("Price of Call: $", round(call, 4),
            "\n   Call Delta:  ", round(cDelta, 4),
            "\n        Gamma:  ", round(gamma, 4),
            "\n         Vega:  ", round(vega, 4),
            "\n   Call Theta:  ", round(cTheta, 4),
            "\n     Call Rho:  ", round(cRho, 4),
            "\n           d1:  ", round(d1, 4),
            "\n           d2:  ", round(d2, 4))

        elif (call.lower() == "p") or (call.lower() == "put"):
            put = (K * np.exp(-r * T) * n2 - S * n1)
            pDelta = N1 - 1
            pTheta = -((S * nPrime * sigma)/(2 * np.sqrt(T))) + (r * K * np.exp(-r * T) * n2)
            pRho = -K * T * np.exp(-r * T) * n2

            print("Price of Put: $", round(put, 4),
            "\n   Put Delta:  ", round(pDelta, 4),
            "\n       Gamma:  ", round(gamma, 4),
            "\n        Vega:  ", round(vega, 4),
            "\n   Put Theta:  ", round(pTheta, 4),
            "\n     Put Rho:  ", round(pRho, 4),
            "\n           d1:  ", round(d1, 4),
            "\n           d2:  ", round(d2, 4))

        else:
            return "Invalid input."

    elif (q > 0): # Dividends.

        d1 = (np.log(S / K) + (r - q + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
        d2 = (np.log(S / K) + (r - q - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
        N1 = si.norm.cdf(d1, 0.0, 1.0)
        N2 = si.norm.cdf(d2, 0.0, 1.0)
        n1 = si.norm.cdf(-d1, 0.0, 1.0)
        n2 = si.norm.cdf(-d2, 0.0, 1.0)
        nPrime = np.exp((n1 ** 2)/2) / np.sqrt(2 * np.pi)

        gamma = nPrime / (S * sigma * np.sqrt(T)) * np.exp(-q * T)
        vega = nPrime * S * np.sqrt(T) * np.exp(-q * T)

        if (call.lower() == "c") or (call.lower() == "call"):
            call = (S * np.exp(-q * T) * N1 - K * np.exp(-r * T) * N2)
            cDelta = N1 * np.exp(-q * T)
            cTheta = -((S * nPrime * sigma * np.exp(-q * T))/(2 * np.sqrt(T))) - (r * K * np.exp(-r * T) * N2) + (q * S * np.exp(-q * T) * N1)
            cRho = K * T * np.exp(-r * T) * N2

            print("Price of Call: $", round(call, 4),
            "\n   Call Delta:  ", round(cDelta, 4),
            "\n        Gamma:  ", round(gamma, 4),
            "\n         Vega:  ", round(vega, 4),
            "\n   Call Theta:  ", round(cTheta, 4),
            "\n     Call Rho:  ", round(cRho, 4),
            "\n           d1:  ", round(d1, 4),
            "\n           d2:  ", round(d2, 4))

        elif (call.lower() == "p") or (call.lower() == "put"):
            put = (K * np.exp(-r * T) * n2 - S * np.exp(-q * T) * n1)
            pDelta = (N1 - 1) * np.exp(-q * T)
            pTheta = -((S * nPrime * sigma * np.exp(-q * T))/(2 * np.sqrt(T))) + (r * K * np.exp(-r * T) * n2) - (q * S * np.exp(-q * T) * n1)
            pRho = -K * T * np.exp(-r * T) * n2

            print("Price of Put: $", round(put, 4),
            "\n   Put Delta:  ", round(pDelta, 4),
            "\n       Gamma:  ", round(gamma, 4),
            "\n        Vega:  ", round(vega, 4),
            "\n   Put Theta:  ", round(pTheta, 4),
            "\n     Put Rho:  ", round(pRho, 4),
            "\n           d1:  ", round(d1, 4),
            "\n           d2:  ", round(d2, 4))

        else:
            return "Invalid input."

    else:
        return "Invalid dividends."


from math import pi, log, sqrt
from numpy import array, hstack, vstack
import numpy as np

def hilbert_indices(N):
    """Genrate 2^N x 2^N integer array, filled with values from 0 to 4^N along hilbert curve"""
    m = array([[0]], dtype=np.int)
    for i in range(N):
        d = 4**i
        m1 = vstack((hstack((m.T, m.T[::-1, ::-1] + 3*d)),
                      hstack((m+d, m+2*d))
                 )
       )
        m = m1
    return m

def hilbert_binary_diagram(N):
    """Generate 2^N x 2^N array of 0 and 1, drawing Hilbert curve"""
    m = array([[1,0],
               [0,0]], dtype = np.uint8)
    for i in range(1, N):

        a = 2**i
        m1 = np.zeros((2*a, 2*a), dtype = m.dtype)

        m1[0:a, 0:a] = m.T
        m1[a:2*a, 0:a] = m
        m1[a:2*a, a:2*a] = m
        m1[0:a, a:(2*a-1) ] = m.T[:, a-2::-1]

        #put additional ones
        m1[a-1,0] = 1
        m1[a, a-1] = 1
        m1[a-1, 2*a-2] = 1

        m = m1
    return m


"""
Here we collect some PDFs and CDFs used in the computations.
"""
import numpy as np
from scipy.stats import gamma, norm

def gamma_pdf(x: float, alpha: float, beta: float) -> float:
    """
    PDF of gamma distribution.
    """
    return gamma.pdf(x, a=alpha, scale=1 / beta)

def gamma_cdf(x: float, alpha: float, beta: float) -> float:
    """
    CDF of gamma distribution.
    """
    return gamma.cdf(x, a=alpha, scale=1 / beta)

def lognormal_cdf(x: float, mu: float, sigma: float) -> float:
    """
    CDF of log-normal distribution.
    """
    return norm.cdf((np.log(x) - mu) / sigma)

def weibull_pdf(x: float, k: float, lambda_: float) -> float:
    """
    PDF of Weibull distribution with shape k and scale lambda_.
    """
    return k / lambda_ * (x / lambda_) ** (k - 1) * np.exp(-((x / lambda_) ** k))


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

x_list = np.linspace(-2.0, 3.5, 1000)
y_list = np.linspace(-2.0, 3.5, 1000)
X, Y = np.meshgrid(x_list, y_list)

# Functions
Z1 = 2 * X + 3 * Y + 1
Z2 = X**2 + Y**2 - X * Y - 5
Z3 = (X - 5)*np.cos(Y - 5) - (Y - 5)*np.sin(X - 5)

# Create subplots for each function
fig, (f1, f2, f3) = plt.subplots(1, 3)

f1.contour(X, Y, Z1)
# Gradient of f1 at (1, 0) is [2, 3]
f1.quiver(1, 0, 2, 3)
f1.set_title('Contour Plot 1')
f1.set_xlabel('x')
f1.set_ylabel('y')

f2.contour(X, Y, Z2)
# Gradient of f2 at (1, 0) is [2, -2]
f2.quiver(1, 0, 2, -2)
f2.set_title('Contour Plot 2')
f2.set_xlabel('x')
f2.set_ylabel('y')

f3.contour(X, Y, Z3)
# Gradient of f3 at (1, 0) is about [-2.98, 3.08]
f3.quiver(1, 0, -2.98, 3.08)
f3.set_title('Contour Plot 3')
f3.set_xlabel('x')
f3.set_ylabel('y')

# Create plots for each function
fig2, mesh1 = plt.subplots(1, 1)
fig3, mesh2 = plt.subplots(1, 1)
fig4, mesh2 = plt.subplots(1, 1)

mesh1 = fig2.gca(projection='3d')
mesh2 = fig3.gca(projection='3d')
mesh3 = fig4.gca(projection='3d')

# Find tangent surfaces with linear approximations
TAN1 = 3 + 2 * (X - 1) + 3 * Y
TAN2 = -4 + 2 * (X - 1) - 2 * Y
TAN3 = 2.649 - 2.98 * (X - 1) + 3.08 * Y

mesh1.plot_surface(X, Y, Z1)
mesh1.plot_surface(X, Y, TAN1)
mesh1.set_title('Mesh Plot 1')
mesh1.set_xlabel('x')
mesh1.set_ylabel('y')

mesh2.plot_surface(X, Y, Z2)
mesh2.plot_surface(X, Y, TAN2)
mesh2.set_title('Mesh Plot 2')
mesh2.set_xlabel('x')
mesh2.set_ylabel('y')

mesh3.plot_surface(X, Y, Z3)
mesh3.plot_surface(X, Y, TAN3)
mesh3.set_title('Mesh Plot 3')
mesh3.set_xlabel('x')
mesh3.set_ylabel('y')

plt.show()


import numpy as np

def random_initialisation(X, K, random_state=None):
  if random_state:
    np.random.seed(random_state)

  indices = np.random.choice(X.shape[0], K, replace=False)
  centroids = X[indices]
  return centroids

def find_closest_centroids(X, centroids):
  K = centroids.shape[0]
  idx = np.zeros([X.shape[0], 1])

  idx_val = np.linalg.norm(X - centroids[0], axis=1) ** 2
  idx = np.zeros(X.shape[0])
  for i in range(1, K):
    new_val = np.linalg.norm(X - centroids[i], axis=1) ** 2
    idx[new_val < idx_val] = i
    idx_val[new_val < idx_val] = new_val[new_val < idx_val]
  return idx

def compute_centroids(X, idx, K):
  centroids = np.zeros([K, X.shape[1]])

  for i in range(K):
    if len(X[idx == i]) != 0 :
      centroids[i] = np.sum(X[idx == i], axis=0) / len(X[idx == i])
  return centroids

def cost_function(X, centroids, idx):
  return (sum(np.linalg.norm(X - centroids[idx.astype(int)], axis=1) ** 2) / X.shape[0])


from sage.all import *
import random

def brute_ecdlp(P, Q, E):
    """
    Brute Force algorithm to solve ECDLP and retrieve value of secret key `x`.
    Use only if group is very small.
    Includes memoization for faster computation
    [Warning]: Tested for Weierstrass Curves only
    :parameters:
        E : sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category
            Elliptic Curve defined as y^2 = x^3 + a*x + b mod p
        P : sage.schemes.elliptic_curves.ell_point.EllipticCurvePoint_finite_field
            Base point of the Elliptic Curve E
        Q : sage.schemes.elliptic_curves.ell_point.EllipticCurvePoint_finite_field
            Q = x*P, where `x` is the secret key
    """
    _order = P.order()
    try:
        assert P == E((P[0], P[1]))
    except TypeError:
        print "[-] Point does not lie on the curve"
        return -1

    res = 2*P
    if res == Q:
        return 2
    if Q == E((0, 1, 0)):
        return _order
    if Q == P:
        return 1
    i = 3
    while i <= P.order() - 1:
        res = res + P
        if res == Q:
            return i
        i += 1
    return -1

if __name__ == "__main__":
    E = EllipticCurve(GF(17), [2, 2])
    P = E((5, 1))
    try:
        for _ in range(100):
            x = random.randint(2, 18)
            assert brute_ecdlp(E((5, 1)), x*P, E) == x
    except Exception as e:
        print e
        print "[-] Function inconsistent and incorrect"
        print "[-] Check your implementation"


# 1. 배열 만들기
import numpy as np

a = np.array([[1, 2], [3, 4]])
print(a)

# 2. 사칙 연산
print('====================================================================================================')
print('== 문제 1. 아래의 a 배열에 모든 원소에 5를 더한 결과를 출력하시오!')
print('====================================================================================================\n')
a = np.array([[1, 2], [3, 4]])
print(a + 5)

print('====================================================================================================')
print('== 문제 2. 아래의 배열의 원소들의 평균값을 출력하시오!')
print('====================================================================================================\n')
a = np.array([1,2,4,5,5,7,10,13,18,21])
print(np.mean(a))

print('====================================================================================================')
print('== 문제 3. a 배열의 중앙값을 출력하시오!')
print('====================================================================================================\n')
print(np.median(a))

print('====================================================================================================')
print('== 문제 4. a 배열의 최대값과 최소값을 출력하시오!')
print('====================================================================================================\n')
print(np.max(a), np.min(a))

print('====================================================================================================')
print('== 문제 5. a 배열의 표준편차와 분산을 출력하시오!')
print('====================================================================================================\n')
print(np.std(a), np.var(a))

print('====================================================================================================')
print('== 문제 6. 아래의 행렬식을 numpy 로 구현하시오!')
print('====================================================================================================\n')
a = np.array([[1, 3, 7], [1, 0, 0]])
b = np.array([[0, 0, 5], [7, 5, 0]])
print(a + b)

print('====================================================================================================')
print('== 문제 7. 아래의 numpy 배열을 생성하고 원소중에 10 만 출력해보시오!')
print('====================================================================================================\n')
a = np.array([[1, 2, 3], [4, 10, 6], [8, 9, 20]])
print(a[1][1])

print('====================================================================================================')
print('== 문제 8. (점심시간 문제) 아래의 행렬 연산을 파이썬으로 구현하시오!')
print('====================================================================================================\n')
a = np.array([[1, 2], [3, 4]])
b = np.array([10, 20])
print(a * b)

print('====================================================================================================')
print('== 문제 9. 아래의 그림의 행렬 연산을 numpy 로 구현하시오!')
print('====================================================================================================\n')
a = np.array([[0], [10], [20], [30]])
b = np.array([0, 1, 2])
print(a + b)

print('====================================================================================================')
print('== 문제 10. 아래의 행렬식을 numpy 로 구현하고 아래의 요소에서 15 이상인것만 출력하시오!')
print('====================================================================================================\n')
a = np.array([[51, 55], [14, 19], [0, 4]])
a[a>=15]

print('====================================================================================================')
print('== 문제 11. 아래의 행렬식을 numpy 를 이용하지 않고 list 변수로 구현하고 아래의 행렬식에서 행의 개수가 몇 개 인지 출력하시오!')
print('====================================================================================================\n')
a = [[1, 3, 7], [1, 0, 0]]
print(len(a))

print('====================================================================================================')
print('== 문제 12. 아래의 행렬식을 numpy 를 이용하지 않고 list 변수로 구현하고 열의 개수가 몇개인지 출력하시오!')
print('====================================================================================================\n')
a = [[1, 3, 7], [1, 0, 0]]
print(len(a[0]))

print('====================================================================================================')
print('== 문제 13. 아래의 행렬식의 덧셈 연산을 numpy 를 이용하지 않고 수행하시오!')
print('====================================================================================================\n')
a = [[1, 3, 7], [1, 0, 0]]
b = [[0, 0, 5], [7, 5, 0]]
result = []

for row_idx in range(len(a)):
    temp = []
    for col_idx in range(len(a[row_idx])):
        temp.append(a[row_idx][col_idx] + b[row_idx][col_idx])
    result.append(temp)
print(result)

print('====================================================================================================')
print('== 문제 14. 아래의 행렬식을 numpy 이용하지 않고 구현하시오!')
print('====================================================================================================\n')
a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]
result = []

for row_idx in range(len(a)):
    temp = []
    for col_idx in range(len(a[row_idx])):
        temp.append(a[row_idx][col_idx] * b[row_idx][col_idx])
    result.append(temp)
print(result)

print('====================================================================================================')
print('== 문제 15. 아래의 행렬 연산을 numpy 와 numpy 를 이용하지 않았을 때 2가지 방법으로 구현하시오!')
print('====================================================================================================\n')
a = [[10, 20], [30, 40]]
b = [[5, 6], [7, 8]]
result = []

for row_idx in range(len(a)):
    temp = []
    for col_idx in range(len(a[row_idx])):
        temp.append(a[row_idx][col_idx] - b[row_idx][col_idx])
    result.append(temp)
print(result)

print('====================================================================================================')
print('== 문제 16. numpy 의 broadcast 를 사용한 연산을 numpy 를 이용하지 않는 방법으로 구현하시오!')
print('====================================================================================================\n')
a = np.array([[1, 2], [3, 4]])
b = np.array([10, 20])
c = [[v[col_idx]*b[col_idx] for col_idx in range(len(v))] for v in a]
print(c)

# ■ matplotlib 사용법
import matplotlib.pyplot as plt
import numpy as np

t = np.arange(0, 12, 0.01)
print(t)

plt.figure()
plt.plot(t)
plt.show()

print('====================================================================================================')
print('== 문제 18. 위의 그래프에 x 축의 이름을 size 라고 하고 y 축의 이름을 cost 라고 하시오!')
print('====================================================================================================\n')
import matplotlib.pyplot as plt
import numpy as np

t = np.arange(0, 12, 0.01)
print(t)

plt.figure()
plt.plot(t)
plt.grid()
plt.xlabel('size')
plt.ylabel('cost')
plt.show()

print('====================================================================================================')
print('== 문제 19. 위의 그래프에 전체 제목을 size & cost 라고 하시오!')
print('====================================================================================================\n')
import matplotlib.pyplot as plt
import numpy as np

t = np.arange(0, 12, 0.01)
print(t)

plt.figure()
plt.plot(t)
plt.grid()
plt.xlabel('size')
plt.ylabel('cost')
plt.title('size & cost')
plt.show()

print('====================================================================================================')
print('== 문제 20. 아래의 numpy 배열로 산포도 그래프를 그리시오!')
print('====================================================================================================\n')
x = np.array([0,1,2,3,4,5,6,7,8,9])
y = np.array([9,8,7,9,8,3,2,4,3,4])
plt.figure()
plt.scatter(x, y)
plt.show()

print('====================================================================================================')
print('== 문제 21. 위의 그래프를 라인 그래프로 출력하시오!')
print('====================================================================================================\n')
x = np.array([0,1,2,3,4,5,6,7,8,9])
y = np.array([9,8,7,9,8,3,2,4,3,4])
plt.figure()
plt.plot(x, y)
plt.show()

print('====================================================================================================')
print('== 문제 22. 치킨집 년도별 창업건수를 가지고 라인 그래프를 그리시오.')
print('====================================================================================================\n')
start = np.loadtxt('D:\\KYH\\02.PYTHON\\PythonRepository\\DeepLearningClass\\chapter1\\data\\start.csv', skiprows=1, unpack=True, delimiter=',')
start_x = start[0]
start_y = start[4]
plt.figure(figsize=(6,4))
plt.plot(start_x, start_y)
plt.show()

print('====================================================================================================')
print('== 문제 23. 폐업건수도 위의 그래프에 겹치게 해서 출력하시오.')
print('====================================================================================================\n')
end = np.loadtxt('D:\\KYH\\02.PYTHON\\PythonRepository\\DeepLearningClass\\chapter1\\data\\end.csv', skiprows=1, unpack=True, delimiter=',')
end_x = end[0]
end_y = end[4]
plt.figure()
plt.plot(end_x, end_y, label='open')
plt.show()

print('====================================================================================================')
print('== 문제 24. 위의 그래프에 legend 도 출력하시오.')
print('====================================================================================================\n')
end = np.loadtxt('D:\\KYH\\02.PYTHON\\PythonRepository\\DeepLearningClass\\chapter1\\data\\end.csv', skiprows=1, unpack=True, delimiter=',')
end_x = end[0]
end_y = end[4]
plt.figure()
plt.plot(end_x, end_y, label='end')
plt.legend()
plt.show()

print('====================================================================================================')
print('== 문제 25. 책 44 페이지의 이미지 표시를 파이썬으로 구현하시오.')
print('====================================================================================================\n')
from matplotlib.image import imread
img = imread('data/lena.png')
plt.imshow(img)
plt.show()

print('====================================================================================================')
print('== 문제 26. 고양이 사진을 출력하시오.')
print('====================================================================================================\n')
from matplotlib.image import imread
img = imread('data/cat.png')
plt.imshow(img)
plt.show()


# -*- coding: utf-8 -*-
# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# Importing the dataset
from sklearn.datasets import load_iris
iris = load_iris()

from sklearn.cluster import DBSCAN
dbscan = DBSCAN()

print dbscan
"""
DBSCAN(eps=0.5, metric='euclidean', min_samples=5,
  random_state=111)
"""

dbscan.fit(iris.data)

dbscan.labels_

# Visualising the clusters
# as data is in 3d space, we need to apply PCA for 2d ploting
from sklearn.decomposition import PCA
pca = PCA(n_components=2).fit(iris.data)
pca_2d = pca.transform(iris.data)
explained_variance = pca.explained_variance_ratio_

df_pca =  pd.DataFrame(pca.components_,columns=iris.feature_names,index = ['PC-1','PC-2'])

"""
#alternative way, fit_transform
pca = PCA(n_components = 2)
pca_2d =  pca.fit_transform(iris.data)
"""
for i in range(0, pca_2d.shape[0]):
    if dbscan.labels_[i] == 0:
        c1 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='r', marker='+')
    elif dbscan.labels_[i] == 1:
        c2 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='g',
                        marker='o')
    elif dbscan.labels_[i] == -1:
        c3 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='b',
                        marker='*')

plt.legend([c1, c2, c3], ['Cluster 1', 'Cluster 2','Noise'])
plt.title('DBSCAN finds 2 clusters and noise')
plt.savefig("dbscan.jpg")
plt.show()

"""
plt.scatter(pca_2d[dbscan.labels_ == 0,0], pca_2d[dbscan.labels_ == 0,1],c='r', marker='+' )
plt.scatter(pca_2d[dbscan.labels_ == 1,0], pca_2d[dbscan.labels_ == 1,1],c='g', marker='o' )
plt.scatter(pca_2d[dbscan.labels_ == -1,0], pca_2d[dbscan.labels_ == -1,1],c='b', marker='*' )
"""

pca.components_

for i in range(0, pca_2d.shape[0]):
    if iris.target[i] == 0:
        c1 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='r', marker='+')
    elif iris.target[i] == 1:
        c2 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='g',
                        marker='o')
    elif iris.target[i] == 2:
        c3 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='b',
                        marker='*')

plt.legend([c1, c2, c3], ['Cluster 1', 'Cluster 2','Noise'])
plt.title('DBSCAN finds 2 clusters and noise')

plt.savefig("classifier.jpg")
plt.show()

# Using the elbow method to find the optimal number of clusters
from sklearn.cluster import KMeans
# Fitting K-Means to the dataset
kmeans = KMeans(n_clusters = 3, init = 'k-means++', random_state = 0)
y_kmeans = kmeans.fit_predict(iris.data)
for i in range(0, pca_2d.shape[0]):
    if y_kmeans[i] == 0:
        c1 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='r', marker='+')
    elif y_kmeans[i] == 1:
        c2 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='g',
                        marker='o')
    elif y_kmeans[i] == 2:
        c3 = plt.scatter(pca_2d[i,0],pca_2d[i,1],c='b',
                        marker='*')

plt.legend([c1, c2, c3], ['Cluster 1', 'Cluster 2','Noise'])
plt.title('DBSCAN finds 2 clusters and noise')
plt.savefig("kmeans.jpg")

plt.show()

"""
Very important about noise points
You can see that DBSCAN produced three groups.
Note, however, that the figure closely resembles a two-cluster
solution: It shows only 17 instances of label – 1.
That’s because it’s a two-cluster solution; the third group (–1)
 is noise (outliers). You can increase the distance parameter
 (eps) from the default setting of 0.5 to 0.9, and it will
 become a two-cluster solution with no noise.

The distance parameter is the maximum distance an
observation is to the nearest cluster. The greater the value
for the distance parameter, the fewer clusters are found
because clusters eventually merge into other clusters. The –1
labels are scattered around Cluster 1 and Cluster 2 in a few
locations:

Near the edges of Cluster 2 (Versicolor and Virginica classes)

Near the center of Cluster 2 (Versicolor and Virginica classes)

"""

"""
DBSCAN Details

https://towardsdatascience.com/how-dbscan-works-and-why-should-i-use-it-443b4a191c80

https://www.dummies.com/programming/big-data/data-science/how-to-create-an-unsupervised-learning-model-with-dbscan/
"""

"""
Animation
https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/
"""

"""
eps: if the eps value chosen is too small,
a large part of the data will not be clustered.
It will be considered outliers because don’t
satisfy the number of points to create a dense
region. On the other hand, if the value that was
chosen is too high, clusters will merge and the
majority of objects will be in the same cluster.
The eps should be chosen based on the distance of
the dataset (we can use a k-distance graph to find
it), but in general small eps values are preferable.

minPoints: As a general rule, a minimum
minPoints can be derived from a number of
dimensions (D) in the data set, as minPoints ≥ D + 1.
Larger values are usually better for data sets
with noise and will form more significant clusters.
The minimum value for the minPoints must be 3,
but the larger the data set, the larger the
minPoints value that should be chosen.
"""


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as pdates
import headers.linear_algebra_pack as lag
import headers.auxiliary_functions_pack as aux

def plot_matrix(matrix, title=""):
    plt.imshow(matrix)
    plt.title(title)
    plt.xticks([])  # nothing to show, only the matrix plots themselves => no specific axes ticks for matrices
    plt.yticks([])

def plot_contribution(spectrum):
    # spectrum_copy = np.insert(spectrum, 0, 0, axis=0)
    sum_spec = spectrum.sum()
    plt.plot(spectrum / sum_spec * 100, 'red', label='$\mathcal{R}(i)$', lw=2.5)
    plt.plot(spectrum.cumsum() / sum_spec * 100, 'firebrick', label='$\mathcal{C}(i)$', lw=2.5)
    plt.style.use('seaborn-talk')
    plt.title("Relative [$\mathcal{R}(i)$] and Cumulative [$\mathcal{C}(i)$] contributions [in %] of $\mathcal{W}_i$ to $\mathbf{X}$")
    plt.xlabel("$i$")
    plt.ylabel("Contribution, %")
    plt.xlim(0, 15)
    plt.xticks(range(1, 15))
    plt.legend()
    plt.show()

def full_svd_process_and_plot_snp500(date, np_time_series, string_period, num_of_ts='', plot=False):
    l, k, n = aux.get_LKN(np_time_series)
    x = np.arange(n)
    _X = lag.trajectory_matrix(np_time_series, l)
    u, v, s = lag.specific_singular_value_decomposition(_X)
    d = lag.rank(_X)
    a_span = lag.singular_elementary_decomposition(u, v, s, d)

    if plot:
        ''' 1st: plotting the time series itself '''
        figure, ax = plt.subplots()
        ax.plot(date.astype('datetime64',copy=False), np_time_series, lw=2.5)
        plt.legend([r"$\mathcal{F}_{%s}(x)$" % num_of_ts])
        plt.xlabel("$Dates$")
        plt.ylabel(r"$\mathcal{F}_{%s}(x)$" % num_of_ts)
        plt.title(r"Time series of S&P500* index ($\mathcal{F}_{%s}(x)$), period: %s (%s months)" % (num_of_ts, string_period, n))

        five_yr = pdates.YearLocator(5)
        ax.xaxis.set_major_locator(five_yr)

        one_yr = pdates.YearLocator(1)
        ax.xaxis.set_minor_locator(one_yr)

        ax.xaxis.set_major_formatter(pdates.DateFormatter('%Y-%m'))
        datemin = np.datetime64(date[0], 'M') - np.timedelta64(6, 'M')
        datemax = np.datetime64(date[len(date) - 1], 'M') + np.timedelta64(6, 'M')

        ax.set_xlim(datemin, datemax)
        ax.format_xdata = pdates.DateFormatter('%Y-%m')
        figure.autofmt_xdate()

        plt.show()

        ''' 2nd: plotting the trajectory matrix of $\mathcal{F}(x)$ '''
        figure = plt.matshow(_X)
        plt.xlabel(r"Column Vectors of $\mathbf{X}^{[%s]}$" % num_of_ts)
        plt.ylabel(r"Row Vectors of $\mathbf{X}^{[%s]}$" % num_of_ts)
        plt.colorbar(figure.colorbar, fraction=0.05)
        figure.colorbar.set_label(r"$\mathcal{F}_{%s}(x)$" % num_of_ts)
        plt.title(r"The Trajectory Matrix of $\mathcal{F}_{%s}(x)$" % num_of_ts)
        plt.show()

        ''' 3rd: plotting first 15 elementary matrices obdained by SVD of $\mathbf{X}$ '''
        if 15 <= d:
            for i in range(15):
                plt.subplot(3, 5, i + 1)
                title = r"$\mathcal{W}_{%s}^{[%s]}$" % (str(i), num_of_ts)
                plot_matrix(a_span[i], title)
            plt.tight_layout()
            plt.show()
        else:
            print("\n\nSorry, unable to print first 15 elementary matrices of X due to internal length-value error.\n\n")

        ''' 4th: plotting both relative and cumulative contribution of $$'''
        plot_contribution(s)

        ''' 5th: plotting the $w$-correlation matrix for the reconstructed diagonally averaged time series' components '''
        w_corr = lag.w_correlation_matrix(np_time_series, a_span)
        figure = plt.imshow(w_corr, cmap=plt.get_cmap('binary'))
        plt.xlabel(r"$\tilde{\mu}^{(i)}$")
        plt.ylabel(r"$\tilde{\mu}^{(j)}$")
        plt.colorbar(figure.colorbar, fraction=0.05)
        figure.colorbar.set_label(r"$\mathbb{W}^{[%s]}_{i,j}$" % num_of_ts)
        plt.clim(0, 1)
        plt.title(r"$w$-correlation matrix for projected groupings of $\tilde{\mu}^{(i,j)}$ (%s)" % string_period)
        plt.show()
    return a_span, x

def plot_ts_and_components(_range, list_of_specials, list_noisy, str_period, num_of_ts):
    figure, ax = plt.subplots()

    plt.xlabel("$Dates$")
    plt.ylabel(r"$\mathcal{F}_{%s}(x)$" % num_of_ts)
    plt.title(r"Time series of S&P500* index ($\mathcal{F}_{%s}(x)$) and its"
              r" components, period: %s (%s months)" % (num_of_ts, str_period, len(_range)))

    for plot_components, names in list_of_specials:
        ax.plot(_range.astype('datetime64',copy=False), plot_components, label=(names % num_of_ts), lw=2.5)
    ax.plot(_range.astype('datetime64',copy=False), list_noisy[0][0], color='red',
              label=(list_noisy[0][1] % num_of_ts), lw=2.5)
    ax.plot(_range.astype('datetime64',copy=False), list_noisy[1][0], color='black',
              label=(list_noisy[1][1] % num_of_ts), lw=2.5)

    plt.legend(loc=(0.98, 0.25), fancybox=True, shadow=True)
    five_yr = pdates.YearLocator(5)
    ax.xaxis.set_major_locator(five_yr)

    one_yr = pdates.YearLocator(1)
    ax.xaxis.set_minor_locator(one_yr)

    ax.xaxis.set_major_formatter(pdates.DateFormatter('%Y-%m'))
    datemin = np.datetime64(_range[0], 'M') - np.timedelta64(6, 'M')
    datemax = np.datetime64(_range[len(_range) - 1], 'M') + np.timedelta64(6, 'M')

    ax.set_xlim(datemin, datemax)
    ax.format_xdata = pdates.DateFormatter('%Y-%m')
    figure.autofmt_xdate()
    plt.show()

def plot_full_snp500(_range, list_of_specials_01, y_scale="linear"):
    figure, ax = plt.subplots()

    plt.xlabel("$Dates$")
    plt.ylabel(r"$\mathcal{F}(x)$")
    plt.title(r"Time series of S&P500* index ($\mathcal{F}(x)$) and its "
              r"roughly estimated elements, full period [1926-2018*]")
    plt.yscale(y_scale)

    flag = False
    for plot_components, names, colored, indicator in list_of_specials_01:
        if indicator:
            if colored != '':
                ax.plot(_range.astype('datetime64',copy=False), plot_components, color=colored, label=names, lw=2.5)
            else:
                ax.plot(_range.astype('datetime64',copy=False), plot_components, label=names, lw=2.5)
        flag |= indicator

    if flag:
        plt.legend(loc=(0, 0.25), fancybox=True, shadow=True)

        five_yr = pdates.YearLocator(5)
        ax.xaxis.set_major_locator(five_yr)

        one_yr = pdates.YearLocator(1)
        ax.xaxis.set_minor_locator(one_yr)

        ax.xaxis.set_major_formatter(pdates.DateFormatter('%Y-%m'))
        datemin = np.datetime64(_range[0], 'M') - np.timedelta64(6, 'M')
        datemax = np.datetime64(_range[len(_range) - 1], 'M') + np.timedelta64(6, 'M')

        ax.set_xlim(datemin, datemax)
        ax.format_xdata = pdates.DateFormatter('%Y-%m')
        figure.autofmt_xdate()

        plt.show()
    else:
        print("\n\nSorry, nothing to print.\n\n")

### Checks ###

def main():
    # TODO: play - use some data with my functions, with accordance to their definition.
    pass

if __name__ == "__main__":
    main()


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from scipy.stats import norm
import statsmodels.api as sm
from statsmodels.stats.stattools import durbin_watson
from statsmodels.sandbox.regression.predstd import wls_prediction_std
from sklearn.metrics import mean_squared_error, r2_score

def mult_normality(data, cols, method='shapiro', hist=True, qq=True, prt=False):
    table = None
    res = []
    for col in cols:
        X = data[col]
        tst = test()
        if hist:
            hist_name = 'Distribution of '+col

        tst.sgl_normality(X=X, method=method, hist=hist, qq=qq, prt=prt)
        res.append(tst.res)

        if method == 'anderson':
            tmp_table = tst.table
            tmp_table.index = [col +"_"+ c for c in tmp_table.index]
            table = pd.concat([table,tmp_table],axis=0)
        elif method == 'shapiro':
            tmp_table = tst.table
            tmp_table.index = [col]
            table = pd.concat([table,tmp_table],axis=0)
        elif method == 'kolmogorov':
            tmp_table = tst.table
            tmp_table.index = [col]
            table = pd.concat([table,tmp_table],axis=0)

    tst = test()
    tst.res = res
    tst.table = table

    return tst

class test:
    def __init__(self):
        self.res = None
        self.type = None
        self.table = None

    # test normality of one single sample
    def sgl_normality(self, X, method='shapiro', hist_name=None, hist=True, qq=True, prt=True):
        self.type = 'normality test'

        # plot the distribution if hist==True
        if hist:
            plt.figure(figsize=(8, 6), dpi=100)
            if hist_name is not None:
                plt.title(hist_name)
            sns.distplot(X, rug=False, hist=True, kde=True, label = 'Sample distribution')
            support = np.linspace(min(X), max(X), num=100)
            dens = norm.pdf(support, loc=np.mean(X), scale=np.std(X))
            sns.lineplot(support, dens, label='Gaussian with sample mean and std')

        # plot the qq-plot
        if qq:
            plt.figure(figsize=(8, 6), dpi=100)
            stats.probplot(X, plot=sns.mpl.pyplot)

        # normality test
        if method == 'anderson':
            # anderson test
            # return decisions for different significance levels
            self.res = stats.anderson(X, dist='norm')
            self.table = pd.DataFrame(np.concatenate(([self.res.significance_level],
                                                 [self.res.critical_values],[self.res.critical_values]),axis=0))
            self.table.index = ['sig_level','crit_vals','decision']
            #print("ad_stat:", res.statistic)
            self.table.loc['decision'] = (self.table.loc['crit_vals']<self.res.statistic)
            self.table.loc['decision'] = self.table.loc['decision'].apply(lambda x: 'Rej' if x else 'no Rej')

        if method == 'shapiro':
            # shapiro test
            self.res = stats.shapiro(X)
            self.table = pd.DataFrame([['{:.4e}'.format(float(self.res[0])),'{:.4e}'.format(float(self.res[1]))]])
            self.table.columns = ['test stat','p-value']
            if prt:
                print("Shapiro test statistic:",'{:.4e}'.format(float(self.res[0])) )
                print("Shapiro test p-value:",'{:.4e}'.format(float(self.res[1])) )

        if method == 'kolmogorov':
            # Kolmogorov-Smirnov test
            self.res = stats.kstest(X, 'norm')
            self.table = pd.DataFrame([['{:.4e}'.format(float(self.res[0])),'{:.4e}'.format(float(self.res[1])) ]])
            self.table.columns = ['test stat','p-value']
            if prt:
                print("Kolmogorov-Smirnov test statistic:",'{:.4e}'.format(float(self.res[0])) )
                print("Kolmogorov-Smirnov test p-value:",'{:.4e}'.format(float(self.res[1])) )

    # 1-sample t tests whether mean is mu, requires normality
    # but if sample size > 15, robust
    # or use Wilcoxon Test by setting normality=False
    # data is a dataframe, cols indicating which columns to test
    # mu is the target mean array
    def t_1sample(self, data, cols, mu, normality=True):
        self.type = 'one-sample t test'

        if normality:
            # usual t-test
            self.res = stats.ttest_1samp(data[cols], mu)
            self.table = pd.concat((pd.DataFrame(['{:.4e}'.format(float(c)) for c in self.res[0]]),
                                    pd.DataFrame(['{:.4e}'.format(float(c)) for c in self.res[1]])),axis=1)
            self.table.columns = ['test stat','p-value']
            self.table.index = cols
        else:
            # wilcoxon t-test
            self.res = []
            for i in range(len(mu)):
                x = data[cols[i]]
                tmp_res = stats.wilcoxon(x - mu[i])
                self.res.append(tmp_res)
                tmp_table = pd.DataFrame(['{:.4e}'.format(tmp_res[0]),'{:.4e}'.format(tmp_res[1])]).transpose()
                self.table = pd.concat((self.table,tmp_table),axis=0)
            self.table.columns = ['test stat','p-value']
            self.table.index = cols

    # test whether group 1 and 2 has different mean
    # perform welch-t if normality == False
    # plot violin plot of two samples if plot == True
    # print results if prt == True
    def t_2sample(self, gp1, gp2, normality=True, plot=True, prt=True, sig_level=0.05):
        self.type = '2-sample t test'
        self.res = stats.ttest_ind(gp1, gp2, equal_var=normality, nan_policy='omit')
        table = pd.DataFrame(['{:.4e}'.format(float(c)) for c in self.res]).transpose()
        table.columns = ['test stat', 'p-value']
        self.table = table
        reject = False
        if self.res[1] < sig_level:
            reject = True

        if prt:
            print("2-sample test statistic: ",'{:.4e}'.format(float(self.res[0])))
            print("2-sample test p-value: ",'{:.4e}'.format(float(self.res[1])))
            if reject:
                print("have confidence to assert the groups have different means at significant level",sig_level)
            else:
                print("have no evidence to say the groups have different means at significant level",sig_level)

        if plot:
            gp = pd.DataFrame({'group1':list(X.iloc[0:100]),
                   'group2':list(X.iloc[100:200])})
            gpp = gp.melt().assign(x='vars')
            plt.figure(figsize=(8, 6), dpi=100)
            plt.title('violin plot of two groups')
            sns.violinplot(data=gpp, x='x', y='value',
                           hue='variable', split=True, inner='quart')

    # test H0: submodel (with p features in cols1)
    #   vs H1: full model (q>p features in col2) in linear regression
    # calculate the residuals of the two Rsub, Rful (Rsub >= Rful)
    # under H0, (Rsub-Rful)/Rful * n-q/q-p ~ F_q-p,n-q
    def full_model_test(self, data, y, cols1, cols2, add_const=True, summary = False, prt = True, sig_lev = 0.05):
        if add_const:
            subX_ = sm.add_constant(data[cols1])
            fulX_ = sm.add_constant(data[cols2])
        n = len(y)
        p = len(cols1) + 1
        q = len(cols2) + 1
        submd = sm.OLS(y.values, np.asarray(subX_))
        fulmd = sm.OLS(y.values, np.asarray(fulX_))
        subres = submd.fit()
        fulres = fulmd.fit()
        self.res = [subres, fulres]

        if summary:
            print("summary of submodel:")
            print(subres.summary()) # Robusted Results
            print("summary of fullmodel:")
            print(fulres.summary())

        sub_resid = np.sum(subres.resid**2)
        ful_resid = np.sum(fulres.resid**2)
        F_stat = ((sub_resid-ful_resid)/(q-p)) / (ful_resid/(n-q))
        p_val = 1 - stats.f.cdf(F_stat, q-p, n-q)

        table = pd.DataFrame({"F_stat":['{:.4e}'.format(float(F_stat))], "p_value":['{:.4e}'.format(float(p_val))]})
        self.table = table

        if prt:
            print("F-test statistic is", '{:.4e}'.format(float(F_stat)))
            print("F-test has df",q-p,",",n-q)
            print("p-value is", '{:.4e}'.format(float(p_val)))
            if p_val > sig_lev:
                print("under significance level",sig_lev,"cannot say submodel is not sufficient")
            else: #reject H0
                print("under significance level",sig_lev,"can say submodel is not sufficient")

import numpy,from scipy,import statsmodels,from statsmodels


"""

References:

- https://web.stanford.edu/~lmackey/stats306b/doc/stats306b-spring14-lecture13_scribed.pdf

"""

import numpy as np
from scipy import linalg

def _center(X, Y, Xmean, Ymean):
    X, Y = X.copy(), Y.copy()
    X = X - Xmean
    Y = Y - Ymean
    return X, Y

class CCA:

    def __init__(self):
        pass

    def fit(self, X, Y, n_components, regfactor, center=False, regscaled=False):

        N = X.shape[0]
        assert Y.shape[0] == N

        self._center = center
        if center:
            self._Xmean = X.mean(axis=0)
            self._Ymean = Y.mean(axis=0)
            X, Y = _center(X, Y, self._Xmean, self._Ymean)

        Cxy = X.T.dot(Y)
        Cyx = Y.T.dot(X)
        Cxx = X.T.dot(X)
        Cyy = Y.T.dot(Y)

        # regularize
        if regscaled:
            xscale = linalg.eigh((Cxx.T + Cxx) / 2)[0][-1]
            yscale = linalg.eigh((Cyy.T + Cyy) / 2)[0][-1]
            Cxx += np.eye(Cxx.shape[0]) * xscale * regfactor
            Cyy += np.eye(Cyy.shape[0]) * yscale * regfactor
        else:
            Cxx += regfactor * np.eye(Cxx.shape[0])
            Cyy += regfactor * np.eye(Cyy.shape[0])

        # construct eigenvalue problem
        rhs = linalg.block_diag(Cxx, Cyy)
        lhs = np.zeros(rhs.shape)
        lhs[:Cxy.shape[0], Cyx.shape[1]:] = Cxy
        lhs[Cxy.shape[0]:, :Cyx.shape[1]] = Cyx

        max_components = lhs.shape[0]
        assert n_components <= max_components

        # symmetrize
        rhs = (rhs + rhs.T) / 2.0
        lhs = (lhs + lhs.T) / 2.0

        r, Ev = linalg.eigh(
            lhs, rhs, eigvals=(max_components - n_components, max_components - 1))

        U, V = Ev[:X.shape[1]], Ev[X.shape[1]:]

        self.U = U
        self.V = V
        self.r = r

        return self

    def predict(self, X, Y, scale_by_eigs=False, norm=False):

        if self._center:
            X, Y = _center(X, Y, self._Xmean, self._Ymean)

        X_c, Y_c = X.dot(self.U), Y.dot(self.V)

        if scale_by_eigs:
            X_c, Y_c = X_c * self.r, Y_c * self.r

        if norm:
            X_c, Y_c = X_c / np.sum(np.square(X_c), axis=0), Y_c / np.sum(np.square(Y_c), axis=0)

        return X_c, Y_c


"""Kernel functions"""

import logging
import numpy as np

def rbf_kernel(x, x_prime, sigma=1.0, theta=1.0):
    """Radial Basis function kernel

    Parameters
    ----------
    x: ndarray
        vector of x points
    x_prime: ndarray
        vector of x points
    sigma: float
        variance
    theta: float
        modulation factor

    Returns
    -------
    ndarray
        RBF result on the given points.

    """
    # TODO: Investigate why this gives different results than the scalar version
    if not isinstance(x, (np.ndarray, np.generic)):
        logging.warning("[rbf_kernel] x is not a numpy object: type={}".format(type(x)))

    if not isinstance(x_prime, (np.ndarray, np.generic)):
        logging.warning("[rbf_kernel] x is not a numpy object: type={}".format(type(x_prime)))

    x_list = [x, x_prime]
    for i, x_ in enumerate(x_list):
        # Convert scalars to 1x1 matrices
        if np.isscalar(x_):
            x_list[i] = np.array([[x_]])
        elif x_.shape == (1,):
            x_list[i] = np.array([x_])
        # Convert N vectors to Nx1 matrices
        elif len(x_.shape) == 1:
            x_list[i] = x.reshape((-1, 1))
    x, x_prime = x_list

    # logging.debug("[rbf_kernel_matrix] x shape: {}".format(x.shape))
    # logging.debug("[rbf_kernel_matrix] x: {}".format(x))
    # logging.debug("[rbf_kernel_matrix] x_prime shape: {}".format(x_prime.shape))

    square_distance = np.sum(x ** 2, 1).reshape(-1, 1) + np.sum(x_prime ** 2, 1) - 2 * np.dot(x, x_prime.T)
    # logging.info("[rbf_kernel_matrix] square_distance shape: {}".format(square_distance.shape))
    return sigma * np.exp(-square_distance / (2 * theta))