import numpy as np
import collections

class K_Means:

    def __init__(self, k=2, tol = 0.001, max_iter = 300):
        self.k = k
        self.tol = tol
        self.max_iter = max_iter

    def fit(self,data):

        self.centroids = {}
        for i in range(self.k):
            self.centroids[i] = data[i]

        for i in range(self.max_iter):
            self.classification = collections.defaultdict(list)

            for featureset in data:
                distances = [np.linalg.norm(featureset - self.centroids[c]) for c in self.centroids]
                classification = distances.index(min(distances))
                self.classification[classification].append(featureset)

            prev = dict(self.centroids)

            for classification in self.classification:
                self.centroids[classification] = np.average(self.classification[classification], axis = 0)

            optimized = True

            for c in self.centroids:
                original_centroid = prev[c]
                current_centroid = self.centroids[c]
                if np.sum((current_centroid-original_centroid)/original_centroid*100.0) > self.tol:
                    optimized = False
            if optimized:
                break

    def predict(self,x):
        distances = [np.linalg.norm(x-self.centroids[centroid]) for centroid in self.centroids]
        classification = distances.index(min(distances))
        return classification

# def distEclud(vecA,vecB):
#     return np.sqrt(np.sum(np.power(vecA-vecB,2)))
#
# def randCent(dataset,k):
#     n = dataset.shape[1]
#     centroids = np.mat(np.zeros((k,n)))
#     for i in range(n):
#         minI = min(dataset[:,i])
#         rangeI = np.float(max(dataset[:,i]) - minI)
#         centroids[:,i] = minI + rangeI*np.random.rand(k,1)
#     return centroids
#
# def kMeans(dataset, k, distMeans = distEclud, createCent = randCent):
#     m = dataset.shape[0]
#     clusterAssment = np.mat(np.zeros((m,2))) # index of cluster, distance
#     centroids = createCent(dataset,k)
#     clusterChanged = True
#     while clusterChanged:
#         clusterChanged = False
#         for i in range(m):
#             minDist = float('-inf')
#             minIndex = -1
#             for j in range(k):
#                 distJI = distMeans(centroids[j,:], dataset[i,:])
#                 if distJI < minDist:
#                     minDist = distJI
#                     minIndex = j
#             if clusterAssment[i,0] != minIndex:
#                 clusterChanged = True
#         for cent in range(k):
#             ptsInClust = dataset[np.nonzero(clusterAssment[:,0]==cent)]
#             centroids[cent,:] = np.mean(ptsInClust, axis=0)
#     return centroids, clusterAssment


from scipy.stats import norm, poisson
import numpy as np

def weiner_process(m, N, t0, T):
	"""
	Function for modelling a Weiner process

		Parameters:

			m (int): number of sample paths
			N (int): number of approximation points
			t0 (float): simulation start time
			T (float): simulation end time

		Returns:

			trajectories (numpy.ndarray): a matrix with m lines and N columns where each line corresponds to a different
			sample path of a Weiner process from t0 to T, approximated at N points
			time (numpy.ndarray): an array equal to numpy.linspace(t0, T, N)
	"""

	dt = (T - t0) / (N - 1)
	trajectories = np.zeros((m, N))

	distr = norm(0, 1)

	for j in range(1, N):
		trajectories[:, j] = trajectories[:, j-1] + distr.rvs(size=m) * np.sqrt(dt)

	time = np.linspace(t0, T, N)
	return time, trajectories

def brownian_bridge(existent_points, new_time_points):
	"""
	Function for adding new approximation points to existing trajectory via the brownian bridge

		Parameters:

			existent_points (2-dim matrix (list or numpy.ndarray)): a matrix with the first line corresponding to
			time points and the second line corresponding to the process values at these time points
			new_time_points (iterable): list of new approximation points

		Returns:

			Two-dimensional numpy.ndarray with the first line corresponding to both existing and added time points
			and the second line corresponding to the process values at these time points
	"""
	if isinstance(existent_points, list):
		existent_points = np.array(existent_points)

	ep = existent_points[:, existent_points[0].argsort()]  # just in case
	new_time_points.sort()

	tn = ep[0][-1]
	for t in new_time_points:
		if t > tn:
			# append this point using the Weiner process definition

			Wtn = ep[1][-1]

			xi = norm(0, t - tn).rvs()
			Wt = Wtn + xi

			ep = np.c_[ep, [t, Wt]]
			tn = t
		else:
			# construct Brownian Bridge between a = W(t_{i - 1}) and b = W(t_i)

			i = np.searchsorted(ep[0], t)

			t1 = ep[0][i - 1]
			t2 = ep[0][i]

			if t == t1 or t == t2:
				continue

			a = ep[1][i - 1]
			b = ep[1][i]

			mu = a + (b - a) * (t - t1) / (t2 - t1)
			sigma = (t - t1) * (t2 - t) / (t2 - t1)

			Wt = norm(mu, sigma).rvs()

			ep = np.c_[ep[:, :i], [t, Wt], ep[:, i:]]

	return ep

def poisson_process(m, N, t0, T, lam):
	"""
	Function for modelling a Poisson process

		Parameters:

			m (int): number of sample paths
			N (int): number of approximation points
			t0 (float): simulation start time
			T (float): simulation end time
			lam (float): lambda parameter for Poisson process. Should be > 0

		Returns:

			time (numpy.ndarray): an array equal to numpy.linspace(t0, T, N)
			trajectories (numpy.ndarray): a matrix with m lines and N columns where each line corresponds to a different
			sample path of a Poisson process from t0 to T, approximated at N points

	"""
	dt = (T - t0) / N
	trajectories = np.zeros((m, N))

	p = poisson(dt * lam)

	for j in range(1, N):
		trajectories[:, j] = trajectories[:, j-1] + p.rvs(size=m)

	time = np.linspace(t0, T, N)
	return time, trajectories

def _ito_integration(f, a, b, k=2, step=0.1, m=1000):
	"""
	Function for modelling Ito's integrals and approximate calculation of its expectations

		Parameters:

			f (callable): integrand
			a (float): lower integration limit
			b (float): upper integration limit
			k (int): order of expectation
			step (float): integration step
			m (int): number of sample paths in Monte-Carlo simulation

		Returns:

			approximate value of k-th order expectation and matrix of sample paths
	"""
	n = int((b - a) / step)  # number of intervals
	t = np.linspace(a, b, n+1)

	_, trajectories = weiner_process(m, n+1, a, b)
	F = np.zeros((m, n))  # matrix of function values

	for i in range(m):
		F[i] = f(t[:-1], trajectories[i][:-1])

	I_f = np.zeros((m, n))
	for i in range(n):
		I_f[:, i] = F[:, i] * (trajectories[:, i + 1] - trajectories[:, i])

	return (I_f.sum(axis=1) ** k).sum() / m, trajectories

def ito_int_expect(f, a, b, k=2, step=0.1, m=1000):
	"""
	Returns approximate value of k-th order expectation of Ito's integral f(t, W(t))dW from a to b
	calculated using Monte-Carlo simulation.

		Parameters:

			f (callable): integrand
			a (float): lower integration limit
			b (float): upper integration limit
			k (int): order of expectation
			step (float): integration step
			m (int): number of sample paths in Monte-Carlo simulation

		Returns:

			expect(float): approximate value of k-th order expectation
	"""
	expect, _ = _ito_integration(f, a, b, k=k, step=step, m=m)
	return expect

def ito_int_paths(f, a, b, step=0.1, m=1000):
	"""
	Returns sample paths of Ito's integral f(t, W(t))dW

		Parameters:

			f (callable): integrand
			a (float): lower integration limit
			b (float): upper integration limit
			step (float): integration step
			m (int): number of sample paths to generate

		Returns:

			expect(float): array of time points and a matrix in which each line corres
	"""
	_, paths = _ito_integration(f, a, b, k=1, step=step, m=m)
	time = np.arange(a, b+step, step)
	return time, paths

def sde(dy, y0, t, step, nsamp=1000, method='euler'):
	"""
	Solves Ito's stochastic differential equations of the form "dy = f*dt + g*dW"
	using Monte-Carlo simulation and Milstein or Euler's method

		Parameters:

			dy (callable): function for calculation of dy; should take 3 arguments corresponding to y, dt and dW
			and return tuple with values of f and g for Euler's method or values of f, g, and partial derivative
			dg/dy for Milstein's method
			y0 (float): initial condition
			t (tuple <float, float>): starting and final time of the solution
			step (float): integration step
			nsamp (int), optional: number of sample paths used in Monte-Carlo simulation; default 1000
			method (str), optional: numerical method; either 'milstein' or 'euler' (default);
			Milstein's method is more precise, but requires additional derivation

		Returns:

			time: 1d numpy.ndarray with time points of approximation
			paths: matrix in which each row corresponds to a different solution sample path
	"""

	n = norm(0, step)
	N = int((t[1] - t[0]) / step)  # number of intervals

	paths = np.zeros((nsamp, N + 1))
	if method == 'euler':
		for j in range(nsamp):
			y = np.zeros(N + 1)
			y[0] = y0
			W = n.rvs(size=N)
			for i in range(N):
				f, g = dy(y[i], step, W[i])
				y[i + 1] = y[i] + f * step + g * W[i]
			paths[j] = y

	elif method == 'milstein':
		for j in range(nsamp):
			y = np.zeros(N + 1)
			y[0] = y0
			W = n.rvs(size=N)
			for i in range(N):
				f, g, dgdx = dy(y[i], step, W[i])
				y[i + 1] = y[i] + f * step + g * W[i] + 1 / 2 * g * dgdx * (W[i] - step) ** 2
			paths[j] = y
	time = np.arange(t[0], t[1] + step, step)
	return time, paths


import numpy as np

def euclidean_distance(features_1, features_2):
    dis = np.sqrt(np.sum(np.square(features_1 - features_2)))
    return dis

def cos_distance(features_1, features_2):
    dis = np.dot(features_1, features_2) / (np.linalg.norm(features_1) * (np.linalg.norm(features_2)))
    return dis

def pearson_correlation(features_1, features_2):
    features_1_ = features_1 - np.mean(features_1)
    features_2_ = features_2 - np.mean(features_2)
    dis = cos_distance(features_1_, features_2_)
    return dis

if __name__ == '__main__':
    a = np.array([1, 2, 3])
    b = np.array([5, 6, 7])
    print(np.dot(a, b))


import cv2
import numpy as np

def get_gaussian_kernel_2D(ksize, sigma):

    gaussian_kernel = np.zeros((ksize, ksize))
    offset = int(ksize / 2)
    for i in range(-offset, offset + 1):
        for j in range(-offset, offset + 1):
            gaussian_kernel[i + offset][j + offset] = np.exp(-(i ** 2 + j ** 2) / (2 * sigma ** 2)) / (2 * np.pi * sigma ** 2)
    gaussian_kernel = gaussian_kernel / np.sum(gaussian_kernel)

    return gaussian_kernel

def get_Rscore_matrix(image,window_size,ksize,k,gaussian_weights=False,std=1):
    """

    """
    gaussian_kernel = get_gaussian_kernel_2D(window_size,std)
    #Gradient using sobel operator
    sx = cv2.Sobel(image,cv2.CV_64F,1,0,ksize = ksize)
    sy = cv2.Sobel(image,cv2.CV_64F,0,1,ksize = ksize)

    Ixx = sx**2
    Iyy = sy**2
    Ixy = sx*sy

    R_score_matrix = np.zeros(image.shape)
    rows,cols = image.shape

    offset = window_size/2

    corner_count = 0
    for i in range(offset,rows-offset):
        for j in range(offset,cols-offset):

            xx_window = Ixx[i-offset:i+offset+1,j-offset:j+offset+1]
            yy_window = Iyy[i-offset:i+offset+1,j-offset:j+offset+1]
            xy_window = Ixy[i-offset:i+offset+1,j-offset:j+offset+1]

            if gaussian_weights:
                xx_window = xx_window*gaussian_kernel
                yy_window = yy_window*gaussian_kernel
                xy_window = xy_window*gaussian_kernel

            sum_xx = np.sum(xx_window)
            sum_yy = np.sum(yy_window)
            sum_xy = np.sum(xy_window)

            det_window = sum_xx*sum_yy - sum_xy*sum_xy
            trace_window = sum_xx + sum_yy

            R_score = det_window - k*trace_window*trace_window

            R_score_matrix[i][j] = R_score

    return R_score_matrix

def mark_corner_points(image,window_size,ksize,k,gaussian_weights=False,std=1):
    """
    Return image with corner points marked and a list of corners
    """

    new_image = image.copy()
    new_image = cv2.cvtColor(new_image,cv2.COLOR_GRAY2RGB)

    R_score_matrix = get_Rscore_matrix(image,window_size,ksize,k,gaussian_weights,std)

    corner_flag_matrix = np.zeros(image.shape)
    corner_count = 0

    threshold = 0.005*np.max(R_score_matrix)

    offset = window_size/2
    rows,cols = image.shape

    for i in range(offset,rows-offset):
        for j in range(offset,cols-offset):

            if R_score_matrix[i][j] >= threshold:
                flag = True
                try:
                    if R_score_matrix[i][j] == np.max(R_score_matrix[i-5:i+5,j-5:j+5]):
                        corner_count += 1
                        corner_flag_matrix[i][j] = 1
                        cv2.circle(new_image,(int(j),int(i)),4,(0,0,255),1)
                except ValueError:
                        pass

    print corner_count
    return new_image,corner_flag_matrix


#!/usr/bin/python3

# MIT License
#
# Copyright (c) 2021 Mario Blanco Dominguez, Juan Tecedor
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import numpy as np
import matplotlib.pyplot as plt
from pandas.io.parsers import read_csv
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter

def getMat(file_name):
    return read_csv(file_name, header=None).to_numpy().astype(float)

# Prediction of the value y. In this case using linear regression.
def hypothesis(X, theta_0, theta_1):
    return X * theta_1 + theta_0

# Cost function J(theta), measures how good are our guesses
def cost(X, Y, theta_0, theta_1):
    return (1 / (2 * len(X))) * (((hypothesis(X, theta_0, theta_1) - Y)**2).sum())

def gradientDescent(X, Y, iterations, alpha):
    theta_0 = theta_1 = 0
    costs = []

    for i in range(iterations):
        H = hypothesis(X, theta_0, theta_1)
        temp_0 = theta_0 - (alpha / len(X)) * (H - Y).sum()
        temp_1 = theta_1 - (alpha / len(X)) * ((H - Y) * X).sum()
        theta_0 = temp_0
        theta_1 = temp_1
        costs.append(cost(X, Y, theta_0, theta_1))

    plt.suptitle('Cost')
    plt.xlabel('Iterations')
    plt.ylabel('J(theta)')
    plt.plot(np.arange(0, iterations), costs)
    plt.savefig('costs.png')
    plt.show()
    return theta_0, theta_1

def plot_surfaces(theta_0_, theta_1_, theta_0_range, theta_1_range, X, Y):
    step = .1
    theta_0 = np.arange(theta_0_range[0], theta_0_range[1], step)
    theta_1 = np.arange(theta_1_range[0], theta_1_range[1], step)
    theta_0, theta_1 = np.meshgrid(theta_0, theta_1)
    Cost = np.empty_like(theta_0)
    for i_x, i_y in np.ndindex(theta_0.shape):
        Cost[i_x, i_y] = cost(X, Y, theta_0[i_x, i_y], theta_1[i_x, i_y])

    fig = plt.figure()
    ax = Axes3D(fig)
    ax.plot_surface(theta_0, theta_1, Cost, cmap=cm.coolwarm)
    plt.show()

    plt.contour(theta_0, theta_1, Cost, np.logspace(-2, 3, 20), colors='red')
    plt.scatter(theta_0_, theta_1_)
    plt.show()

def main():
    data = getMat('./ex1data1.csv')
    X = data[:, 0]
    Y = data[:, 1]
    alpha = 0.01
    iterations = 1500

    theta_0, theta_1 = gradientDescent(X, Y, iterations, alpha)
    x = np.linspace(min(X), max(X), 100)
    y = theta_0 + theta_1 * x

    plt.suptitle('Result')
    plt.xlabel('City population in 10k\'s')
    plt.ylabel('Income in 10k\'s')
    plt.plot(X, Y, 'x')
    plt.plot(x, y, label=('y = ' + str(theta_1) + 'x + ' + str(theta_0)))
    plt.legend()
    plt.savefig('result.png')
    plt.show()

    plot_surfaces(theta_0, theta_1, [-10, 10], [-1, 4], X, Y)

main()


import numpy as np
import math
import tarfile
import pandas as pd

small_graph = np.array([[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                     [1,0,0,0,0,0,0,0,0,0,0,0],
                     [0,1,0,0,0,0,0,0,0,0,0,0],
                     [0,0,0,0,0.5,0.5,0,0,0,0,0,0],
                     [0,0,0,0.5,0,0.5,0,0,0,0,0,0],
                     [0,0,0,0,1,0,0,0,0,0,0,0],
                     [0,0,0,0,0.5,0.5,0,0,0,0,0,0],
                     [0,0,0,0,0,0.5,0.5,0,0,0,0,0],
                     [0,0,1.0/3,0,0,0,0,1.0/3,0,0,0,1.0/3],
                     [0,0,0,0,0,0,0,0.5,0.5,0,0,0],
                     [0,0,0,0,0,0,0,0.5,0,0.5,0,0],
                     [0,0,0,0,0,0,0,0.5,0.5,0,0,0]])

alpha = 0.85 #damping factor
eps = 10

# open compressed p2p_gnut archive

comp_gnut = tarfile.open('p2p_gnut.tar.gz')
uncomp_gnut = comp_gnut.extractall()
comp_gnut.close()

# load p2p_gnut graph into panda dataframe then numpy array

#df_gnut = pd.read_csv('p2p_gnut.csv', header=None)

#p2p_gnut_graph = df_gnut.iloc[:,:].values

def maxnorm(x):
    norm = 0
    for i in range(len(x)):
        if (abs(x[i]) > norm):
            norm = abs(x[i])
    return norm

def maxnormdiffer(x1, x2):
    norm = 0
    for i in range(len(x1)):
        if (abs(x1[i]-x2[i]) > norm):
            norm = abs(x1[i]-x2[i])
    return norm

def euclnorm(x):
    norm = 0
    for i in range(len(x)):
        norm += abs(x[i])**(2)
    return math.sqrt(norm)

def phi(x, M):
    x1 = []
    for i in range(len(x)):
        x1.append((M*(np.matrix(x).T)).getA1()[i]-x[i])
    return (euclnorm(x1)+eps*euclnorm(x))

def pagerank (M):
    """
    The function gets a contingency matrix of a graph and computes the pagerank score with alpha = 0.85
    It implements an iterative approach and also returns the arrays of deviations
    from the optimum on every step to evaluate the rate of convergence
    args:
        M - contingency matrix of a graph, scaled to be a probabilistic matrix (numpy nxn array)
    return (weights, conv_func, conv_norm)
        weights - pagerank scores (numpy n*1 vector)
        conv_func - numpy vector with deviations from the optimum, described in terms of target function
        conv_norm - numpy vector with deviations from the optimum, described in terms of norm (euklid?)
    """

    n = len(M)

    v = [] #personalization vector
    for i in range(n):
        v.append(1/n)

    d = []#dangling nodes column
    for i in range(n):
        iszero = 1
        for j in range(n):
            if (M[i, j] != 0): iszero = 0
        d.append(iszero)
    d = np.matrix(d).T

    M = M + d*v #matrix with fixed dangling nodes

    M = M.T

    weights = []
    conv_func = np.array([]) #if it is more convenient to you, you can use simple python list here

    n = len(M)

    e = [1/n for i in range(n)]
    e = np.matrix(e).T

    x = []#iterations to optimum
    conv_norm = []#deviations from optimum
    x.append(e)
    k = 1

    x_new = (1-1/(k+1))*M*x[k-1] + (1/(k+1))*e
    x.append(x_new)
    k+=1

    while(1):
        x_new = (1-1/(k+1))*M*x[k-1] + (1/(k+1))*e
        x.append(x_new)
        k+=1
        if (k > 10**(2)): break

    for i in range(0, k-1):
        conv_norm.append(maxnormdiffer(x[k-1].getA1(), x[i].getA1()))

    weights = x[k-1].getA1()

    return (weights, conv_norm)

print(pagerank(small_graph)[0])

#v = pagerank(small_graph)
#np.savetxt('5PagerankSmall,eps=10,iter=100.txt', v[0], delimiter=" ")
#np.savetxt('5Conv,eps=10,iter=100.txt', v[1], delimiter=" ")

#f = open('test.txt', 'r')
#print(f.read())


import math
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import scipy
from  scipy.stats import linregress as lin
from scipy.optimize import curve_fit as fit
from scipy.integrate import quad
x = [ 1.,   1.5,  2.,   2.5,  3.,   3.5,  4.,   4.5,  5.,   5.5,  6.,   6.5,  7.,   7.5, 8.,   8.5,  9.,   9.5, 10. ]
y = [3.43, 4.94, 6.45, 9.22, 6.32, 6.11, 4.63, 8.95, 7.8, 8.35, 11.45, 14.71, 11.97, 12.46, 17.42, 17.0, 15.45, 19.15, 20.86]
"""Linera regression"""
slope, intercept, r_value, p_value, std_err = lin(x,y)
"""apparently a float conversion is needed to avoid numpy errors"""
x=np.float64(x)
LinFit=x*slope+intercept
"""Cube fitting"""
def CubeFun(x,a,b,c,d):
   return a*(x**3)+b*(x**2)+c*x+d
params, params_covariance=fit(CubeFun,x,y)
CubeFit=CubeFun(x,*params)
"""integration"""
A=quad(lambda x:CubeFun(x,*params),min(x),max(x))
"""BIC calculation"""
def BIC(y, yhat, k, weight = 1):
    err = y - yhat
    sigma = np.std(np.real(err))
    n = len(y)
    B = n*np.log(sigma**2) + weight*k*np.log(n)
    return B
LineError=BIC(y,LinFit,2)
CubeError=BIC(y,CubeFit,4)
LineError=round(LineError,2)
CubeError=round(CubeError,2)

"""plotting of data"""
Fig=plt.figure()

axes = Fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
plt.xticks(np.arange(int(min(x)-2), int(max(x)+2), 2))
plt.yticks(np.arange(int(min(y))-3, int(max(y))+3, 3))

plt.scatter(x,y,color='black',label='Data points')
"""Plotting of linear fit"""
plt.plot(x,LinFit,'r',label='Linear fit, BIC=%s'%(LineError))
plt.plot(x,CubeFit,'g',label='Cubic fit, BIC=%s'%(CubeError))
Area=A[0]
Area=round(Area,2)
plt.text(5,19,'Area=%s'%(Area))
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('Fitting of data')
plt.legend()
Fig.savefig('DataPlot.pdf')


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, mesh3 = plt.subplots(1, 1)
fig5, mesh4 = plt.subplots(1, 1)
fig6, mesh5 = plt.subplots(1, 1)
fig7, mesh6 = plt.subplots(1, 1)
fig8, mesh7 = plt.subplots(1, 1)
fig9, mesh8 = plt.subplots(1, 1)
fig10, mesh9 = plt.subplots(1, 1)

mesh1 = fig2.gca(projection='3d')
mesh2 = fig3.gca(projection='3d')
mesh3 = fig4.gca(projection='3d')
mesh4 = fig5.gca(projection='3d')
mesh5 = fig6.gca(projection='3d')
mesh6 = fig7.gca(projection='3d')
mesh7 = fig8.gca(projection='3d')
mesh8 = fig9.gca(projection='3d')
mesh9 = fig10.gca(projection='3d')

# Quadratic approximations
QUAD_APPROX1 = 2 * X + 3
QUAD_APPROX2 = X ** 2 + 2 * X - 4
QUAD_APPROX3 = -1.892 * X ** 2 - 2.985 * X + 2.649

# Part c)
QUAD_APPROX4 = 2 * X + 5.6
QUAD_APPROX5 = X ** 2 - 3.4 * X + 0.89
QUAD_APPROX6 = -0.826 * X ** 2 + 0.034 * X + 7.295

QUAD_APPROX7 = 2 * X + 3
QUAD_APPROX8 = X ** 2 + 6 * X + 4.75
QUAD_APPROX9 = 1.795 * X ** 2 - 3.847 * X - 5.991

mesh1.plot_surface(X, Y, QUAD_APPROX1)
mesh1.set_title('Quadratic Approximation 1')
mesh1.set_xlabel('x')
mesh1.set_ylabel('y')

mesh2.plot_surface(X, Y, QUAD_APPROX2)
mesh2.set_title('Quadratic Approximation 2')
mesh2.set_xlabel('x')
mesh2.set_ylabel('y')

mesh3.plot_surface(X, Y, QUAD_APPROX3)
mesh3.set_title('Quadratic Approximation 3')
mesh3.set_xlabel('x')
mesh3.set_ylabel('y')

mesh4.plot_surface(X, Y, QUAD_APPROX4)
mesh4.set_title('Quadratic Approximation 4')
mesh4.set_xlabel('x')
mesh4.set_ylabel('y')

mesh5.plot_surface(X, Y, QUAD_APPROX5)
mesh5.set_title('Quadratic Approximation 5')
mesh5.set_xlabel('x')
mesh5.set_ylabel('y')

mesh6.plot_surface(X, Y, QUAD_APPROX6)
mesh6.set_title('Quadratic Approximation 6')
mesh6.set_xlabel('x')
mesh6.set_ylabel('y')

mesh7.plot_surface(X, Y, QUAD_APPROX7)
mesh7.set_title('Quadratic Approximation 7')
mesh7.set_xlabel('x')
mesh7.set_ylabel('y')

mesh8.plot_surface(X, Y, QUAD_APPROX8)
mesh8.set_title('Quadratic Approximation 8')
mesh8.set_xlabel('x')
mesh8.set_ylabel('y')

mesh9.plot_surface(X, Y, QUAD_APPROX9)
mesh9.set_title('Quadratic Approximation 9')
mesh9.set_xlabel('x')
mesh9.set_ylabel('y')

plt.show()


from math import *
import numpy as np
import matplotlib.pyplot as plt

initial_P1 = np.array([0, 0])  # first coordinate of the initial segment
initial_P2 = np.array([3, 3])  # second coordinate of the initial segment
nbiter = 8  # number of iterations

def tiers(A, B):
    """Add a fractal step

    Args:
        A (array): point in 2D space
        B (array): point in 2D space

    Returns:
        C, D, E: 3 new points in 2D space
    """
    step = (B - A) / 3
    C = A + step
    E = C + step
    rotation = np.array([[cos(pi / 3), -sin(pi / 3)],
                         [sin(pi / 3), cos(pi / 3)]])
    D = np.dot(rotation, (E - C)) + C
    return C, D, E

def fractal(n, A, B):
    """Calculate all the new points added by cutting our segment [A,B] n times

    Args:
        n (int): number of iterations
        A (array): point in 2D space
        B (array): point in 2D space

    Returns:
        list: List of all the points (array)
    """
    L = [A]

    def iteration(n, A, B):
        if n > 0:
            (C, D, E) = tiers(A, B)
            iteration(n - 1, A, C)
            L.append(C)
            iteration(n - 1, C, D)
            L.append(D)
            iteration(n - 1, D, E)
            L.append(E)
            iteration(n - 1, E, B)
    iteration(n, A, B)
    L.append(B)
    return L

def snowflake(n, A, B):
    """Plot the Helge von Koch snowflake

    Args:
        n (int): number of iteration
        A (array): point in 2D space
        B (array): point in 2D space
    """
    rotationC = np.array([[cos(pi / 3), -sin(-pi / 3)],
                          [sin(-pi / 3), cos(pi / 3)]])
    C = np.dot(rotationC, (B - A)) + A
    L = fractal(n, A, B) + fractal(n, B, C) + fractal(n, C, A)
    n = len(L)
    plt.axis('equal')
    plt.axis('off')
    absciss = []
    ordonate = []
    for k in range(0, n):
        absciss.append(L[k][0])
        ordonate.append(L[k][1])
    plt.plot(absciss, ordonate)
    plt.show()

snowflake(nbiter, initial_P1, initial_P2)


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

i_vector = np.identity(2)

not_vector = np.array([[0, 1],
                       [1, 0]], dtype=np.complex)

y_vector = np.array([[0, -1j],
                     [1j, 0]], dtype=np.complex)

h_vector = (1/sqrt(2)) * np.array([[1, 1],
                                   [1, -1]], dtype=np.complex)

#  Identity gate
def I(state):
    """Applies the Identity gate.

    state -- state of a single qubit
    """
    return i_vector @ state

#  Pauli-X / NOT gate / Half turn
def X(state):
    """Applies the NOT gate.

    state -- state of a single qubit
    """
    return not_vector @ state

#  Hadamard gate / Half turn
def H(state):
    """Applies the Hadamard gate.

    state -- state of a single qubit
    """
    return h_vector @ state

#  Pauli-Y / Y gate / Half turn
def Y(state):
    """Applies the Y gate.

    state -- state of a single qubit
    """
    return y_vector @ state

#  Pauli-Z / Z gate / Half turn
def Z(state):
    """Applies the Z gate.

    state -- state of a single qubit
    """
    z_vector = np.array([[1, 0],
                         [0, -1]], dtype=np.complex)
    return z_vector @ state

#  Phase shift / RZ gate
def RZ(phi, state):
    """Applies the RZ gate.

    state -- state of a single qubit
    """
    rz_vector = np.array([[1, 0],
                          [0, e ** (phi * 1j)]], dtype=np.complex)
    return rz_vector @ state

#  S gate / sqrt(Z) / Quarter turn
def S(state):
    """Applies the S gate.

    state -- state of a single qubit
    """
    return RZ(pi/2, state)

#  T gate / sqrt(S) / Eighth turn
def T(state):
    """Applies the T gate.

    state -- state of a single qubit
    """
    return RZ(pi/4, state)

# Controlled NOT / CNOT / CX gate
def CNOT(joint_state):
    """Applies the CNOT gate.

    joint_state -- joint state of 2 qubits
    """
    cnot_vector = np.array([[1, 0, 0, 0],
                            [0, 1, 0, 0],
                            [0, 0, 0, 1],
                            [0, 0, 1, 0]], dtype=np.complex)
    return cnot_vector @ joint_state

#  Controlled Phase shift / CPHASE gate
def CPHASE(phi, joint_state):
    """Applies the CPHASE gate.

    joint_state -- joint state of 2 qubits
    """
    cr_vector = np.array([[1, 0, 0, 0],
                          [0, 1, 0, 0],
                          [0, 0, 1, 0],
                          [0, 0, 0, e ** (phi * 1j)]], dtype=np.complex)
    return cr_vector @ joint_state

# Controlled Z / CZ gate
def CZ(joint_state):
    """Applies the CZ gate.

    joint_state -- joint state of 2 qubits
    """
    cz_vector = np.array([[1, 0, 0, 0],
                          [0, 1, 0, 0],
                          [0, 0, 1, 0],
                          [0, 0, 0, -1]], dtype=np.complex)
    return cz_vector @ joint_state

# Controlled U / CU gate
def CU(U, joint_state):
    """Applies the CU gate.

    U           -- Pauli matrices
    joint_state -- joint state of 2 qubits
    """
    cu_vector = np.identity(4, dtype=np.complex)
    cu_vector[2:4, 2:4] = U
    return cu_vector @ joint_state

# Controlled X / CX gate / same as CNOT
def CX(joint_state):
    """Applies the CX gate.

    joint_state -- joint state of 2 qubits
    """
    return CU(not_vector, joint_state)

# Controlled Y / CY gate
def CY(joint_state):
    """Applies the CY gate.

    joint_state -- joint state of 2 qubits
    """
    return CU(y_vector, joint_state)

# SWAP gate
def SWAP(joint_state):
    """Applies the SWAP gate.

    joint_state -- joint state of 2 qubits
    """
    swap_vector = np.array([[1, 0, 0, 0],
                            [0, 0, 1, 0],
                            [0, 1, 0, 0],
                            [0, 0, 0, 1]], dtype=np.complex)
    return swap_vector @ joint_state

# Hadamard gate extended with Identity
# K will leave the second qubit untouched and apply the Hadamard transform to the first qubit
def K(joint_state):
    """Applies the K / HI gate.

    joint_state -- joint state of 2 qubits
    """
    return np.kron(h_vector, i_vector) @ joint_state

#  Hadamard transform - Hadamard gate (H) applied in parallel on 2 qubits
def H2(joint_state):
    """Applies the Hadamard transform.

    joint_state -- joint state of 2 qubits
    """
    return np.kron(h_vector, h_vector) @ joint_state

# Toffoli / CCNOT gate
def CCNOT(joint_state):
    """Applies the CCNOT gate.

    joint_state -- joint state of 3 qubits
    """
    ccnot_vector = np.array([[1, 0, 0, 0, 0, 0, 0, 0],
                             [0, 1, 0, 0, 0, 0, 0, 0],
                             [0, 0, 1, 0, 0, 0, 0, 0],
                             [0, 0, 0, 1, 0, 0, 0, 0],
                             [0, 0, 0, 0, 1, 0, 0, 0],
                             [0, 0, 0, 0, 0, 1, 0, 0],
                             [0, 0, 0, 0, 0, 0, 0, 1],
                             [0, 0, 0, 0, 0, 0, 1, 0]], dtype=np.complex)
    return ccnot_vector @ joint_state

# Fredkin / CSWAP gate
def CSWAP(joint_state):
    """Applies the CSWAP gate.

    joint_state -- joint state of 3 qubits
    """
    cswap_vector = np.array([[1, 0, 0, 0, 0, 0, 0, 0],
                             [0, 1, 0, 0, 0, 0, 0, 0],
                             [0, 0, 1, 0, 0, 0, 0, 0],
                             [0, 0, 0, 1, 0, 0, 0, 0],
                             [0, 0, 0, 0, 1, 0, 0, 0],
                             [0, 0, 0, 0, 0, 0, 1, 0],
                             [0, 0, 0, 0, 0, 1, 0, 0],
                             [0, 0, 0, 0, 0, 0, 0, 1]], dtype=np.complex)
    return cswap_vector @ joint_state

# Universal quantum gates for single qubit
def U3(_theta, _phi, _lambda, state):
    """Applies the U3 gate.

    state   -- state of a single qubit
    """
    u3_vector = np.array([[cos(_theta/2), -((e ** (_lambda * 1j) * (sin(_theta/2))))],
                         [((e ** (_phi * 1j) * (sin(_theta/2)))), ((e ** ((_lambda * 1j) + (_phi * 1j)) * (cos(_theta/2))))]], dtype=np.complex)
    return u3_vector @ state

def U2(_phi, _lambda, state):
    return U3(pi/2, _phi, _lambda, state)

def U1(_lambda, state):
    return U3(0, 0, _lambda, state)


import numpy as np
import cv2
import math

def discreteFourierTransform(image):
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

    dft = cv2.dft(np.float32(gray), flags = cv2.DFT_COMPLEX_OUTPUT)
    dft_shift = np.fft.fftshift(dft)

    magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))

    return magnitude_spectrum

def butterworthLowPassMask(width,height,dinit = 20,n = 1):
    width = width / 2
    height = height / 2

    hw = np.arange(-width, width)
    hh = np.arange(-height, height)

    x, y = np.meshgrid(hh, hw)
    mg = np.sqrt(x**2 + y**2)
    return 1 / (1 + (mg/dinit)**(2*n))

def butterworthHighPassMask(width,height,dinit = 20,n = 1):
    width = width / 2
    height = height / 2

    hw = np.arange(-width, width)
    hh = np.arange(-height, height)

    x, y = np.meshgrid(hh, hw)
    mg = np.sqrt(x**2 + y**2)
    return 1 / (1 + (dinit/mg)**(2*n))

def butterworthFilter(image, d=20, n=1, filter_type="low"):
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    width, height = gray.shape

    mask = ""
    if filter_type == "low":
        mask = butterworthLowPassMask(width, height, d, n)
    elif filter_type == "high":
        mask = butterworthHighPassMask(width, height, d, n)

    fft = np.fft.fftshift(np.fft.fft2(np.float32(gray)))

    img_pass = mask * fft
    result = np.abs(np.fft.ifft2(np.fft.ifftshift(img_pass)))

    return result

def notchFilter(image):
    pass

if __name__ == "__main__":
    img = cv2.imread("../sample/hw4_radiograph_1.jpg")
    cv2.imwrite("../output/output.jpg", butterworthFilter(img, 20, 1, "high"))


import random
import math
import numpy as np
import matplotlib.pyplot as plt

def single_spiral(grid_size, noise = 0):
	step = 1
	radius = float(grid_size)
	theta = 0
	result = []
	for i in range(int(grid_size / step)):
		theta_rad = theta * math.pi / 180
		actual_noise = noise * math.sqrt(radius / grid_size)
		x = radius * math.cos(theta_rad) + random.uniform(-actual_noise, actual_noise)
		y = radius * math.sin(theta_rad) + random.uniform(-actual_noise, actual_noise)
		result.append((x, y))
		theta += 4
		radius -= step
	return result

def double_spiral(grid_size, noise = 0):
	original = single_spiral(grid_size, noise)
	result = []
	rotation = math.pi
	sin = math.sin(rotation)
	cos = math.cos(rotation)
	for i in range(len(original)):
		(x, y) = original[i]
		xn = x * cos - y * sin
		yn = x * sin + y * cos
		result.append((xn, yn))
	return [single_spiral(grid_size, noise), result]


import numpy as np

from .Scoring import Scoring

class SimpleLinearRegression(Scoring):

    def __init__(self):
        super().__init__()

    def fit(self, X, Y):
        self.m, self.n = X.shape

        ones = np.ones(shape=self.m).reshape(-1, 1)
        X = np.concatenate((ones, X), 1)

        inv_mat = np.linalg.inv(X.transpose().dot(X))

        coefficient = inv_mat.dot(X.transpose()).dot(Y)

        self.intercept_ = coefficient[0]
        self.coef_ = coefficient[1:]

        return self

    def __str__(self):
        res = ""
        res += f"Slope: {list(self.coef_)}, Intercept: {self.intercept_}\n"
        res_p = f"Equation {list(self.coef_)}X + {self.intercept_}"
        if self.intercept_ < 0:
            res_p = f"Equation: Y = {list(self.coef_)}X - {np.abs(self.intercept_)}" # noqa
        res += res_p
        return res


import pandas as pd
import numpy as np
import math
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.utils.validation import check_array, check_is_fitted

def fourier_sin_encoding(series, max_val, n=1):
    return np.sin((series / max_val) * (2 * math.pi * n))

def fourier_cos_encoding(series, max_val, n=1):
    return np.cos((series / max_val) * (2 * math.pi * n))

class DateFourier(BaseEstimator, TransformerMixin):
    """ A transformer that adds fourier terms for a given date period.

    For each passed in date column this transformer will compute
    a number of columns for the fourier series based on the passed in
    periods.

    Parameters
    ----------
    cols : List[str], default=None
        A list of the columns that should be transformed. If it is None
        then all detected datetime columns will be transformed.

    periods: List[{'dayfoweek', 'dayofmonth', 'dayofyear', 'monthofyear'}],
             default=['dayofyear']
        List of the different periods we want to capture with fourier terms.

    fourier : int > 0
        Integer representing how many terms of the fourier series
        should be added.

    drop_base_cols: boolean, default=True
        if true the base datetime columns will be dropped.

    Attributes
    ----------
    n_features_ : int
        The number of features of the data passed to :meth:`fit`.
    """

    def __init__(self,
                 cols=None,
                 fourier=1,
                 periods=['dayofyear'],
                 drop_base_cols=True):
        self.cols = cols
        self.fourier = fourier
        self.periods = periods
        self.drop_base_cols = drop_base_cols

        # check to make sure periods are valid
        valid_periods = [
            'dayofweek',
            'dayofmonth',
            'dayofyear',
            'monthofyear',
            # 'minuteofday',  # TODO add functionality for time of day
        ]
        if not all([x in valid_periods for x in self.periods]):
            raise ValueError(
                'Periods must be a subset of {}'.format(valid_periods))

    def fit(self, X, y=None):
        """Check data and if cols=None select all datetime columns.
        Parameters
        ----------
        X : {array-like, sparse matrix}, shape (n_samples, n_features)
            The training input samples.
        y : None
            There is no need of a target in a transformer, yet the pipeline API
            requires this parameter.
        Returns
        -------
        self : object
            Returns self.
        """
        # Check input
        #X = check_array(X, accept_sparse=True, dtype=None)

        self.n_features_ = X.shape[1]

        if type(X) != pd.DataFrame:
            raise TypeError('This Transformer currently only accepts pandas \
                dataframes as inputs')

        # If no columns are passed we identify any
        # datetime columns for transformation
        if self.cols is None:
            self.cols = X.select_dtypes(
                include=[np.datetime64]).columns.tolist()
        return self

    def transform(self, X):
        """ Add Fourier series columns to datetframe.
        Parameters
        ----------
        X : {array-like, sparse-matrix}, shape (n_samples, n_features)
            The input samples.
        Returns
        -------
        X_transformed : array, shape (n_samples, n_features)
            The array containing the element-wise square roots of the values
            in ``X``.
        """
        # Check is fit had been called
        check_is_fitted(self, 'n_features_')

        # Input validation
        #X = check_array(X, accept_sparse=True, dtype=None)
        df = X

        for col in self.cols:
            cyclical_cols = {}
            if 'dayofweek' in self.periods:
                df['{}_day_of_week'.format(col)] = df[col].dt.dayofweek
                cyclical_cols['{}_day_of_week'.format(col)] = 7
            if 'dayofmonth' in self.periods:
                df['{}_day_of_month'.format(col)] = df[col].dt.day
                cyclical_cols['{}_day_of_month'.format(col)] = 31
            if 'dayofyear' in self.periods:
                df['{}_day_of_year'.format(col)] = df[col].dt.dayofyear
                cyclical_cols['{}_day_of_year'.format(col)] = 365
            if 'monthofyear' in self.periods:
                df['{}_month'.format(col)] = df[col].dt.month
                cyclical_cols['{}_month'.format(col)] = 12

            for fcol, max_val in cyclical_cols.items():
                for i in range(1, self.fourier + 1):
                    df[fcol + '_fourier_sin_' +
                        str(i)] = fourier_sin_encoding(df[fcol], max_val, n=i)
                    df[fcol + '_fourier_cos_' +
                        str(i)] = fourier_cos_encoding(df[fcol], max_val, n=i)

            df = df.drop(list(cyclical_cols.keys()), axis='columns')
        if self.drop_base_cols:
            df = df.drop(self.cols, axis='columns')
        return df


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

K_list = [1, 2, 3, 4, 5, 100] #和を取る一様乱数の数
n_iter = 1000000 #乱数の発生個数
#step = 1/1000
#x = np.arange(-2, 2+step, step)

#def norm_dist(x:np.ndarray, mu:float, sigma:float) -> np.ndarray:
#  return np.exp(-np.square(x-mu)/(2*sigma))/(np.sqrt(2*np.pi)*sigma)

#a=np.random.rand(K, n_iter)-0.5
#plt.hist(np.sum(a, axis=0), bins=1000, normed=True)
#plt.plot(x, norm_dist(x, 0, 1))
#plt.show()

nrow_fig, ncol_fig = 3, 2 # グラフの横の数と縦の数を求める
fig = plt.figure(figsize=(8,8)) # グラフの描画処理
for i, K in enumerate(K_list):
    ax = plt.subplot2grid((nrow_fig, ncol_fig), (i//ncol_fig, i%ncol_fig))
    # K*n_iterの一様乱数[-0.5, 0.5)の発生
    sum_uniform = np.sum(np.random.rand(K, n_iter)-0.5, axis=0) #行方向に和を取る(n_iter個の一様乱数の和になっている)
    ax.hist(sum_uniform, bins=1000, normed=True) #ヒストグラムの描画
    ax.legend(f"K={K}") #サブプロットにタイトルを表示

plt.tight_layout() #サブプロット間の間隔調整
plt.show()


import numpy as np

def sphere(x):
    return np.sum(np.power(x, 2))

def griewank(x):
    D = x.shape[0]
    return np.sum(np.power(x, 2) / 4000) - \
        np.prod(np.cos(x / np.sqrt(np.linspace(1, D, D)))) + 1

def rastrigin(x):
    return np.sum(np.power(x, 2) - 10 * np.cos(2 * np.pi * x) + 10)

def schwefel(x):
    D = x.shape[0]
    return 418.9829 * D - np.sum(x * np.sin(np.power(np.abs(x), 0.5)))

def rosenbrock(x):
    return np.sum(
        100 * np.power(x[:-1] **  2 - x[1:], 2) + \
        (x[:-1] - 1) ** 2)

def ackley(x):
    return -20 * np.exp(-0.2 * np.sqrt(np.mean(np.power(x, 2)))) - \
        np.exp(np.mean(np.cos(2 * np.pi * x))) + 20 + np.exp(1)

# Weierstrass function
def get_weierstrass_const(D, a=0.5, b=3, kmax=20):
    return np.sum([a ** k * np.cos(2 * np.pi * b ** k * 0.5) for k in range(kmax)])

weierstrass_const = {
    25: get_weierstrass_const(25),
    50: get_weierstrass_const(50),
}
def weierstrass(x, a=0.5, b=3, kmax=20):
    D = x.shape[0]
    return np.sum(np.stack([a ** k * np.cos(2 * np.pi * b ** k * (x + 0.5))
                            for k in range(kmax)])) - D * weierstrass_const[D]


# --------------
import pandas as pd
import scipy.stats as stats
import math
import numpy as np
import warnings

warnings.filterwarnings('ignore')
#Sample_Size
sample_size=2000

#Z_Critical Score
z_critical = stats.norm.ppf(q = 0.95)

# path        [File location variable]
data = pd.read_csv(path)

data_sample = data.sample(n=sample_size,random_state =0)
sample_mean = data_sample['installment'].mean()
sample_std = data_sample['installment'].std()
margin_of_error = z_critical*(sample_std/math.sqrt(sample_size))
confidence_interval =(sample_mean - margin_of_error,
sample_mean + margin_of_error)
true_mean = data['installment'].mean()
print("True mean :{}".format(true_mean))

import matplotlib.pyplot as plt
import numpy as np

#Different sample sizes to take
sample_size=np.array([20,50,100])

fig ,axes = plt.subplots(nrows = 3 , ncols = 1)
for i in range(len(sample_size)):
    m = []
    for j in range(1000):
        data['installment'].sample(n=sample_size[i])
        m.append(data['installment'].mean())
    mean_series = pd.Series(m)
    axes[i].hist(mean_series)

#Importing header files
from statsmodels.stats.weightstats import ztest
import statsmodels

data['int.rate'] = data['int.rate'].str.replace('%','')
data['int.rate'] = data['int.rate'].astype(float)/100
x1 = data[data['purpose']=='small_business']['int.rate']
z_statistic,p_value= statsmodels.stats.weightstats.ztest(x1,value=data['int.rate'].mean(),alternative='larger')
if p_value < 0.05:    # alpha value is 0.05 or 5%
   print(" we are rejecting null hypothesis")
else:
  print("we are failed to reject  null hypothesis")

#Importing header files

from statsmodels.stats.weightstats import ztest

x1 = data[data['paid.back.loan']=='No']['installment']
x2 = data[data['paid.back.loan']=='Yes']['installment']
z_statistic,p_value = statsmodels.stats.weightstats.ztest(x1,x2)
if p_value < 0.05:    # alpha value is 0.05 or 5%
   print(" we are rejecting null hypothesis")
else:
  print("we are failed to reject  null hypothesis")

#Importing header files
from scipy.stats import chi2_contingency

#Critical value
critical_value = stats.chi2.ppf(q = 0.95, # Find the critical value for 95% confidence*
                      df = 6)   # Df = number of variable categories(in purpose) - 1

yes = data[data['paid.back.loan']=='Yes']['purpose'].value_counts()
no = data[data['paid.back.loan']=='No']['purpose'].value_counts()
observed = pd.concat([yes.transpose(),no.transpose()], 1,keys=['Yes','No'])

chi2, p, dof, ex = chi2_contingency(observed, correction=False)

print("Critical value")
print(critical_value)
print("Chi Statistic")
print(chi2)

# --------------

import numpy,import scipy,from scipy,import statsmodels,from statsmodels


# Enter your code here. Read input from STDIN. Print output to STDOUT
import numpy as np
import scipy as sp
import scipy.stats

n = int(raw_input())

data = [float(val) for val in raw_input().split()]
d_a = np.array(data)

# mean
#print str(np.mean(d_a))
print "{0:.1f}".format(np.mean(d_a))

# median
#print str(np.median(d_a))
print "{0:.1f}".format(np.median(d_a))

# mode
#counts = np.bincount(d_a)
#print np.argmax(counts)
from scipy import stats
ans = stats.mode(d_a, axis=None)
b = int(ans[0])
print str(b)
#print ' '.join(map(str, b))
#print ' '.join(map(str, stats.mode(d_a)[0]))

# std
print "{0:.1f}".format(np.std(d_a))

# confidence interval
import math

def confidence_interval(a, z_critical = 1.96):
    # http://hamelg.blogspot.com/2015/11/python-for-data-analysis-part-23-point.html

    sample_mean = np.mean(a)
    sample_size = len(a)

    #z_critical = stats.norm.ppf(q = 0.96)  # Get the z-critical value*

    pop_stdev = np.std(a)  # Get the population standard deviation

    margin_of_error = z_critical * (pop_stdev/math.sqrt(sample_size))

    print "{0:.1f}".format(sample_mean - margin_of_error) + " " + "{0:.1f}".format(sample_mean + margin_of_error)

confidence_interval(d_a)
#print str(m__h) + ' ' +str(m_h)


# Newton interpolating polynomial

from divdiff import divdiff
import numpy as np

def newton_interp(x, y, X):
    '''
    Newton interpolation method
    Input:
      - x : precomputed points x axis values
      - y : precomputed points y axis values
      - X : query points x axis
    Output:
      - Y : query points y axis (interpolation results)
    '''
    n = len(x)
    Y = np.zeros(len(X))
    for k in range(n):
        L = np.ones(len(X))
        for i in range(k):
            L *= (X - x[i])
        a = divdiff(x[0:k+1], y[0:k+1])
        Y += a*L
    return Y


import torch
import numpy as np

def xyz2sphere(xyz, normalize=True):
    """
    Convert XYZ to Spherical Coordinate

    reference: https://en.wikipedia.org/wiki/Spherical_coordinate_system

    :param xyz: [N, 3] / [N, G, 3]
    :return: (rho, theta, phi) [N, 3] / [N, G, 3]
    """
    rho = torch.sqrt(torch.sum(torch.pow(xyz, 2), dim=-1, keepdim=True))
    rho = torch.clamp(rho, min=0)  # range: [0, inf]
    theta = torch.acos(xyz[..., 2, None] / rho)  # range: [0, pi]
    phi = torch.atan2(xyz[..., 1, None], xyz[..., 0, None])  # range: [-pi, pi]
    # check nan
    idx = rho == 0
    theta[idx] = 0

    if normalize:
        theta = theta / np.pi  # [0, 1]  TODO Use range of [-1, 1] instead
        phi = phi / (2 * np.pi) + .5  # [0, 1]
    out = torch.cat([rho, theta, phi], dim=-1)
    return out

def xyz2sphere_np(xyz, normalize=True):
    """
    Convert XYZ to Spherical Coordinate

    reference: https://en.wikipedia.org/wiki/Spherical_coordinate_system

    :param xyz: [N, 3] / [N, G, 3]
    :return: (rho, theta, phi) [N, 3] / [N, G, 3]
    """
    rho = np.sqrt(np.sum(np.power(xyz, 2), axis=-1))[..., np.newaxis]
    rho = np.clip(rho, 0, None)  # range: [0, inf]
    theta = np.arccos(xyz[..., 2, None] / rho)  # range: [0, pi]
    phi = np.arctan2(xyz[..., 1, None], xyz[..., 0, None])  # range: [-pi, pi]
    # check nan
    idx = rho == 0
    theta[idx] = 0

    if normalize:
        theta = theta / np.pi  # [0, 1]  TODO Use range of [-1, 1] instead
        phi = phi / (2 * np.pi) + .5  # [0, 1]
    out = np.concatenate([rho, theta, phi], axis=-1).astype(np.float32)
    return out

def xyz2sphere_aug(xyz, normalize=True):
    """
    Convert XYZ to Spherical Coordinate (Augmentation by YZ & XZ direction)

    reference: https://en.wikipedia.org/wiki/Spherical_coordinate_system

    :param xyz: [B, N, 3] / [B, N, G, 3]
    :return: (rho, theta, phi) [B, N, 3] / [B, N, G, 3]
    """
    rho = torch.sqrt(torch.sum(torch.pow(xyz, 2), dim=-1, keepdim=True))
    rho = torch.clamp(rho, 0, 1)  # range: [0, 1]

    # XY direction
    theta_xy = torch.acos(xyz[..., 2, None] / rho)  # range: [0, pi]
    phi_xy = torch.atan2(xyz[..., 1, None], xyz[..., 0, None])  # range: [-pi, pi]
    # XZ direction
    theta_xz = torch.acos(xyz[..., 1, None] / rho)  # range: [0, pi]
    phi_xz = torch.atan2(xyz[..., 2, None], xyz[..., 0, None])  # range: [-pi, pi]
    # YZ direction
    theta_yz = torch.acos(xyz[..., 0, None] / rho)  # range: [0, pi]
    phi_yz = torch.atan2(xyz[..., 2, None], xyz[..., 1, None])  # range: [-pi, pi]

    # check nan
    idx = rho == 0
    theta_xy[idx] = 0
    theta_xz[idx] = 0
    theta_yz[idx] = 0

    theta = torch.cat([theta_xy, theta_xz, theta_yz], dim=-1)
    phi = torch.cat([phi_xy, phi_xz, phi_yz], dim=-1)

    if normalize:
        theta = theta / np.pi
        phi = phi / (2 * np.pi) + .5
    out = torch.cat([rho, theta, phi], dim=-1)
    return out

def normal2sphere(xyz, normalize=False):
    """
    Convert Normal Vector to Spherical Coordinate

    reference: https://en.wikipedia.org/wiki/Spherical_coordinate_system

    :param xyz: [B, N, 3] / [B, N, G, 3]
    :return: (theta, phi) [B, N, 2] / [B, N, G, 2]
    """
    theta = torch.acos(xyz[..., 2, None])  # range: [0, pi]
    phi = torch.atan2(xyz[..., 1, None], xyz[..., 0, None])  # range: [-pi, pi]

    if normalize:
        theta = theta / np.pi
        phi = phi / (2 * np.pi) + .5
    out = torch.cat([theta, phi], dim=-1)
    return out

def sphere2normal(sphere):
    x = torch.cos(sphere[..., 1, None]) * torch.sin(sphere[..., 0, None])
    y = torch.sin(sphere[..., 1, None]) * torch.sin(sphere[..., 0, None])
    z = torch.cos(sphere[..., 0, None])
    return torch.cat([x, y, z], dim=-1)

def xyz2cylind(xyz, normalize=True):
    """
    Convert XYZ to Cylindrical Coordinate

    reference: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system

    :param normalize: Normalize phi & z
    :param xyz: [B, N, 3] / [B, N, G, 3]
    :return: (rho, phi, z) [B, N, 3]
    """
    rho = torch.sqrt(torch.sum(torch.pow(xyz[..., :2], 2), dim=-1, keepdim=True))
    rho = torch.clamp(rho, 0, 1)  # range: [0, 1]
    phi = torch.atan2(xyz[..., 1, None], xyz[..., 0, None])  # range: [-pi, pi]
    z = xyz[..., 2, None]
    z = torch.clamp(z, -1, 1)  # range: [-1, 1]

    if normalize:
        phi = phi / (2 * np.pi) + .5
        z = (z + 1.) / 2.
    out = torch.cat([rho, phi, z], dim=-1)
    return out


from math import log
import numpy as np
import aux

def _stochastic_block_model(n, p, q):
    """
    Generates a SBM observation with inner and inter cluster probability.
    """

    z_sbm = np.hstack(
        (np.ones(int(n / 2)), -np.ones(int(n / 2)))).reshape(n, 1)
    R1_vec = aux.rounding_with_prob(
        np.random.random_sample(int(n / 2) * int(n / 2)), p)
    R3_vec = aux.rounding_with_prob(
        np.random.random_sample(int(n / 2) * int(n / 2)), p)
    R1_pre = R1_vec.reshape((int(n / 2), int(n / 2)))
    R3_pre = R3_vec.reshape((int(n / 2), int(n / 2)))
    for i in range(int(n / 2)):
        for j in range(int(n / 2)):
            if i > j:
                R1_pre[i, j] = R1_pre[j, i]
                R3_pre[i, j] = R3_pre[j, i]
            elif i == j:
                R1_pre[i, i] = 1
                R3_pre[i, i] = 1
    R2_vec = aux.rounding_with_prob(
        np.random.random_sample(int(n / 2) * int(n / 2)), q)
    R2_pre = R2_vec.reshape((int(n / 2), int(n / 2)))
    Y = np.vstack((np.hstack((R1_pre, R2_pre)), np.hstack((R2_pre.T, R3_pre))))
    return Y, z_sbm

def sbm_logarithm(n, a, b):
    """
    Returns an observation with logarithmic regime.
    """

    p = a * log(n) / n
    q = b * log(n) / n
    Y, z_sbm = _stochastic_block_model(n, p, q)
    print('Adjacency matrix for SBM (logarithmic regime) is generated!')
    return Y, z_sbm

def sbm_linear(n, a, b):
    """
    Returns an observation with linear regime.
    """

    p = a / n
    q = b / n
    Y, z_sbm = _stochastic_block_model(n, p, q)
    print('Adjacency matrix for SBM (linear regime) is generated!')
    return Y, z_sbm

if __name__ == "__main__":
    print('Test starts for module sbm_generator...')
    Y_logarithm, z_logarithm = sbm_logarithm(10, 3, 9)
    Y_linear, z_linear = sbm_linear(10, 3, 9)
    print(Y_logarithm)
    print(z_logarithm)
    print(Y_linear)
    print(z_linear)


import numpy as np

def calc_stats(file):
    data = np.loadtxt(file, delimiter=',')
    mean = np.mean(data)
    median = np.median(data)
    return np.round(mean, decimals=1), np.round(median, decimals=1)

if __name__ == '__main__':
    # Test Case 1
    print(calc_stats('data.csv'))

    # Test Case 2
    print(calc_stats('data2.csv'))

    # Test Case 3
    print(calc_stats('data3.csv'))


import numpy as np

from dslr.stats import sigmoid_

class LogisticRegression:
    """
    Logistic Regression Class, fitting data and predicting the values
    """

    def __init__(self, learning_rate=0.001, n_iters=1000):
        self.learning_rate = learning_rate
        self.n_iters = n_iters
        self.weights = None
        self.bias = None

    def fit(self, x_train, y_test):  # pylint: disable=missing-function-docstring, invalid-name
        """
        train x data
        :param x_train:    the path containing the dataset as csv
        :param y_test:    the path containing the dataset as csv
        """
        # init parameters
        n_samples, n_features = x_train.shape
        self.weights = np.zeros(n_features)
        self.bias = 0

        for _ in range(self.n_iters):
            # approximate
            y_predicted = self.approximation(x_train)

            weights_derivative = (1 / n_samples) * np.dot(x_train.T, (y_predicted - y_test))
            bias_derivative = (1 / n_samples) * np.sum(y_predicted - y_test)

            # gradient descent
            self.weights -= self.learning_rate * weights_derivative
            self.bias -= self.learning_rate * bias_derivative

    def predict(self, to_predict):  # pylint: disable=invalid-name
        y_predicted = self.approximation(to_predict)
        return [1 if i > 0.5 else 0 for i in y_predicted]

    def approximation(self, to_approx):  # pylint: disable=invalid-name
        linear_model = np.dot(to_approx, self.weights) + self.bias
        return sigmoid_(linear_model)


import numpy as np
import cvxpy as cp
import itertools
from scipy.sparse.csgraph import connected_components
from scipy.sparse import csr_matrix
import scipy

def distance(x1, y1, x2, y2):
    return np.sqrt((x1-x2)**2 + (y1-y2)**2)

def pathloss(d, eta):
    delta = 1.0e-1
    return (d+delta)**(-eta)

def genLocation(size, len_area):
    x = np.random.uniform(0.0, len_area, size)
    y = np.random.uniform(0.0, len_area, size)
    return x, y

'''Signal-to-Noise power Ratio in True Domain'''
def calcSNR(ptx, eta, d, awgn_mw, bw):
    prx = ptx * pathloss(d, eta)
    return prx / (awgn_mw*bw)

''' Channel Capacity '''
def calcCapacity(ptx, eta, d, awgn_mw, bw):
    snr = calcSNR(ptx, eta, d, awgn_mw, bw)
    return bw * np.log2(1.0+snr)

'''distance matrix'''
def genDistanceMatrix(x, y):
    return distance(x, y, x[:, np.newaxis], y[:, np.newaxis])

'''compute whether the topology is strongly connected'''
## a: adjacency matrix WITHOUT self loop
def DFS(a):
    n = len(a) #number of nodes
    seen = np.zeros(n, dtype=bool) #seen vector
    seen[0] = True
    tmp = np.where(a[0]==1)[0]
    seen[tmp] = True
    td = tmp.tolist()

    while len(td) > 0:
        indx = td[len(td)-1] #stack structure for DFS
        td.pop(len(td)-1)
        t = np.where(a[indx]==1)[0]
        for w in t:
            if seen[w] == False:
                seen[w] = True
                td.append(w)

    return len(np.where(seen[:] == True)[0]) == len(seen)

'''Gen Adjacency matrix with self loop (based on communication distance)'''
def genConnmat(dmat, d_vec):
    connmat = np.array([(dmat[j] <= d_vec[j]) for j in range(len(dmat))]) * 1
    np.fill_diagonal(connmat, 1)
    return connmat

'''Gen Adjacency matrix with self loop (based on capacity)'''
def genConnmatRate(cmat, r_vec):
    connmat = np.array([(cmat[j] >= r_vec[j]) for j in range(len(cmat))]) * 1
    np.fill_diagonal(connmat, 1)
    return connmat

def convertConnmatToWeightMat(connmat):
    n_node = len(connmat)
    w = np.array([connmat[i] / connmat[i].sum() for i in range(n_node)])
    return w

def optimizeTopologyDirectedMod(x, y, xi_target, eta, ptx_mw, awgn_mw, bw):
    dmat = genDistanceMatrix(x, y)

    n = len(x)
    indx_opt = []
    t_min = np.inf

    p = itertools.product([i for i in range(n-1)], repeat=n)
    indx_kouho = np.array([np.argsort(dmat[i])[1:][::-1] for i in range(len(dmat))])
    ## "kouho" means "candidate"
    for v in p:
        d_vec = np.array([dmat[j, indx_kouho[j, v[j]]] for j in range(n)])
        connmat = genConnmat(dmat, d_vec)
        weight = convertConnmatToWeightMat(connmat)
        eig= np.linalg.eig(weight)
        a = np.sort(np.abs(eig[0]))[::-1]

        if (a[1] <= xi_target):
            adjmat = np.copy(connmat)
            np.fill_diagonal(adjmat, 0)

            if (DFS(adjmat) == True):
                rate = calcCapacity(ptx_mw, eta, d_vec, awgn_mw, bw)
                t = (1.0 / rate ).sum() #total communication time
                if t < t_min:
                    t_min = t
                    indx_opt = [indx_kouho[j, v[j]] for j in range(n)]

    d_min = np.array([dmat[j, indx_opt[j]] for j in range(len(indx_opt))])
    connmat_opt = genConnmat(dmat, d_min)

    return d_min, connmat_opt

#assuming R_1=R_2=...=R{ij}
def optimizeTopologyUndirectedMod(x, y, xi_target, eta, ptx_mw, awgn_mw, bw, approx=False):
    dmat = genDistanceMatrix(x, y)
    cmat = calcCapacity(ptx_mw, eta, dmat, awgn_mw, bw)
    n = len(x)

    t_min = np.inf

    r_kouho = np.sort(np.triu(cmat).flatten())
    r_kouho = r_kouho[r_kouho>0.0]

    if approx==True: #quantized solution (for Appendix)
        r_kouho = np.linspace(np.min(r_kouho), np.max(r_kouho), 2000)

    for r in r_kouho:
        r_vec = np.full(n, r)
        connmat = genConnmatRate(cmat, r_vec)

        adjmat = np.copy(connmat)
        np.fill_diagonal(adjmat, 0)

        graph = csr_matrix(adjmat)
        n_con = connected_components(graph, directed=False, return_labels=False)
        if (n_con==1): ## strongly connected case
            weight = convertConnmatToWeightMat(connmat)

            eig = scipy.linalg.eigvalsh(weight, check_finite=False, eigvals=(n-2, n-2))[0]
            if (eig <= xi_target):
                t = (1.0 / r_vec ).sum() #total communication time
                if t < t_min:
                    t_min = t
                    r_min = np.copy(r_vec)
        else:
            break

    connmat_opt = genConnmatRate(cmat, r_min)

    d_min = np.array([np.max(connmat_opt[i]*dmat[i]) for i in range(n)])

    return d_min, connmat_opt

def stochasticOptimizedTopology(x, y, xi_target, eta, pout, ptx_mw, awgn_mw, bw):
    dmat = genDistanceMatrix(x, y)
    n = len(x)

    '''brute force search'''
    indx_opt = []
    p = itertools.product([i for i in range(n-1)], repeat=n)
    indx_kouho = np.array([np.argsort(dmat[i])[1:][::-1] for i in range(len(dmat))])

    t_min = np.inf
    r_opt = np.zeros(n)
    for v in p:
        d_vec = np.array([dmat[j, indx_kouho[j, v[j]]] for j in range(n)])
        connmat = genConnmat(dmat, d_vec)
        weight = convertConnmatToWeightMat(connmat)
        eig= np.linalg.eig(weight)
        a = np.sort(np.abs(eig[0]))[::-1]

        adjmat = np.array([(dmat[j] <= d_vec[j]) for j in range(n)]) * 1
        for j in range(len(adjmat)):
            adjmat[j][j] = 0

        if (DFS(adjmat) == True) and (a[1] <= xi_target):
            rvec, status = rateAlloc(d_vec, dmat, eta, pout, ptx_mw, awgn_mw, bw)
            t = (1.0/rvec).sum()
            if t < t_min:
                t_min = t
                indx_opt = [indx_kouho[j, v[j]] for j in range(n)]
                r_opt = np.copy(rvec)

    d_min = np.array([dmat[j, indx_opt[j]] for j in range(len(indx_opt))])
    connmat_opt = genConnmat(dmat, d_min)

    # return d_min, connmat_opt, t_min, r_opt, status
    return d_min, connmat_opt

def rateAlloc(d_com, dmat, eta, pout, ptx_mw, awgn_mw, bw):
    d_tmp = []
    n = len(dmat)

    for i in range(len(dmat)):
        a = dmat[i, np.where(dmat[i]<=d_com[i])][0]
        d_tmp.append(a[a>0])

    b = np.zeros(n)
    for i in range(n):
        tmp = calcSNR(ptx_mw, eta, d_tmp[i], awgn_mw, bw)
        b[i] = (1.0/tmp).sum()

    r = cp.Variable(n, pos=True)
    obj = cp.Minimize(cp.sum(cp.inv_pos(r)))

    constraints = [-r <= 0, cp.log(1.0 - pout) - cp.sum(b) + cp.sum(cp.exp(r*cp.log(2.0) + cp.log(b))) <= 0]
    #note: all SNRs should be larger than 1.0

    prob = cp.Problem(obj, constraints)
    result = prob.solve(solver='SCS', verbose=False)

    return (r.value) * bw, prob.status

import numpy,import scipy,from scipy,import cvxpy


# -*- coding:utf-8 -*-
"""
Project   : numpy
File Name : 5_13_to_5_14.py
Keywords :
Abstract  : The Fibonacci numbers are based on a recurrence relation.
            It is difficult to express this relation
            directly with NumPy code.
            However, we can express this relation
            in a matrix form or use the golden ratio formula.
            This will introduce the matrix and rint functions.
            The matrix function creates matrices
            and the rint function rounds numbers to
            the closest integer, but the result is not integer.
Author    : Focus
Date      : 8/21/2021 1:27 PM
"""

import numpy as np

"""
1. Computing.
"""
F = np.matrix([[1, 1], [1, 0]])
print("F: ", F)

"""
2. The eighth Fibonacci number(ignore 0)
"""
print("The 8th Fibonacci: ", (F ** 7)[0, 0])

"""
3. Binet's formula.
The golden ratio formula,
better known as Binet's formula,
allows us to calculate Fibonacci numbers
with a rounding step at the end.
Calculate the first eight Fibonacci numbers:
"""

n = np.arange(1, 9)
sqrt5 = np.sqrt(5)
phi = (1 + sqrt5) / 2
fibonacci = np.rint((phi ** n - (-1 / phi) ** n) / sqrt5)
print("Fibonacci: ", fibonacci)


import numpy as np
import matplotlib.pyplot as plt

phi = -0.8
times = list(range(16))
y1 = [phi**k / (1 - phi**2) for k in times]
y2 = [np.cos(np.pi * k) for k in times]
y3 = [a * b for a, b in zip(y1, y2)]

num_rows, num_cols = 3, 1
fig, axes = plt.subplots(num_rows, num_cols, figsize=(10, 8))
plt.subplots_adjust(hspace=0.25)

# Autocovariance when phi = -0.8
ax = axes[0]
ax.plot(times, y1, 'bo-', alpha=0.6, label=r'$\gamma(k)$')
ax.legend(loc='upper right')
ax.set_xlim(0, 15)
ax.set_yticks((-2, 0, 2))
ax.hlines(0, 0, 15, linestyle='--', alpha=0.5)

# Cycles at frequence pi
ax = axes[1]
ax.plot(times, y2, 'bo-', alpha=0.6, label=r'$\cos(\pi k)$')
ax.legend(loc='upper right')
ax.set_xlim(0, 15)
ax.set_yticks((-1, 0, 1))
ax.hlines(0, 0, 15, linestyle='--', alpha=0.5)

# Product
ax = axes[2]
ax.stem(times, y3, label=r'$\gamma(k) \cos(\pi k)$')
ax.legend(loc='upper right')
ax.set_xlim((0, 15))
ax.set_ylim(-3, 3)
ax.set_yticks((-1, 0, 1, 2, 3))
ax.hlines(0, 0, 15, linestyle='--', alpha=0.5)

plt.show()


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

global god
god = 365

global step
step = 0.01

class Calculation():

    def d1(self, S, K, V, T):
        return (math.log(S / float(K)) + (V**2 / 2) * T) / (V * math.sqrt(T))

    def d2(self, S, K, V, T):
        return self.d1(S, K, V, T) - (V * math.sqrt(T))

    def theo(self, S, K, V, T, dT):
        if dT == 'C':
            return S * scipy.stats.norm.cdf(self.d1(S, K, V, T)) - K * scipy.stats.norm.cdf(self.d2(S, K, V, T))
        else:
            return K * scipy.stats.norm.cdf(-self.d2(S, K, V, T)) - S * scipy.stats.norm.cdf(-self.d1(S, K, V, T))

    def delta(self, S, K, V, T, dT):
        if dT == 'C':
            delta = scipy.stats.norm.cdf(self.d1(S, K, V, T))
        elif dT == 'P':
            delta = scipy.stats.norm.cdf(self.d1(S, K, V, T)) - 1
        else:
            delta = 1
        return delta

    def vega(self, S, K, V, T):
        vega = (S * math.sqrt(T) * scipy.stats.norm.pdf(self.d1(S, K, V, T))) / 100
        return vega

    def theta(self, S, K, V, T):
        theta = -((S * V * scipy.stats.norm.pdf(self.d1(S, K, V, T))) / (2 * math.sqrt(T))) / god
        return theta

    def gamma(self, S, K, V, T):
        gamma = scipy.stats.norm.pdf(self.d1(S, K, V, T))/(S * V * math.sqrt(T))
        return gamma

    def deltaFull(self, fPrice, params, exp):
        i = 0
        n = len(params)
        deltaFull = 0
        while i < n:
            param = params[i]
            if exp:
                param['exp'] = exp
            deltaSingle = self.delta(fPrice, param['strike'], param['vola'], param['exp'], param['dType']) * param['quant']
            deltaFull = deltaFull + deltaSingle
            i+=1
        return deltaFull

    def vegaFull(self, fPrice, params, exp):
        i = 0
        n = len(params)
        vegaFull = 0
        while i < n:
            param = params[i]
            if exp:
                param['exp'] = exp
            if param['dType'] != 'F':
                vegaSingle = self.vega(fPrice, param['strike'], param['vola'], param['exp']) * param['quant']
                vegaFull = vegaFull + vegaSingle
            i+=1
        return vegaFull

    def thetaFull(self, fPrice, params, exp):
        i = 0
        n = len(params)
        thetaFull = 0
        while i < n:
            param = params[i]
            if exp:
                param['exp'] = exp
            if param['dType'] != 'F':
                thetaSingle = self.theta(fPrice, param['strike'], param['vola'], param['exp']) * param['quant']
                thetaFull = thetaFull + thetaSingle
            i+=1
        return thetaFull

    def gammaFull(self, fPrice, params, exp):
        i = 0
        n = len(params)
        gammaFull = 0
        while i < n:
            param = params[i]
            if exp:
                param['exp'] = exp
            if param['dType'] != 'F':
                gammaSingle = self.gamma(fPrice, param['strike'], param['vola'], param['exp']) * param['quant']
                gammaFull = gammaFull + gammaSingle
            i+=1
        return gammaFull

    def p_l(self, fPrice, params, exp):
        i = 0
        n = len(params)
        plF = 0
        while i < n:
            param = params[i]
            if exp:
                param['exp'] = exp
            if param['dType'] == 'F':
                plS = (fPrice - param['price']) * param['quant']
            else:
                theo = round(self.theo(fPrice, param['strike'], param['vola'], param['exp'], param['dType']), 3)
                plS = (theo - param['price']) * param['quant']
            #print(param['dType'], plS)
            plF = plF + plS
            i+=1
        return plF

    def plotPL(self, bePriceS, bePriceF, params, exp):
        bePrice = []
        i = bePriceS
        while i <= bePriceF:
            bePrice.append(i)
            i+=step
        P_L = []
        for s in bePrice:
           P_L.append(self.p_l(s, params, exp))
        plt.plot(bePrice, P_L, label=int(exp*god))

    def plotDelta(self, bePriceS, bePriceF, params, exp):
        bePrice = []
        i = bePriceS
        while i <= bePriceF:
            bePrice.append(i)
            i+=step
        D = []
        for s in bePrice:
           D.append(self.deltaFull(s, params, exp))
        plt.plot(bePrice, D, label=int(exp*god))

    def plotTheta(self, bePriceS, bePriceF, params, exp):
        bePrice = []
        i = bePriceS
        while i <= bePriceF:
            bePrice.append(i)
            i+=step
        T = []
        for s in bePrice:
           T.append(self.thetaFull(s, params, exp))
        plt.plot(bePrice, T, label=int(exp*god))

    def plotVega(self, bePriceS, bePriceF, params, exp):
        bePrice = []
        i = bePriceS
        while i <= bePriceF:
            bePrice.append(i)
            i+=step
        V = []
        for s in bePrice:
           V.append(self.vegaFull(s, params, exp))
        plt.plot(bePrice, V, label=int(exp*god))

    def plotGamma(self, bePriceS, bePriceF, params, exp):
        bePrice = []
        i = bePriceS
        while i <= bePriceF:
            bePrice.append(i)
            i+=step
        V = []
        for s in bePrice:
           V.append(self.gammaFull(s, params, exp))
        plt.plot(bePrice, V, label=int(exp*god))

    def searchDelta(self, fPrice, deep, acc, paramD, params):
        """if paramD['dType'] == 'C':
            if paramD['quant'] < 0:
                direct = 'U'
            else:
                direct = 'D'
        else:
            if paramD['quant'] < 0:
                direct = 'D'
            else:
                direct = 'U'
        if direct == 'U':
            start = fPrice
            finish = fPrice + deep
        else:
            start = fPrice - deep
            finish = fPrice"""
        matrix = []
        start = fPrice - deep
        finish = fPrice + deep
        while start <= finish:
            deltaD = round((self.delta(start, paramD['strike'], paramD['vola'], paramD['exp'], paramD['dType'])) * paramD['quant'], 4)
            deltaF = round(self.deltaFull(start, params, 0), 3)
            #print(start, '|', deltaD, '|', deltaF)
            if deltaD == -deltaF:
                if paramD['dType'] != 'F':
                    theo = round(self.theo(start, paramD['strike'], paramD['vola'], paramD['exp'], paramD['dType']), 3)
                else:
                    theo = 0
                matrix.append([round(start, 2), paramD['dType'], paramD['strike'], paramD['quant'], deltaD, deltaF , theo])
                #break
            start = start + acc
        i = 0
        n = len(matrix)
        prices = []
        while i < n:
            if prices:
                if matrix[i-1][4] != matrix[i][4]:
                    prices.append(matrix[i])
            else:
                prices.append(matrix[i])
            i = i + 1
        for j in prices:
            print(j[0], '|', j[1], '|', j[2], '|', j[3], '|', j[4], '|', j[5], '|', j[6])

calc = Calculation()

deep = 2

acc = 0.0001

exp = 15 / god

fPrice = 55

volaShift = 0/100

exp2 = 12
exp3 = 9

params = []

dType = 'F'
quant = 4
price = 55.36
strike = 0
vola = 0
params.append({'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp})

dType = 'C'
quant = 10
price = 1.31
strike = 56
vola = 27.25/100 + volaShift
params.append({'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp})

dType = 'P'
quant = 8
price = 1.24
strike = 56
vola = 27.25/100 + volaShift
params.append({'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp})

dType = 'P'
quant = 5
price = 0.82
strike = 55
vola = 27.7/100 + volaShift
params.append({'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp})

bePriceS = fPrice - deep
bePriceF = fPrice + deep

calc.plotPL(bePriceS, bePriceF, params, exp)
calc.plotPL(bePriceS, bePriceF, params, exp2/god)
calc.plotPL(bePriceS, bePriceF, params, exp3/god)
plt.ylabel("P/L")
plt.xlabel("Price")
plt.title("Option")
plt.grid(True)
plt.legend()
plt.show()

calc.plotDelta(bePriceS, bePriceF, params, exp)
calc.plotDelta(bePriceS, bePriceF, params, exp2/god)
calc.plotDelta(bePriceS, bePriceF, params, exp3/god)
plt.xlabel("Price")
plt.title("Option")
plt.grid(True)
plt.legend()
plt.ylabel("Delta")
plt.show()

calc.plotTheta(bePriceS, bePriceF, params, exp)
calc.plotTheta(bePriceS, bePriceF, params, exp2/god)
calc.plotTheta(bePriceS, bePriceF, params, exp3/god)
plt.xlabel("Price")
plt.title("Option")
plt.grid(True)
plt.legend()
plt.ylabel("Theta")
plt.show()

calc.plotVega(bePriceS, bePriceF, params, exp)
calc.plotVega(bePriceS, bePriceF, params, exp2/god)
calc.plotVega(bePriceS, bePriceF, params, exp3/god)
plt.xlabel("Price")
plt.title("Option")
plt.grid(True)
plt.legend()
plt.ylabel("Vega")
plt.show()

calc.plotGamma(bePriceS, bePriceF, params, exp)
calc.plotGamma(bePriceS, bePriceF, params, exp2/god)
calc.plotGamma(bePriceS, bePriceF, params, exp3/god)
plt.xlabel("Price")
plt.title("Option")
plt.grid(True)
plt.legend()
plt.ylabel("Gamma")
plt.show()

print('D:\t', round(calc.deltaFull(fPrice, params, exp), 2))

print('V:\t', round(calc.vegaFull(fPrice, params, exp), 2))

print('T:\t', round(calc.thetaFull(fPrice, params, exp), 2))

print('G:\t', round(calc.gammaFull(fPrice, params, exp), 2))

print('P/L:\t', calc.p_l(fPrice, params, exp))

#Donee

dType = 'F'
strike = 0
price = 0
quant = -1
vola = 0
paramD_1 = {'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp}

dType = 'F'
strike = 0
price = 0
quant = 1
vola = 0
paramD1 = {'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp}

dType = 'F'
strike = 0
price = 0
quant = -2
vola = 0
paramD_2 = {'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp}

dType = 'F'
strike = 0
price = 0
quant = 2
vola = 0
paramD2 = {'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp}

dType = 'F'
strike = 0
price = 0
quant = -3
vola = 0
paramD_3 = {'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp}

dType = 'F'
strike = 0
price = 0
quant = 3
vola = 0
paramD3 = {'dType': dType, 'price': price, 'quant': quant, 'strike': strike, 'vola': vola, 'exp': exp}

calc.searchDelta(fPrice, deep, acc, paramD1, params)
calc.searchDelta(fPrice, deep, acc, paramD_1, params)
calc.searchDelta(fPrice, deep, acc, paramD2, params)
calc.searchDelta(fPrice, deep, acc, paramD_2, params)
calc.searchDelta(fPrice, deep, acc, paramD3, params)
calc.searchDelta(fPrice, deep, acc, paramD_3, params)

S = 54
K = 53
V = 0.35
T = 3
dT = "P"

#print('One: ', round(calc.theo(S, K, V, T/god, dT), 2))


import numpy as np

def PCA(data):
    '''
    PCA	Principal Component Analysis

    Input:
      data      - Data numpy array. Each row vector of fea is a data point.
    Output:
      eigvector - Each column is an embedding function, for a new
                  data point (row vector) x,  y = x*eigvector
                  will be the embedding result of x.
      eigvalue  - The sorted eigvalue of PCA eigen-problem.
    '''

    # YOUR CODE HERE
    # Hint: you may need to normalize the data before applying PCA
    # begin answer
    N, P = data.shape
    mu = np.mean(data, axis=0)
    X = data - mu             # mu(X) = 0
    S = np.matmul(X.T, X)/N   # S.shape = (P, P)
    ex, ev = np.linalg.eig(S)
    tmp = zip(ex, range(len(ex)))
    stmp = sorted(tmp, key=lambda x:x[0], reverse=True)
    eigvalue = np.array([x[0] for x in stmp])
    eigvector = np.vstack([ev[:,x[1]] for x in stmp]).T
    return eigvector, eigvalue
    # end answer


# #### To caclulate a Gröbner Basis

x,y,z = QQ["x,y,z"].gens()
f1, f2 = y-2*x, 1+2*x*y
I = ideal(f1,f2)
B = I.groebner_basis()
print(B)

I2 = ideal(x - 2*y, 1+2*x*y)
B2 = I2.groebner_basis()
print(B2)

I3 = ideal(1+x*z, 2+y**2*x**2)
B3 = I3.groebner_basis()
print(B3)

[0,-1,0]
[0,0,3]
[0,0,0]

[-1,0,0]
[0,0,0]
[0,5,0]

# #### To use verbose Buchberger's

from sage.rings.polynomial.toy_buchberger import *

I3 = ideal(1+x, 1+y)
B3 = I3.groebner_basis()
print(B3)

set_verbose(1)
buchberger(I3)

f1 = 1 + x
f2 = 1+ y
f3 = 1+x**2*y+x
I = ideal(f1,f2,f3)
buchberger(I)


import numpy as np

def problem(x):

    transl = 1/ np.sqrt(2)
    part1 = (x[0] - transl)**2 + (x[1] - transl)**2
    part2 = (x[0] + transl)**2 + (x[1] + transl)**2
    f1 = 1 - np.exp(-part1)
    f2 = 1 - np.exp(-part2)
    return [f1, f2]

def bounds():

    return np.array([[-np.pi, -5.,-5.],[np.pi,5.,5.]])


"""File for non sklearn metrics that are to be used for reference for tests."""
from typing import Optional, Union

import numpy as np
from sklearn.metrics._regression import _check_reg_targets
from sklearn.utils import assert_all_finite, check_consistent_length, column_or_1d

def symmetric_mean_absolute_percentage_error(
    y_true: np.ndarray,
    y_pred: np.ndarray,
    sample_weight: Optional[np.ndarray] = None,
    multioutput: str = "uniform_average",
):
    r"""Symmetric mean absolute percentage error regression loss (SMAPE_):

    .. math:: \text{SMAPE} = \frac{2}{n}\sum_1^n\frac{max(|   y_i - \hat{y_i} |}{| y_i | + | \hat{y_i} |, \epsilon)}

    Where :math:`y` is a tensor of target values, and :math:`\hat{y}` is a tensor of predictions.

    Args:
        y_true: array-like of shape (n_samples,) or (n_samples, n_outputs)
            Ground truth (correct) target values.
        y_pred: array-like of shape (n_samples,) or (n_samples, n_outputs)
            Estimated target values.
        sample_weight: array-like of shape (n_samples,), default=None
            Sample weights.
        multioutput: {'raw_values', 'uniform_average'} or array-like
            Defines aggregating of multiple output values.
            Array-like value defines weights used to average errors.
            If input is list then the shape must be (n_outputs,).

                - 'raw_values': Returns a full set of errors in case of multioutput input.
                - 'uniform_average': Errors of all outputs are averaged with uniform weight.

    Returns:
        loss: float or ndarray of floats in the range [0, 1]
            If multioutput is 'raw_values', then symmetric mean absolute percentage error
            is returned for each output separately.
            If multioutput is 'uniform_average' or an ndarray of weights, then the
            weighted average of all output errors is returned.
            MAPE output is non-negative floating point. The best value is 0.0.
            But note the fact that bad predictions can lead to arbitarily large
            MAPE values, especially if some y_true values are very close to zero.
            Note that we return a large value instead of `inf` when y_true is zero.

    """
    _, y_true, y_pred, multioutput = _check_reg_targets(y_true, y_pred, multioutput)
    check_consistent_length(y_true, y_pred, sample_weight)
    epsilon = np.finfo(np.float64).eps
    smape = 2 * np.abs(y_pred - y_true) / np.maximum(np.abs(y_true) + np.abs(y_pred), epsilon)
    output_errors = np.average(smape, weights=sample_weight, axis=0)
    if isinstance(multioutput, str):
        if multioutput == "raw_values":
            return output_errors
        # pass None as weights to np.average: uniform mean
        multioutput = None

    return np.average(output_errors, weights=multioutput)

# sklearn reference function from
# https://github.com/samronsin/scikit-learn/blob/calibration-loss/sklearn/metrics/_classification.py.
# TODO: when the PR into sklearn is accepted, update this to use the official function.
def calibration_error(
    y_true: np.ndarray,
    y_prob: np.ndarray,
    sample_weight: Optional[np.ndarray] = None,
    norm: str = "l2",
    n_bins: int = 10,
    strategy: str = "uniform",
    pos_label: Optional[Union[int, str]] = None,
    reduce_bias: bool = True,
) -> float:
    """Compute calibration error of a binary classifier. Across all items in a set of N predictions, the
    calibration error measures the aggregated difference between (1) the average predicted probabilities assigned
    to the positive class, and (2) the frequencies of the positive class in the actual outcome. The calibration
    error is only appropriate for binary categorical outcomes. Which label is considered to be the positive label
    is controlled via the parameter pos_label, which defaults to 1.

    Args:
        y_true: array-like of shape (n_samples,)
            True targets of a binary classification task.
        y_prob: array-like of (n_samples,)
            Probabilities of the positive class.
        sample_weight: array-like of shape (n_samples,)
        norm: {'l1', 'l2', 'max'}
            Norm method. The l1-norm is the Expected Calibration Error (ECE),
            and the max-norm corresponds to Maximum Calibration Error (MCE).
        n_bins: int, default=10
        The number of bins to compute error on.
        strategy: {'uniform', 'quantile'}
            Strategy used to define the widths of the bins.
            uniform
                All bins have identical widths.
            quantile
                All bins have the same number of points.
        pos_label: int or str, default=None
            Label of the positive class. If None, the maximum label is used as positive class.
        reduce_bias: bool, default=True
            Add debiasing term as in Verified Uncertainty Calibration, A. Kumar.
            Only effective for the l2-norm.

    Returns:
        score: float with calibration error
    """
    y_true = column_or_1d(y_true)
    y_prob = column_or_1d(y_prob)
    assert_all_finite(y_true)
    assert_all_finite(y_prob)
    check_consistent_length(y_true, y_prob, sample_weight)
    if any(y_prob < 0) or any(y_prob > 1):
        raise ValueError("y_prob has values outside of [0, 1] range")

    labels = np.unique(y_true)
    if len(labels) > 2:
        raise ValueError(f"Only binary classification is supported. Provided labels {labels}.")

    if pos_label is None:
        pos_label = y_true.max()
    if pos_label not in labels:
        raise ValueError(f"pos_label={pos_label} is not a valid label: {labels}")
    y_true = np.array(y_true == pos_label, int)

    norm_options = ("l1", "l2", "max")
    if norm not in norm_options:
        raise ValueError(f"norm has to be one of {norm_options}, got: {norm}.")

    remapping = np.argsort(y_prob)
    y_true = y_true[remapping]
    y_prob = y_prob[remapping]
    if sample_weight is not None:
        sample_weight = sample_weight[remapping]
    else:
        sample_weight = np.ones(y_true.shape[0])

    n_bins = int(n_bins)
    if strategy == "quantile":
        quantiles = np.percentile(y_prob, np.arange(0, 1, 1.0 / n_bins) * 100)
    elif strategy == "uniform":
        quantiles = np.arange(0, 1, 1.0 / n_bins)
    else:
        raise ValueError(
            f"Invalid entry to 'strategy' input. \
                The strategy must be either quantile' or 'uniform'. Got {strategy} instead."
        )

    threshold_indices = np.searchsorted(y_prob, quantiles).tolist()
    threshold_indices.append(y_true.shape[0])
    avg_pred_true = np.zeros(n_bins)
    bin_centroid = np.zeros(n_bins)
    delta_count = np.zeros(n_bins)
    debias = np.zeros(n_bins)

    loss = 0.0
    count = float(sample_weight.sum())
    for i, i_start in enumerate(threshold_indices[:-1]):
        i_end = threshold_indices[i + 1]
        # ignore empty bins
        if i_end == i_start:
            continue
        delta_count[i] = float(sample_weight[i_start:i_end].sum())
        avg_pred_true[i] = np.dot(y_true[i_start:i_end], sample_weight[i_start:i_end]) / delta_count[i]
        bin_centroid[i] = np.dot(y_prob[i_start:i_end], sample_weight[i_start:i_end]) / delta_count[i]
        if norm == "l2" and reduce_bias:
            # NOTE: I think there's a mistake in the original implementation.
            # delta_debias = (
            #     avg_pred_true[i] * (avg_pred_true[i] - 1) * delta_count[i]
            # )
            # delta_debias /= (count * delta_count[i] - 1)
            delta_debias = avg_pred_true[i] * (avg_pred_true[i] - 1) * delta_count[i]
            delta_debias /= count * (delta_count[i] - 1)
            debias[i] = delta_debias

    if norm == "max":
        loss = np.max(np.abs(avg_pred_true - bin_centroid))
    elif norm == "l1":
        delta_loss = np.abs(avg_pred_true - bin_centroid) * delta_count
        loss = np.sum(delta_loss) / count
    elif norm == "l2":
        delta_loss = (avg_pred_true - bin_centroid) ** 2 * delta_count
        loss = np.sum(delta_loss) / count
        if reduce_bias:
            # convert nans to zero
            loss += np.sum(np.nan_to_num(debias))
        loss = np.sqrt(max(loss, 0.0))
    return loss


import numpy as np

from sigmoid import sigmoid

def costFunction(theta, X, y):

    theta = theta.reshape((theta.size, 1))

    m = y.size
    h = sigmoid(X.dot(theta))

    J = np.mean(-y * np.log(h) - (1 - y) * np.log(1 - h))

    grad = X.T.dot(h - y) / m

    return J, grad.ravel()


# -*- coding: utf-8 -*-
"""2. numpy linearRegression-with-CostFn.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1V1eAdA5KWorgeq9P6vR8x2IME3lLEQ1q
"""

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

# from: https://ml-cheatsheet.readthedocs.io/en/latest/linear_regression.html#cost-function
#
# We need a cost fn and its derivative...

dataset = pandas.read_csv("data/Advertising.csv").as_matrix()

def cost_function(X, y, weight, bias):
    n = len(X)
    total_error = 0.0
    for i in range(n):
        total_error += (y[i] - (weight * X[i] + bias)) ** 2
    return total_error / n

def update_weights(X, y, weight, bias, alpha):
    weight_deriv = 0
    bias_deriv = 0
    n = len(X)

    for i in range(n):
        # Calculate partial derivatives
        # -2x(y - (mx + b))
        weight_deriv += -2 * X[i] * (y[i] - (weight * X[i] + bias))

        # -2(y - (mx + b))
        bias_deriv += -2 * (y[i] - (weight * X[i] + bias))

    # We subtract because the derivatives point in direction of steepest ascent
    weight -= (weight_deriv / n) * alpha
    bias -= (bias_deriv / n) * alpha

    return weight, bias

def train(X, y, weight, bias, alpha, iters):
    cost_history = []

    for i in range(iters):
        weight, bias = update_weights(X, y, weight, bias, alpha)

        # Calculate cost for auditing purposes
        cost = cost_function(X, y, weight, bias)
        # cost_history.append(cost)

        # Log Progress
        if i % 10 == 0:
            print("iter: " + str(i) + " weight: " + str(weight) + " bias: " + str(bias) + " cost: " + str(cost))

    return weight, bias  # , cost_history

# work out
y = dataset[:, 4].reshape(200, 1)
X = dataset[:, 1].reshape(200, 1)

m = 0
c = 0

alpha = 0.1
iters = 100

# normalise the data
y = y / np.linalg.norm(y, ord=np.inf, axis=0, keepdims=True)
X = X / np.linalg.norm(X, ord=np.inf, axis=0, keepdims=True)

weight, bias = train(X, y, m, c, alpha, iters)

# a picture is worth a thousand words...
_ = plt.plot(X, y, 'o', [0, 1], [bias, weight + bias], '-')
plt.show()


# Copyright (c) AIRBUS and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import numpy as np
import math

def f_sum(args):
	return 0.5 * (args[0] + args[1])

def f_aminus(args):
	return 0.5 * (abs(args[0] - args[1]))

def f_mult(args):
	return args[0] * args[1]

def f_exp(args):
	return (np.exp(args[0]) - 1.0) / (np.exp(1.0) - 1.0)

def f_abs(args):
	return abs(args[0])

def f_sqrt(args):
	return np.sqrt(abs(args[0]))

def f_sqrtxy(args):
	return np.sqrt(args[0] * args[0] + args[1] * args[1]) / np.sqrt(2.0)

def f_squared(args):
	return args[0] * args[0]

def f_pow(args):
	return pow(abs(args[0]), abs(args[1]))

def f_one(args):
	return 1.0

def f_zero(args):
	return 0.0

def f_inv(args):
	if args[0] != 0.0:
		return args[0] / abs(args[0])
	else:
		return 0.0

def f_gt(args):
	return float(args[0] > args[1])

def f_acos(args):
	return math.acos(args[0]) / np.pi

def f_asin(args):
	return 2.0 * math.asin(args[0])/ np.pi

def f_atan(args):
	return 4.0 * math.atan(args[0]) / np.pi

def f_min(args):
	return np.min(args)

def f_max(args):
	return np.max(args)

def f_round(args):
	return round(args[0])

def f_floor(args):
	return math.floor(args[0])

def f_ceil(args):
	return math.ceil(args[0])


# --------------
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Load the dataframe
df = pd.read_csv(path)

p_a = len(df[df['fico'] > 700])/len(df)
p_b = len(df[df['purpose'] == 'debt_consolidation'])/len(df)

# Given debt consolidation probability of fico being greater than 700 p(a/b)
df1 = df[df['purpose'] == 'debt_consolidation']
p_b_a = len(df1[df1['fico']> 700])/len(df1)

# Given fico being greater than 700 probability of debt consolidation p(b/a)
df2 = df[df['fico'] > 700]
p_a_b = len(df2[df2['purpose'] == 'debt_consolidation'])/len(df2)

prob_lp = len(df[df['paid.back.loan']== 'Yes'])/len(df)
prob_cs = len(df[df['credit.policy']== 'Yes'])/len(df)

new_df = df[df['paid.back.loan']== 'Yes']
prob_pd_cs = len(new_df[new_df['credit.policy'] == 'Yes'])/len(new_df)
bayes = round((prob_pd_cs*prob_lp)/prob_cs,4)
bayes

da = df['purpose'].value_counts()
plt.bar(da.index,da)
plt.xticks(rotation = 45)
plt.show()

df1 = df[df['paid.back.loan']=='No']
db = df1['purpose'].value_counts()
plt.bar(db.index,db)
plt.xticks(rotation = 45)
plt.show()

inst_median = df['installment'].median()
inst_mean = df['installment'].mean()

plt.hist(df['installment'])
plt.show()

plt.hist(df['log.annual.inc'])
plt.show()