import numpy as np
from math import ceil
from . import base

class LagrangianInterpolator(base.Interpolator):
    def __init__(self, degree, fitting_profile='local'):
        """Lagrangian Integrator.

        :param degree: int
            The degree of the polynomial form.

        :param fitting_profile: str (default='local')
            The fitting profile of the interpolation.

            If 'local', will interpolate using the closest points to t.
            If 'sparse', will use the most sparse collection of points possible.

        """
        super().__init__(degree)

        self.fitting_profile = fitting_profile

    @property
    def fitting_profile(self):
        return self.__fitting_profile

    @fitting_profile.setter
    def fitting_profile(self, value):
        if value not in ('local', 'sparse'):
            raise ValueError('Cannot set fitting_profile property to %s' % str(value))

        self.__fitting_profile = value

    def l(self, i, t, indices):
        """Calculate the discreet Dirac Delta.

        :param i:
            The index L_i. References the current landmark.

        :param t:
            The point of interest for prediction.

        :return:
            :float: the value L_i(t).
        """
        l = 1

        for j in indices:
            if i == j:
                continue

            l *= ((t - self.X[j]) / (self.X[i] - self.X[j]))[0]

        return l

    def predict(self, t):
        """Interpolate the function f described by the data X to predict f(t).

        :param t:
            The point of interest, where f(t) should be predicted.

        :return:
            :float: the interpolated value for f(t).
        """
        if self.fitting_profile == 'local':
            # Select the "degree+1" closest points to t.
            indices = np.argsort(np.abs(self.X - t), axis=0)[:self.degree + 1]

        else:
            # Select the "degree + 1" most sparse points.
            indices = [i * self.X.shape[0] // self.degree + self.X.shape[0]
                       // (2 * self.degree) for i in range(self.degree)]

            # Shift points so the extremes of the interval are included.
            indices = [v - self.X.shape[0] // (2 * self.degree) for i, v in
                       enumerate(indices[:len(indices) // 2 + 1])] \
                      + [v + (self.X.shape[0] - 1) // (2 * self.degree) for i, v in
                         enumerate(indices[len(indices) // 2:])]

        # The points found are ordered by distance to :t (e.g., 5, 1, 0, 3).
        # Reorder them by their indices (e.g.: 0, 1, 3, 5).
        indices = np.sort(indices).flatten()
        return sum((self.y[i] * self.l(i, t, indices) for i in indices))


import numpy as np

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

def log_loss(x, y, eps=1e-6):
    x = np.clip(x, eps, 1-eps)
    return -(y*np.log(x) + (1-y)*np.log(1-x))


import numpy as np #type: ignore
from bikinematicsolver.dtypes import Pos

def find_intersection(a1,a2,b1,b2):
    """
    Finds intersection of lines a and b, described by points a1,a2,b1,b2
    Accepts vector input of shape (2,N)
    Returns (x_int,y_int)
    """
    #Eqn first line
    m_a = np.subtract( a2.y , a1.y ) / np.subtract( a2.x , a1.x )
    c_a = np.subtract( a1.y,  m_a * a1.x )
    #Eqn second line
    m_b = np.subtract( b2.y , b1.y ) / np.subtract( b2.x , b1.x )
    c_b = np.subtract( b1.y, m_b * b1.x )
    #Intersction point
    x0 = np.subtract( c_b , c_a ) / np.subtract( m_a, m_b )
    y0 = np.add( m_b * x0  , c_b )

    ic = Pos(x0,y0)
    return ic

def tangent_eqn(cen,r1,r2):
    """
    Finds equation of line in form ax + by = c, that is tangent to two circles. The first circle is at the origin, and the other is at an arbitrary point

    cen: centrepoint of offset circle (or vector between the centres of both circles)
    r1: radius of first circle
    r2: radius of second circle
    """
    delta_r = r2-r1
    z = np.add( np.power(cen[0],2) , np.power(cen[1],2))
    d = np.sqrt( np.subtract( z , np.power(delta_r,2) ) )

    a = np.add( cen[0]*delta_r, cen[1]*d  ) / z
    b = np.subtract( cen[1]*delta_r, cen[0]*d  ) / z
    c = r1
    ret = [a,b,c]
    return ret

def find_common_circle_tangent(cen1,r1,cen2,r2):
    """
    Finds all the tangent lines between two circles in form ax + by = c
    """
    tan_lines = []
    for i in [-1,1]:
        for j in [-1,1]:
            cen = np.subtract(cen2 , cen1)
            #print(cen)
            tan_lines.append(tangent_eqn(cen, r1 * i, r2 * j))
    for line in tan_lines:
        s = np.add( line[0] * cen1[0] , line[1] * cen1[1])
        line[2] = np.subtract( line[2] , s )
    return tan_lines

def find_circle_tangent_intersection(cen,tangent_line):
    """
    Finds the intersection point of a circle and a line TANGENT!!!!!!!!!!!!!!!!!!!!!! to the circle
    """
    line = tangent_line[:]
    s = np.add( line[0] * cen[0] , line[1] * cen[1])
    line[2] = np.add( line[2] , s )

    z = np.add( np.power(line[0],2) , np.power(line[1],2) )
    x0 = -(line[0] * line[2]) / z + cen[0]
    y0 = -(line[1] * line[2] ) / z + cen[1]

    ic = Pos(x0,y0)
    return ic

def find_upper_tangent_points(t_lines,cen1,cen2):
    """
    Given a set of circles and their appropriate tangent lines (ax + by = c format) this finds the intersection points between the 'upper' tangent line and the circles - this is the chainline on a bike
    """
    p1 =[]
    p2 = []

    for line in t_lines:
        p1.append(find_circle_tangent_intersection(cen1,line))
        p2.append(find_circle_tangent_intersection(cen2,line))

    positive_inds_1 = [p1.index(point) for point in p1
                        if point.y-cen1[1] > 0]
    positive_inds_2 = [p2.index(point) for point in p2
                        if point.y-cen2[1] > 0]

    ind = [i for i in positive_inds_1 if i in positive_inds_2]
    if ind:
        ind = ind[0]
        return [p1[ind],p2[ind]]
    else:
        return [Pos(0,0),Pos(0,0)]


import numpy as np
import math
import random
from tree import Node
def readData():
	data=[]
	with open("iris.data", "r") as f:
		for line in f.readlines():
			words = line.split(",")
			words[0] = float(words[0])
			words[1] = float(words[1])
			words[2] = float(words[2])
			words[3] = float(words[3])
			words[4] = words[4].replace("\n","")
			data.append(tuple(words))
	return data

#########Construct Desicion Tree #########
def calculateEntropy(data):
	count = {}
	entropy = 0.0
	for instance in data:
		if not instance[4] in count:
			count[instance[4]] = 1
		else:
			count[instance[4]] += 1
	for freq in count.values():
		entropy += -(freq/len(data)) * math.log(freq/len(data), 2)
	return entropy

def minRemAndThreshold(data,attrIndex):
	min_rem = float('inf')
	rem = float('inf')
	best_threshold = float('inf')
	split = 0
	sortedData = sorted(data,key=lambda x: x[attrIndex])
	for i in range(len(sortedData)-1):
		if sortedData[i][4] != sortedData[i+1][4]:
			leftData = []
			rightData = []
			threshold = (sortedData[i][attrIndex] + sortedData[i+1][attrIndex])/2
			# split instances by threshold
			for instance in sortedData:
				if instance[attrIndex] < threshold:
					leftData.append(instance)
				else:
					rightData.append(instance)
			rem = calculateEntropy(leftData)*(len(leftData)/len(sortedData)) + calculateEntropy(rightData)*(len(rightData)/len(sortedData))
			if rem < min_rem:
				min_rem = rem
				best_threshold = threshold

	return min_rem, best_threshold

def chooseBestFeature(data, RF):
	best_rem = float('inf')
	best_threshold = float('inf')
	best_feature = 0
	if RF:
		sample = random.sample(range(4), 2)
		for attrIndex in sample:
			rem, threshold = minRemAndThreshold(data,attrIndex)
			if rem < best_rem:
				best_rem = rem
				best_threshold = threshold
				best_feature = attrIndex

	else:
		for attrIndex in range(4):
			rem, threshold = minRemAndThreshold(data,attrIndex)
			if rem < best_rem:
				best_rem = rem
				best_threshold = threshold
				best_feature = attrIndex
	return best_threshold, best_feature

def voteMajority(data):
	count = {}
	for instance in data:
		if not instance[4] in count:
			count[instance[4]] = 1
		else:
			count[instance[4]] += 1
	majority = max(count, key=lambda i: count[i])
	return majority

def isPure(node):
	sameclasscount = 0
	target = node.data[0][4]    #take first instance's class as compare standard
	for instance in node.data:
		if target == instance[4]:
			sameclasscount += 1
	if sameclasscount == len(node.data):
		return True
	else:
		return False

def makeTree(currnode, RF=None):
	leftData = []
	rightData = []
	if RF:
		threshold, feature_idx = chooseBestFeature(currnode.data, RF=True)
	else:
		threshold, feature_idx = chooseBestFeature(currnode.data, RF=False)
	currnode.set_threshold(threshold)
	currnode.set_feature_index(feature_idx)

	for instance in currnode.data:
		if instance[feature_idx] < threshold:
			leftData.append(instance)
		else:
			rightData.append(instance)

	if isPure(currnode):    # all instances are the same class
		currnode.set_label(currnode.data[0][4])
		return currnode
	elif len(leftData)==0 or len(rightData)==0:   # threshold can't split data into two parts
		majority = voteMajority(currnode.data)
		currnode.set_label(majority)
		return currnode
	else:
		currnode.left = Node(leftData)
		makeTree(currnode.left)
		currnode.right = Node(rightData)
		makeTree(currnode.right)

#########Calculate Accuracy#########
def classify(node,testingInstance):
	if len(node.label)>0:   #Has label only if the node is leaf
		return node.label
	if testingInstance[node.feature_index] < node.threshold:
		return classify(node.left, testingInstance)
	else:
		return classify(node.right, testingInstance)

def validate(root, testingData, trainingData, treeNum):
	correct = 0
	data_count={
		'Iris-setosa':0,
		'Iris-versicolor':0,
		'Iris-virginica':0
	}
	TP_count={
		'Iris-setosa':0,
		'Iris-versicolor':0,
		'Iris-virginica':0
	}
	predict_count={
		'Iris-setosa':0,
		'Iris-versicolor':0,
		'Iris-virginica':0
	}
	precision={
		'Iris-setosa':0.0,
		'Iris-versicolor':0.0,
		'Iris-virginica':0.0
	}
	recall={
		'Iris-setosa':0.0,
		'Iris-versicolor':0.0,
		'Iris-virginica':0.0
	}

	for instance in testingData:
		data_count[instance[4]] += 1
		if treeNum > 1:    #Forest
			majority={}
			for n in range(treeNum):
				sample_trainingData = [trainingData[x] for x in random.sample(range(len(trainingData)), 40)]   #bagging
				root = Node(sample_trainingData)
				makeTree(root)
				predict_class = classify(root,instance)
				if not predict_class in majority:
					majority[predict_class] = 1
				else:
					majority[predict_class] += 1
			predict = max(majority, key=lambda p: majority[p])
			predict_count[predict] += 1
			correct = totalcorrect(predict, correct, instance)
			if predict == instance[4]:
				TP_count[instance[4]] += 1
		else:
			predict = classify(root,instance)
			predict_count[predict] += 1
			correct = totalcorrect(predict, correct, instance)
			if predict == instance[4]:
				TP_count[instance[4]] += 1

	#accuarcy
	accuracy = correct / len(testingData)
	#precision
	precision['Iris-setosa'] =TP_count['Iris-setosa'] / predict_count['Iris-setosa']
	precision['Iris-versicolor'] =TP_count['Iris-versicolor'] / predict_count['Iris-versicolor']
	precision['Iris-virginica'] =TP_count['Iris-virginica'] / predict_count['Iris-virginica']
	#recall
	recall['Iris-setosa'] =TP_count['Iris-setosa'] / data_count['Iris-setosa']
	recall['Iris-versicolor'] =TP_count['Iris-versicolor'] / data_count['Iris-versicolor']
	recall['Iris-virginica'] =TP_count['Iris-virginica'] / data_count['Iris-virginica']
	return (accuracy, precision, recall)

def totalcorrect(predict, correct, instance):
	if predict == instance[4]:
		correct += 1
	return correct


import numpy as np

class Activations:
    def __init__(self,fnc_name):
        self.fnc_type = fnc_name
        self.f = None
        self.f_dot = None
        self.__select_fnc()

    def __select_fnc(self):
        if self.fnc_type == 'sigmoid' or self.fnc_type == 'logistic':
            self.f = self.__sigmoid
            self.f_dot = self.__sigmoid_der

        elif self.fnc_type == 'tanh' :
            self.f = self.__tanh
            self.f_dot = self.__tanh_der

        elif self.fnc_type == 'relu' or  self.fnc_type == "RELU" :
            self.f = self.__relu
            self.f_dot = self.__relu_der

        elif self.fnc_type == 'final':
            self.f = None
            self.f_dot = None

    def __sigmoid(self,Z):
        return 1 / (1 + np.exp(-Z))

    def __tanh(self,Z):
        return np.tanh(Z)

    def __relu(self,Z):
        return np.maximum(0,Z)

    def __sigmoid_der(self,dA,cache):
        """dZ[L] = da[L] * g'[l](Z[l]) where g'(x) = sigmoid(x)*(1-sigmoid(x)) """
        Z = cache
        g_dot = self.__sigmoid(Z)*( 1- self.__sigmoid(Z) )
        dZ = dA * g_dot
        return dZ

    def __tanh_der(self,dA,cache):
        """dZ[L] = da[L] * g'[l](Z[l]) where g'(x) = 1 - tanh(x)^2 """
        Z = cache
        g_dot = 1.0 - np.tanh(Z)**2
        dZ  =  dA * g_dot
        return dZ

    def __relu_der(self,dA,cache):
        """dZ[L] = da[L] * g'[l](Z[l]) where g'(x) = 0 if x<0  and 1 if x>0"""
        Z = cache
        dZ = np.array(dA, copy=True)
        dZ[Z <= 0] = 0
        return dZ


"""
Author: Peratham Wiriyathammabhum

"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# import scipy.sparse.linalg as linalg
from numpy import linalg as LA

def pca(Xin):
	"""
	Perform PCA on an input row matrix X.

	"""
	X = Xin.copy() # for safety
	ni, nd = X.shape

	# centering
	X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)

	# TODO: PCA for small samples where nd >> ni
	C = np.cov(X.T)

	w, v = LA.eig(C)
	ind = np.argsort(-w, axis=0) # sorting descending
	w = w[ind]
	v = v[:, ind]

	proj_v = v[:,0:2] # projection matrix
	X_r = np.matmul(X, proj_v)
	return X_r

def main():
	# load data
	from sklearn import datasets
	X, color = datasets.make_swiss_roll(n_samples=2500)

	# dimred
	X_r = pca(X)

	# plot
	fig = plt.figure()

	ax = fig.add_subplot(211, projection='3d')
	ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=color, cmap=plt.cm.Spectral)

	ax.set_title("Original data")
	ax = fig.add_subplot(212)
	ax.scatter(X_r[:, 0], X_r[:, 1], c=color, cmap=plt.cm.Spectral)
	plt.axis('tight')
	plt.xticks([]), plt.yticks([])
	plt.title('Projected data')
	plt.show()
	input("Press Enter to continue...")

	return

if __name__ == '__main__':
	main()


import numpy as np
from numpy.random import rand

PRECISION_VALUE = 1e-5

def solve_CTMC(Q):
    """
    Solve stationary distribution vector x for a CTMC with generator matrix Q
    balance equation: x * Q = 0

    Parameters
    ----------
    Q: generator matrix of a CTMC, row sum == 0

    Return
    -------
    x.T: 1-D row vector, stationary distribution vector
    """

    if np.any(abs(np.sum(Q, 1) - 0.0) > PRECISION_VALUE):
        raise ValueError('Invalid CTMC Q matrix: Row sum not equal to 0')
    A = Q.copy()
    A[:, 0] = np.ones(A.shape[0])
    b = np.zeros((A.shape[0], 1))
    b[0] = 1.0
    x = np.linalg.solve(A.T, b)

    return x.T

def solve_DTMC(P):
    P = np.asarray(P)
    if np.any(np.sum(P, 1) - 1.0 > PRECISION_VALUE):
        raise ValueError('Invalid DTMC P matrix: Row sum not equal to 1')
    return solve_CTMC(P - np.eye(P.shape[0]))

def sum_matrix_list(mat_list):
    sum_mat = np.zeros(mat_list[0].shape)
    for mat in mat_list:
        sum_mat += mat
    return sum_mat

def check_BMAP_representation(D_list, prec=PRECISION_VALUE):
    if len(D_list) == 2:
        print('Input: MAP representation')
    elif len(D_list) > 2:
        print('Input: BMAP representation')
    else:
        print('neither MAP or BMAP representation')
        return False

    D0 = D_list[0]
    for Dk in D_list[1:]:
        if D0.shape != Dk.shape:
            print('D0 and Dk have different shapes')
            return False
    for Dk in D_list[1:]:
        if np.min(Dk) < -prec:
            print('Dk has negative entry')
            return False

    if np.any(np.abs(np.sum(sum_matrix_list(D_list), 1)) > prec):
        print('row sum is not zero')
        return False

    return True

def BMAP_generator(D_list, initial=None):
    """
    Generates random samples from a batch Markovian
    arrival process.

    Parameters
    ----------
    D_list: list of matrices of shape(M,M), length(N)
        The D0...DN matrices of the BMAP
    num_samples: integer
        The number of samples to generate.

    Yield:
    -------
    x : one sample.
        if BMAP: list consisting of two values: the inter-arrival time and the type of the
        arrival.
        if MAP: float, inter-arrival time
    """

    if not check_BMAP_representation(D_list):
        raise ValueError(
            "Samples From BMAP: Input is not a valid BMAP representation!")

    M = D_list[0].shape[0]

    if initial is None:
        # draw initial state according to the stationary distribution
        stat_distr_vec = solve_CTMC(sum_matrix_list(D_list))
        cumm_initial = np.cumsum(stat_distr_vec)
        r = rand()
        state = 0
        while cumm_initial[state] <= r:
            state += 1
    else:
        state = initial

    # auxilary variables
    sojourn = -1.0 / np.diag(D_list[0])
    nextpr = np.diag(sojourn) @ D_list[0]
    nextpr = nextpr - np.diag(np.diag(nextpr))
    for Dk in D_list[1:]:
        nextpr = np.hstack((nextpr, np.diag(sojourn) * Dk))
    nextpr = np.cumsum(nextpr, 1)

    while True:
        iat = 0

        # play state transitions
        while state < M:
            iat -= np.log(rand()) * sojourn[state]
            r = rand()
            nstate = 0
            while nextpr[state, nstate] <= r:
                nstate += 1
            state = nstate
        state = nstate % M
        if len(D_list) > 2:
            yield [iat, nstate // M]
        else:
            yield iat


from numpy import array, cos, sin, tan, identity

def Txyz(d):
    T = identity(4)
    T[0:3,3] = d

    return T

def Rxyz(phi):
    rx = phi[0]
    ry = phi[1]
    rz = phi[2]

    R = identity(4)
    R[0:3,0:3] = array([
        [                           cos(ry)*cos(rz),                          -cos(ry)*sin(rz),          sin(ry)],
        [ cos(rx)*sin(rz) + cos(rz)*sin(rx)*sin(ry), cos(rx)*cos(rz) - sin(rx)*sin(ry)*sin(rz), -cos(ry)*sin(rx)],
        [ sin(rx)*sin(rz) - cos(rx)*cos(rz)*sin(ry), cos(rz)*sin(rx) + cos(rx)*sin(ry)*sin(rz),  cos(rx)*cos(ry)]
    ])
    return R

def Rzyx(phi):
    rx = phi[0]
    ry = phi[1]
    rz = phi[2]

    R = identity(4)
    R[0:3,0:3] = array([
        [ cos(ry)*cos(rz), cos(rz)*sin(rx)*sin(ry) - cos(rx)*sin(rz), sin(rx)*sin(rz) + cos(rx)*cos(rz)*sin(ry)],
        [ cos(ry)*sin(rz), cos(rx)*cos(rz) + sin(rx)*sin(ry)*sin(rz), cos(rx)*sin(ry)*sin(rz) - cos(rz)*sin(rx)],
        [        -sin(ry),                           cos(ry)*sin(rx),                           cos(rx)*cos(ry)]
    ])
    return R

def InvH(H):
    R = H[0:3,0:3]
    t = H[0:3,3]

    invH = identity(4)

    invH[0:3,0:3] = R.transpose()
    invH[0:3,3] = -R.transpose().dot(t)

    return invH

# Denavit-Hartenberg
def DH(theta, d, a, alpha):
    '''
    Deneavit-Hartenberg transformation matrix
    '''
    return array([
        [ cos(theta),-sin(theta)*cos(alpha), sin(theta)*sin(alpha), a*cos(theta)],
        [ sin(theta), cos(theta)*cos(alpha),-cos(theta)*sin(alpha), a*sin(theta)],
        [ 0         , sin(alpha)           , cos(alpha)           , d           ],
        [ 0         , 0                    , 0                    , 1           ]
    ])


#!/usr/bin/env python3

import numpy as np

def multivariateGaussian(X, mu, Sigma2):
    #MULTIVARIATEGAUSSIAN Computes the probability density function of the
    #multivariate gaussian distribution.
    #    p = MULTIVARIATEGAUSSIAN(X, mu, Sigma2) Computes the probability
    #    density function of the examples X under the multivariate gaussian
    #    distribution with parameters mu and Sigma2. If Sigma2 is a matrix, it is
    #    treated as the covariance matrix. If Sigma2 is a vector, it is treated
    #    as the \sigma^2 values of the variances in each dimension (a diagonal
    #    covariance matrix)
    #

    k = mu.size

    if Sigma2.ndim == 1:
        Sigma2 = np.diag(Sigma2)
    #end

    X = X - mu
    p = (2 * np.pi) ** (- k / 2) * np.linalg.det(Sigma2) ** (-0.5) * np.exp(-0.5 * np.sum(np.dot(X, np.linalg.pinv(Sigma2)) * X, axis=1))

    return p
    #end


#=================================================\\Documentation//==================================================

"""
This module contains some types of numerical analysis methods for solving systems of equations & matrix decompositions,
such as Gauss-Jordan, LU decomposition and Cholesky decomposition.

"""

#================================================\\Libraries needed//================================================

import numpy as np

#=========================================\\The Elimination Of Gauss-Jordan//========================================

# 1.The Inverse of a Matrix:

def inverse( M ):
    """
    inverse( M ).
    This method calculate the inverse of a matrix (M).

    Parameters:
    M(array): the matrix that you want to inverse

    Returns:
    I: the inverted matrix.

    """
    n=len(M)
    I=np.eye(n)
    for indice in range(0,n-1):
        p=M[indice][indice]
        for i in range(indice+1,n):
            q =M[i][indice]/p
            for k in range(n):
                M[i][k]=M[i][k]-q*M[indice][k]
                I[i][k]=I[i][k]-q*I[indice][k]

    for indice in range(n-1,0,-1):
        p=M[indice][indice]
        for i in range(indice-1,-1,-1):
            q =M[i][indice]/p
            for k in range(n):
                M[i][k]=M[i][k]-q*M[indice][k]
                I[i][k]=I[i][k]-q*I[indice][k]

    for k in range(0,n):
        q=M[k][k]
        for j in range(0,n):
            I[k][j]=I[k][j]/q
            M[k][j]=M[k][j]/q
    return I

# 2.Gauss_Jordan method to solve system of linear equations:

def Gauss_jordan( M ):
    """
    Gauss_jordan( M ).
    This method solves a system of linear equations and returns the solutions in a list.

    Parameters:
    M(array): array which each line of it is a linear equation of the system

    Returns:
    list(M[:,n:n+1]): a list of the system solutions.

    """
    n=len(M)
    for i in range(0,n-1):
        p=M[i][i]
        for j in range(i+1,n):
            q =M[j][i]/p
            for k in range(n+1):
                M[j][k]=M[j][k]-q*M[i][k]

    M[n-1][n] = M[n-1][n]/M[n-1][n-1]
    M[n-1][n-1]= 1
    for i in range(n-1,0,-1):
        p=M[i][i]
        for j in range(i-1,-1,-1):
            q =M[j][i]/p
            for k in range(n+1):
                M[j][k]=M[j][k]-q*M[i][k]

    M[0][n] = M[0][n]/M[0][0]
    M[0][0]= 1
    return list(M[:,n:n+1])

#=============================================\\LU Decomposition Method//============================================

# 1.LU Decomposition:

def LU_decomposition( M ):
    """
    LU_decomposition( M ).
    This method applies the LU decomposition to a square matrix (M).

    Parameters:
    M(array): a square matrix

    Returns:
    (I,M): tuple containing lower and upper triangular matrix

    """
    n=len(M)
    I=np.eye(n)
    for i in range(0,n-1):
        p=M[i][i]
        for j in range(i+1,n):
            q =M[j][i]/p
            for k in range(n):
                M[j][k]=M[j][k]-q*M[i][k]

            I[j][i]=q

    return (I,M)

# 2.LU Decomposition method to solve system of equations:

def LU_decomposition_solve( M ):
    """
    LU_decomposition_solve( M ).
    This method applies the LU decomposition to solve a system of equations.

    Parameters:
    M(array): array which each line of it is a linear equation of the system

    Returns:
    x: a list of the system solutions.

    """
    n=len(M)
    L,U=LU_decomposition(M[:,0:n])
    y=[]
    y.append(M[0,n]/L[0,0])
    for i in range(1,n):
        sum=0
        for j in range(i):
            sum+=L[i,j]*y[j]
        y.append((M[i,n]-sum)/L[i,i])
    x=[]
    x.append(y[n-1]/U[n-1,n-1])
    for i in range(n-2,-1,-1):
        sum=0
        for j in range(i+1,n):
            sum+=U[i,j]*x[n-j-1]
        x.append((y[i]-sum)/U[i,i])
    x.reverse()
    return x

#===========================================\\Cholesky Decomposition Method//=========================================

# 1.Cholesky Decomposition:

def Cholesky_Decomposition( M ):
    """
    Cholesky_Decomposition( M ).
    This method applies the Cholesky decomposition to a positive definite matrix (M).

    Parameters:
    M(array): positive definite matrix

    Returns:
    A: lower triangular matrix.

    """
    n=len(M)
    A=np.zeros((n,n))
    A[0][0]=M[0][0]**(1/2)
    for i in range(1,n):
        A[i][0]=M[i][0]/A[0][0]
    for j in range(1,n):
        sum=0
        for k in range(0,j):
            sum+=A[j][k]**2
        A[j][j]=(M[j][j]-sum)**(1/2)
        for i in range(j+1,n):
            sum=0
            for k in range(j):
                sum+=A[i][k]*A[j][k]
        A[i][j]=(M[i][j]-sum)/A[j][j]
    return A

# 2.Cholesky Decomposition method to solve system of equations:

def Cholesky_Decomposition_solve( M ):
    """
    Cholesky_Decomposition_solve( M ).
    This method applies the Cholesky decomposition to solve a system of equations.

    Parameters:
    M(array): array which each line of it is a linear equation of the system

    Returns:
    x: a list of the system solutions.

    """
    n=len(M)
    L=Cholesky_Decomposition(M[:,0:n])
    y=[]
    y.append(M[0,n]/L[0,0])
    for i in range(1,n):
        sum=0
        for k in range(i):
            sum+=L[i,k]*y[k]
        y.append((M[i,n]-sum)/L[i,i])
    U=L.T
    x=[]
    x.append(y[n-1]/U[n-1,n-1])
    for i in range(n-2,-1,-1):
        sum=0
        for k in range(i+1,n):
            sum+=U[i,k]*x[n-k-1]
        x.append(round((y[i]-sum)/U[i,i]))
    x.reverse()
    return x

#====================================================================================================================


"""
Cosine angle between two vectors for determining similarity of vectors

Parameters:
    w1: vector of word 1
    w2: vector of word 2

Returns:
    Cosine distance between two vectors. Ranges from -1 (vectors pointing in opposite direction)
    to 1 (vectors pointing in the same direction)

cosine(w1, w2) = (w1·w2) / (|w1| |w2|)

eg. word-word matrix
             |  pie | data | computer
-------------------------------------
cherry       | 442  |  8   |  2
-------------------------------------
digital      |  5   | 1683 | 1670
-------------------------------------
information  |  5   | 3982 | 3325

Represented in the data structures:

matrix = np.array([
    [442, 8, 2],
    [5, 1683, 1670],
    [5, 3982, 3325]
])

cherry = matrix[0]
information = matrix[2]

cosine_distance(cherry, data)
# 0.01775392946668344
"""
import numpy as np
from numpy.linalg import norm

def cosine_distance(w1, w2):
   dist = np.dot(w1, w2) / (norm(w1) * norm(w2))
   return dist


import numpy as np
from sympy import *
from math import *
import matplotlib.pyplot as pl
x1 = -1

x = Symbol('x')

f = x**2/(x**2+1)
fx = lambdify(x, f, modules=['numpy'])

d = diff(fx(x), x)
df = lambdify(x, d,  modules=['numpy'])

print(f'Funcao {fx(x)}')
print(f'Derivada {df(x)} (coeficiente agular m)')

y1 = fx(x1)
#  (x1, y1)
#  Y - Y1 = m (X - X1)

funcao = df(x1)*x - df(x1)*x1 + y1

reta_tangente = lambdify(x, funcao, modules=['numpy'])

grafico_val = np.linspace(-4,4,2000)
grafico_reta = np.linspace(-4,4,100)
pl.plot(grafico_val, fx(grafico_val)) #  grafico da funcao
pl.plot(x1, fx(x1), 'ro')  #  Ponto x1 da funcao
pl.plot(grafico_val, reta_tangente(grafico_val))
pl.show()


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

df = pd.read_csv("polynominal_regression.csv", sep=";")

y = df.araba_max_hiz.values.reshape(-1, 1)
x = df.araba_fiyat.values.reshape(-1, 1)

plt.scatter(x, y)
plt.ylabel("araba max hız")
plt.xlabel("araba fiyat")

from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(x, y)

# predict
y_head = lr.predict(x)
print(y_head)

plt.plot(x, y_head, color="red", label="linear")

# polynomial regression

from sklearn.preprocessing import PolynomialFeatures

polynomial_regression = PolynomialFeatures(degree=4)  # degree artarsa mse (ortalama hata) azalır
x_polynomial = polynomial_regression.fit_transform(x)

# fit
linear_regression_2 = LinearRegression()
linear_regression_2.fit(x_polynomial, y)

y_head2 = linear_regression_2.predict(x_polynomial)

plt.plot(x, y_head2, color="green", label="poly")
plt.legend()
plt.show()


#This is numerical estimate of pi based on Monte Carlo method using unit circle inscribed in rectangle.
#Outputs pi estimate in terminal and also plot based on number of random points inputed by user.
#This code based on previous version at https://gist.github.com/louismullie/3769218.

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

# input total number of random points
total_random_points = int(input("\nNumber of random points for Monte Carlo estimate of Pi?\n>"))

# start time of calculation
start_time = time.time()

# number of random points inside unit cicrle and total random points
inside_circle = 0

# create empty x and y arrays for eventual scatter plot of generated random points
x_plot_array = np.empty(shape=(1,total_random_points))
y_plot_array = np.empty(shape=(1,total_random_points))

# generate random points and count points inside unit circle
# top right quadrant of unit cicrle only
for i in range(0, total_random_points):
    # generate random x, y in range [0, 1]
    x = np.random.rand()
    x_plot_array = np.append(x_plot_array, [x])
    y = np.random.rand()
    y_plot_array = np.append(y_plot_array, [y])
    # calc x^2 and y^2 values
    x_squared = x**2
    y_squared = y**2
    # count if inside unit circle, top right quadrant only
    if np.sqrt(x_squared + y_squared) < 1.0:
        inside_circle += 1
    # calc approximate pi value
    pi_approx = inside_circle / (i+1) * 4

# final numeric output for pi estimate
print ("\n--------------")
print (f"\nApproximate value for pi: {pi_approx}")
print (f"Difference to exact value of pi: {pi_approx-np.pi}")
print (f"Percent Error: (approx-exact)/exact*100: {(pi_approx-np.pi)/np.pi*100}%")
print (f"Execution Time: {time.time() - start_time} seconds\n")

# plot output of random points and circle, top right quadrant only
random_points_plot = plt.scatter(x_plot_array, y_plot_array, color='blue', s=.1)
circle_plot = plt.Circle( ( 0, 0 ), 1, color='red', linewidth=2, fill=False)

ax = plt.gca()
ax.cla()

ax.add_artist(random_points_plot)
ax.add_artist(circle_plot)

plt.show()


#obtenido de aca https://geekytheory.com/pylab-parte-1-python-se-viste-de-matlab

import numpy as np
import matplotlib.pyplot as pyplot

#Se crea la nube de puntos
x = np.array([0, 1, 2, 3])
y = np.array([1,1.5,1.8,2.6])

#Construimos una matriz
A = np.vstack([x, np.ones(len(x))])
A = A.T #hacemos su traspuesta

#Obtenemos parametros de la recta
m, c = np.linalg.lstsq(A,y)[0]
print("La recta obtenida es: y = " + str(m) + "x + " + str(c))

pyplot.plot(x, y, 'o', label='Nubes puntos', markersize=15 )
pyplot.plot(x, m*x + c, 'r', label='Regresion Lineal')
pyplot.legend()
pyplot.show()

raw_input("Enter para salir")


# importing Needed Packages
import matplotlib.pyplot as plt
import pandas as pd
import pylab as pl
import numpy as np
%matplotlib inline

# Downloading Data
# use !wget to download the data from IBM Object Storage
!wget -O FuelConsumption.csv https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/ML0101ENv3/labs/FuelConsumptionCo2.csv

# Reading the data in
df = pd.read_csv("FuelConsumption.csv")
# take a look at the dataset
df.head()

# select some features that we want to use for regression
cdf = df[['ENGINESIZE', 'CYLINDERS', 'FUELCONSUMPTION_CITY', 'FUELCONSUMPTION_HWY', 'FUELCONSUMPTION_COMB', 'CO2EMISSIONS']]
cdf.head(9)

# plot Emission values with respect to Engine size
plt.scatter(cdf.ENGINESIZE, cdf.CO2EMISSIONS, color='blue')
plt.xlabel("Engine size")
plt.ylabel("Emission")
plt.show()

# Creating train and test dataset
# Train/Test Split will split the dataset into training and testing sets respectively, which are mutually exclusive
# Testing dataset is not part of the dataset that have been used to train the data, which is out-of-sample, this way is more realistic for real world problems.
msk = np.random.rand(len(df)) < 0.8
train = cdf[msk]
test = cdf[~msk]

# Train data distribution
plt.scatter(train.ENGINESIZE, train.CO2EMISSIONS, color='blue')
plt.xlabel("Engine size")
plt.ylabel("Emission")
plt.show()

# Multiple Regression Model: there are more than one independent varaible, thus called multiple regression, which is the extension of simple linear regression model

from sklearn import linear_model
regr = linear_model.LinearRegression()
x = np.asanyarray(train[['ENGINESIZE', 'CYLINDERS', 'FUELCONSUMPTION_COMB']])
y = np.asanyarray(train[['CO2EMISSIONS']])
regr.fit(x, y)
# The coefficients
# Coefficient and Intercept are the parameters of the fit line. sklearn can estimate them from our data. Scikit-learn uses plain Ordinary Least Squares method to solve thid problem
# Ordinary Least Squares (OLS) can find the best parameters using the following methods:
    # - Solving the model parameters analytically using closed-form equations
    # - Using an optimization algorithm (Gradient Descent, Stochastic Gradient Descent, Newton's Method, etc.)
print('Coefficients:', regr.coef_)

# Prediction
y_hat = regr.predict(test[['ENGINESIZE', 'CYLINDERS', 'FUELCONSUMPTION_COMB']])
x = np.asanyarray(test[['ENGINESIZE', 'CYLINDERS', 'FUELCONSUMPTION_COMB']])
y = np.asanyarray(test[['CO2EMISSIONS']])
print("Residual sum of squres:%.2f" % np.mean((y_hat - y) ** 2))

# Explained variance score: 1 is perfect prediction
print('Variance score: %.2f' % regr.score(x, y))


import torch
import torch.distributions as td
import torch.optim as opt
import numpy as np

TPrior = td.Normal(0.0, 1.0)

torch.manual_seed(0)
data = torch.randn(100).to(torch.float64) + 3.0

# Parameters
mu = torch.tensor(0.0, dtype=torch.float64, requires_grad=True)
logstd = torch.tensor(0.0, dtype=torch.float64, requires_grad=True)

def get_elbo():
    q_distribution = td.Normal(mu, logstd.exp())
    theta_sample = q_distribution.rsample()

    log_prob_theta_model = TPrior.log_prob(theta_sample)
    log_prob_data_model = td.Normal(theta_sample, 1).log_prob(data).sum()

    # Second bit, variational distribution log prob, assuming theta is the hidden param
    log_prob_q = q_distribution.log_prob(theta_sample)

    loss = log_prob_theta_model + log_prob_data_model - log_prob_q

    # import torch.autograd

    # print("mu_grad=", torch.autograd.grad(loss, [mu], retain_graph=True))

    return loss

NUM_STEPS = 1001
optimizer = opt.SGD([mu, logstd], lr=0.001, momentum=0.1)

for step in range(NUM_STEPS):
    optimizer.zero_grad()
    loss = -get_elbo()
    loss.backward()
    optimizer.step()

    if step % 100 == 0:
        print("step {} loss = {}".format(step, loss))

print("MU=", mu.item())
print("LOGSTD=", logstd.item())

# For this simple (conjugate) model we know the exact posterior. In
# particular we know that the variational distribution should be
# centered near 3.0. So let's check this explicitly.
assert abs(mu.item() - 3.0) < 0.1


from __future__ import division
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import sys
import numpy as np
from numpy import linalg
from random import random
import code

def getMinVolEllipse(P=None, tolerance=0.01, v_center_px=[], v_diam_px=[]):
    """ Find the minimum volume ellipsoid which holds all the points"""
    (N, d) = np.shape(P)
    d = float(d)

    # Q is the working array
    Q = np.vstack([np.copy(P.T), np.ones(N)])
    QT = Q.T

    # initializations
    err = 1.0 + tolerance
    u = (1.0 / N) * np.ones(N)

    # Khachiyan Algorithm
    while err > tolerance:
        V = np.dot(Q, np.dot(np.diag(u), QT))
        try:
            M    = np.diag(np.dot(QT , np.dot(linalg.inv(V), Q)))    # M the diagonal vector of an NxN matrix
        except linalg.linalg.LinAlgError:
            center = [int(x) for x in v_center_px]
            radii  = np.array(v_diam_px)/5.

            rotation = [[0,0,0],[0,0,0],[0,0,0]]

            return (center, radii, rotation)

        j = np.argmax(M)
        maximum = M[j]
        step_size = (maximum - d - 1.0) / ((d + 1.0) * (maximum - 1.0))
        new_u = (1.0 - step_size) * u
        new_u[j] += step_size
        err = np.linalg.norm(new_u - u)
        u = new_u

    # center of the ellipse
    center = np.dot(P.T, u)

    # the A matrix for the ellipse
    A = linalg.inv(
                   np.dot(P.T, np.dot(np.diag(u), P)) -
                   np.array([[a * b for b in center] for a in center])
                   ) / d

    # Get the values to return
    U, s, rotation = linalg.svd(A)
    radii = 1.0/np.sqrt(s)

    return (center, radii, rotation)

def getEllipsoidVolume(radii):
    """Calculate the volume of the blob"""
    return 4./3.*np.pi*radii[0]*radii[1]*radii[2]

def plotEllipsoid(center, radii, rotation, ax=None, plotAxes=False, cageColor='b', cageAlpha=0.2):
    """Plot an ellipsoid"""
    make_ax = ax == None
    if make_ax:
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')

    u = np.linspace(0.0, 2.0 * np.pi, 100)
    v = np.linspace(0.0, np.pi, 100)

    # cartesian coordinates that correspond to the spherical angles:
    # x,y,z in shape (100x100)
    x = radii[0] * np.outer(np.cos(u), np.sin(v)) #all possible x for these angles
    y = radii[1] * np.outer(np.sin(u), np.sin(v))
    z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
    # rotate accordingly
    for i in range(len(x)):
        for j in range(len(x)):
            [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], rotation) + center
            [x[i,j],y[i,j],z[i,j]] = [round(x[i,j]),round(y[i,j]),round(z[i,j])]
    # code.interact(local=dict(globals(), **locals()))
    ax.plot_wireframe(x, y, z,  rstride=10, cstride=10, color=cageColor, alpha=cageAlpha)

    if make_ax:
        plt.show()
def plot__ellipse(P):
    # find the ellipsoid
    (center, radii, rotation) = getMinVolEllipse(P, .01)
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    # plot points
    ax.scatter(P[:,0], P[:,1], P[:,2], color='g', marker='o', s=100)
    # plot ellipsoid
    plotEllipsoid(center, radii, rotation, ax=ax, plotAxes=True)

    plt.show()

def plot__scatter(P):
    print("plotting scatter")
    # find the ellipsoid
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.scatter(P[:,0], P[:,1], P[:,2], color='b', marker='o', s=100)
    plt.show()

def plot__both_scatters(new, old):
    print("plotting scatter")
    # find the ellipsoid
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.scatter(new[:,0], new[:,1], new[:,2], color='b', marker='o', s=100)
    ax.scatter(old[:,0], old[:,1], old[:,2], color='g', marker='o', s=100)

    plt.show()


""" Classes for defining fitness functions."""

# Author: Genevieve Hayes (Modified by Andrew Rollings)
# License: BSD 3 clause

import numpy as np

class Queens:
    """Fitness function for N-Queens optimization problem. Evaluates the
    fitness of an n-dimensional state vector
    :math:`x = [x_{0}, x_{1}, \\ldots, x_{n-1}]`, where :math:`x_{i}`
    represents the row position (between 0 and n-1, inclusive) of the 'queen'
    in column i, as the number of pairs of attacking queens.

    Example
    -------
    .. highlight:: python
    .. code-block:: python

        >>> import mlrose_hiive
        >>> import numpy as np
        >>> fitness = mlrose_hiive.Queens()
        >>> state = np.array([1, 4, 1, 3, 5, 5, 2, 7])
        >>> fitness.evaluate(state)
        6

    References
    ----------
    Russell, S. and P. Norvig (2010). *Artificial Intelligence: A Modern
    Approach*, 3rd edition. Prentice Hall, New Jersey, USA.

    Note
    ----
    The Queens fitness function is suitable for use in discrete-state
    optimization problems *only*.
    """

    def __init__(self):

        self.prob_type = 'discrete'

    @staticmethod
    def shift(a, num, fill_value=np.nan):
        result = np.empty(a.shape)
        if num > 0:
            result[:num] = fill_value
            result[num:] = a[:-num]
        elif num < 0:
            result[num:] = fill_value
            result[:num] = a[-num:]
        else:
            result[:] = a
        return result

    def evaluate(self, state):
        """Evaluate the fitness of a state vector.

        Parameters
        ----------
        state: array
            State array for evaluation.

        Returns
        -------
        fitness: float
            Value of fitness function.
        """

        # check for horizontal matches.
        f_h = (np.unique(state, return_counts=True)[1]-1).sum()

        # check for diagonal matches.
        # look at the state_shifts to figure out how this works. (I'm quite pleased with it)
        ls = state.size
        # rows 0-3:   checking up left.
        # rows 4-7:   checking down right.
        # rows 8-11:  checking up right
        # rows 12-15: checking down left
        state_shifts = np.array([self.shift(state, i)+i for i in np.arange(1-ls, ls) if i != 0] +
                                [self.shift(state, -i)+i for i in np.arange(1-ls, ls) if i != 0])
        # state_shifts[(state_shifts < 0)] = np.NaN
        # state_shifts[(state_shifts >= ls)] = np.NaN

        f_d = np.sum(state_shifts == state) // 2  # each diagonal piece is counted twice
        fitness = f_h + f_d
        return fitness

    def get_prob_type(self):
        """ Return the problem type.

        Returns
        -------
        self.prob_type: string
            Specifies problem type as 'discrete', 'continuous', 'tsp'
            or 'either'.
        """
        return self.prob_type


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np

dat = [
    [300, 0.024],
    [400, 0.035],
    [500, 0.046],
    [600, 0.058],
    [700, 0.067],
    [800, 0.083],
    [900, 0.097],
    [1000, 0.111],
    [1100, 0.125],
]

class CubicSpline(object):

    """
    """

    def __init__(self, dat):
        self.dat = dat
        self._make_h()
        self._make_x()
        self._make_a()
        self._make_c()
        self._make_d()
        self._make_b()

    def _make_h(self):
        self.h = []
        for i in range(0, len(self.dat) - 1):
            #: x[i+1] - x[i]
            self.h.append(self.dat[i + 1][0] - self.dat[i][0])

    def _make_a(self):
        #: ai = yi
        self.a = [_[1] for _ in self.dat]

    def _make_x(self):
        #: ai = yi
        self.x = [_[0] for _ in self.dat]

    def _make_c(self):
        A, C = self._make_tridiagonal()
        self.c = list(np.linalg.solve(A, C))

    def _make_d(self):
        self.d = []

        for i in range(0, len(self.dat) - 3):
            _d = (self.c[i + 1] - self.c[i]) / 3 * self.h[i]
            self.d.append(_d)

    def _make_b(self):
        self.b = []

        for i in range(0, len(self.dat) - 3):
            _b = ((self.a[i + 1] - self.a[i]) / self.h[i]) - ((2 * self.c[i] + self.c[i + 1]) * self.h[i] / 3)
            self.b.append(_b)

    def _make_tridiagonal(self):
        d = []
        lim = len(self.dat) - 2
        A = []
        B = []
        C = []

        for i in range(lim):
            row = []
            if i == 0:
                s = self.Eq9()
                row.append(s[0])
                row.append(s[1])
                C.append(s[2])
                row += [0] * (lim - 2)
            elif i == (lim - 1):
                s = self.Eq10()
                row += [0] * (lim - 2)
                row.append(s[0])
                row.append(s[1])
                C.append(s[2])
            else:
                s = self.Astar(i)
                row += [0] * (i - 1)
                row.append(s[0])
                row.append(s[1])
                row.append(s[2])
                C.append(s[3])
                row += [0] * (lim - (i - 1) - 3)
            A.append(row)
        return A, C

    def Astar(self, i):
        a = self.h[i - 1]
        b = 2 * (self.h[i - 1] + self.h[i])
        c = self.h[i]
        d = 3 * ((self.a[i + 1] - self.a[i]) / self.h[i]) - 3 * ((self.a[i] - self.a[i - 1]) / self.h[i - 1])
        return a, b, c, d

    def Eq9(self):
        a = (3 * self.h[0]) + (2 * self.h[1]) + (self.h[0] ** 2 / self.h[1])
        b = self.h[1] - (self.h[0] ** 2 / self.h[1])
        c = (3 * (self.a[2] - self.a[1]) / self.h[1]) - (3 * (self.a[1] - self.a[0]) / self.h[0])
        return a, b, c

    def Eq10(self):
        n = len(self.dat) - 1
        a = self.h[n - 2] - (self.h[n - 1] ** 2 / self.h[n - 2])
        b = 3 * self.h[n - 1] + 2 * self.h[n - 1] + (self.h[n - 1] ** 2 / self.h[n - 2])
        c = (3 * (self.a[n] - self.a[n - 1]) / self.h[n - 1]) - (3 * (self.a[n - 1] - self.a[n - 2]) / self.h[n - 2])
        return a, b, c

    def print_eq(self):
        eq = "<{0}> + <{1}>(x - <{2}>) + <{3}>(x - <{4}>)^2 + <{5}>(x - <{6}>)^3"
        e = []
        for i in range(len(self.dat) - 3):
            e.append(eq.format(self.a[i], self.b[i], self.x[i], self.c[i], self.x[i], self.d[i], self.x[i]))
        return e

if __name__ == "__main__":
    sol = CubicSpline(dat)
    A,C = sol._make_tridiagonal()
    print(np.array(A))
    print(np.array(C))
    print(np.array(sol.print_eq()))


import numpy as np
import pydrake.symbolic as sym

def car_continuous_dynamics(x, u):
    # x = [x position, y position, heading, speed, steering angle]
    # u = [acceleration, steering velocity]
    m = sym if x.dtype == object else np  # Check type for autodiff
    heading = x[2]
    v = x[3]
    steer = x[4]
    x_d = np.array([
        v*m.cos(heading),
        v*m.sin(heading),
        v*m.tan(steer),
        u[0],
        u[1]
    ])
    return x_d

def discrete_dynamics(x, u, dt):
    # forward Euler
    x_next = x + dt * car_continuous_dynamics(x, u)
    return x_next

def rollout(x0, u_trj, n_x, dt):
    ''' Returns state trajectory projected in time, x_trj: [N, number of states] '''
    x_trj = np.zeros((n_x, u_trj.shape[1]+1))
    x_trj[:, 0] = x0
    for n in range(1, u_trj.shape[1]+1):
        x_trj[:, n] = discrete_dynamics(x_trj[:, n-1], u_trj[:, n-1], dt)
    return x_trj

class derivatives():
    def __init__(self, discrete_dynamics, n_x, n_u):
        self.x_sym = np.array([sym.Variable("x_{}".format(i))
                              for i in range(n_x)])
        self.u_sym = np.array([sym.Variable("u_{}".format(i))
                              for i in range(n_u)])
        x = self.x_sym
        u = self.u_sym
        f = car_continuous_dynamics(x, u)
        self.f_x = sym.Jacobian(f, x)
        self.f_u = sym.Jacobian(f, u)

    def get_jacobians(self, x, u):
        env = {self.x_sym[i]: x[i] for i in range(x.shape[0])}
        env.update({self.u_sym[i]: u[i] for i in range(u.shape[0])})
        f_x = sym.Evaluate(self.f_x, env)
        f_u = sym.Evaluate(self.f_u, env)
        return f_x, f_u

def get_linear_dynamics(derivs, x, u):
    ''' Linearize dynamics to take form dx = x[n+1] - x[n] = A*dx + B*du '''
    f_x, f_u = derivs.get_jacobians(x, u)
    A = f_x
    B = f_u
    return A, B

def step_car_dynamics(x0, u0, sigmas, dt):
    ''' For simulation '''
    n_x = x0.shape[0]
    xn = discrete_dynamics(x0, u0, dt)
    w = np.random.normal(0, sigmas, n_x)
    return xn + w

if __name__ == "__main__":
    dt = 0.1
    n_x = 5
    n_u = 2
    derivs = derivatives(discrete_dynamics, n_x, n_u)
    dfx, dfu = derivs.f_x, derivs.f_u
    print(dfx, dfu)


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

from matplotlib.pyplot import imread

def Generte_Masks(sigma,T):
    '''
    A method for generating Gaussian Derivative Filters.
    Arguments

    sigma: Standard Deviation of Gaussian
    T:     (T>=0.5) Threshold the gaussian for selecting
            a finite segment of gaussian

    '''
    assert sigma>=0.5
    #Calculating Size of Filter By threshholding the value of Gaussian at T
    half_size=np.round(np.sqrt(-np.log(T)*2*sigma**2))
    size=half_size*2+1

    normal = 1 / (2.0 * np.pi * sigma**2)
    # Creating X and Y axis
    x, y = np.mgrid[-half_size:half_size+1, -half_size:half_size+1]

    # Creating Filters
    g =  np.exp(-((x**2 + y**2) / (2.0*sigma**2))) * normal
    Gx =  (-x/(sigma**2))*np.exp(-((x**2 + y**2) / (2.0*sigma**2))) * normal
    Gy =  (-y/(sigma**2))*np.exp(-((x**2 + y**2) / (2.0*sigma**2))) * normal
    # Scaling by 255
    Gx=np.round(Gx*255)
    Gy=np.round(Gy*255)

    return Gx,Gy

def rgb2gray(rgb):
    '''
    A method for converting RGB to Gray scale
    '''

    return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])

def hysteresis(img, TI, TH):
    '''
    An Implementation of hysteresis By getting iterating over all pixels
    which have values equal or greater than TI and its aat leat one from
    eight neighbours is greater than TH.
    It is recursive because I am updating same Image.
    ARGUMENTS:
    img: input Image
    TI:  lower threshold
    TH:  upper threshold

    '''
    M, N = img.shape
    for i in range(1, M-1):
        for j in range(1, N-1):
            if ((img[i,j] >= TI) and (img[i,j] < TH)):
                try:
                    if ((img[i+1, j-1] >= TH) or (img[i+1, j] >= TH) or (img[i+1, j+1] >= TH)
                        or (img[i, j-1] >= TH) or (img[i, j+1] >= TH)
                        or (img[i-1, j-1] >= TH) or (img[i-1, j] >= TH) or (img[i-1, j+1] >= TH)):

                        img[i, j] = max( img[i+1, j-1]  , img[i+1, j]   , img[i+1, j+1], img[i, j-1] ,
                                         img[i, j+1]    , img[i-1, j-1] ,img[i-1, j]  ,img[i-1, j+1] )
                    else:
                        img[i, j] = 0
                except IndexError as e:
                    pass
    return img


import plotly
import plotly.graph_objs as go
import pandas as pd
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np
import pylab

def camel_3(x1, x2):
    term1 = 2 * pow(x1, 2)
    term2 = -1.05 * pow(x1, 4)
    term3 = pow(x1, 6) / 6
    term4 = x1 * x2
    term5 = pow(x2, 2)
    f = term1 + term2 + term3 + term4 + term5
    return f

def matplot1():
    fig = plt.figure()
    ax = fig.gca(projection='3d')

    # Make data.
    X = np.arange(-5, 5, 0.01)
    Y = np.arange(-5, 5, 0.01)
    X, Y = np.meshgrid(X, Y)
    zs = np.array([camel_3(x, y) for x, y in zip(np.ravel(X), np.ravel(Y))])
    Z = zs.reshape(X.shape)

    my_col = cm.jet(Z/np.amax(Z))

    # surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=my_col,
    #                        linewidth=0, antialiased=False)

    # # Plot the surface.
    surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
                           linewidth=0, antialiased=False)

    # Customize the z axis.
    ax.set_zlim(0, 2048)
    ax.zaxis.set_major_locator(LinearLocator(10))
    # ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('f(x, y)')

    # Add a color bar which maps values to colors.
    fig.colorbar(surf, shrink=0.5, aspect=5)

    plt.show()
    fig.savefig("plot55.pdf", bbox_inches='tight')

def plotly():
    plotly.offline.plot({
        "data": [go.Scatter(x=[1, 2, 3, 4], y=[4, 3, 2, 1])],
        "layout": go.Layout(title="hello world")
    })

def matplot2():
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    x = y = np.arange(-2.0, 2.0, 0.005)
    X, Y = np.meshgrid(x, y)
    zs = np.array([camel_3(x, y) for x, y in zip(np.ravel(X), np.ravel(Y))])
    Z = zs.reshape(X.shape)

    ax.plot_surface(X, Y, Z)

    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('f(x, y)')

    plt.show()

if __name__ == '__main__':
    print(camel_3(5, 5))
    matplot1()


import numpy as np
import ast

def lagrangeInterpolation(x,y):
    x = ast.literal_eval(x)
    y = ast.literal_eval(y)
    y = np.array(y)
    x = np.array(x)
    nx = len(x)
    res = {}
    Li = []

    # fill the y[i]*L[i]x
    for xi in range(nx):
        Li.append({"numerator": "", "multiplier": 0, "multiplier2": 0})
        auxMultiplier = 1
        for xi2 in range(nx):
            if (xi != xi2):
                auxNumerator = round(-1 * x[xi2],4)
                if (auxNumerator >= 0):
                    auxNumerator = "+" + str(auxNumerator)
                else:
                    auxNumerator = str(auxNumerator)
                Li[xi]['numerator'] += "*(x" + auxNumerator + ")"

                auxMultiplier *= x[xi] - x[xi2]

        Li[xi]['multiplier'] = round(1 / auxMultiplier,4)
        Li[xi]['multiplier2'] = round(y[xi] * (1 / auxMultiplier),4)

    Li.append({"result": ""})

    L = []
    for i in range(0, len(Li) - 1):
        if (Li[i]["multiplier"] >= 0):
            Li[len(Li) - 1]["result"] += "+"

        Li[len(Li) - 1]["result"] += str(Li[i]['multiplier2']) + Li[i]['numerator']
        string = str(round(Li[i]['multiplier'],4))+str((Li[i]['numerator']))
        string = string.replace(" ", "").replace("--", "+").replace("++", "+").replace("+-", "-").replace("-+", "-")
        L.append({"index":i, "L" : string })
    result = Li[len(Li) - 1]["result"]
    result = result.replace(" ", "").replace("--", "+").replace("++", "+").replace("+-", "-").replace("-+", "-")
    res["L"] = L
    res["result"] = result
    return res


import numpy as np
import timeit

NUM_RUNS = 10

def mat_trig_upper_dot(mat, v, y, n):

    for i in range(n-1,-1,-1):
        for j in range(n-1, i-1, -1):
            y[i] += mat[i][j] * v[j]

    return y

def mat_trig_upper_axpy(mat, v, y, n):
    for j in range(n-1,-1,-1):
        for i in range(j+1):
            y[i] += mat[i][j] * v[j]

    return y

def mat_trig_lower_dot(mat, v, y, n):
    for i in range(n):
        for j in range(i+1):
            y[i] += mat[i][j] * v[j]

    return y

def mat_trig_lower_axpy(mat, v, y, n):
    for j in range(n):
        for i in range(n-1, j-1, -1):
            y[i] += mat[i][j] * v[j]

    return y

def mat_sym_trig_upper_dot(mat, v, y, n):
    for i in range(n):
        for j in range(n):
            if i > j:
                y[i] += mat[j][i] * v[j]
            else:
                y[i] += mat[i][j] * v[j]

    return y

def mat_vector_dot(mat, v, y, n):
    for i in range(n):
        for j in range(n):
            y[i] += mat[i][j] * v[j]
    return y

def assertion(func, mat, v, n):

    y = np.zeros(n, dtype=int)

    # numpy
    dot = np.dot(mat, v)

    # mine
    my_dot = func(mat, v, y, n)

    return np.array_equal(dot, my_dot)

def make_tests():
    mat_trig_upper = np.array([
        [1,2,3],
        [0,4,5],
        [0,0,6]
    ])

    mat_trig_lower = np.array([
        [1,0,0],
        [2,3,0],
        [4,5,6]
    ])

    mat_sym = np.array([
        [1,2,3],
        [2,5,6],
        [3,6,7]
    ])

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

    v = np.array([1,0,1])
    n = len(v)

    # Testes
    assert assertion(mat_trig_upper_dot,mat_trig_upper,v,n)
    print("Matriz Triangular Superior Dot - [!] PASSOU")

    assert assertion(mat_trig_lower_dot,mat_trig_lower,v,n)
    print("Matriz Triangular Inferior Dot - [!] PASSOU")

    assert assertion(mat_sym_trig_upper_dot,mat_sym,v,n)
    print("Matriz Simétrica Dot - [!] PASSOU")

    assert assertion(mat_vector_dot,mat,v,n)
    print("Matriz-Vetor Dot - [!] PASSOU\n\n")

def benchmark(func, msg=None, *args):
    duration = timeit.Timer(lambda: func(*args)).timeit(number = NUM_RUNS)

    avg_duration = duration/NUM_RUNS

    if msg:
        print(f'[+] {msg}: Demorou, aproximadamente, {avg_duration} segundos')

if "__main__" == __name__:

    make_tests()

    n = 3000
    v = np.random.randint(low=1, high=5, size=n, dtype=int)
    mat = np.random.randint(low=1, high=10, size=(n, n), dtype=int)

    mat_trig_upper = np.triu(mat)
    mat_trig_lower = np.tril(mat)
    #mat_sym = np.tril(mat) + np.tril(mat, -1).T

    print("### Dot: Matriz Triangular Superior ###")

    benchmark(np.dot, "Numpy func", mat_trig_upper, v)

    y = np.zeros(n, dtype=int)
    benchmark(mat_vector_dot, "Naive func", mat_trig_upper, v, y, n)

    y = np.zeros(n, dtype=int)
    benchmark(mat_trig_upper_dot, "Efficient func", mat_trig_upper, v, y, n)

    print("### Dot: Matriz Triangular Inferior ###")

    benchmark(np.dot, "Numpy func", mat_trig_lower, v)

    y = np.zeros(n, dtype=int)
    benchmark(mat_vector_dot, "Naive func", mat_trig_lower, v, y, n)

    y = np.zeros(n, dtype=int)
    benchmark(mat_trig_lower_dot, "Efficient func", mat_trig_lower, v, y, n)

    print("### AxPy: Matriz Triangular Superior ###")

    benchmark(np.dot, "Numpy func", mat_trig_upper, v)

    y = np.zeros(n, dtype=int)
    benchmark(mat_vector_dot, "Naive func", mat_trig_upper, v, y, n)

    y = np.zeros(n, dtype=int)
    benchmark(mat_trig_upper_axpy, "Efficient func", mat_trig_upper, v, y, n)

    print("### AxPy: Matriz Triangular Inferior ###")

    benchmark(np.dot, "Numpy func", mat_trig_lower, v)

    y = np.zeros(n, dtype=int)
    benchmark(mat_vector_dot, "Naive func", mat_trig_lower, v, y, n)

    y = np.zeros(n, dtype=int)
    benchmark(mat_trig_lower_axpy, "Efficient func", mat_trig_lower, v, y, n)


import numpy as np
import tensorflow as tf

@tf.function
def unit_interval(x, xmin, xmax, scale_factor=1.):
    """
    Rescale tensor values to lie on the unit interval.

    If values go beyond the stated xmin/xmax, they are rescaled
    in the same way, but will be outside the unit interval.

    Parameters
    ----------
    x : Tensor
        Input tensor, of any shape.

    xmin, xmax : float
        Minimum and maximum values, which will be rescaled to the
        boundaries of the unit interval: [xmin, xmax] -> [0, 1].

    scale_factor : float, optional
        Scale the unit interval by some arbitrary factor, so that
        the output tensor values lie in the interval [0, scale_factor].

    Returns
    -------
    y : Tensor
        Rescaled version of x.
    """
    return scale_factor * (x - xmin) / (xmax - xmin)

def build_hex_array(hex_spec=(3,4), ants_per_row=None, d=14.6):
    """
    Build an antenna position dict for a hexagonally close-packed array.

    Parameters
    ----------
    hex_spec : tuple, optional
        If `ants_per_row = None`, this is used to specify a hex array as
        `hex_spec = (nmin, nmax)`, where `nmin` is the number of antennas in
        the bottom and top rows, and `nmax` is the number in the middle row.
        The number per row increases by 1 until the middle row is reached.

        Default: (3,4) [a hex with 3,4,3 antennas per row]

    ants_per_row : array_like, optional
        Number of antennas per row. Default: None.

    d : float, optional
        Minimum baseline length between antennas in the hex array, in meters.
        Default: 14.6.

    Returns
    -------
    ants : dict
        Dictionary with antenna IDs as the keys, and tuples with antenna
        (x, y, z) position values (with respect to the array center) as the
        values. Units: meters.
    """
    ants = {}

    # If ants_per_row isn't given, build it from hex_spec
    if ants_per_row is None:
        r = np.arange(hex_spec[0], hex_spec[1]+1).tolist()
        ants_per_row = r[:-1] + r[::-1]

    # Assign antennas
    k = -1
    y = 0.
    dy = d * np.sqrt(3) / 2. # delta y = d sin(60 deg)
    for j, r in enumerate(ants_per_row):

        # Calculate y coord and x offset
        y = -0.5 * dy * (len(ants_per_row)-1) + dy * j
        x = np.linspace(-d*(r-1)/2., d*(r-1)/2., r)
        for i in range(r):
            k += 1
            ants[k] = (x[i], y, 0.)

    return ants


from sympy import * # Module to work with symbolic variables
from sympy.abc import _clash1 # So that sympify will be able to convert string to symbolic objects
from findExtremums import findExtremums

# Checks a numbers parity
def isOdd(number: int):
    return False if number % 2 == 0 else True

# Receives a function as a string and evaluate it at a chosen value
def funEvaluate(function, variable, value: float):
    try: # Try and convert the function from string to symbolic
        function = sympify(function)
    except: # If it fails, print error message
        raise Exception("The entered function string was formatted wrongly. Try something like: '3*x*exp(-7*x**2)'.")

    try: # Same goes for for the variable
        variable = sympify(variable)
    except:
        raise Exception("The entered variable is invalid.")

    # Actually evaluate the function and return the result
    return (function.subs(variable,value)).evalf()

# Return max and min values for a function in specified interval
def intervalMaxMin(func, infLim, supLim, var = 'x'):
    var = sympify(var)
    func = sympify(func)
    maxList, minList, inflection = findExtremums(func, var)

    # [infLim,supLim] --> a = func(infLim) , b = func(supLim)
    a = funEvaluate(func,var,infLim)
    b = funEvaluate(func,var,supLim)

    maxValue = max(a,b)
    minValue = min(a,b)

    for point in maxList:
        if point < supLim and point > infLim:
            aux = funEvaluate(func,var,point)
            if aux > maxValue: maxValue = aux

    for point in minList:
        if point < supLim and point > infLim:
            aux = funEvaluate(func,var,point)
            if aux < minValue: minValue = aux

    for point in inflection:
        if point < supLim and point > infLim:
            aux = funEvaluate(func,var,point)
            if aux > maxValue: maxValue = aux
            elif aux < minValue: minValue = aux

    return maxValue, minValue

# Substitutes a matrix's row or column for another
def subMatrix(matrix: Matrix, sub: str, index: int, new: Matrix):
    if sub == "row":
        matrix.row_del(index)
        matrix = matrix.row_insert(index, new)

    elif sub == "col":
        matrix.col_del(index)
        matrix = matrix.col_insert(index, new)

    else:
        raise Exception("The argument 'sub' accepts only 'row' or 'col'.")

    return matrix

# Swap a matrix's rows or columns
def swapMatrix(matrix: Matrix, sub: str, i: int, j: int):
    if sub == "row":
        tmp = matrix.row(i)
        matrix = subMatrix(matrix, sub, i, matrix.row(j))
        matrix = subMatrix(matrix, sub, j, tmp)

    elif sub == "col":
        tmp = matrix.col(i)
        matrix = subMatrix(matrix, sub, i, matrix.col(j))
        matrix = subMatrix(matrix, sub, j, tmp)

    else:
        raise Exception("The argument 'sub' accepts only 'row' or 'col'.")

    return matrix

if __name__ == "__main__":
    print(intervalMaxMin("E**x**2-4*x",0,1))
    print(intervalMaxMin("E**x**2-4*x",1,2))


import sys, math
import re
import math
from scipy.special import erfinv
import time
import os

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.gridspec as gridspec
from copy import deepcopy
from scipy import linalg
from scipy.optimize import curve_fit

import warnings
warnings.filterwarnings("ignore");

SNUMBER = pow(10, -124);

#https://stephens999.github.io/fiveMinuteStats/inverse_transform_sampling.html
def expInvCDF(L, x):
    return -np.log(1 - x)/L;
def gausInvCDF(mu, sig, x):
    return erfinv(2*x - 1)*sig*np.sqrt(2) + mu;

def main():
    verbosity = 1;
    binN = 100;
    rangeX = [0.0, 3.0];

    np.random.seed(2);
    sampleN = 2000;
    expL = 2.0;
    gausMu = 1.5;
    gausSig = 0.5;
#histogram
    nbins = np.linspace(rangeX[0], rangeX[1], binN);
    uniformPDF = np.random.uniform(0, 1, sampleN);
    uniformHist = np.zeros(binN);
    expHist = np.zeros(binN);
    gausHist = np.zeros(binN);
    for x in uniformPDF:
        if rangeX[0] < x and x < rangeX[1]:
            uniformHist[int(binN*(x-rangeX[0])/(rangeX[1]-rangeX[0]))] += 1;
        expX = expInvCDF(expL, x);
        if rangeX[0] < expX and expX < rangeX[1]:
            expHist[int(binN*(expX-rangeX[0])/(rangeX[1]-rangeX[0]))] += 1;
        gausX = gausInvCDF(gausMu, gausSig, x);
        if rangeX[0] < gausX and gausX < rangeX[1]:
            gausHist[int(binN*(gausX-rangeX[0])/(rangeX[1]-rangeX[0]))] += 1;
#plots
    fig = plt.figure(figsize=(18, 14));
    gs = gridspec.GridSpec(2, 2);
    ax0 = fig.add_subplot(gs[0]);
    ax1 = fig.add_subplot(gs[1]);
    ax2 = fig.add_subplot(gs[2]);
    ax3 = fig.add_subplot(gs[3]);
    #plot 0
    ax0.plot(nbins, uniformHist, linewidth=2,color="blue",linestyle="steps-mid");
    ax0.set_title("Uniform Distribution", fontsize=24, y=1.03);
    ax0.set_xlabel("x", fontsize=18);
    ax0.set_ylabel("count", fontsize=18);
    ax0.set_xlim(rangeX[0], rangeX[1]);
    ax0.set_ylim(bottom=0);
    #plot 1
    ax1.plot(nbins, expHist, linewidth=2,color="blue",linestyle="steps-mid");
    ax1.set_title("Exopential Distribution", fontsize=24, y=1.03);
    ax1.set_xlabel("x", fontsize=18);
    ax1.set_ylabel("count", fontsize=18);
    ax1.set_xlim(rangeX[0], rangeX[1]);
    ax1.set_ylim(bottom=0);
    #plot 2
    ax2.plot(nbins, gausHist, linewidth=2,color="blue",linestyle="steps-mid");
    ax2.set_title("Normal Distribution", fontsize=24, y=1.03);
    ax2.set_xlabel("x", fontsize=18);
    ax2.set_ylabel("count", fontsize=18);
    ax2.set_xlim(rangeX[0], rangeX[1]);
    ax2.set_ylim(bottom=0);
#save plots
    exepath = os.path.dirname(os.path.abspath(__file__));
    filenameFig = exepath + "/fig/invTransSampling.png";
    gs.tight_layout(fig);
    plt.savefig(filenameFig);

    if verbosity >= 1:
        print("Creating the following files:");
        print(filenameFig);

if __name__ == "__main__":
    print("\n##############################################################Head");
    main();
    print("##############################################################Tail");


import numpy as np
from random import shuffle

def softmax_loss_naive(W, X, y, reg):
    """
    Softmax loss function, naive implementation (with loops)

    Inputs have dimension D, there are C classes, and we operate on minibatches
    of N examples.

    Inputs:
    - W: A numpy array of shape (D, C) containing weights.
    - X: A numpy array of shape (N, D) containing a minibatch of data.
    - y: A numpy array of shape (N,) containing training labels; y[i] = c means
      that X[i] has label c, where 0 <= c < C.
    - reg: (float) regularization strength

    Returns a tuple of:
    - loss as single float
    - gradient with respect to weights W; an array of same shape as W
    """
    num_train = X.shape[0]
    num_classes = W.shape[1]

    # Initialize the loss and gradient to zero.
    loss = 0.0
    dW = np.zeros_like(W)

    # Calculate scores for each class
    scores = np.dot(X, W)
    scores -= np.max(scores, axis=1)[:, np.newaxis]

    # Iterate for each image in input tensor X
    for i in np.arange(0, num_train):
        exp_sum = np.sum(np.exp(scores[i]))
        loss += -scores[i][y[i]] + np.log(exp_sum)

        # Calculate the contribution of each class to overall gradient
        for j in np.arange(0, num_classes):
            dW[:, j] += X[i] * ((np.exp(scores[i][j]) / exp_sum) - (j == y[i]))

    # Average and add a regularisation term
    loss = loss / num_train + 0.5 * reg * np.sum(W * W)
    dW = dW / num_train + reg * W

    return loss, dW

def softmax_loss_vectorized(W, X, y, reg):
    """
    Softmax loss function, vectorized version.

    Inputs and outputs are the same as softmax_loss_naive.
    """
    num_train = X.shape[0]
    num_classes = W.shape[1]

    # Initialize the loss and gradient to zero.
    loss = np.float64(0)
    dW = np.zeros_like(W, dtype=np.float64)
    scores = np.zeros((num_train, num_classes), dtype=np.float64)

    scores += np.dot(X, W)
    scores -= np.max(scores, axis=1)[:, np.newaxis]

    exp_scores = np.exp(scores)
    loss = np.sum(-scores[np.arange(0, num_train), y] + np.log(np.sum(exp_scores, axis=1)))
    loss = loss / num_train + 0.5 * reg * np.sum(np.square(W))

    exp_scores /= np.sum(exp_scores, axis=1)[:, np.newaxis]
    exp_scores[np.arange(0, num_train), y] -= 1

    dW = np.dot(X.T, exp_scores)
    dW = dW / num_train + reg * W

    return loss, dW


import numpy as np

__all__ = ['pooledVar', 'moving_average']

def moving_average(x,w,mode='linear'):
    """
    Moving Average for an Array.

    Parameters
    ----------
    x: Array Vector
        The arrays must have the same shape, except in the dimension.

    w: Int
        Window size

    mode: {linear, exp}
        Linear: Simple Moving Average
        Exponential: Exponetial Weighted Moving Average

    Returns
    -------
    mean : array
        The calculated moving average.
    """
    if mode == 'linear':
        weight = np.ones(w)/w
    elif mode == 'exp':
        weight = np.exp(-np.linspace(0,w,w))
    x = np.array(x)
    mean = np.convolve(x,weight, mode='full')[:-w+1]

    return mean

def pooledVar(x, y):
    """
    Pooled Variance of two samples.

    Parameters
    ----------
    x, y : 1 dimensional array_like
        The arrays must have the same shape, except in the dimension.

    Returns
    -------
    sp : float
        The calculated pooled variance.
    """
    n1 = np.size(x)
    n2 = np.size(y)
    s1 = np.var(x, ddof=1)
    s2 = np.var(y, ddof=1)
    return ((n1-1)*s1+(n2-1)*s2)/(n1+n2-2)


from __future__ import print_function
import sys
from galgebra.printer import  Format, xpdf
Format()
from sympy import symbols, sin, pi, latex, Array, permutedims
from galgebra.ga import Ga

print(r'\bm{\mbox{Base manifold (three dimensional)}}')
print(r'\bm{\mbox{Metric tensor (cartesian coordinates - norm = False)}}')
from sympy import cos, sin, symbols
g3coords = (x,y,z) = symbols('x y z')
g3 = Ga('ex ey ez', g = [1,1,1], coords = g3coords,norm=False) # Create g3
(e_x,e_y,e_z) = g3.mv()

print('g =',g3.g)
print('\\')

print(r'\bm{\mbox{Two dimensioanal submanifold - Unit sphere}}')
print(r'\text{Basis not normalised}')

sp2coords = (theta, phi) = symbols('theta phi', real = True)
sp2param = [sin(theta)*cos(phi), sin(theta)*sin(phi), cos(theta)]

sp2 = g3.sm(sp2param, sp2coords, norm = False) # submanifold

(etheta, ephi) = sp2.mv() # sp2 basis vectors
(rtheta, rphi) = sp2.mvr() # sp2 reciprocal basis vectors

sp2grad = sp2.grad

sph_map = [1, theta, phi]  # Coordinate map for sphere of r = 1
print(r'(\theta,\phi)\rightarrow (r,\theta,\phi) = ', latex(sph_map))

(etheta, ephi) = sp2.mv()
print(r'e_\theta | e_\theta = ', etheta|etheta)
print(r'e_\phi | e_\phi = ', ephi|ephi)

print('g =',sp2.g)
print(r'\text{g\_inv = }', latex(sp2.g_inv))

#print(r'\text{signature = ', latex(sp2.signature()))

Cf1 = sp2.Christoffel_symbols(mode=1)
Cf1 = permutedims(Array(Cf1), (2, 0, 1))
print(r'\text{Christoffel symbols of the first kind: }')
print(r'\Gamma_{1, \alpha, \beta} = ', latex(Cf1[0, :, :]), r'\quad', r'\Gamma_{2, \alpha, \beta} = ', latex(Cf1[1, :, :]))

Cf2 = sp2.Christoffel_symbols(mode=2)
Cf2 = permutedims(Array(Cf2), (2, 0, 1))
print(r'\text{Christoffel symbols of the second kind: }')
print(r'\Gamma^{1}_{\phantom{1,}\alpha, \beta} = ', latex(Cf2[0, :, :]), r'\quad', r'\Gamma^{2}_{\phantom{2,}\alpha, \beta} = ', latex(Cf2[1, :, :]))

F = sp2.mv('F','vector',f=True) #scalar function)
f = sp2.mv('f','scalar',f=True) #vector function)
print('grad = ', sp2grad)
print('grad f =',sp2.grad * f)
print('F =',F)
print('grad F = ',sp2.grad * F)
print('\\')

print(r'\mbox{One dimensioanal submanifold}')
print(r'\mbox{Basis not normalised}')

cir_th = phi = symbols('phi',real = True)
cir_map = [pi/8, phi]
print(r'(\phi)\rightarrow (\theta,\phi) = ', latex(cir_map))

cir1d = sp2.sm( cir_map , (cir_th,), norm = False) # submanifold

cir1dgrad = cir1d.grad

(ephi) = cir1d.mv()
print(r'e_\phi | e_\phi = ', latex(ephi[0] | ephi[0]))
print('g = ', latex(cir1d.g))

h = cir1d.mv('h','scalar',f= True)

H = cir1d.mv('H','vector',f= True)

print('grad = ', cir1dgrad)
print(r'\nabla h = ', (cir1d.grad * h).simplify())
print('H =', H)
print(r'\nabla H = ', (cir1d.grad * H).simplify())
print('\\' )

# xpdf(paper=(9,10))
xpdf(paper=(9,10),pdfprog=None)


# Autores: Mercedes Miranda
#          El nombre de tu amigo
# Fecha; 9 de septiembre de 2019
# Metodo Newton Raphson

import sympy as sym
#se define el simbolo variable principal, no mover
x = sym.Symbol('x')
#se define la funcipon para desarrollar el metodo
#funcion es la función en terminos de sympy, trataré de agregar un apendice
#de funciones posibles que se pueden agregar
#x0 es el valor semilla, tomar las consideraciones necesarias para ello
#errorRelativo es el criterio de paro dado por el usuario
#es importante tener en cuenta que las iteraciones seran pocas debido a la
#eficacia del metodo
def newton(funcion,x0,errorRelativo,digitos):
    #se calcula la derivada y la division de f(x)/f'(x)
    derivada   = funcion.diff(x,1)
    diferencia=funcion/derivada
    #se muestra la division
    print("h(x) = f(x)/f'(x)")
    print("h(x) = ",diferencia)

    #variable auxiliar para las iteraciones
    iteracion=0
    banderaConvergencia=0
    #listas para guardar la información
    valoresAproximados=[x0]
    valoresErrorRelativo=['-']
    criterioDeConvergencia=[round(CriterioConvergencia(funcion,x0),digitos)]

    while(True):
        #se calcula la aproximacion
        xAnterior=x0
        a=diferencia.subs(x,x0)
        a=x0-a.evalf()
        x0=round(a,digitos)
        valoresAproximados.append(x0)

        #si estamos en una iteracion diferente a la primera, se calcula el
        #error relativo
        if(iteracion!=0):
            errorR=round((abs((x0-xAnterior)/x0))*100,digitos)
            valoresErrorRelativo.append(errorR)
            #si se cumple el criterio de paro, sale de las iteraciones
            if(errorR<errorRelativo):
                break
        #se calcula el valor de convergencia
        valorG=round(CriterioConvergencia(funcion,x0),digitos)
        criterioDeConvergencia.append(valorG)
        #se checa si el valor cumple o no lo especificado
        if abs(valorG)>1:
            banderaConvergencia=1
            break

        #se incrementa en 1 el contador de iteraciones
        iteracion+=1
    #se retornan todas las listas y el valor de la bandera
    return valoresAproximados,valoresErrorRelativo,criterioDeConvergencia,banderaConvergencia

#esta función evalua para el criterio de convergencia en cada aproximación generada y regresa
#el valor de la evaluación de |G'(x)|
def CriterioConvergencia(funcion,x0):
    #se calculan las dos derivadas
    derivada   = funcion.diff(x,1)
    derivadaDos = funcion.diff(x,2)
    #se genera a la función G'(x)
    G=(funcion*derivadaDos)/(derivada**2)
    #se evalua para la raiz encontrada
    a=G.subs(x,x0)
    a=a.evalf()

    return a

#solo genera la grafica de la funcion
def Grafica(funcion):
    grafica=sym.plotting.plot(funcion,show=True)

#función maestra
def main():
    #la función se muestra aquí
    funcion=sym.cos(x)-(x**2)
    #si quieres que el usuario ingrese la función, descomenta las lineas entre
    #signos de suma y comenta la linea de arriba de "funcion"
    #recuerda usar la documentación para saber como ingresar ciertas funciones
    #++++++++++++++++++++++++++
    #funcion=input("ingresa la función en terminos de x")
    #++++++++++++++++++++++++++

    #grafica
    Grafica(funcion)
    #criterio de paro
    errorRelativo=float(input("introduce el porcentaje de error para el criterio de paro "))
    #valor semilla
    semilla=float(input("ingresa el valor semilla "))
    #cantidad de digitos al redondear
    digitos=int(input("cantidad de digitos de redondeo, hasta 8 permitidos "))

    #se generan todos los valores necesarios para desplegar la tabla
    valores,errores,criterios,bandera=newton(funcion,semilla,errorRelativo,digitos)
    #se imprimen los valores
    print("{:2}|{:^12}|{:^12}|{:^12}|{:^12}".format("I","xi","xi+1","ErrorR","CritConv"))
    for i in range(len(valores)-1):
        print("{:2}|{:12}|{:12}|{:12}|{:12}".format(i+1,valores[i],valores[i+1],errores[i],criterios[i]))
    #hasta acá es donde se checa el criterio de convergencia
    if bandera==1 :
        print("hubo un problema con el criterio de paro en la ultima iteración, quizá por esto terminó el proceso")
        print("revisa tu valor semilla e intenta con otro ")

main()


# zipf distribution are used to sample data based in zipf's law.
# zipf's law - in a collection the nth common term is 1/n times of the most common term.
# E.g. 5th common word in english has occurs nearly 1/5th times as of the most used word.
# it has two parameters
# a = distribution parameter.
# size - shape of returned array.
from numpy import random
import matplotlib.pyplot as plt
import seaborn as sns

arr1 = random.zipf(a=2, size=1000)
print(arr1)
sns.distplot(arr1[arr1 < 25], kde=False)       # shows how many of 1000 values are below 25
plt.show()

Python/Numpy/numpy 30 - zipf distribution.py


import numpy as np
from helpers import *
from implementations import *

def build_k_indices(y, k_fold, seed):
    """build k indices for k-fold."""
    num_row = y.shape[0]
    interval = int(num_row / k_fold)
    np.random.seed(seed)
    indices = np.random.permutation(num_row)
    k_indices = [indices[k * interval: (k +  1) * interval] for k in range(k_fold)]
    return np.array(k_indices)

def cross_validation(y, x, k_indices, k, lambda_, degree):
    # 4-fold, hence k = 4, k-th group is for testings, the other k-1
    # groups are for training
    subgroups = k_indices
    testIndices = subgroups[k]
    trainIndices = np.delete(subgroups,k,axis=0)
    trainIndices = np.concatenate((trainIndices[0],trainIndices[1],trainIndices[2]),axis=None)
    xTrain = x[trainIndices]
    xTest = x[testIndices]
    yTrain = y[trainIndices]
    yTest = y[testIndices]

    #build data
    featureMatrixTest = build_poly(xTest,degree)
    featureMatrixTrain = build_poly(xTrain,degree)

    #wTrain,_ = ridge_regression(yTrain,featureMatrixTrain,lambda_)
    #wTrain,_ = logistic_regression(yTraiyTrainn, featureMatrixTrain, None, 40, 0.01)
    #wTrain,_ = least_squares_SGD(yTrain, featureMatrixTrain, None, 30, 0.01)
    #wTrain,_ = ridge_regression(yTrain, featureMatrixTrain, lambda_)
    wTrain,_ = least_squares(yTrain, featureMatrixTrain)
    #wTrain,_ = reg_logistic_regression(yTrain, featureMatrixTrain, lambda_, None, 30, 0.1**(17))

    # calculate MSE for train and test data !! using the training weights !!
    loss_tr = np.sqrt(2*compute_loss(yTrain, featureMatrixTrain, wTrain))
    loss_te = np.sqrt(2*compute_loss(yTest, featureMatrixTest, wTrain))

    return loss_tr, loss_te, wTrain

def find_best_degree(x,y,degrees, k_fold, lambdas, seed = 1):
    '''find out the best degree of the model
    in order to minimize the resulting loss
    '''

    k_indices = build_k_indices(y, k_fold, seed)

    # store in lists (rmse and lambdas)
    best_lambdas = []
    best_rmses = []
    # iterate over given array of degrees
    for degree in degrees:
        #store test errors
        rmse_te = []
        for lambda_ in lambdas:
            rmse_te_tmp = []
            # perform cross validation
            for k in range(k_fold):
                _, loss_te, _ = cross_validation(y, x, k_indices, k, lambda_, degree)
                rmse_te_tmp.append(loss_te)
            rmse_te.append(np.mean(rmse_te_tmp))
        #argmin gives smallest rmse
        ind_lambda_opt = np.argmin(rmse_te)
        best_lambdas.append(lambdas[ind_lambda_opt])
        #print("degree",degree,"lambda",lambdas[ind_lambda_opt])
        best_rmses.append(rmse_te[ind_lambda_opt])

    ind_best_degree =  np.argmin(best_rmses)

    return degrees[ind_best_degree]


# -*- coding: utf-8 -*-
"""
Created on Tue Mar 26 19:46:14 2019

@author: Nate
"""

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

'''
Determine the value of π to ≈ 14 digits by solving for the root of the equation

f(x) = cos(x) = 0

using the second order Newton’s method. The exact solution is

    x∗ = π/2, so that π = 2x∗.

Use the initial guess of x = 1.5, corresponds to a guess of π ≈ 3. How many
iterations are needed to achieve 14 digits? Repeat the calculation with initial guesses
x = 1, x = 0.5 and x = 0.25.
'''

def f(guess):
    return(np.cos(guess))

def df(guess):
    return(-np.sin(guess))

guess = [1.5,1,.5,.25]

for i in range(len(guess)):
    for val in range(4):
        nextguess = guess[i] - f(guess[i])/df(guess[i])
        guess[i] = nextguess

    if i == 3:
        answer = guess[i]
        #print(guess[i])
        #print(answer)
        print(i, ": " , (3/2)*np.pi-answer)
        if abs((3/2)*np.pi-answer) < 10**(-12):
            print('True')
    else:
        answer = 2*guess[i]
        print(i, ": " , np.pi-answer)
        if abs(np.pi-answer) < 10**(-12):
            print('True')

print(10**(-10))


# Chapter 10

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

## Review

So far we have been working with distributions of only one variable.  In this notebook we'll take a step toward multivariate distributions, starting with two variables.

We'll use cross-tabulation to compute a **joint distribution**, then use the joint distribution to compute **conditional distributions** and **marginal distributions**.

We will re-use `pmf_from_seq`, which I introduced in a previous notebook.

def pmf_from_seq(seq):
    """Make a PMF from a sequence of values.

    seq: sequence

    returns: Series representing a PMF
    """
    pmf = pd.Series(seq).value_counts(sort=False).sort_index()
    pmf /= pmf.sum()
    return pmf

## Cross tabulation

To understand joint distributions, I'll start with cross tabulation.  And to demonstrate cross tabulation, I'll generate a dataset of colors and fruits.

Here are the possible values.

colors = ['red', 'yellow', 'green']
fruits = ['apple', 'banana', 'grape']

And here's a random sample of 100 fruits.

np.random.seed(2)
fruit_sample = np.random.choice(fruits, 100, replace=True)

We can use `pmf_from_seq` to compute the distribution of fruits.

pmf_fruit = pmf_from_seq(fruit_sample)
pmf_fruit

And here's what it looks like.

pmf_fruit.plot.bar(color='C0')

plt.ylabel('Probability')
plt.title('Distribution of fruit');

Similarly, here's a random sample of colors.

color_sample = np.random.choice(colors, 100, replace=True)

Here's the distribution of colors.

pmf_color = pmf_from_seq(color_sample)
pmf_color

And here's what it looks like.

pmf_color.plot.bar(color='C1')

plt.ylabel('Probability')
plt.title('Distribution of colors');

Looking at these distributions, we know the proportion of each fruit, ignoring color, and we know the proportion of each color, ignoring fruit type.

But if we only have the distributions and not the original data, we don't know how many apples are green, for example, or how many yellow fruits are bananas.

We can compute that information using `crosstab`, which computes the number of cases for each combination of fruit type and color.

xtab = pd.crosstab(color_sample, fruit_sample,
                   rownames=['color'], colnames=['fruit'])
xtab

The result is a DataFrame with colors along the rows and fruits along the columns.

## Heatmap

The following function plots a cross tabulation using a pseudo-color plot, also known as a heatmap.

It represents each element of the cross tabulation with a colored square, where the color corresponds to the magnitude of the element.

The following function generates a heatmap using the Matplotlib function `pcolormesh`:

def plot_heatmap(xtab):
    """Make a heatmap to represent a cross tabulation.

    xtab: DataFrame containing a cross tabulation
    """

    plt.pcolormesh(xtab)

    # label the y axis
    ys = xtab.index
    plt.ylabel(ys.name)
    locs = np.arange(len(ys)) + 0.5
    plt.yticks(locs, ys)

    # label the x axis
    xs = xtab.columns
    plt.xlabel(xs.name)
    locs = np.arange(len(xs)) + 0.5
    plt.xticks(locs, xs)

    plt.colorbar()
    plt.gca().invert_yaxis()

plot_heatmap(xtab)

## Joint Distribution

A cross tabulation represents the "joint distribution" of two variables, which is a complete description of two distributions, including all of the conditional distributions.

If we normalize `xtab` so the sum of the elements is 1, the result is a joint PMF:

joint = xtab / xtab.to_numpy().sum()
joint

Each column in the joint PMF represents the conditional distribution of color for a given fruit.

For example, we can select a column like this:

col = joint['apple']
col

If we normalize it, we get the conditional distribution of color for a given fruit.

col / col.sum()

Each row of the cross tabulation represents the conditional distribution of fruit for each color.

If we select a row and normalize it, like this:

row = xtab.loc['red']
row / row.sum()

The result is the conditional distribution of fruit type for a given color.

## Conditional distributions

The following function takes a joint PMF and computes conditional distributions:

def conditional(joint, name, value):
    """Compute a conditional distribution.

    joint: DataFrame representing a joint PMF
    name: string name of an axis
    value: value to condition on

    returns: Series representing a conditional PMF
    """
    if joint.columns.name == name:
        cond = joint[value]
    elif joint.index.name == name:
        cond = joint.loc[value]
    return cond / cond.sum()

The second argument is a string that identifies which axis we want to select; in this example, `'fruit'` means we are selecting a column, like this:

conditional(joint, 'fruit', 'apple')

And `'color'` means we are selecting a row, like this:

conditional(joint, 'color', 'red')

**Exercise:** Compute the conditional distribution of color for bananas.  What is the probability that a banana is yellow?

# Solution goes here

# Solution goes here

## Marginal distributions

Given a joint distribution, we can compute the unconditioned distribution of either variable.

If we sum along the rows, which is axis 0, we get the distribution of fruit type, regardless of color.

joint.sum(axis=0)

If we sum along the columns, which is axis 1, we get the distribution of color, regardless of fruit type.

joint.sum(axis=1)

These distributions are called "[marginal](https://en.wikipedia.org/wiki/Marginal_distribution#Multivariate_distributions)" because of the way they are often displayed.  We'll see an example later.

As we did with conditional distributions, we can write a function that takes a joint distribution and computes the marginal distribution of a given variable:

def marginal(joint, name):
    """Compute a marginal distribution.

    joint: DataFrame representing a joint PMF
    name: string name of an axis

    returns: Series representing a marginal PMF
    """
    if joint.columns.name == name:
        return joint.sum(axis=0)
    elif joint.index.name == name:
        return joint.sum(axis=1)

Here's the marginal distribution of fruit.

pmf_fruit = marginal(joint, 'fruit')
pmf_fruit

And the marginal distribution of color:

pmf_color = marginal(joint, 'color')
pmf_color

The sum of the marginal PMF is the same as the sum of the joint PMF, so if the joint PMF was normalized, the marginal PMF should be, too.

joint.to_numpy().sum()

pmf_color.sum()

However, due to floating point error, the total might not be exactly 1.

pmf_fruit.sum()

**Exercise:** The following cells load the data from the General Social Survey that we used in Notebooks 1 and 2.

# Load the data file
import os

if not os.path.exists('gss_bayes.csv'):
    !wget https://github.com/AllenDowney/BiteSizeBayes/raw/master/gss_bayes.csv

gss = pd.read_csv('gss_bayes.csv', index_col=0)

As an exercise, you can use this data to explore the joint distribution of two variables:

* `partyid` encodes each respondent's political affiliation, that is, the party the belong to.  [Here's the description](https://gssdataexplorer.norc.org/variables/141/vshow).

* `polviews` encodes their political alignment on a spectrum from liberal to conservative.  [Here's the description](https://gssdataexplorer.norc.org/variables/178/vshow).

The values for `partyid` are

```
0	Strong democrat
1	Not str democrat
2	Ind,near dem
3	Independent
4	Ind,near rep
5	Not str republican
6	Strong republican
7	Other party
```

The values for `polviews` are:

```
1	Extremely liberal
2	Liberal
3	Slightly liberal
4	Moderate
5	Slightly conservative
6	Conservative
7	Extremely conservative
```

Make a cross tabulation of `gss['partyid']` and `gss['polviews']` and normalize it to make a joint PMF.

# Solution goes here

Use `plot_heatmap` to display a heatmap of the joint distribution.  What patterns do you notice?

plot_heatmap(joint2)

plt.xlabel('polviews')
plt.title('Joint distribution of polviews and partyid');

Use `marginal` to compute the marginal distributions of `partyid` and `polviews`, and plot the results.

# Solution goes here

# Solution goes here

Use `conditional` to compute the conditional distribution of `partyid` for people who identify themselves as "Extremely conservative" (`polviews==7`).  How many of them are "strong Republicans" (`partyid==6`)?

# Solution goes here

Use `conditional` to compute the conditional distribution of `polviews` for people who identify themselves as "Strong Democrat" (`partyid==0`).  How many of them are "Extremely liberal" (`polviews==1`)?

# Solution goes here

## Review

In this notebook we started with cross tabulation, which we normalized to create a joint distribution, which describes the distribution of two (or more) variables and all of their conditional distributions.

We used heatmaps to visualize cross tabulations and joint distributions.

Then we defined `conditional` and `marginal` functions that take a joint distribution and compute conditional and marginal distributions for each variables.

As an exercise, you had a chance to apply the same methods to explore the relationship between political alignment and party affiliation using data from the General Social Survey.

You might have noticed that we did not use Bayes's Theorem in this notebook.  [In the next notebook](https://colab.research.google.com/github/AllenDowney/BiteSizeBayes/blob/master/11_faceoff.ipynb) we'll take the ideas from this notebook and apply them Bayesian inference.


#Implementing and in neural network
import pandas as pd

# TODO: Set weight1, weight2, and bias
weight1 = 1
weight2 = 1
bias = -2

# DON'T CHANGE ANYTHING BELOW
# Inputs and outputs
test_inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
correct_outputs = [False, False, False, True]
outputs = []

# Generate and check output
for test_input, correct_output in zip(test_inputs, correct_outputs):
    linear_combination = weight1 * test_input[0] + weight2 * test_input[1] + bias
    output = int(linear_combination >= 0)
    is_correct_string = 'Yes' if output == correct_output else 'No'
    outputs.append([test_input[0], test_input[1], linear_combination, output, is_correct_string])

# Print output
num_wrong = len([output[4] for output in outputs if output[4] == 'No'])
output_frame = pd.DataFrame(outputs, columns=['Input 1', '  Input 2', '  Linear Combination', '  Activation Output', '  Is Correct'])
if not num_wrong:
    print('Nice!  You got it all correct.\n')
else:
    print('You got {} wrong.  Keep trying!\n'.format(num_wrong))
print(output_frame.to_string(index=False))

#Implementing not in nueral network
import pandas as pd

# TODO: Set weight1, weight2, and bias
weight1 = -1
weight2 = -2
bias = 1

# DON'T CHANGE ANYTHING BELOW
# Inputs and outputs
test_inputs = [(0, 0), (0, 1), (1, 0), (1, 1)]
correct_outputs = [True, False, True, False]
outputs = []

# Generate and check output
for test_input, correct_output in zip(test_inputs, correct_outputs):
    linear_combination = weight1 * test_input[0] + weight2 * test_input[1] + bias
    output = int(linear_combination >= 0)
    is_correct_string = 'Yes' if output == correct_output else 'No'
    outputs.append([test_input[0], test_input[1], linear_combination, output, is_correct_string])

# Print output
num_wrong = len([output[4] for output in outputs if output[4] == 'No'])
output_frame = pd.DataFrame(outputs, columns=['Input 1', '  Input 2', '  Linear Combination', '  Activation Output', '  Is Correct'])
if not num_wrong:
    print('Nice!  You got it all correct.\n')
else:
    print('You got {} wrong.  Keep trying!\n'.format(num_wrong))
print(output_frame.to_string(index=False))

#Implementing perceptron algorithm
import numpy as np
# Setting the random seed, feel free to change it and see different solutions.
np.random.seed(42)

def stepFunction(t):
    if t >= 0:
        return 1
    return 0

def prediction(X, W, b):
    return stepFunction((np.matmul(X,W)+b)[0])

# TODO: Fill in the code below to implement the perceptron trick.
# The function should receive as inputs the data X, the labels y,
# the weights W (as an array), and the bias b,
# update the weights and bias W, b, according to the perceptron algorithm,
# and return W and b.

def perceptronStep(X, y, W, b, learn_rate = 0.001):
    for i in range(len(X)):
        y_hat = prediction(X[i],W,b)
        if y[i]-y_hat == 1:
            W[0] += X[i][0]*learn_rate
            W[1] += X[i][1]*learn_rate
            b += learn_rate
        elif y[i]-y_hat == -1:
            W[0] -= X[i][0]*learn_rate
            W[1] -= X[i][1]*learn_rate
            b -= learn_rate
    return W, b

# This function runs the perceptron algorithm repeatedly on the dataset,
# and returns a few of the boundary lines obtained in the iterations,
# for plotting purposes.
# Feel free to play with the learning rate and the num_epochs,
# and see your results plotted below.
def trainPerceptronAlgorithm(X, y, learn_rate = 0.01, num_epochs = 50):
    x_min, x_max = min(X.T[0]), max(X.T[0])
    y_min, y_max = min(X.T[1]), max(X.T[1])
    W = np.array(np.random.rand(2,1))
    b = np.random.rand(1)[0] + x_max
    # These are the solution lines that get plotted below.
    boundary_lines = []
    for i in range(num_epochs):
        # In each epoch, we apply the perceptron step.
        W, b = perceptronStep(X, y, W, b, learn_rate)
        boundary_lines.append((-W[0]/W[1], -b/W[1]))
    return boundary_lines

#IMplementing softmax
import numpy as np

# Write a function that takes as input a list of numbers, and returns
# the list of values given by the softmax function.
def softmax(x):
    y=np.exp(x)
    sumre=sum(y)
    result = []
    for i in x:
        result.append(np.exp(i)/sumre)
    return result

#Implementing cross entrophy
import numpy as np

def cross_entropy(Y, P):
    Y = np.float_(Y)
    P = np.float_(P)
    return -np.sum(Y * np.log(P) + (1 - Y) * np.log(1 - P))


from __future__ import print_function
import tensorflow as tf
import numpy as np
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

#
# t_x = np.floor(10 * np.random.random([5]),dtype=np.float32)
# print(t_x)
#
# t_y = t_x * 3.0 + 8.0
# print(t_y)
#
# node1 = tf.constant(3.0, dtype=tf.float32)
# node2 = tf.constant(4.0) # also tf.float32 implicitly
# print(node1, node2)
#
sess = tf.Session()
# print(sess.run([node1, node2]))
#
#
# node3 = tf.add(node1, node2)
# print("node3:", node3)
# print("sess.run(node3):", sess.run(node3))

# a = tf.placeholder(tf.float32)
# b = tf.placeholder(tf.float32)
# adder_node = a + b
# print(sess.run(adder_node, {a:3, b:4.5}))
# print(sess.run(adder_node, {a:[1,3], b: [2,4]}))
#
# add_and_triple = adder_node * 3
# print(sess.run(add_and_triple, {a: 3, b:4.5}))

# W = tf.Variable([.3], dtype=tf.float32)
# b = tf.Variable([-.3], dtype=tf.float32)
# x = tf.placeholder(tf.float32)
# linear_model = W*x + b
#
# init = tf.global_variables_initializer()
# sess.run(init)
#
# print(sess.run(linear_model, {x: [1,2,3,4]}))
#
# y = tf.placeholder(tf.float32)
# square_deltas = tf.square(linear_model - y)
# loss = tf.reduce_sum(square_deltas)
# print(sess.run(loss,{x: [1,2,3,4], y:[0,-1,-2,-3]}))
#
# fixW = tf.assign(W, [-1.0])
# fixb = tf.assign(b, [1.])
# sess.run([fixW, fixb])
#
# print(sess.run(loss,{x: [1,2,3,4], y:[0,-1,-2,-3]}))
#
#
# optimizer = tf.train.GradientDescentOptimizer(0.01)
# train = optimizer.minimize(loss)
#
# sess.run(init) # reset values to incorrect defaults
# for i in range(1000):
#     sess.run(train, {x:[1,2,3,4], y:[0,-1,-2,-3]})
#
# print(sess.run([W,b]))

"""initialize parameters"""
W = tf.Variable([0.3], dtype = tf.float32)
b = tf.Variable([-0.3], dtype = tf.float32)
x = tf.placeholder(tf.float32)

linear_model = W*x + b

y = tf.placeholder(tf.float32)

loss = tf.reduce_sum(tf.square(linear_model - y))
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)

trainingX = [1.0,2.0,3.0,4.0]
trainingY = [0.0,-1.0,-2.0,-3.0]
# training loop
init = tf.global_variables_initializer()
sess.run(init) # reset values to wrong
for i in range(1000):
    sess.run(train, {x: trainingX, y: trainingY})

print(sess.run([W,b]))
print(sess.run(loss,{ x: trainingX, y: trainingY}))

"""Multi parameter

"""end of file"""


from matplotlib import pyplot as plt
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
import numpy as np
X = np.array([[1, 3], [4, 2], [5, 6], [3, 1], [7, 2], [3, 3], ])

#Plotting Data
labels = range(1, 7)
plt.figure(figsize=(7, 3))
plt.subplots_adjust(bottom=0.1)
plt.scatter(X[:, 0], X[:, 1], label='True Position')

for label, x, y in zip(labels, X[:, 0], X[:, 1]):
    plt.annotate(
        label,
        xy=(x, y), xytext=(-3, 3),
        textcoords='offset points', ha='right', va='bottom')
plt.show()

## Use Hierarchical Algorithm Single Method
linked = linkage(X, 'single')
labelList = range(1, 7)
plt.figure(figsize=(7, 3))
dendrogram(linked, orientation='top',labels=labelList,distance_sort='descending',show_leaf_counts=True)
plt.show()

# Use Hierarchical Algorithm Complete Method
linked = linkage(X, 'complete')
labelList = range(1, 7)
plt.figure(figsize=(7, 3))
dendrogram(linked, orientation='top', labels=labelList,
           distance_sort='descending', show_leaf_counts=True)
plt.show()

# Use Hierarchical Algorithm Average Method
linked = linkage(X, 'average')
labelList = range(1, 7)
plt.figure(figsize=(7, 3))
dendrogram(linked, orientation='top', labels=labelList,
           distance_sort='descending', show_leaf_counts=True)
plt.show()

# Use Hierarchical Algorithm Ward Method
linked = linkage(X, 'ward')
labelList = range(1, 7)
plt.figure(figsize=(7, 3))
dendrogram(linked, orientation='top', labels=labelList,
           distance_sort='descending', show_leaf_counts=True)
plt.show()

# Use Hierarchical Algorithm Centroid Method
linked = linkage(X, 'centroid')
labelList = range(1, 7)
plt.figure(figsize=(7, 3))
dendrogram(linked, orientation='top', labels=labelList,
           distance_sort='descending', show_leaf_counts=True)
plt.show()

# Use Hierarchical Algorithm Median Method
linked = linkage(X, 'median')
labelList = range(1, 7)
plt.figure(figsize=(7, 3))
dendrogram(linked, orientation='top', labels=labelList,
           distance_sort='descending', show_leaf_counts=True)
plt.show()