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

cities = ["Mugla", "Bursa", "Ankara", "Gaziantep",
          "Diyarbakir", "Hatay", "Adiyaman", "Kocaeli",
          "Istanbul", "Eskisehir"]

distances=np.array([[np.inf,543,619,1058,1371,1037,1181,671,782,499],
		   [543,np.inf,385,1026,1272,1033,1114,132,243,152],
		   [619,385,np.inf,655,901,683,742,342,453,233],
		   [1058,1026,655,np.inf,313,193,150,1000,1111,874],
		   [1371,1272,901,313,np.inf,506,207,1246,1357,1121],
		   [1037,1033,683,193,506,np.inf,316,1028,1139,881],
		   [1181,1114,742,150,207,316,np.inf,1087,1198,962],
		   [671,132,342,1000,1246,1028,1087,np.inf,111,214],
		   [782,243,453,1111,1357,1139,1198,111,np.inf,325],
		   [499,152,233,874,1121,881,962,214,324,np.inf]])

pheromone = np.ones((len(distances),len(distances)))
eta = 1/distances

best_distance = np.inf

evaporation_rate = 0.1
r_damp = 1
Q = 1
alfa = 1
beta = 1

nAnts  = 20
nIter = 100

best_array = []

for _ in range(nIter):
    for ant in range(nAnts):

        visited = []

        unvisited = list(range(0,len(cities)))

        start = cities.index("Mugla")

        visited.append(start)
        unvisited.remove(start)

        tour = [start]

        current_city = start

        distance = 0

        for i in range(len(cities)-1):

            # Probability Calculation
            probability_denominator = sum((pheromone[current_city][j]**alfa)*(eta[current_city][j]**beta) for j in unvisited)
            probability = []
            for j in unvisited:
                probability_nominator = (pheromone[current_city][j]**alfa)*(eta[current_city][j]**beta)
                P = probability_nominator/probability_denominator
                probability.append(P)
            # print(probability, sum(probability))

            # Roulette Wheel
            rand = random.uniform(0,1)
            # cumulative sum
            roulette = []
            cumulative_sum = 0
            for r in range(0,len(probability)):
                cumulative_sum+=probability[r]
                roulette.append(cumulative_sum)
            # print(roulette)

            for wheel in roulette:
                # print(rand,wheel)
                if rand <= wheel:
                    index = roulette.index(wheel)
                    # print(index)
                    break

            # next_city = random.choice(unvisited)
            next_city = unvisited[index]
            visited.append(next_city)
            unvisited.remove(next_city)
            distance += distances[current_city][next_city]
            current_city = next_city

        distance += distances[current_city][start]
        visited.append(start)

        # Pheromone Update
        for a in range(len(tour)-1):
            pheromone[tour[a]][tour[a+1]] = pheromone[tour[a]][tour[a+1]]+Q/distance

        evaporation_rate*=r_damp
        pheromone = (1-evaporation_rate)*pheromone

        if distance < best_distance:
            best_distance = distance
            best_tour = visited

    best_array.append(best_distance)

best_tour_cities = []
for name in best_tour:
    best_tour_cities.append(cities[name])

#%%%%%%%%%%%%% PLOT THE RESULTS %%%%%%%%%%%%%

x = np.arange(1,nIter+1)
y = best_array

plt.plot(x,y)
plt.xlabel("Iteration")
plt.ylabel("Best Ant")
plt.title("Travelling Salesman Problem")
plt.show()
plt.savefig('aco.png')

file1 = open("tour.txt","w")#write mode
for i in range(len(best_tour_cities)):
    file1.write(best_tour_cities[i]+"\n")
file1.close()

print("Parameters;",
      "\nEvaporation Rate: ", evaporation_rate,
      "\nBeta: ", 1,
      "\nAlfa: ", 1,
      "\nNumber of Ants: ",nAnts,
      "\nNumber of Iteration: ",nIter)


from numpy import *
import scipy.linalg
import numpy as np
from sympy import Symbol
# from sympy import *
from numpy import linalg
pi = 3.141592653589793

# returns transformation Matrix
def transformMatrix(arg):
    mat=zeros((4,4))
    arg=arg*(pi/180)
    mat[0,0]=np.cos(arg)
    mat[0,1]=-np.sin(arg)
    mat[1,0]=np.sin(arg)
    mat[1,1]=np.cos(arg)
    mat[2,2]=np.cos(arg)
    mat[2,3]=-np.sin(arg)
    mat[3,2]=np.sin(arg)
    mat[3,3]=np.cos(arg)
    return(mat)

# returns element angle and length
def elementParams():
    theta=[]
    length=[]
    for i in range(len(x1coord)):
        length.append(((y1coord[i]-y2coord[i])**2+(x1coord[i]-x2coord[i])**2)**(0.5))
        try:
            theta.append((180/pi)*np.arctan(abs(y1coord[i]-y2coord[i])/abs(x1coord[i]-x2coord[i])))
        except ZeroDivisionError:
            theta.append(90)
    return(theta,length)

# returns kMatrix and solution
def calculation():
    angle,length = elementParams()
    kMatrix = zeros((2*nodes,2*nodes))
    localK = zeros((4,4))
    localK[0,0] = 1
    localK[0,2] = -1
    localK[2,0] = -1
    localK[2,2] = 1
    localK[:,:] = (AE/l)*localK[:,:]
    for i in range(3):
        if i==0:
            kMatrix[0:4,0:4] = (1/length[i])*transformMatrix(angle[i])@localK[:,:]@linalg.inv(transformMatrix(angle[i]))
        elif i==1:
            kMatrix[2:6,2:6] = kMatrix[2:6,2:6]+ (1/length[i])*transformMatrix(angle[i])@localK[:,:]@linalg.inv(transformMatrix(angle[i]))
        elif i==2:
            temp= (1/length[i])*transformMatrix(angle[i])@localK[:,:]@linalg.inv(transformMatrix(angle[i]))
            kMatrix[0:2,0:4]=kMatrix[0:2,0:4]+temp[0:2,0:4]
            kMatrix[4:6,2:6]=kMatrix[4:6,2:6]+temp[2:4,0:4]
    return(kMatrix,linalg.inv(kMatrix)@f)

# user inputs for the problem discussed in class
# assuming all the nodes are placed in unform square grid
x1coord=[1,2,2]
y1coord=[1,1,2]
x2coord=[2,2,1]
y2coord=[1,2,1]
# force matrix f= [f1x,f1y,f2x,f2y,f3x,f3y]
f = [0,0,10,-20,0,0]
AE = 10
nodes=3 #number of nodes
l=2.2 #length of the horizontal or vertical element

a,b=calculation()
print("\nKmatrix\n",a)
print("\nSolutionMatrix\n",b)

import numpy,from numpy,import scipy,from sympy


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

np.seterr(all='raise')

factor = 2.0

class LinearModel(object):
    """Base class for linear models."""

    def __init__(self, theta=None):
        """
        Args:
            theta: Weights vector for the model.
        """
        self.theta = theta

    def fit(self, X, y):
        """Run solver to fit linear model. You have to update the value of
        self.theta using the normal equations.

        Args:
            X: Training example inputs. Shape (n_examples, dim).
            y: Training example labels. Shape (n_examples,).
        """
        self.theta = np.linalg.solve(X.T @ X, y @ X)

    def create_poly(self, k, X):
        """
        Generates a polynomial feature map using the data x.
        The polynomial map should have powers from 0 to k
        Output should be a numpy array whose shape is (n_examples, k+1)

        Args:
            X: Training example inputs. Shape (n_examples, 2).
        """
        feature = np.empty([X.shape[0], k + 1])
        for i in range(k + 1):
            feature[:, i] = X[:, 1] ** i
        return feature

    def create_sin(self, k, X):
        """
        Generates a sin with polynomial featuremap to the data x.
        Output should be a numpy array whose shape is (n_examples, k+2)

        Args:
            X: Training example inputs. Shape (n_examples, 2).
        """
        feature = np.empty([X.shape[0], k + 2])
        for i in range(k + 1):
            feature[:, i] = X[:, 1] ** i
        feature[:, k + 1] = np.sin(X[:, 1])
        return feature

    def predict(self, X):
        """
        Make a prediction given new inputs x.
        Returns the numpy array of the predictions.

        Args:
            X: Inputs of shape (n_examples, dim).

        Returns:
            Outputs of shape (n_examples,).
        """
        return self.theta @ X.T

def run_exp(train_path, sine=False, ks=[1, 2, 3, 5, 10, 20], filename='plot.png'):
    train_x, train_y = util.load_dataset(train_path,add_intercept=True)
    plot_x = np.ones([1000, 2])
    plot_x[:, 1] = np.linspace(-factor*np.pi, factor*np.pi, 1000)
    plt.figure()
    plt.scatter(train_x[:, 1], train_y)

    for k in ks:
        # train model
        reg = LinearModel()
        if sine:
            trans_train_x = reg.create_sin(k, train_x)
            trans_plot_x = reg.create_sin(k, plot_x)
        else:
            trans_train_x = reg.create_poly(k, train_x)
            trans_plot_x = reg.create_poly(k, plot_x)

        reg.fit(trans_train_x, train_y)
        plot_y = reg.predict(trans_plot_x)

        # plot hypothesis
        plt.ylim(-2, 2)
        plt.plot(plot_x[:, 1], plot_y, label='k=%d' % k)

    plt.legend()
    plt.savefig(filename)
    plt.clf()

def main(train_path, small_path, eval_path):
    """
    Run all expetriments.
    """
    run_exp(train_path, ks=[3], filename='deg3.png')
    run_exp(train_path, ks=[3, 5, 10, 20], filename='poly.png')
    run_exp(train_path, sine=True, ks=[0, 1, 2, 3, 5, 10, 20], filename='sine.png')
    run_exp(small_path, ks=[1, 2, 5, 10, 20], filename='overfit.png')

if __name__ == '__main__':
    main(train_path='train.csv',
        small_path='small.csv',
        eval_path='test.csv')


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author：lowkeyway time:8/2/2019

import sys, os, math
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

def showImgPara(img):
    print("Sizeof img is: " + str(img.size))
    print("rows x cols is: " + str(np.size(img, 0)) + " x " + str(np.size(img, 1)))
    print("dimension is: ", img.ndim)
    print("dtype is: ", img.dtype)
    print("itemsize is: ", img.itemsize)
    print("shape is(rows, cols, depth): ", img.shape)

def highPass(rows, cols):
    mask = np.ones((rows, cols), np.uint8)
    # mask[int(rows/4):int(rows*3/4), int(cols/4):int(cols*3/4)] = 0
    cv.circle(mask, (int(cols/2), int(rows/2)), int(min(rows, cols)/8), 0, -1)
    return mask

def lowPass(rows, cols):
    mask = np.zeros((rows, cols), np.uint8)
    # mask[int(rows/4):int(rows*3/4), int(cols/4):int(cols*3/4)] = 1
    cv.circle(mask, (int(cols/2), int(rows/2)), int(min(rows, cols)/8), 1, -1)
    return mask

def npFFTshow(array):
    oriFFT = np.fft.fft2(array)
    cenFFT = np.fft.fftshift(oriFFT)

    cenFFTALog = np.log(np.abs(cenFFT))
    plt.figure("Array Show")
    plt.subplot(111)
    plt.imshow(cenFFTALog, "gray")

    plt.show()

def FFT(fileName):
    imgOri = cv.imread(fileName, 0)
    original = np.fft.fft2(imgOri)
    center = np.fft.fftshift(original)

    # Amplitude
    oriALog = np.log(np.abs(original))
    cenALog = np.log(np.abs(center))

    # Phase
    oriPh = np.angle(original)
    cenPh = np.angle(center)

    # iFFT
    iCenter = np.fft.ifftshift(center)
    iOriginal = np.fft.ifft2(iCenter)
    imgBack = np.abs(iOriginal)

    # Smoothing High Pass
    rows, cols = imgOri.shape
    HP = highPass(rows, cols)
    highPassCenter = center * HP

    ihighPassCenter = np.fft.ifftshift(highPassCenter)
    iHighPassOriginal = np.fft.ifft2(ihighPassCenter)
    imgHighPass = np.abs(iHighPassOriginal)

    # Smoothing Low Pass
    rows, cols = imgOri.shape
    LP = lowPass(rows, cols)
    lowPassCenter = center * LP

    iLowPassCenter = np.fft.ifftshift(lowPassCenter)
    iLowPassOriginal = np.fft.ifft2(iLowPassCenter)
    imgLowhPass = np.abs(iLowPassOriginal)

    # fingure 1
    plt.figure(fileName.split(".")[0] + "_FFT")

    plt.subplot(131), plt.imshow(imgOri, "gray"), plt.title("ImgOri")
    plt.subplot(132), plt.imshow(cenALog, "gray"), plt.title("FFT_Amplitude_Center")
    plt.subplot(133), plt.imshow(cenPh, "gray"), plt.title("FFT_Phase_Center")

    # finger 2
    plt.figure(fileName.split(".")[0] + "IFFT")
    plt.subplot(231), plt.imshow(cenALog, "gray"), plt.title("FFT_Amplitude_Center")
    plt.subplot(232), plt.imshow(HP, "gray"), plt.title("High Pass")
    plt.subplot(233), plt.imshow(LP, "gray"), plt.title("Low Pass")

    plt.subplot(234), plt.imshow(imgBack, "gray"), plt.title("IFFT_BACK")
    plt.subplot(235), plt.imshow(imgHighPass, "gray"), plt.title("IFFT_HighPass")
    plt.subplot(236), plt.imshow(imgLowhPass, "gray"), plt.title("IFFT_LowPass")

    plt.show()

def magnitude(x, y):
    x_m = x * x
    y_m = y * y
    z_m = x_m + y_m
    return np.sqrt(z_m)

def DFT(fileName):
    imgOri = cv.imread(fileName, 0)
    showImgPara(imgOri)
    dftOri = cv.dft(np.float32(imgOri), flags=cv.DFT_COMPLEX_OUTPUT)
    dftShift = np.fft.fftshift(dftOri)

    cenALog = 20 * np.log10(magnitude(dftShift[:, :, 0], dftShift[:, :, 1]))
    # fingure 1
    plt.figure(fileName.split(".")[0] + "_DFT")

    plt.subplot(121), plt.imshow(imgOri, "gray"), plt.title("ImgOri")
    plt.subplot(122), plt.imshow(cenALog, cmap="gray"), plt.title("DFT_Amplitude_Center")

    plt.show()

def main_func(argv):
    FFT("eg.png")
    # DFT("eg.png")

    # average = np.ones([3, 3], np.uint8)*1/9
    # npFFTshow(average)

if __name__ == '__main__':
    main_func(sys.argv)


from sympy import *

print("-"*72)
print("Structure problem in the reference configuration (S)")
print("-"*72)

# Declare useful symbols
X, Y, t = symbols('x[0] x[1] t')
A, rho_S, rho_F, mu, lam, eta = symbols('A rho_S rho_F mu lambda eta')

# Define a suitable solution field for the solid displacement
U_S = Matrix([0.0,
              -A*sin(pi*t)*sin(pi*X)*2*Y])
print("U_S =\n%s" % U_S)

# The kinematics of the motion are then described as follows
I = Matrix([[1, 0], [0, 1]])
Grad_U_S = Matrix([[simplify(diff(U_S[0], X)), simplify(diff(U_S[0], Y))],
                   [simplify(diff(U_S[1], X)), simplify(diff(U_S[1], Y))]])
F_S = I + Grad_U_S
C = F_S.T*F_S
E = Rational(1, 2)*(C - I)

# Compute the terms in (S) defined by U_S
Sigma_S = F_S*(2*mu*E + lam*E.trace()*I)
Div_Sigma_S = Matrix([simplify(diff(Sigma_S[0], X) + diff(Sigma_S[1], Y)),
                      simplify(diff(Sigma_S[2], X) + diff(Sigma_S[3], Y))])
d2U_S_dt2 = Matrix([simplify(diff(U_S[0], t, 2)), simplify(diff(U_S[1], t, 2))])

# Use (S) to determine B_S
B_S = rho_S*d2U_S_dt2 - Div_Sigma_S
print("B_S =\n%s" % B_S)

# Check if (S) is satisfied
check_S = rho_S*d2U_S_dt2 - Div_Sigma_S - B_S
print("check_S =\n%s" % Matrix([simplify(check_S[0]), simplify(check_S[1])]))

print("-"*72)
print("Mesh problem in the reference configuration (M)")
print("-"*72)

# Define a suitable solution field for the mesh displacement
U_M = Matrix([0.0,
              -A*sin(pi*t)*sin(pi*X)*2*(1 - Y)])
print("U_M =\n%s" % U_M)

# Check whether U_S = U_M on the interface
check_M = U_S.subs(Y, Rational(1, 2)) - U_M.subs(Y, Rational(1, 2))
print("check_M =\n%s" % check_M)

# Compute some kinematic quantities defined by U_M to be used in
# pulling-back the Navier-Stokes equations to the reference fluid
# configuration
Grad_U_M = Matrix([[simplify(diff(U_M[0], X)), simplify(diff(U_M[0], Y))],
                   [simplify(diff(U_M[1], X)), simplify(diff(U_M[1], Y))]])
F_M = I + Grad_U_M
J_M = F_M.det()
F_M_inv = F_M.inv()
V_M = Matrix([simplify(diff(U_M[0], t)),
              simplify(diff(U_M[1], t))])

print("-"*72)
print("Fluid problem in the reference configuration (F)")
print("-"*72)

# Define the solution field for the fluid velocity based on the time
# derivative of the solid velocity on the interface to enforce the
# no-slip condition
V_F = Matrix([diff(U_S[0].subs(Y, Rational(1, 2)), t),
              diff(U_S[1].subs(Y, Rational(1, 2)), t)])
print("V_F =\n%s" % V_F)

# Check whether this functional form is divergence-free in the
# reference configuration
Div_term = J_M*F_M_inv*V_F
Div_V_F = simplify(diff(Div_term[0], X) + diff(Div_term[1], Y))
print("check_F_1 =\n%s" % Div_V_F)

# Construct a part of the fluid stress, to determine the fluid
# pressure based on equality with the solid stress at the interface
P_F = symbols('P_F')
N_F = Matrix([0, -1.0])
Grad_V_F = Matrix([[simplify(diff(V_F[0], X)), simplify(diff(V_F[0], Y))],
                   [simplify(diff(V_F[1], X)), simplify(diff(V_F[1], Y))]])

Sigma_F = J_M*(eta*(Grad_V_F*F_M_inv + F_M_inv.T*Grad_V_F.T) - P_F*I)*F_M_inv.T
Sigma_F_int_dot_N = (N_F.T*Sigma_F*N_F).subs(Y, Rational(1, 2))
Sigma_S_int_dot_N = (N_F.T*Sigma_S*N_F).subs(Y, Rational(1, 2))

# Solve for the fluid pressure to satisfy the condition that the solid
# and fluid stresses are equal on the boundary
P_F_sol = solve(Eq(Sigma_F_int_dot_N[0], Sigma_S_int_dot_N[0]), P_F)
print("P_F =\n%s" % simplify(P_F_sol))

# Insert this pressure field into the definition of the fluid stress
Sigma_F = Sigma_F.subs(P_F, simplify(P_F_sol)[0])
print("check_F_2 =")
print(simplify(((N_F.T*Sigma_F*N_F - N_F.T*Sigma_S*N_F)[0].subs(Y, Rational(1, 2)))))

# Construct terms of the Navier-Stokes equations starting with the
# time derivative of the velocity
dV_F_dt = Matrix([simplify(diff(V_F[0], t)), simplify(diff(V_F[1], t))])

# Divergence of the stress field
Div_Sigma_F = Matrix([simplify(diff(Sigma_F[0], X) + diff(Sigma_F[1], Y)),
                      simplify(diff(Sigma_F[2], X) + diff(Sigma_F[3], Y))])

# Use (F) to determine B_F
B_F = rho_F*J_M*(dV_F_dt + Grad_V_F*F_M_inv*(V_F - V_M)) - Div_Sigma_F
print("B_F =\n%s" % B_F)

# Check if (F) is satisfied
check_F_3 = rho_S*d2U_S_dt2 - Div_Sigma_S - B_S
print("check_F_3 =\n%s" % Matrix([simplify(check_F_3[0]), simplify(check_F_3[1])]))


import numpy as np
from nanalysis.num_methods import NumMethods

class Interpolation:
    """
    Methods of approximation by different polynomial interpolants using either a known f(x)
    or a set of x,y values.

        - Lagrange interpolation (with or w/o divided differences)
        - Hermite interpolation (by divided differences)
        - Cubic spline interpolation (Natural - satisfies S''(a) = S''(b) = 0)
        - Chebyshev polynomial approximation

    """

    def __init__(self, func=None):
        self.func = func

    def lagrange(self, x, approx, y=None):
        """
          Approximation via Lagrange polynomial interpolation.

          Args:
              x (1D array): x,y interpolation point
              approx (float): Value to approximate
              y (1D array): x,y interpolation point

          Returns:
              float: Approximation
        """
        n = len(x)
        if y is None:
            y = np.zeros(n)
            for i in range(n):
                y[i] = self.func(x[i])
        interp = 0
        l = np.zeros(n)
        for i in range(n):
            l[i] = 1
            for k in range(n):
                if k != i:
                    l[i] *= (approx - x[k]) / (x[i] - x[k])
            interp += y[i] * l[i]
        return interp

    def lagrange_dd(self, x, approx, y=None):
        """
          Approximation via Lagrange polynomial interpolation with divided-difference coefficients.

          Args:
              x (1D array): x,y interpolation point
              approx (float): Value to approximate
              y (1D array): x,y interpolation point

          Returns:
              float: Approximation
        """
        n = len(x)
        if y is None:
            y = np.zeros(n)
            for i in range(n):
                y[i] = self.func(x[i])
        dd = self.div_diff(x, y)
        interp = dd[0, 0]
        for i in range(1, n):
            d = 1
            for j in range(i):
                d *= (approx - x[j])
            interp += d * dd[i, i]
        return interp

    def div_diff(self, x, y=None):
        """
          Obtains Newton's divided-difference coefficients for the interpolating polynomial.

          Args:
              x (1D array): x,y interpolation point
              y (1D array): x,y interpolation point

          Returns:
              ndarray: 2D (n x n) array of divided-difference coefficients. ith column represents
              i-1th divided differences.
        """
        n = len(x)
        dd = np.zeros((n, n))
        if y is None:
            dd[:, 0] = np.transpose(self.func(x))
        else:
            dd[:, 0] = np.transpose(y)
        for i in range(n-1):
            for j in range(i+1):
                dd[i+1, j+1] = (dd[i+1, j] - dd[i, j]) / (x[i+1] - x[i-j])
        return dd

    def hdiv_diff(self, x, y=None, yp=None):
        """
          Obtains coefficients of Hermite interpolating polynomial using divided-differences.
          Requires equal-length x,y,yp arrays or just x array if f(x) is known and differentiable.

          Args:
              x (1D array): x,y interpolation point
              y (1D array): x,y interpolation point
              yp (1D array): First derivative y' evaluated at x

          Returns:
              ndarray: 2D (2n x 2n) array of divided-difference coefficients. ith column represents
              i-1th divided differences.
        """
        n = len(x)
        z = np.zeros((2*n))
        q = np.zeros((2*n, 2*n))
        if y is None and yp is None:
            y, yp = np.zeros(n), np.zeros(n)
            for i in range(n):
                y[i] = self.func(x[i])
                yp[i] = NumMethods(self.func).mid_3diff(x[i])
        for i in range(n):
            z[2*i] = x[i]
            z[2*i+1] = x[i]
            q[2*i, 0] = y[i]
            q[2*i+1, 0] = y[i]
            q[2*i+1, 1] = yp[i]
            if i != 0:
                q[2*i, 1] = (q[2*i, 0] - q[2*i-1, 0]) / (z[2*i]-z[2*i-1])
        for i in range(2, 2*n):
            for j in range(2, i+1):
                q[i, j] = (q[i, j-1] - q[i-1, j-1]) / (z[i]-z[i-j])
        return q, z

    def hermite(self, x, approx, y=None, yp=None):
        """
          Gives approximation using Hermite polynomial with divided-difference coefficients.
          Requires equal-length x,y,yp arrays or just x array if f(x) is known and differentiable.

          Args:
              x (1D array): x,y interpolation point
              approx (float): Value to approximate
              y (1D array): x,y interpolation point
              yp (1D array): First derivative y' evaluated at x

          Returns:
              float: Hermite approximate
        """
        hdd, z = self.hdiv_diff(x, y, yp)
        n = int(len(z)/2)
        hp = hdd[0, 0]
        for i in range(1, 2*n):
            d = 1
            for j in range(i):
                d *= (approx - z[j])
            hp += d * hdd[i, i]
        return hp

    def spline_nat_coeff(self, x, y=None):
        """
          Construct cubic spline coefficients with natural boundary condition S''(a) = 0 and S''(b) = 0
          to approximate on appropriate interval(s).
          Ex: for x in [x(i-1), x(i)], spline S_i(x) = a_i + b_ix + c_ix^2 + d_ix^3

          Args:
              x (1D array): x,y interpolation point
              y (1D array): x,y interpolation point

          Returns:
              1D array: a, b, c, d are the spline coefficients: a + bx +cx^2 +dx^3
        """
        n = len(x)
        a = np.zeros(n)
        if y is None:
            for i in range(n):
                a[i] = self.func(x[i])
        else:
            a = y
        h, alpha, mu, l, z, c, b, d = np.zeros((8, n))
        for i in range(n-1):
            h[i] = x[i+1] - x[i]
        for i in range(1, n-1):
            alpha[i] = (3/h[i]) * (a[i+1] - a[i]) - (3/h[i-1]) * (a[i] - a[i-1])
        l[0] = 1
        mu[0] = 0
        z[0] = 0
        for i in range(1, n-1):
            l[i] = 2*(x[i+1] - x[i-1]) - h[i-1] * mu[i-1]
            mu[i] = h[i] / l[i]
            z[i] = (alpha[i] - h[i-1] * z[i-1]) / l[i]
        l[n-1] = 1
        z[n-1] = 0
        c[n-1] = 0
        for j in range(n-2, -1, -1):
            c[j] = z[j] - mu[j] * c[j+1]
            b[j] = ((a[j+1] - a[j]) / h[j]) - (h[j] * (c[j+1] + 2*c[j])/3)
            d[j] = (c[j+1] - c[j]) / (3*h[j])
        a = a[:n-1]
        b = b[:n-1]
        c = c[:n-1]
        d = d[:n-1]
        return a, b, c, d

    def spline_clamp_coeff(self, x, y=None, fpo=None, fpn=None):
        """
          Construct cubic spline coefficients with clamped boundary condition S'(a) = f'(a) and S'(b) = f'(b)
          to approximate on appropriate interval(s).
          Ex: for x in [x(i-1), x(i)], spline S_i(x) = a_i + b_ix + c_ix^2 + d_ix^3

          Args:
              x (1D array): x,y interpolation point
              y (1D array): x,y interpolation point
              fpo (float): f'(a) aka f'(x_0)
              fpn (float): f'(b) aka f'(x_n)

          Returns:
              1D array: a, b, c, d are the spline coefficients: a + bx +cx^2 +dx^3
        """
        n = len(x)
        a = np.zeros(n)
        if y is None:
            for i in range(n):
                a[i] = self.func(x[i])
        if fpo is None and fpn is None:
            fpo = NumMethods(self.func).mid_3diff(x[0])
            fpn = NumMethods(self.func).mid_3diff(x[n-1])
        else:
            a = y
        h, alpha, mu, l, z, c, b, d = np.zeros((8, n))
        for i in range(n-1):
            h[i] = x[i+1] - x[i]
        alpha[0] = 3*(a[1] - a[0])/h[0] - 3*fpo
        alpha[n-1] = 3*fpn - 3*(a[n-1] - a[n-2])/h[n-2]
        for i in range(1, n-1):
            alpha[i] = (3/h[i]) * (a[i+1] - a[i]) - (3/h[i-1]) * (a[i] - a[i-1])
        l[0] = 2*h[0]
        mu[0] = 0.5
        z[0] = alpha[0]/l[0]
        for i in range(1, n-1):
            l[i] = 2*(x[i+1] - x[i-1]) - h[i-1] * mu[i-1]
            mu[i] = h[i]/l[i]
            z[i] = (alpha[i] - h[i-1] * z[i-1])/l[i]
        l[n-1] = h[n-2] * (2 - mu[n-2])
        z[n-1] = (alpha[n-1] - h[n-2] * z[n-2])/l[n-1]
        c[n-1] = z[n-1]
        for j in range(n-2, -1, -1):
            c[j] = z[j] - mu[j] * c[j+1]
            b[j] = ((a[j+1] - a[j])/h[j]) - (h[j]/3)*(c[j+1] + 2*c[j])
            d[j] = (c[j+1] - c[j])/(3*h[j])
        a = a[:n-1]
        b = b[:n-1]
        c = c[:n-1]
        d = d[:n-1]
        return a, b, c, d

    def cubic_spline(self, x, approx, y=None, bound="natural", fpo=None, fpn=None):
        """
          Construct cubic splines to approximate on appropriate interval(s). Specify boundary conditions
          natural or clamped.

          Args:
              x (1D array): x,y interpolation point
              approx (float or 1D array): Value(s) to approximate
              y (1D array): x,y interpolation point
              bound (str): Natural boundary - "natural"
                           Clamp boundary - "clamp"
              fpo (float): f'(a) aka f'(x_0)
              fpn (float): f'(b) aka f'(x_n)

          Returns:
              ndarray: 1D array of approximations
        """
        n = len(x)
        if bound == "natural":
            a, b, c, d = self.spline_nat_coeff(x, y)
        elif bound == "clamp":
            a, b, c, d = self.spline_clamp_coeff(x, y, fpo=fpo, fpn=fpn)
        else:
            print("Invalid boundary: use 'natural' or 'clamp'.")
            return None
        if type(approx) == float:
            approx = [approx]
        m = len(approx)
        sy = np.zeros(m)
        for j in range(n):
            for i in range(m):
                if x[j] < approx[i] < x[j+1]:
                    sy[i] = a[j] + b[j]*(approx[i] - x[j]) + c[j]*(approx[i] - x[j])**2 + d[j]*(approx[i] - x[j])**3
        return sy

    def cheby_coeff(self, n):
        """
          Compute Chebyshev coefficients for Chebyshev polynomial approximations.
          Requires known function f(x).

          Args:
              n (int): Degree of Chebyshev polynomial

          Returns:
              ndarray: 1D array of coefficients to be used in polynomial approximation
        """
        f = self.func
        var_trans = lambda a: f(np.cos(a))
        a = np.zeros(n+2)
        a[1] = (1/np.pi) * NumMethods(var_trans).simp_comp(0, np.pi, 50)
        for i in range(1, n+1):
            t_i = lambda x: (f(np.cos(x)) * np.cos(i*x))
            a[i+1] = (2/np.pi) * NumMethods(t_i).simp_comp(0, np.pi, 50)
        return a[1:n+2]

    def chebyshev(self, approx, n=4):
        """
          Compute Chebyshev polynomial approximation of f(x).

          Args:
              approx (float): Approximation value
              n (int): Max degree Chebyshev polynomial

          Returns:
              float: Approximation to f(x) at approx value
        """
        c = self.cheby_coeff(n)
        p = 0
        for i in range(n+1):
            t_i = lambda a: np.cos(i * np.arccos(a))
            p += c[i] * t_i(approx)
        return p


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

sigma_0=0.1
sigma_1=sigma_0
sigma_2=0.2
mu_1=10
mu_2=np.random.normal(0, sigma_2, 1 )
v=1
H=1
K=(H*sigma_1**2)/(H**2*sigma_1**2+sigma_2**2)

mu_fused=mu_1
sigma_fused=sigma_1

length=21.0
mu_t=np.arange(length)#optimal estimate value
sigma_t=np.arange(length)
z_t=np.arange(length)#measure value
x_t=np.arange(length)#pridiction value
t=np.arange(length)

t[0] = 0
mu_t[0] = mu_fused
sigma_t[0] = sigma_fused
x_t[0]=mu_1
z_t[0]=mu_2

for i in range(1,int(length)):
    mu_1=np.random.normal(mu_fused+v, sigma_fused, 1 )
    mu_2=np.random.normal(i, sigma_2, 1 )
    mu_fused=mu_1+K*(mu_2-H*mu_1)
    sigma_fused=math.sqrt( sigma_1**2-K*H*sigma_1**2)
    sigma_1=sigma_fused
    print(i,mu_1, mu_2, mu_fused,sigma_fused)
    #
    t[i]=i
    mu_t[i]=mu_fused
    sigma_t[i]=sigma_fused
    x_t[i] = mu_1
    z_t[i] = mu_2
#plot
fig,ax=plt.subplots(1,2,figsize=(10,5))
ax[0].plot(t,t,label="real value",marker='s')
ax[0].plot(t,z_t,label="measure value")
ax[0].plot(t,x_t,label="pridiction value")
ax[0].plot(t,mu_t,label="optimal estimate value",marker='o')
ax[0].legend(loc=2)
ax[0].grid(True)
ax[0].set_title('kalman filter ($\sigma_1=$'+str(sigma_0)+',$\sigma_2=$'+str(sigma_2)+')')

ax[1].plot(t,sigma_t,label="$\sigma$")
ax[1].legend(loc=1)
ax[1].grid(True)
ax[1].set_title('kalman filter ($\sigma$)')

plt.show()


import numpy as np                 # Numpy is a library support computation of large, multi-dimensional arrays and matrices.
from PIL import Image              # Python Imaging Library (abbreviated as PIL) is a free and open-source additional library for the Python programming language that adds support for opening, manipulating, and saving many different image file formats.
import matplotlib.pyplot as plt    # Matplotlib is a plotting library for the Python programming language.
import math

def BetterSpecAnal(x,plot=False):
	N=64
	x_shape = np.shape(x)
	total_center_window = 5*N
	center_image = x[math.ceil((x_shape[0]-total_center_window)/2):math.ceil((x_shape[0]-total_center_window)/2)+total_center_window,
					math.ceil((x_shape[1]-total_center_window)/2):math.ceil((x_shape[1]-total_center_window)/2)+total_center_window]
	W = np.outer(np.hamming(N), np.hamming(N))

	Sum = np.zeros((N,N))
	for i in range(5):
		for j in range(5):
			sub_fig = center_image[i*N:i*N+N,j*N:j*N+N]
			x_windowed = np.multiply(sub_fig,W)
			Z = (1/N**2)*np.abs(np.fft.fft2(x_windowed))**2
			Sum += Z
	Sum = Sum/25
	Sum = np.fft.fftshift(Sum)
	Sum_abs = np.log(Sum)

	if plot:
		fig = plt.figure()
		ax = fig.add_subplot(111, projection='3d')
		a = b = np.linspace(-np.pi, np.pi, num = N)
		X, Y = np.meshgrid(a, b)

		surf = ax.plot_surface(X, Y, Sum_abs, cmap=plt.cm.coolwarm)

		ax.set_xlabel('$\mu$ axis')
		ax.set_ylabel('$\\nu$ axis')
		ax.set_zlabel('Average PSD')

		fig.colorbar(surf, shrink=0.5, aspect=5, location="left")
		plt.title('Average PSD after windowing by Hamming window')
		plt.savefig('Power_Spectral_Average.tif')
		plt.savefig('Power_Spectral_Average.png')
		plt.show()
	return Sum_abs

def Main():
	# Read in a gray scale TIFF image.
	im = Image.open('img04g.tif')
	print('Read img04.tif.')
	print('Image size: ', im.size)
	x = np.array(im)
	x = np.double(x)/255.0
	S = BetterSpecAnal(x,plot=True)

Main()


"""
This module deals with binary stars. The two main functions are:

- a , e = get_parameters(r,v,mt,G):
    This retrieves orbital parameters of a binary system when
    only relative position, relative velocity and masses are known.

- r1,r2,v1,v2 = RandomBinary( a,e,m1,m2,G )
    This retrieves position and velocity as seen from center of mass
    given orbital parameters. The phase and orientation of the binary
     are randomly chosen.

In many functions, the default gravitationnal constant is 1. Positions
masses and velocities should be in nbody units for this to make sense.
"""

from numpy import cos,sin,sqrt
from numpy.linalg import norm
import numpy as np
Pi=np.pi

#********************************************************************
#***  From position and velocity, get the orbital parameters  *******
#********************************************************************

def scalar(a,b):
    """Returns the scalar product of 2 3d vectors (list/array)"""
    s = a[0]*b[0] + a[1]*b[1] + a[2]*b[2]
    return s

def vectorial(a,b):
    """Returns the scalar product of 2 3d vectors (list/array)"""
    v1= a[1]*b[2]-a[2]*b[1]
    v2= a[2]*b[0]-a[0]*b[2]
    v3= a[0]*b[1]-a[1]*b[0]
    return np.array([v1,v2,v3])

def get_a(r,v,mt,G=1):
    """
    This function takes the relative radius and velocity vector of
    a system, the total mass, and returns the semi-major axis.
    """
    r=norm(r)
    v=norm(v)
    a= r / ( 2 - r*v**2 / (G*mt) )
    return a

def get_e(r,v,a,mt,G=1):
    """
    This function takes the relative radius, velocity, as well as the
    previously obtained semi-major axis of the system and the total
    mass to return the computed eccentricity.
    """
    h=vectorial(r,v)
    h=norm(h)
    e2= 1 - h**2 / ( a * G * mt )
    e=sqrt(e2)
    return e

def get_parameters(r,v,mt,G=1):
    """
    This functions takes relative distance (3d vector) relative
    velocity (3d vector) and total mass to return the semi major axis
    and eccentricity as a,e.
    """
    V2 = norm(v)**2
    R = norm(r)
    ebin = V2/2. - G * mt / R
    if ebin > 0:
        raise Exception("get_parameters was fed with data from"
                        "two unbound stars. Cannot compute a and e.")
    a=get_a(r,v,mt,G)
    e=get_e(r,v,a,mt,G)
    return a,e

#*********************************************************************
#*****  From the orbital parameters, get position and velocity  ******
#*********************************************************************

def rotate(vec,phi1,phi2,phi3):
    """
    Rotate the given 3d vector along the three axis with given angles.
    Useful for rotated_binary_sample
    """
    matrot1=np.matrix([ [1,0,0] ,
                        [0, cos(phi1) , -sin(phi1)] ,
                        [0, sin(phi1) , cos(phi1)] , ])
    matrot2=np.matrix([ [cos(phi2), 0, sin(phi2)] ,
                        [0,1,0] ,
                        [-sin(phi2), 0, cos(phi2)]  ])
    matrot3=np.matrix([ [cos(phi3) , -sin(phi3) , 0] ,
                        [sin(phi3) , cos(phi3) , 0] ,
                        [0,0,1] ])
    vec=np.matrix(vec)
    vec=vec*matrot1*matrot2*matrot3
    return np.array(vec)

def ang_momentum(a,e,m1,m2,G=1):
    """returns the angular momentum  in the appropriate units."""
    return sqrt(a*(1-e**2)*G*(m1+m2))

def r_orbit(a,e,m1,m2,theta=0,G=1):
    """
    For two orbiting particles and a given theta,
    returns relative radius.
    """
    r = a* ( 1 - e**2 ) / ( 1 - e*cos(theta))
    return r

def r_dot(a,e,m1,m2,theta=0,G=1):
    """
    For two orbiting particles and a given theta,
    returns relative radius derivative.
    """
    h=ang_momentum(a,e,m1,m2,G)
    rd= - h  *  e*sin(theta) / ( a * (1-e**2) )
    return rd

def theta_dot(a,e,m1,m2,theta=0,G=1):
    """
    For two orbiting particles and a given theta,
    returns theta derivative.
    """
    r=r_orbit(a,e,m1,m2,theta,G)
    h=ang_momentum(a,e,m1,m2,G)
    return h /r**2

def elliptical_orbit(e,a,n):
    """returns a [0:2Pi] array and the coordinates of a 2d ellipsis"""
    th=np.arange(float(n))/n*2*3.1415
    r=a*(1-e**2)/(1+e*np.cos(th))
    return th,r

def velocity_binary(a,e,m1,m2,theta=0,G=1):
    """
    Returns x1,y1,x2,y2,vx1,vy1,vx2,vy2
    for two gravitating particles (planar motion)
    """
    if e<0 or e>1:
        raise Exception("Error, bad eccentricity fed to the function.")
    r=r_orbit(a,e,m1,m2,theta,G)
    rd=r_dot(a,e,m1,m2,theta,G)
    thd=theta_dot(a,e,m1,m2,theta,G)
    mu1,mu2= m2/(m1+m2) , m1/(m1+m2)

    x1=-mu1*r*cos(theta)
    y1=-mu1*r*sin(theta)
    x2=mu2*r*cos(theta)
    y2=mu2*r*sin(theta)
    vx1= - mu1 * (rd*cos(theta)-r*thd*sin(theta))
    vy1= - mu1 * (rd*sin(theta)+r*thd*cos(theta))
    vx2=  mu2 * (rd*cos(theta)-r*thd*sin(theta))
    vy2= mu2 * (rd*sin(theta)+r*thd*cos(theta))

    return x1,y1,x2,y2,vx1,vy1,vx2,vy2

def rotated_binary_sample(a,e,m1,m2,theta,phi1,phi2,phi3,G=1):
    """
    Returns r1,r2,v1,v2: numpy arrays of positions and velocities of a
    binary rotated along three axes with phi1,phi2,phi3,
    at an internal angle theta
    """
    x1,y1,x2,y2,vx1,vy1,vx2,vy2 = velocity_binary( a,e,m1,m2,theta,G)
    r1=rotate([x1,y1,0],phi1,phi2,phi3)[0]
    r2=rotate([x2,y2,0],phi1,phi2,phi3)[0]
    v1=rotate([vx1,vy1,0],phi1,phi2,phi3)[0]
    v2=rotate([vx2,vy2,0],phi1,phi2,phi3)[0]
    return r1,r2,v1,v2

def RandomBinary(a,e,m1,m2,G=1):
    """
    Return position and velocity of generated binary system.

    r1,r2,v1,v2 = RandomBinary(a,e,m1,m2,G=1)

    The binary system is created, rotated with random angles along 3
    axis, then its internal angle is also set to a random angle.
    """
    theta,phi1,phi2,phi3=[np.random.random()*2*Pi for i in [1,2,3,4]]
    return rotated_binary_sample(a,e,m1,m2,theta,phi1,phi2,phi3,G=G)


from numpy.matlib import *
import numpy
import time
import scipy.sparse.linalg

def gausselim(A, b, pivoting = 0, ztol = 1.0e-8, debug = False):

    size = len(A)
    x    = [0.0] * size
    R    = range(size)
    C    = range(size)
    code = 0

    # Triangularization.
    for pivot in range(size-1):
        absm    = abs(A[pivot][pivot])
        exchrow = pivot
        exchcol = pivot

        if pivoting == 1: # partial pivoting.
            for row in range(pivot + 1, size):
                atestm  = abs(A[row][pivot])
                if atestm > absm:
                   absm    = atestm
                   exchrow = row

        elif pivoting == 2: #full pivoting.
            for row in range(pivot + 1, size):
                for col in range(pivot, size):
                   atestm  = abs(A[row][col])
                   if atestm > absm:
                      absm    = atestm
                      exchrow = row
                      exchcol = col

        elif pivoting == 3: # rook pivoting.
           # find element which is maximum in its row and column
           # but using rook moves (alternating vertical and horizontal directions) only
           # NOT OPTIMIZED YET!
           absm  = 0.0
           Done = False
           while not Done:
               Done = True
               #Find row with maximum element in column exchcol.
               for row in range(exchrow, size):
                   atest = abs(A[row][exchcol])
                   if atest > absm:
                      absm  = atest
                      exchrow = row
                      Done = False

               #Find col with maximum element in row exchrow.
               for col in range(pivot, size):
                   atest = abs(A[exchrow][col])
                   if atest > absm:
                      absm = atest
                      exchcol = col
                      Done = False

        #Exchange columns ?
        if pivot != exchcol:
            if debug: print "exhanging columns", pivot, exchcol
            for row in range(pivot, size):
                A[row][pivot], A[row][exchcol] = A[row][exchcol], A[row][pivot]
            #B[pivot], B[exchcol] = B[exchcol],B[pivot]
            C[pivot] = exchcol

        #Exchange rows?
        if pivot != exchrow:
            if debug:
               print "Exchanging rows:",  pivot,  exchrow
            A[exchrow],A[pivot] = A[pivot], A[exchrow]
            b[exchrow],b[pivot] = b[pivot], b[exchrow]
            R[pivot] = exchrow

        if absm > ztol:
           if debug:
               print "pre reduction for row",pivot

           m = float(A[pivot][pivot])
           for row in range(pivot +1, size):
               kmul = float(A[row][pivot])/m
               # Apply rectangular rule.(Reduction)
               for col  in range(size -1, pivot, -1):
                    A[row][col] = float(A[row][col]) - kmul * A[pivot][col]
               b[row] = float(b[row]) - kmul * b[pivot]
               A[row][pivot] = 0.0

           if debug:
               print "post reduction:"
               print

        else:
           code = 1

    # Perform Back substitution.
    if debug:
       print "Back substitution: row, rhs sum, pivot"
    if code == 0:
        for row in range(size-1, -1, -1):
           sum = b[row]
           for k in range(row+1, size):
                sum -= (x[k] * A[row][k])
           #print row, sum, A[row][row]
           x[row] = sum/A[row][row]
        reorder(x,C)
        if debug: print "Computed value of X = ",  x
    return (code,R,C, A,x,b)

def reorder(x   , C):
    for i, c in enumerate(C):
        if i != c:
           #exchange elements at positions i and c.
           x[i], x[c] =  x[c], x[i]
    return x

def Solve(A,b):

    (code, R,C, A, x, b) = gausselim(A, b)
    if code==0:
        return x
    else:
        return None

if __name__ == "__main__":
    data = numpy.zeros((100,100))
    data[numpy.arange(99), numpy.arange(99)+1] = [-1]
    data[numpy.arange(99)+1, numpy.arange(99)] = [-1]
    data[numpy.arange(100), numpy.arange(100)] = [-2]
    A = data

    data = numpy.zeros((100,1))
    data[numpy.arange(98)+1, numpy.arange(1)] = [1]
    data[numpy.arange(1), numpy.arange(1)] = [2]
    data[numpy.arange(1)+99, numpy.arange(1)] = [2]
    b =  data

    code, R,C, A,x, b = gausselim(A,b, pivoting=1, debug =True)

    print "X \n", x
    print '\n\nresidual', scipy.linalg.norm(numpy.dot(A, Solve(A, b)) - b)\
                          /scipy.linalg.norm(A)

    tic = time.clock()
    toc = time.clock()
    print "Processing time is : %f" %(toc - tic)


import numpy as np

def vec_dir(v0, v1):
    """Returns a normalized vector pointing from v0 towards v1"""
    delta = v1 - v0
    norm = np.linalg.norm(delta)
    return delta / norm

def random_dir():
    """Returns a random direction in the form of a normalized vector."""
    x, y = np.random.uniform(-1,1), np.random.uniform(-1, 1)
    pt = np.array((x,y))
    return pt / np.linalg.norm(pt)

def random_angle():
    return np.random.uniform(-np.pi, np.pi)

def angle_from(p0, p1):
    """Returns the angle from p0 to p1"""
    delta = p1 - p0
    x, y = delta
    return np.arctan2(y, x)

def polar_from_pt(pt, a, r):
    """Given a starting point, returns another point at
    a given distance and angle from the starting point.
    pt: a starting point.
    a: an angle
    r: a radius
    """
    x0,y0 = pt
    x1 = r * np.cos(a) + x0
    y1 = r * np.sin(a) + y0
    return np.array((x1, y1))

def to_deg(a):
    return a / np.pi * 180

def relative_angle(p0, dir0, p1):
    """
    p0: A vector with the position of an object.
    dir0: A normalized vector indicating the direction the object at p0 is facing.
    p1: The position of a target object.
    Returns the relative angle left/right that point p1 lies in the field of view of p0.
    Returns a positive number if the target is to the left, and negative if it is to the right.
    """
    x0, y0 = dir0
    angle0 = np.arctan2(y0, x0)
    angle1 = angle_from(p0, p1)
    delta_angle = angle1 - angle0
    #print('relang p0=%s dir0=%s p1=%s' % (p0, dir0, p1))
    #print('angle0=%s angle1=%s delta=%s' % (to_deg(angle0), to_deg(angle1), to_deg(delta_angle)))
    return delta_angle

def clamp(pt, width, height):
    """Returns a point that is constrained to being >0 and up to the given width and height."""
    pt[0] = max(pt[0], 0)
    pt[1] = max(pt[1], 0)
    pt[0] = min(pt[0], width)
    pt[1] = min(pt[1], height)
    return pt

def lerp_3d(a, b, f):
    """
    Linear interpolation between 2 3d vectors.
    f: a scalar from 0 to 1.
    If f=0 then a is returned, if f=1 then b is returned.
    A blending of a and b is returned for values of f between 0-1.
    """
    return (1-f) * a + f * b

def test_relative_angle():
    p0 = np.array((1,1))
    p0_facing = np.array((20, 100)) # Looking a little to the right of the top left corner.
    p0_dir = vec_dir(p0, p0_facing) # Mostly up and a little right. [0.18847945 0.98207713]
    targets = [(100,100), (70,2), (50,12), (16, 80)]
    for t in targets:
        print('From %s to %s' % (p0, t))
        a = relative_angle(p0, p0_dir, t)
        print('t=%s a=%s' % (t, to_deg(a)))

def test_relative_angle2():
    def offset(pt, a, r): # Returns a point at the given angle and distance
        x0,y0 = pt
        x1 = r * np.cos(a) + x0
        y1 = r * np.sin(a) + y0
        return np.array((x1, y1))
    p0 = np.array([20,20])
    a = 0
    r = 5
    # For several points around a circle, select a target point and face that point.
    # Then place a target a little to the left of that.
    for i in range(8):
        p0_dir = vec_dir(p0, offset(p0, a, r))
        target_a = a + np.pi/12 # Target is a little to the left
        p1 = offset(p0, target_a, r)
        ra = relative_angle(p0, p0_dir, p1)
        assert (ra  - np.pi/12) < 0.0001, 'expected angle to be equal'
        a += np.pi / 8


import numpy as np
import time
from math import exp
import matplotlib.pyplot as plt

def gradient_descent( func, initial_x, eps=1e-5, maximum_iterations=65536, learning_rate=1e-2 ):
    """
    Gradient Descent
    func:               the function to optimize It is called as "value, gradient = func( x, 1 )
    initial_x:          the starting point, should be a float
    eps:                the maximum allowed error in the resulting stepsize t
    maximum_iterations: the maximum allowed number of iterations
    linesearch:         the linesearch routine
    *linesearch_args:   the extra arguments of linesearch routine
    """

    if eps <= 0:
        raise ValueError("Epsilon must be positive")
    x = np.matrix(initial_x)

    # initialization
    values = []
    runtimes = []
    xs = []
    start_time = time.time()
    iterations = 0

    # gradient updates
    while True:

        value, gradient = func( x , 1 )
        value = np.double( value )
        gradient = np.matrix( gradient )

        # updating the logs
        values.append( value )
        runtimes.append( time.time() - start_time )
        xs.append( x.copy() )

        direction = -gradient

        if np.linalg.norm(direction)<eps:
            break

        t = learning_rate

        x = x + t * direction

        iterations += 1
        if iterations >= maximum_iterations:
            break
    return (x, values, runtimes, xs)

def linear_regression(x, y, w, b, order=0):
    output = w*x.T + b
    error = np.mean((y-output)**2)
    if order == 1:
        grad_w = -2*x.T*(y-(w*x.T + b))
        grad_b = -2*(y-(w*x.T + b))
        grad_w = np.mean(grad_w)
        grad_b = np.mean(grad_b)
        return output, grad_w, grad_b
    return output

def boyd_example_func(x, order=0):
  a=np.matrix('1  3')
  b=np.matrix('1  -3')
  c=np.matrix('-1  0')
  x=np.asmatrix(x)

  value = exp(a*x-0.1)+exp(b*x-0.1)+exp(c*x-0.1)
  if order==0:
      return value
  elif order==1:
      gradient = a.T*exp(a*x-0.1)+b.T*exp(b*x-0.1)+c.T*exp(c*x-0.1)
      return (value, gradient)
  elif order==2:
      gradient = a.T*exp(a*x-0.1)+b.T*exp(b*x-0.1)+c.T*exp(c*x-0.1)
      hessian = a.T*a*exp(a*x-0.1)+b.T*b*exp(b*x-0.1)+c.T*c*exp(c*x-0.1)
      return (value, gradient, hessian)
  else:
        raise ValueError("The argument \"order\" should be 0, 1 or 2")

def neumann( func, initial_x, learning_rate=1e-2, eps=1e-5, maximum_iterations=65536):
    x = np.matrix(initial_x)
    # moving_average = x
    neumann_iterate = 0
    iterate = 0
    k_value = 10
    values = []
    runtimes = []
    xs = []
    grad_norm = []
    start_time = time.time()
    while True:
        print(x)
        if iterate < 5:
            value, grad = func(x, 1)
            x = x - learning_rate*grad
            iterate += 1
            continue

        values.append( value )
        runtimes.append( time.time() - start_time )
        xs.append( x.copy() )

        eta = 0.5/iterate
        mu = iterate/(iterate + 1)
        mu = min(max(mu, 0.5),0.9)

        value, grad = func(x, 1)

        grad_norm.append(np.linalg.norm(grad)**2)

        if np.linalg.norm(grad)**2 < eps:
            break

        if iterate % k_value == 0:
            neumann_iterate = -eta*grad
            k_value *= 2

        #Removing crazy function as we're only trying on convex function

        neumann_iterate = mu*neumann_iterate - eta*grad

        x = x + mu*neumann_iterate - eta*grad
        # moving_average =
        iterate += 1
        if iterate >= maximum_iterations:
            break
    return x,values,runtimes,xs,grad_norm

def draw_contour( func, neumann_xs, fig, levels=np.arange(5, 1000, 10), x=np.arange(-5, 5.1, 0.05), y=np.arange(-5, 5.1, 0.05)):
    """
    Draws a contour plot of given iterations for a function
    func:       the contour levels will be drawn based on the values of func
    gd_xs:      gradient descent iterates
    newton_xs:  Newton iterates
    fig:        figure index
    levels:     levels of the contour plot
    x:          x coordinates to evaluate func and draw the plot
    y:          y coordinates to evaluate func and draw the plot
    """
    Z = np.zeros((len(x), len(y)))
    for i in range(len(x)):
        for j in range(len(y)):
            Z[i, j] = func( np.matrix([x[i],y[j]]).T , 0 )

    plt.figure(fig)
    plt.contour( x, y, Z.T, levels, colors='0.75')
    plt.ion()
    plt.show()

    # line_gd, = plt.plot( gd_xs[0][0,0], gd_xs[0][1,0], linewidth=2, color='r', marker='o', label='GD' )
    line_newton, = plt.plot( neumann_xs[0][0,0], neumann_xs[0][1,0], linewidth=2, color='m', marker='o',label='Neumann' )

    L = plt.legend(handles=[line_newton])
    plt.draw()
    time.sleep(1)

    for i in range( 1, len(neumann_xs)):

        # line_gd.set_xdata( np.append( line_gd.get_xdata(), gd_xs[ min(i,len(gd_xs)-1) ][0,0] ) )
        # line_gd.set_ydata( np.append( line_gd.get_ydata(), gd_xs[ min(i,len(gd_xs)-1) ][1,0] ) )

        line_newton.set_xdata( np.append( line_newton.get_xdata(), neumann_xs[ min(i,len(neumann_xs)-1) ][0,0] ) )
        line_newton.set_ydata( np.append( line_newton.get_ydata(), neumann_xs[ min(i,len(neumann_xs)-1) ][1,0] ) )

        # L.get_texts()[0].set_text( " GD, %d iterations" % min(i,len(gd_xs)-1) )
        L.get_texts()[0].set_text( " Neumann, %d iterations" % min(i,len(neumann_xs)-1) )

        plt.draw()
        input("Press Enter to continue...")

initial_x = np.matrix('-1.0; -1.0')

x, values, runtimes, neumann_xs, grad_norm = neumann(boyd_example_func, initial_x)
x_gd, gd_values, runtimes_gd, gradient_xs = gradient_descent(boyd_example_func, initial_x)
plt.figure(1)
line_gd, = plt.semilogy([x for x in values], linewidth=2, color='r', marker='o', label='Neumann')
line_neumann, = plt.semilogy([x for x in gd_values], linewidth=2, color='b', marker='o', label='Neumann')
plt.figure(2)
plt.semilogy([x for x in grad_norm], linewidth=2, color='b', marker='o', label='Neumann')
draw_contour( boyd_example_func, neumann_xs, 3, levels=np.arange(0, 15, 1), x=np.arange(-2, 2, 0.1), y=np.arange(-2, 2, 0.1))


#!/anaconda3/bin/python

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from mpl_toolkits.mplot3d import Axes3D # for surface plot

def computeCost(X, y, theta):
    m = len(y)
    J = 0
    J = sum((X.dot(theta) - y.reshape(m, 1))**2) / 2 / m
    return J

def gradientDescent(X, y, theta, alpha, num_iters):
    m = len(y)
    J_history = np.zeros([num_iters, 1])
    for iter in np.arange(1, num_iters + 1):
        delta = 1 / m * (X.T.dot(X).dot(theta) - X.T.dot(y).reshape(2, 1))
        theta = theta - alpha * delta
        J_history[iter - 1] = computeCost(X, y, theta)
    return theta, J_history

data = pd.read_csv('ex1data1.txt', header=-1)
data = np.asarray(data)
X = data[:, 0]
y = data[:, 1]
m = len(y)

plt.plot(X, y, 'rx')  # Plot Data
X = np.insert(np.ones((m, 1)), 1, X, axis=1)
theta = np.zeros((2, 1))

iterations = 1500
alpha = 0.01

J = computeCost(X, y, theta)
print('With theta = [0;0], Expected cost value (approx) 32.07\n')
print(J)
J = computeCost(X, y, np.array([(-1, ), (2, )]))
print('With theta = [-1 ; 2], Expected cost value (approx) 54.24\n')
print(J)

theta, J_history = gradientDescent(X, y, theta, alpha, iterations)
plt.plot(X[:, 1], X.dot(theta), "-", label='Training data')
plt.plot(X[:, 1], y, "rx", label='Linear regression')
plt.legend()
plt.figure()
# contour
theta0_vals = np.linspace(-10, 10, 100)
theta1_vals = np.linspace(-1, 4, 100)

J_vals = np.zeros([len(theta0_vals), len(theta1_vals)])

for i in np.arange(0, len(theta0_vals)):
    for j in np.arange(0, len(theta1_vals)):
        t = np.array([(theta0_vals[i], ), (theta1_vals[j], )])
        J_vals[i, j] = computeCost(X, y, t)

plt.contour(theta0_vals, theta1_vals, J_vals.T, np.logspace(-2, 3, 20))
plt.plot(theta[0], theta[1], 'rx')
plt.show()
# surf

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(theta0_vals, theta1_vals, J_vals)
plt.show()


#https://en.wikipedia.org/wiki/Viterbi_algorithm

obs = ('normal', 'cough', 'headache', 'normal', 'normal')
states = ('Healthy', 'Sick')
start_p = {'Healthy': 0.3, 'Sick': 0.7}
trans_p = {
   'Healthy' : {'Healthy': 0.9, 'Sick': 0.1},
   'Sick' : {'Healthy': 0.2, 'Sick': 0.8}
   }
obs_p = {
   'Healthy' : {'normal': 0.8, 'cough': 0.15, 'headache': 0.05},
   'Sick' : {'normal': 0.1, 'cough': 0.6, 'headache': 0.3}
   }

import numpy as np

periods = 5
health = ['Healthy']
probability = [1.0]
randomNumbers = np.random.rand(periods)
for i in range(periods):
    if trans_p[health[i]]['Healthy'] < randomNumbers[i]:
        health.append('Healthy')
    else:
        health.append('Sick')
    probability.append((trans_p[health[i]][health[i+1]]))

print('health sequence: {}'.format(health))
print('probabilities: {}'.format(probability))
print('sequence probability = {}'.format(np.prod(probability)))

def getPath(V):
    """Backtrack through lattice to retrieve path to optimal solution"""
    opt = []
    max_prob = max(value["prob"] for value in V[-1].values())
    previous = None
    # Get most probable state and its backtrack
    for st, data in V[-1].items():
        if data["prob"] == max_prob:
            opt.append(st)
            previous = st
            break
    # Follow the backtrack till the first observation
    for t in range(len(V) - 2, -1, -1):
        opt.insert(0, V[t + 1][previous]["prior"])
        previous = V[t + 1][previous]["prior"]
    return opt, max_prob

def viterbi(obs, states, start_p, trans_p, obs_p):
    """Construct the lattice using the forward algorithm"""
    V = [{}]
    # Initialize the lattice
    for st in states:
        V[0][st] = {"prob": start_p[st] * obs_p[st][obs[0]], "prior": None}
    # Run Viterbi when t > 0 to incrementally create the lattice
    for t in range(1, len(obs)):
        V.append({})
        for st in states:
            max_tr_prob = V[t-1][states[0]]["prob"] * trans_p[states[0]][st]
            prev_st_selected = states[0]
            for prev_st in states[1:]:
                tr_prob = V[t-1][prev_st]["prob"] * trans_p[prev_st][st]
                if tr_prob > max_tr_prob:
                    max_tr_prob = tr_prob
                    prev_st_selected = prev_st

            max_prob = max_tr_prob * obs_p[st][obs[t]]
            V[t][st] = {"prob": max_prob, "prior": prev_st_selected}

    opt, max_prob = getPath(V)
    print ('The steps of states are ' + ' '.join(opt) + ' with highest probability of %s' % max_prob)
    return V, opt

V, opt = viterbi(obs, states, start_p, trans_p, obs_p)

def roundN(x, d = 6):
    return round(x,d)

import matplotlib.pyplot as plt

def graphDisplay(outfileName = None):
    if outfileName == None:
        plt.show()
    else:
        plt.savefig(outfileName)

def graphNetworkHMM(title, getValues, outfileName = None):
    nsteps = len(obs)
    plt.close()
    fig, ax = plt.subplots()
    plt.rcParams["figure.figsize"] = [2 * (nsteps + 1),6]
    plt.xlim(-1 - 0.5, nsteps - 0.5)
    plt.ylim(-1, 2)
    plt.title(title)
    plt.axis('off')
    optNumbers = [revDict[o] for o in opt]
    for i,x in enumerate(optNumbers[:-1]):
            ax.arrow(i, x, 0.65, 0.75 * (optNumbers[i+1] - x), head_width=0.05, head_length=0.1, fc='k', ec='k')
    for j, s in enumerate(states):
        plt.text(-1, j, s, verticalalignment='center', horizontalalignment='left')
    for i, o in enumerate(obsLabels):
        plt.text(i, 1.75, o, verticalalignment='center', horizontalalignment='center')
        for j, s in enumerate(states):
            ax.add_artist(plt.Rectangle((i-.25, j-.25), 0.5, 0.5, color='white', fill=True))
            ax.add_artist(plt.Rectangle((i-.25, j-.25), 0.5, 0.5, color='black', fill=False))
            plt.text(i, j, roundN(getValues(i,o,j,s)), verticalalignment='center', horizontalalignment='center')
    graphDisplay(outfileName)

def getValues1(i,o,j,s):
    return obs_p[s][obs[i]]

def getValues0(i,o,j,s):
    return V_df[obsLabels[i]][s]

graphNetworkHMM("conditional probability for each state", getValues0, outfileName='graphics/HMMConditionalProb.png')
graphNetworkHMM("cumulative probabilities at each state", getValues1, outfileName='graphics/HMMCumulativeProb.png')

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

import numpy as np
import math

def graphNetwork(plt, title, getValues, placeEdges, states, ncols=4, outfileName = None):
    nrows = len(states)
    plt.close()
    plt.rcParams["figure.figsize"] = [2 * (ncols + 1),2 * nrows]
    fig, ax = plt.subplots()
    plt.xlim(-1, ncols)
    plt.ylim(-.5, nrows - 0.5)
    plt.title(title)
    plt.axis('off')
    placeEdges(ax, nrows, ncols)
    for j, s in enumerate(states):
        plt.text(-1, j, s, verticalalignment='center', horizontalalignment='left')
    for i, o in enumerate(range(ncols)):
        #plt.text(i, 1.75, o, verticalalignment='center', horizontalalignment='center')
        for j, s in enumerate(range(nrows)):
            ax.add_artist(plt.Circle((i, j), 0.25, color='white', fill=True))
            ax.add_artist(plt.Circle((i, j), 0.25, color='black', fill=False))
            plt.text(i, j, getValues(i,o,j,s), verticalalignment='center', horizontalalignment='center')
    graphDisplay(outfileName)

def placeHMMEdges(ax, nrows, ncols):
    for i,x in enumerate(range(ncols)):
        ax.arrow(i, 1, 0.65, 0, head_width=0.05, head_length=0.1, fc='k', ec='k')
        ax.arrow(i, 1, 0, -.65, head_width=0.05, head_length=0.1, fc='k', ec='k')

def getHMMLabels(i,o,j,s):
    return eval("r'$\ {0}_{1}$'".format(['O','t'][j], i))

import matplotlib.pyplot as plt
graphNetwork(plt, "Hidden Markov Model", getHMMLabels, placeHMMEdges, ['observed','hidden'], outfileName='graphics/HiddenMarkovModel.png')

import numpy as np
import math

def graphSetup():
    fig = plt.figure()
    ax = plt.axes()
    x = np.linspace(-6, 6, 100)
    plt.grid(linestyle='--')
    return x

x = graphSetup()
plt.title('logistic function')
plt.plot(x,  [1 / (1 + math.exp(-xx)) for xx in x])
plt.text(-4.5, .8, r'$y = \frac{1}{1 + exp(-x)}$', fontsize=20)
graphDisplay(outfileName='graphics/LogisticFunction.png')

x = graphSetup()
plt.title('RELU')
plt.plot(x,  [max(0,xx) for xx in x])
plt.text(-4.5, .8, r'$y = max(0, x)$', fontsize=20)
graphDisplay(outfileName='graphics/ReLuFunction.png')

def placeNNEdges(ax, nrows, ncols):
    for j1 in range(nrows):
        ax.arrow(-.65, j1, .25, 0, head_width=0.05, head_length=0.1, fc='k', ec='k')
    for i,x in enumerate(range(ncols - 1)):
        for j1 in range(nrows):
            for j2 in range(nrows):
                ax.arrow(i, j1, .65, (j2-j1) * .75, head_width=0.05, head_length=0.1, fc='k', ec='k')

def getNNLabels(i,o,j,s):
    return eval("r'$\ {0}_{1}$'".format(['I','H1','H2','H3'][i], j))

inputLabels = [r'$\ Input_{0}$'.format(i) for i in range(4) ]
graphNetwork(plt, "Neural Network", getNNLabels, placeNNEdges, inputLabels, 3, outfileName='graphics/NeuralNetwork.png')


import numpy as np

a = np.array([[1, 2, 3, 4], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]])
print(a)
print()
#numpy elemanlarıma erişiyorum
b = a[1:3, 1:4] #1.satır ve 3.satır al ve 1. satır ve 4.sütunu al
print(b)
print()
c = a[3, :]
print(c)

# 1)list index
a = np.arange(12)
print(a)
b = a[[2, 5, 7]]  #2,5 ve 7. indisteki elemanları bu şekilde alabilirim burayı bir tuple olarak da verebilirdim a[(1,2,3)]
print(b)

#list indexiyle generic olarak elemanları çekmek istersem
a = np.arange(12)
print(a)
i = np.array([2, 5, 7, 9])
b = a[i]
print(b)
#2)elipsis indexleme:Sütunların hepsini almak istersem elipsis kullanabilirim ve birden fazla boyut varsa elipsis kullanmam uygun olacaktır
#3)bool indexleme:elimizdeki bir np arrayin elemanları aynı eleman sayısındaki bir true false listeye indexleyip işlem yapabiliriz
a = np.array([10, 20, 30, 40, 50])
b = np.array([True, True, False, True, False], dtype='bool')
c = a[b]
print(c)

#Not:Bir numpy dizisini karşılaştırma operatörüyle kullanırsam numpy dizisinin her elemanı işleme sokulur ve sonuç alınır
a = np.array([18, 40, 20, 80, 50])
b = a[a > 30] #bool indeksleme cok yaygın bir kullanım
print(b)

#iki numpy dizisi yardımıyla öğrenciler ve notlarını tutuyorum notu 50 den büyük öğrencilerimi çekiyorum
a = np.array(['ali', 'veli', 'selami', 'ayşe', 'fatma'])
b = np.array([10, 79, 20, 45, 70])
c = a[b >= 50] # notu 50 den büyük öğrenciler koşulu
print(c)

#bool vektörü sum işlemine sokulursa true değer 1 false değer 0 olur
import numpy as np
a = np.array([10, 79, 20, 45, 70, 91, 68])
result = np.sum(a > 30)
print(result)

#ortalamadan büyük değerleri  almak istersem
a = np.array([10, 79, 20, 45, 70, 91, 68])
result = a[a >= np.mean(a)]
print(result)

#belirli bir aralıktaki degerleri almak istersem
a = np.array([10, 79, 20, 45, 70, 91, 68])
result = a[(a > 30) & (a < 80)]
print(result)
""""
a = np.array([10, 79, 20, 45, 70, 91, 68])

result = a[np.logical_and(a > 30, a < 80)]
print(result)
"""
#view:dilimleme ile yaptığımız gibi asıl diziden bir kısım alıp başka bir nesne oluşturmuyoruz.
#b nesnesi asıl dizideki değişikliklerden etkilenen ve kendisindeki değişiliklerle asıl diziyi etkileyebilecek bir nesne
#ek olarak yalnızca numpy da dilimleme işlemlerinde view oluşur.Diğer operasyonlarda view nesnesi oluşmaz
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a)
print()
b = a[1:3, 0:2]
print(b)
print()
a[1, 1] = 100
print(b)
b[0, 0] = 50
print(a)

#ndarray boyut değiştirme nasıl yapılır;
a = np.arange(12)
b = np.reshape(a, (4, 3)) #4 satır 3 sütundan oluşan bir matris elde ettim reshape bağımsız bir nesne vermez view nesnesi verir
print(a)
print()
print(b)

""" boyut değiştirme işleminin global fonk ile yazımı
a = np.arange(12)
b = a.reshape((2, 6))

print(a)
print(b)

"""
#np array oluşturdum ve reshape ettim method ile
a = np.arange(12).reshape(3, 4)
print(a)
#reshape edilmiş bir matrisi başka bir boyuta almak istersem,ilk önce tek boyutmuş gibi düşüneceğiz ardından tek boyutlu matrisimizi yeni boyutlarda reshape ediyoruz

#resize  global methodu ve resize fonksiyonu:esize view oluşturmadan direk copy yoluyla yeni nesne elde ediyoruz
a = np.array([10, 20, 30, 40, 50, 60])
b = np.resize(a, (3, 2))
print(a)
print('-----------')
print(b)
a[0] = 100
print('-----------')
print(a)
print('-----------')
print(b)
#resize aynı zamanda ndarrayin methodu olarakta kullanılıyor burada mevcut nesne kullanılıyor kopya oluşturulmuyor
a = np.array([10, 20, 30, 40, 50, 60])
a.resize(3, 2)
print(a)
print('-----------')

#flatten reshape edilmiş arrayi tek boyutlu hale getiriyor sütunları yan yana getiriyor
a = np.array([[10, 20, 30], [40, 50, 60]])
b = a.flatten()
print(b)

#transpoz global fonksiyonu ve methodu vardır.bu işlemde view nesnesi ile olur yani b deki değişim a yı etkiler
a = np.arange(12).reshape(4, 3)
print(a)
print('------')
b = np.transpose(a)
print(b)
print('------')
c = b.transpose()
print(c)
print('------')

#global vstack ve hstack fonksiyonları :
#1)vstack:n tane satır vektöründen bir tane yeni nesne oluşturuyor:3 bağımsız ndarray birleştirdim
x = np.array([1, 2, 3])
y = np.array([10, 20, 30])
z = np.array([100, 200, 300])
a = np.vstack((x, y, z))
print(a)
#2)hstack:horizontal yığılma yapıyor :hstackte sütun sütun işlem yapabilmek için sütun vektörü olmalı
x = np.array([[1], [2], [3]])
y = np.array([[10], [20], [30]]) #bu şekilde bir yazım ile sütun vektörü oluyor
z = np.array([[100], [200], [300]])

a = np.hstack((x, y, z))
print(a)

"""alternatif hstack yapma
x = np.array([1, 2, 3]).reshape(3, 1)
y = np.array([4, 5, 6]).reshape(3, 1)
z = np.array([7, 8, 9]).reshape(3, 1)

a = np.hstack((x, y, z))
print(a)

"""

#numpy nesnesine  a.base dersek sonuc none  değil ise view nesnesi oluyor.eşitse view nesnesi oluyor


import numpy as np

# see https://jamesgerity.com/remembery/img/numpy_ndarray.png for the structure of ndarray

arr = np.arange(2*2*3)  # 12 distinct values, in terms of how they can be cleanly divided
print(f"{arr.shape=}, {arr.size=}, {arr.ndim}")
print(f"arr=\n{arr}")

# `arr` is one-dimensional, just some numbers in memory:
#   arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

# If we "stride" over those numbers, we can treat them as though they are
# N-dimensional. E.g. let's build an array with two "columns" (a new axis) by
# taking two values at a time to make each "row"

arr2 = arr.reshape(2*3, 2)  # note: reshape() takes an argument called `order`
                            # which is 'C' by default (for the language C,
                            # where the LAST axis varies the "fastest")
print(f"{arr2.shape=}, {arr2.size=}, {arr2.ndim}")
print(f"arr2=\n{arr2}")

# Now, arr2 is two-dimensional, with 6 rows, 2 columns:
#   arr2 = np.array([[0, 1]
#                    [2, 3],
#                    [4, 5],
#                    [6, 7],
#                    [8, 9],
#                    [10, 11]])
# Note how arr2 "counts up" by reading first across the columns, then down the rows

# NOTE: the `order` argument to reshape() tells us which in what order to
# collect values. If we pass `order='F'` (for the language Fortran, where the
# FIRST axis varies "fastest")

arr2_F = arr.reshape(2*3, 2, order='F')
print(f"{arr2_F.shape=}, {arr2_F.size=}, {arr2_F.ndim}")
print(f"arr2_F=\n{arr2_F}")

# Note how arr2_F "counts up" by reading first the first column down the rows, then the second
#   arr2_F = np.array([[0, 6]
#                      [1, 7],
#                      [2, 8],
#                      [3, 9],
#                      [4, 10],
#                      [5, 11]])

arr3 = arr.reshape(2, 2*3)  # this reshape does 2 rows, 6 columns. To build
                            # each row, we'll take the next 6 values in the array
print(f"{arr3.shape=}, {arr3.size=}, {arr3.ndim}")
print(f"arr3=\n{arr3}")

# arr3 is also two-dimension, with 2 rows, 6 columns:
#   arr3 = np.array([[0, 1, 2, 3, 4, 5],
#                    [6, 7, 8, 9, 10, 11]])

# We can have as many axes as we want, as long as the product of all the axis sizes is equal to the number of elements.

arr4 = arr.reshape(2, 2, 3)  # this is a 3D array, with 2 "rows", 2 "columns", and 3 steps of "depth"
print(f"{arr4.shape=}, {arr4.size=}, {arr4.ndim}")
print(f"arr4=\n{arr4}")

# NOTE: since N*1 = N for all N, we can have as many size-1 axes as we want:

arr5 = arr.reshape(1, 2, 2, 3, 1)  # this is a 5D array!
print(f"{arr5.shape=}, {arr5.size=}, {arr5.ndim}")
print(f"arr5=\n{arr5}")


from sympy import Matrix
import numpy as np

A = Matrix( [[3, 4], \
			 [2, 1 ]] )

B = Matrix( [[-1, 0, 1, 2], \
			 [4, 3,2, 1 ]] )

C = Matrix( [[-2, 3, 0], \
			 [2, -2, 1]] )

# a
A.transpose()

# b
C.transpose()

# c
A*A

# d
A*B

# e
A*C

# f
B*A # doesn't exist

# g
C.transpose() * A

# h
A.det()

# i
B.det()

# j
C.det()

# k
A.transpose().det()

# m
A.trace()

# n
A.transpose().trace()


import numpy as np

def linear_kernel(X1, X2):
    return np.dot(X1, X2.T)

def gaussian_kernel(X1, X2, sigma=1.):
    X_cart_diff = X1[:, np.newaxis, :] - X2
    return np.exp(-0.5 * np.linalg.norm(X_cart_diff, axis=2)**2 / sigma**2)


"""
Sum reduction
=====================
"""

####################################################################
# Let's compute the (3000,3) tensor :math:`c` whose entries
# :math:`c_i^u` are given by:
#
# .. math::
#   c_i^u = \sum_j (p-a_j)^2 \exp(x_i^u+y_j^u)
#
# where
#
# * :math:`x` is a (3000,3) tensor, with entries :math:`x_i^u`.
# * :math:`y` is a (5000,3) tensor, with entries :math:`y_j^u`.
# * :math:`a` is a (5000,1) tensor, with entries :math:`a_j`.
# * :math:`p` is a scalar, encoded as a vector of size (1,).
#

####################################################################
# Setup
# -----
#
# Standard imports:

import matplotlib.pyplot as plt
import numpy as np

from pykeops.numpy import Genred

#####################################################################
# Declare random inputs:

M = 3000
N = 5000

dtype = 'float32'  # May be 'float32' or 'float64'

x = np.random.randn(M,3).astype(dtype)
y = np.random.randn(N,3).astype(dtype)
a = np.random.randn(N,1).astype(dtype)
p = np.random.randn(1).astype(dtype)

####################################################################
# Define a custom formula
# -----------------------

formula = 'Square(p-a)*Exp(x+y)'
variables = ['x = Vi(3)',  # First arg   : i-variable, of size 3
             'y = Vj(3)',  # Second arg  : j-variable, of size 3
             'a = Vj(1)',  # Third arg   : j-variable, of size 1 (scalar)
             'p = Pm(1)']  # Fourth  arg : Parameter,  of size 1 (scalar)

####################################################################
# Our sum reduction is performed over the index :math:`j`,
# i.e. on the axis ``1`` of the kernel matrix.
# The output c is an :math:`x`-variable indexed by :math:`i`.

my_routine = Genred(formula, variables, reduction_op='Sum', axis=1, dtype=dtype)
c = my_routine(x, y, a, p, backend='auto')

####################################################################
# The equivalent code in NumPy:
c_np = ((p - a.T)[:,np.newaxis] **2 * np.exp(x.T[:,:,np.newaxis] + y.T[:,np.newaxis,:]) ).sum(2).T

# Plot the results next to each other:
for i in range(3):
    plt.subplot(3, 1, i+1)
    plt.plot(c[:40,i], '-', label='KeOps')
    plt.plot(c_np[:40,i], '--', label='NumPy')
    plt.legend(loc='lower right')
plt.tight_layout() ; plt.show()

####################################################################
# Compute the gradient
# --------------------
# Now, let's compute the gradient of :math:`c` with
# respect to :math:`y`. Since :math:`c` is not scalar valued,
# its "gradient" :math:`\partial c` should be understood as the adjoint of the
# differential operator, i.e. as the linear operator that:
#
# - takes as input a new tensor :math:`e` with the shape of :math:`c`
# - outputs a tensor :math:`g` with the shape of :math:`y`
#
# such that for all variation :math:`\delta y` of :math:`y` we have:
#
# .. math::
#
#    \langle \text{d} c . \delta y , e \rangle  =  \langle g , \delta y \rangle  =  \langle \delta y , \partial c . e \rangle
#
# Backpropagation is all about computing the tensor :math:`g=\partial c . e` efficiently, for arbitrary values of :math:`e`:

# Declare a new tensor of shape (M,3) used as the input of the gradient operator.
# It can be understood as a "gradient with respect to the output c"
# and is thus called "grad_output" in the documentation of PyTorch.
e = np.random.randn(M, 3).astype(dtype)

####################################################################
# KeOps provides an autodiff engine for formulas. Unfortunately though, as NumPy does not provide any support for backpropagation, we need to specify some informations by hand and add the gradient operator around the formula: ``Grad(formula , variable_to_differentiate, input_of_the_gradient)``
formula_grad =  'Grad(' + formula + ', y, e)'

# This new formula makes use of a new variable (the input tensor e)
variables_grad = variables + ['e = Vi(3)'] # Fifth arg: an i-variable of size 3... Just like "c"!

# The summation is done with respect to the 'i' index (axis=0) in order to get a 'j'-variable
my_grad = Genred(formula_grad, variables_grad, reduction_op='Sum', axis=0, dtype=dtype)

g = my_grad(x, y, a, p, e)

####################################################################
# To generate an equivalent code in numpy, we must compute explicitly the adjoint
# of the differential (a.k.a. the derivative).
# To do so, let see :math:`c^i_u` as a function of :math:`y_j`:
#
# .. math::
#
#   g_j^u = [(\partial_{y} c^u(y)) . e^u]_j = \sum_{i} (p-a_j)^2 \exp(x_i^u+y_j^u) \cdot e_i^u
#
# and implement the formula:

g_np = ((p - a.T)[:, np.newaxis, :] **2 * np.exp(x.T[:, :, np.newaxis] \
     + y.T[:, np.newaxis, :]) * e.T[:, :, np.newaxis]).sum(1).T

# Plot the results next to each other:
for i in range(3):
    plt.subplot(3, 1, i+1)
    plt.plot(g[:40,i], '-', label='KeOps')
    plt.plot(g_np[:40,i], '--', label='NumPy')
    plt.legend(loc='lower right')
plt.tight_layout() ; plt.show()


# coding: utf-8

# # Color grading with optimal transport
#
# #### *Nicolas Courty, Rémi Flamary*

# In this tutorial we will learn how to perform color grading of images with optimal transport. This is somehow a very direct usage of optimal transport. You will learn how to treat an image as an empirical distribution, and apply optimal transport to find a matching between two different images seens as distributions.

# First we need to load two images. To this end we need some packages
#

# In[2]:

import numpy as np
import matplotlib.pylab as pl
from matplotlib.pyplot import imread
from mpl_toolkits.mplot3d import Axes3D

I1 = imread('./data/klimt.jpg').astype(np.float64) / 256
I2 = imread('./data/schiele.jpg').astype(np.float64) / 256

# We need some code to visualize them

# In[3]:

def showImage(I,myPreferredFigsize=(8,8)):
    pl.figure(figsize=myPreferredFigsize)
    pl.imshow(I)
    pl.axis('off')
    pl.tight_layout()
    pl.show()

# In[4]:

showImage(I1)
showImage(I2)

# Those are two beautiful paintings of respectively Gustav Klimt and Egon Schiele. Now we will treat them as empirical distributions.

# Write two functions that will be used to convert 2D images as arrays of 3D points (in the color space), and back.

# In[5]:

def im2mat(I):
    """Converts and image to matrix (one pixel per line)"""
    return I.reshape((I.shape[0] * I.shape[1], I.shape[2]))

def mat2im(X, shape):
    """Converts back a matrix to an image"""
    return X.reshape(shape)

X1 = im2mat(I1)
X2 = im2mat(I2)

# It is unlikely that our solver, as efficient it can be, can handle so large distributions (1Mx1M for the coupling). We will use the Mini batch k-means procedure from sklearn to subsample those distributions. Write the code that performs this subsampling (you can choose a size of 1000 clusters to have a good approximation of the image)

# In[6]:

import sklearn.cluster as skcluster
nbsamples=1000
clust1 = skcluster.MiniBatchKMeans(n_clusters=nbsamples,init_size=3000).fit(X1)
Xs = clust1.cluster_centers_
clust2 = skcluster.MiniBatchKMeans(n_clusters=nbsamples,init_size=3000).fit(X2)
Xt = clust2.cluster_centers_

# You can use the following procedure to display them as point clouds

# In[7]:

def showImageAsPointCloud(X,myPreferredFigsize=(8,8)):
    fig = pl.figure(figsize=myPreferredFigsize)
    ax = fig.add_subplot(111, projection='3d')
    ax.set_xlim(0,1)
    ax.scatter(X[:,0], X[:,1], X[:,2], c=X, marker='o', alpha=1.0)
    ax.set_xlabel('R',fontsize=22)
    ax.set_xticklabels([])
    ax.set_ylim(0,1)
    ax.set_ylabel('G',fontsize=22)
    ax.set_yticklabels([])
    ax.set_zlim(0,1)
    ax.set_zlabel('B',fontsize=22)
    ax.set_zticklabels([])
    ax.grid('off')
    pl.show()

# In[8]:

showImageAsPointCloud(Xs)
showImageAsPointCloud(Xt)

# You can now compute the coupling between those two distributions using the exact LP solver (EMD)

# In[9]:

import ot

mu_s = ot.unif(nbsamples)
mu_t = ot.unif(nbsamples)
M = ot.dist(Xs,Xt,"sqeuclidean")
G = ot.emd(mu_s,mu_t, M)

# using the barycentric mapping method, express the tansformation of both images into the other one

# In[10]:

newXs=nbsamples*G.dot(Xt)
showImageAsPointCloud(newXs)

newXt=nbsamples*G.T.dot(Xs)
newXt[newXt>1]=1
showImageAsPointCloud(newXt)

# Since only the centroid of clusters have changed, we need to figure out a simple way of transporting all the pixels in the original image. At first, we will apply a simple strategy where the new value of the pixel corresponds simply to the new position of its corresponding centroid

# Express this transformation in your code, and display the corresponding adapted image.

# In[11]:

newX1 = newXs[clust1.predict(X1),:]
showImage(mat2im(newX1,I1.shape))

newX2 = newXt[clust2.predict(X2),:]
showImage(mat2im(newX2,I2.shape))

# You can use also the entropy regularized version of Optimal Transport (a.k.a. the Sinkhorn algorithm) to explore the impact of regularization on the final result
#

# In[12]:

for reg in np.logspace(-3,0,4):
    G = ot.bregman.sinkhorn(mu_s,mu_t, M, reg)
    newXs=nbsamples*G.dot(Xt)
    showImageAsPointCloud(newXs)
    newX1 = newXs[clust1.predict(X1),:]
    showImage(mat2im(newX1,I1.shape))


"""

https://en.wikipedia.org/wiki/Pauli_matrices
https://physics.stackexchange.com/questions/271419/why-is-there-this-relationship-between-quaternions-and-pauli-matrices

"""

from sympy.abc import *
from sympy import *
import numpy as np

def pauli_matrices():
    u = Matrix([[1, 0], [0, 1]])
    o1 = Matrix([[0, 1], [1, 0]])
    o2 = Matrix([[0, -I], [I, 0]])
    o3 = Matrix([[1, 0], [0, -1]])
    return (u, o1, o2, o3)

"""

Quaternion basis elements can be constructed from
2x2 pauli matrices (kind of like how complex numbers can be represented by a 2x2 matrix)
by the following

1 = identity(2)
i = o1*-I
j = o2*-I
k = o2*-I

then we can verify that it this matrix construction satisfy all properties of a quaternion

"""
def test_quaternion_property():
    u, o1, o2, o3 = pauli_matrices()
    i = -I*o1
    j = -I*o2
    k = -I*o3

    print("Quaternion Property")
    print("1")
    pprint(u)
    print("i")
    pprint(i)
    print("j")
    pprint(j)
    print("k")
    pprint(k)
    print("\n")

    print("i^2 = j^2 = k^2 = -1")
    pprint(i@i)
    pprint(j@j)
    pprint(k@k)
    pprint(-1*u)
    print()

    print("i*j=k")
    pprint(i@j)
    print("j*k=i")
    pprint(j@k)
    print("k*i=j")
    pprint(k@i)
    print("-i*k=j")
    pprint(-i@k)

    print("conjugate")
    Q = u+i+j+k
    Qc = u-i-j-k
    pprint(Q)
    pprint(Qc)
    pprint(simplify(Q@Qc))

"""

The commutator relation is defined on two operator A and B
[A, B] = A*B - B*A
[A, B] = 0 when the two operators are commutative, non-zero otherwise

The anticommutator relation is defined as
{A, B} = A*B + B*A

The pauli matrices can represent a linear operator in this case so we can
apply the commutator/anticommutator relations on them.

In general, pauli matrices have the following commutator/anticommutator relations
[o_a, o_b] = 2*i*e_abc*o_c
{o_a, o_b} = 2*s_ab*I
e_abc is the structure constant in Levi-Cevita symbol
s_ab is the kronecker delta
I is the 2x2 identity matrix

"""

def test_commutation():
    u, o1, o2, o3 = pauli_matrices()
    print("Commutation Properties")
    print("[o1, o2] = 2*I*o3")
    pprint(o1*o2 - o2*o1)
    pprint(2*I*o3)
    print("[o2, o3] = 2*I*o1")
    pprint(o2*o3 - o3*o2)
    pprint(2*I*o1)
    print("[o3, o1] = 2*I*o2")
    pprint(o3*o1 - o1*o3)
    pprint(2*I*o2)
    print("[o1, o1] [o2, o2] [o3, o3] = 0")
    pprint(o1*o1 - o1*o1)
    pprint(o2*o2 - o2*o2)
    pprint(o3*o3 - o3*o3)
    print("Anticommutator Properties")
    print("{o1, o1} = 2*I")
    pprint(o1*o1 + o1*o1)
    pprint(2*u)
    pprint("{o1, o2} = 0")
    pprint(o1*o2 + o2*o1)
    pprint("{o1, o3} = 0")
    pprint(o1*o3 + o3*o1)

"""

The trace properties for the Pauli matrices:

tr(o_a) = 0
tr(o_a*o_b) = 2*s_ab
tr(o_a*o_b*o_c) = 2*i*e_abc
tr(o_a*o_b*o_c*o_d) = 2*(o_ab*o_cd - o_ac*o_bd + o_ad*o_bc)

"""

def test_trace():
    u, o1, o2, o3 = pauli_matrices()
    print("Trace Properties")
    print("tr(o1) tr(o2) tr(o3) = 0")
    print(np.trace(o1), np.trace(o2), np.trace(o3))
    print("tr(o_a*o_b) = 2*s_ab")
    print(np.trace(o1@o1), np.trace(o2@o2), np.trace(o3@o3))
    print(np.trace(o1@o3), np.trace(o2@o1), np.trace(o3@o2))
    print(np.trace(o1@o1@o1@o1))

init_printing()
test_quaternion_property()
test_commutation()
test_trace()


#!/usr/bin/env python

"""
Title: Determining all the roots for f(x) = x^3 - 25x^2 + 165x - 275 using the combined Bisection/Newton-Raphson Method

Solution to Problem Set 1, Problem 5
~ Arsh R. Nadkarni

To run:
python combined_1_5.py

Can change the x-range and tolerance (eps) on lines 103-105

This code computes the midpoint of the x-range initially and uses
Newton method to obtain the intersection of the function to the mid-point slope.
If the value is in the range, it updates the lower-bound(a) or upper-bound(b),
owing to the sign. If not, the lower-bound(a) or upper-bound(b) is replaced with the mid-point.
The same procedure is iterated until the computed root is within the tolerance range.

"""
# import libraries
import sys
import numpy as np
import matplotlib.pyplot as plt

# construct function to find roots
def comb_root(a,b,eps):
    # define f(x)
	def f(x):
		return x**3 - 25*x**2 + 165 * x - 275
	# define the first derivative of f(x)
	def derf(x):
		return 3*x**2 - 50*x + 165
	# ensure that the a is negative and b is positive
	if f(a) > 0:
		a = b
		b = a
	elif f(a)*f(b) > 0: # check the validity of the bounds used
		print("Invalid Bounds. Root cannot be found!")
		exit()
	# define the midpoint
	mid = (a+b)/2
	# begin newton iteration
	dxold = abs(b-a)
	dx = dxold
	fm = f(mid)
	dfm = derf(mid)
	# proceed until within the tolerance range
	while True:
		# condition for bisection/newton-raphson iteration
		if( (mid - b) * dfm - fm) * ( (mid - a) * dfm - fm) > 0 or abs(2*fm) > abs(dxold * dfm):
			dxold = dx
			dx = 0.5 * (b - a)
			mid = a + dx
		else:
			dxold = dx
			dx = fm/dfm
			mid = mid - dx
		# return mid if within in the tolerance range
		if (abs(dx) < eps):
			return mid
		# calculate the function value and the first derivative value at the mid point
		fm = f(mid)
		dfm = derf(mid)
		# updates the bounds
		if fm < 0:
			a = mid
		else:
			b = mid

# function for confirming roots
def rc(root, rootName, eps):
    # define f(x)
	def f(x):
		return x**3 - 25*x**2 + 165 * x - 275
	# print confirmation of roots
	print(rootName + " computed as " + str(root))
	print("f(" + rootName + ") = " + str(f(root)))
	# check for tolerance of roots
	if np.abs(f(root)) <= eps:
		print("Root is within tolerance of " + str(eps))
	else:
		print("Root is not within tolerance of " + str(eps))

# function for outputting answers
def answers():
    # define f(x)
	def f(x):
		return x**3 - 25*x**2 + 165*x - 275
	# define the tolerance
	eps = 1e-3
	# Calculate all the roots using comb_root(a,b,eps)
	r1 = comb_root(2, 4, eps)
	r2 = comb_root(6, 8, eps)
	r3 = comb_root(15, 16, eps)
	# print and confirm roots
	rc(r1, "x1", eps)
	rc(r2, "x2", eps)
	rc(r3, "x3", eps)
	# create an array for x values
	x = np.linspace(0, 20,1000)
	# plot f(x)
	plt.plot(x, f(x))
	plt.ylabel(r'$f(x)$', fontsize='large', fontweight='bold')
	plt.xlabel(r'$x$', fontsize='large', fontweight='bold')
	plt.ylim(-170, 60)
	plt.axhline(y=0, color='r', linestyle='-')
	plt.show()

answers() # call the function

Problem Sets/Problem Set 1/combined_1_5.py


# Polynomial linear regression on synthetic dataset of sin function

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, Lasso
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics.regression import r2_score

# create regression dataset with sin and added noise
np.random.seed(0)
n = 15
x = np.linspace(0,10,n) + np.random.randn(n)/5
y = np.sin(x)+x/6 + np.random.randn(n)/10

X_train, X_test, y_train, y_test = train_test_split(x, y, random_state=0)

plt.figure()
plt.scatter(X_train, y_train, label='training data')
plt.scatter(X_test, y_test, label='test data')
plt.legend(loc=4);

# fit polynomial model with various degrees and test on values 0 to 10
values_to_predict = np.linspace(0,10,100)
i = [0, 1, 2, 3]
deg = [1, 3, 6, 9]
results = np.zeros((4,100))

for i, deg in zip(i, deg):
    poly = PolynomialFeatures(degree=deg)
    X_poly = poly.fit_transform(X_train.reshape(len(X_train),1))
    linreg = LinearRegression().fit(X_poly, y_train)
    results[i,:] = linreg.predict(poly.fit_transform(values_to_predict.reshape(100,1)))

# get R2 scores for train and test for models with degrees 0 to 9
i = np.arange(10)
deg = np.arange(10)
r2_train = np.zeros(10,)
r2_test = np.zeros(10,)

for i, deg in zip(i, deg):
    poly = PolynomialFeatures(degree=deg)
    X_poly_train = poly.fit_transform(X_train.reshape(len(X_train),1))
    X_poly_test = poly.fit_transform(X_test.reshape(len(X_test),1))
    linreg = LinearRegression().fit(X_poly_train, y_train)
    r2_train[i] = r2_score(y_train, linreg.predict(X_poly_train))
    r2_test[i] = r2_score(y_test, linreg.predict(X_poly_test))

# compare between polynomial linear model deg=12 and lasso polynomial model deg=12
poly = PolynomialFeatures(degree=12)
X_poly_train = poly.fit_transform(X_train.reshape(len(X_train),1))
X_poly_test = poly.fit_transform(X_test.reshape(len(X_test),1))

model1 = LinearRegression().fit(X_poly_train, y_train)
model2 = Lasso(alpha=0.01,max_iter=10000).fit(X_poly_train, y_train)

LinearRegression_R2_test_score = r2_score(y_test, model1.predict(X_poly_test))
Lasso_R2_test_score = r2_score(y_test, model2.predict(X_poly_test))


'''
Created on 2013/12/29
@author: Duong Nguyen
@note: Nonnegative Matrix Factorization (NMF) with multiplicative update rules.
@version: Frobenius

V = W*H, where V, W, H >= 0. Here, ">=" means element-wise relation
V: n x m matrix
W: n x b matrix
H: b x m matrix
Minimize_over_W,H || V - W*H || ^ 2 (Frobenius norm)

See also, http://hebb.mit.edu/people/seung/papers/nmfconverge.pdf for more details.
'''

import numpy as np
import matplotlib.pyplot as plt

def fro_distance(A, B):
    """ Compute the Frobenius distance between two matrices A, B.
        d(A, B) = ||A-B||_2 = sqrt{\sum_{i,j} (A_ij-B_ij)^2}
    """
    return np.sqrt(np.sum((A-B)**2))

def factorize(V, b, init="uniform", max_iter=100, tol=1e-8, verbose=False):
    """ Factorization with multiplicative update rules.
        @param init: specify how to initialize W, H. Default: uniformly random in [0,1)
        @param max_iter: Maximum number of iterations of updating
        @param tol: Tolerance value to check if converge
    """

    assert init in ("uniform", "normal"), "Unsupported initialization!"
    n, m = V.shape

    if init == "uniform":
        W, H = np.random.random((n,b)), np.random.random((b,m))
    else:
        W, H = np.random.randn(n,b), np.random.randn(b,m)

    dists = []
    for i in xrange(max_iter):
        WH = W.dot(H)

        cur_dist = fro_distance(V, WH)
        dists.append(cur_dist)

        if verbose and i % 10 == 0:
            print "%d iteration: %f" %(i, cur_dist)

        if cur_dist <= tol:
            break

        # Update H
        nu = (W.T).dot(V)
        de = (W.T).dot(WH)
        H = H*nu/de # element-wise update

        # Update W
        nu = V.dot(H.T)
        de = W.dot(H).dot(H.T)
        W = W*nu/de # element-wise update

    return W, H, dists

def test(plot=False):
    """ Test Frobenius norm-based NMF."""

    V = np.random.random((10, 9))
    W, H, dists = factorize(V, 3, init="uniform", max_iter=200, tol=1e-8, verbose=True)

    if plot:
        plt.figure()
        plt.clf()
        plt.plot(dists, "b-", lw=2)
        plt.xlabel("Iteration")
        plt.ylabel("Frobenius distance as cost function")
        plt.title("Frobenius NMF Demo")
        plt.show()
        plt.savefig("fro_nmf_demo.png") # save figure at current working directory

    print "V =", V
    print "W * H =", W.dot(H)
    print "Frobenius distance d =", dists[-1]

if __name__ == "__main__":
    test(plot=True)


import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LogNorm
from mpl_toolkits.mplot3d import axes3d, Axes3D
from computeCost import *
from gradientDescent import *
from plotData import *

# ===================== Part 1: Plotting =====================
print('Plotting Data...')
data = np.loadtxt('ex1data1.txt', delimiter=',', usecols=(0, 1))
X = data[:, 0]
y = data[:, 1]
m = y.size

plt.ion()
plt.figure(0)
plot_data(X, y)

input('Program paused. Press ENTER to continue')

# ===================== Part 2: Gradient descent =====================
print('Running Gradient Descent...')

X = np.c_[np.ones(m), X]  # Add a column of ones to X

theta = np.zeros(2)  # initialize fitting parameters

# Some gradient descent settings
iterations = 1500
alpha = 0.01

# Compute and display initial cost
print('Initial cost : ' + str(compute_cost(X, y, theta)) + ' (This value should be about 32.07)')

theta, J_history = gradient_descent(X, y, theta, alpha, iterations)

print('Theta found by gradient descent: ' + str(theta.reshape(2)))

# Plot the linear fit
plt.figure(0)
line1, = plt.plot(X[:, 1], np.dot(X, theta), label='Linear Regression')
plt.legend(handles=[line1])
plt.pause(0.5)

input('Program paused. Press ENTER to continue')

# Predict values for population sizes of 35,000 and 70,000
predict1 = np.dot(np.array([1, 3.5]), theta)
print('For population = 35,000, we predict a profit of {:0.3f} (This value should be about 4519.77)'.format(predict1*10000))
predict2 = np.dot(np.array([1, 7]), theta)
print('For population = 70,000, we predict a profit of {:0.3f} (This value should be about 45342.45)'.format(predict2*10000))

input('Program paused. Press ENTER to continue')

# ===================== Part 3: Visualizing J(theta0, theta1) =====================
print('Visualizing J(theta0, theta1) ...')

theta0_vals = np.linspace(-10, 10, 100)
theta1_vals = np.linspace(-1, 4, 100)

xs, ys = np.meshgrid(theta0_vals, theta1_vals)
J_vals = np.zeros(xs.shape)

# Fill out J_vals
for i in range(0, theta0_vals.size):
    for j in range(0, theta1_vals.size):
        t = np.array([theta0_vals[i], theta1_vals[j]])
        J_vals[i][j] = compute_cost(X, y, t)

J_vals = np.transpose(J_vals)

fig1 = plt.figure(1)
ax = fig1.gca(projection='3d')
ax.plot_surface(xs, ys, J_vals)
plt.xlabel(r'$\theta_0$')
plt.ylabel(r'$\theta_1$')

plt.figure(2)
lvls = np.logspace(-2, 3, 20)
plt.contour(xs, ys, J_vals, levels=lvls, norm=LogNorm())
plt.plot(theta[0], theta[1], c='r', marker="x")
plt.pause(0.5)
plt.ioff()

input('ex1 Finished. Press ENTER to exit')


from __future__ import division
import numpy as np
import pylab as pl

one_by_nine = 1/9.0
nine_by_511 = 9/511.0
def getIest_Imp(N):
    y = np.random.random(N)
    # Inverse function calculated manually
    x = np.power(511*y + 1, one_by_nine)
    f = 2*np.power(x,8) -1
    w = nine_by_511 * np.power(x,8)
    Iest = np.mean(np.true_divide(f,w))
    return Iest

def getIest_Sm(N):
    # b = 2 and a = 1 Hence b-a = 1
    # which doesn't affect the integral
    # has been omitted from the calculations
    x = np.random.random(N)+1 # shift the rnadom values between 1 and 2
    f = 2*np.power(x,8)-1
    Iest = np.mean(f)
    return Iest

if __name__ == '__main__':
    np.random.seed(7777)
    exact = 1013/9.0
    Iest_Imp = []
    absErr_Imp = []
    Iest_Sm = []
    absErr_Sm = []
    Ns = map(lambda x: int(round(x)), np.logspace(2, 5, 50))
    for N in Ns:
        estImp = getIest_Imp(N)
        Iest_Imp.append(estImp)
        errImp = abs(exact-estImp)
        absErr_Imp.append(errImp)

        estSm = getIest_Sm(N)
        Iest_Sm.append(estSm)
        errSm = abs(exact-estSm)
        absErr_Sm.append(errSm)

        print "{} & {} & {} & {} & {} \\\\".format(N,estImp,errImp,estSm,errSm)

    pl.plot(Ns, Iest_Imp,label="Importance Sampling")
    pl.plot(Ns, Iest_Sm,label="Sample Mean")
    pl.plot(Ns, np.ones(len(Iest_Sm))*exact, label="Exact")
    pl.legend(framealpha=0.5)
    pl.xlabel("Ns")
    pl.ylabel("Integral")
    pl.savefig("Integrals.png")

    pl.figure()
    pl.loglog(Ns,absErr_Imp,label="Importance Sampling")
    pl.loglog(Ns,absErr_Sm,label="Sample Mean")
    pl.loglog(Ns,map(lambda x:1/(x**0.5),Ns),label="1/sqrt(N)")
    pl.legend(framealpha=0.5)
    pl.xlabel("Ns")
    pl.ylabel("Absolute Errors")
    pl.savefig("Errors.png")
    pl.show()


#!/bin/env python
"""
Smear 1D data of equidistance intervals with Gaussians.

Usage:
    gaussian_smear.py [options] INFILE

Options:
    -h, --help  Show this help messange and exit.
    -s, --sigma=SIGMA
                Width of Gaussian (sigma) in the unit of dx. [default: 2.0]
    -x=<x>      Position of x data (start from 1) [default: 1]
    -y=<y>      Position of y data (start from 1) [default: 1]
"""
from __future__ import print_function

import os,sys,math
import numpy as np
from docopt import docopt

def gsmear(xd,yd,sigma,ngwidth=3):
    """
    Compute Gaussian-smearing of given data with smearing width *sigma*.
    """
    dx= xd[1]-xd[0]
    sgm= sigma*dx
    pref= dx/(np.sqrt(2.0*np.pi)*sgm)
    ndat= len(xd)
    nwidth = int(sigma*ngwidth)
    #nwidth = ndat
    gdat= np.zeros(ndat,dtype=np.float)
    expfact = 1.0/sgm**2/2
    for ix in range(ndat):
        #gdat[ix]= yd[ix]
        for jx in range(-nwidth+1,nwidth):
            kx= ix+jx
            if kx < 0:
                kx = abs(kx)
            elif kx >= ndat:
                kx = 2*ndat -kx -1
            gdat[ix] += yd[kx]*pref*np.exp(-(dx*jx)**2*expfact)
    #gdat /= 2
    return gdat

def gsmear_file(infname,sigma,xp,yp):
    """
    Read data from the given file and pass data to `gsmear` method.
    """
    infile= open(infname,'r')
    nline= 0
    for line in infile.readlines():
        if line[0] == "#":
            continue
        nline += 1
    infile.seek(0)
    xd= np.zeros(nline,dtype=np.float)
    yd= np.zeros(nline,dtype=np.float)
    il= 0
    for line in infile.readlines():
        if line[0] == "#":
            continue
        sline= line.split()
        xd[il]= float(sline[xp])
        yd[il]= float(sline[yp])
        il += 1
    infile.close()
    xd,gdat= gsmear(xd,yd,sigma)
    return xd,gdat

if __name__ == "__main__":

    args= docopt(__doc__)
    xp= int(args['-x']) -1
    yp= int(args['-y']) -1
    sigma= float(args['--sigma'])
    infname= args['INFILE']

    xd,gdat= gsmear_file(infname,sigma,xp,yp)

    outfile= open(infname+'.smeared','w')
    for il in range(len(gdat)):
        outfile.write(' {0:15.2f} {1:15.7f}\n'.format(xd[il],gdat[il]))
    outfile.close()

    print(' write '+infname+'.smeared')
    print(' GAUSSIAN_SMEAR done ')


"""
July 01, 2019.
Luis Da Silva.
luisdanield@gmail.com

This is an implementation of value iteration for finding a tabular solution.

A gambler is offered unlimited coin flips with a coin with probability p of success.
Its objective is to reach 100$.
He sets the value of his bets. If he looses then the bet amount is lost, otherwise he doubles his money.
Find an optimal solution given the capital he has.
"""

import numpy as np
import matplotlib.pyplot as plt

def expected_return(state, action, state_value, p):
    reward = 0
    next_state_value = 0

    # Evaluate positive case
    new_state_positive = state + action
    if new_state_positive >= 100:
        reward = p
    else:
        idx = int(new_state_positive - 1)
        next_state_value += state_value[idx] * p

    # Evaluate negative case
    new_state_negative = state - action
    if new_state_negative > 0:
        idx = int(new_state_negative - 1)
        next_state_value += state_value[idx] * (1-p)

    return reward + next_state_value

def gamble(p, goal, tolerance=1e-1):
    actions = np.linspace(1, goal-1, goal-1)
    policy = np.ones_like(actions, dtype=int)
    state_value = np.zeros_like(actions)

    iter = 0
    while True:
        iter += 1
        old_state_value = state_value.copy()
        old_policy = policy.copy()

        # Evaluate policy
        for state in range(1, state_value.shape[0]):
            state_value[state] = expected_return(state, policy[state], state_value, p)

        # Improve policy
        for state in range(1, state_value.shape[0]):
            rewards = []
            for action in actions:
                if action > state:
                    rewards.append(-np.inf)
                else:
                    rewards.append(expected_return(state, action, state_value, p))
            policy[state] = actions[np.argmax(rewards)]

        change = np.abs(state_value - old_state_value).max()
        policy_stable = (old_policy == policy).all()
        print(f'Iter {iter} finished! SV change: {change}. Policy stable: {policy_stable}.')
        if change <= tolerance and policy_stable:
            break

    return policy, state_value

if __name__ == '__main__':
    p = 0.45
    policy, state_value = gamble(p=p, goal=100, tolerance=1e-5)

    plt.plot(policy)
    plt.title('Policy')
    plt.xlabel('Money')
    plt.ylabel('Gamble')
    plt.savefig(f'graphs/gamblers_problem_policy_p{p}.png')
    plt.show()

    plt.plot(state_value)
    plt.axvline(p*100, 0, 1, color='black', ls='--')
    plt.title('State Value')
    plt.xlabel('Money')
    plt.ylabel('Probability of succeed')
    plt.savefig(f'graphs/gamblers_problem_state_value_p{p}.png')
    plt.show()


import numpy as NP
import scipy as SP
import scipy.signal
import pylab as PL

def pzplot(b,
           a,
           ax=None,
           c='C0',
           guide_opts={'color':  '0.8',
                       'ls':     '--',
                       'zorder': -10}):
    """
    Create pole-zero plot of the rational transfer function defined by
    the polynomial coefficients *b* and *a*. Plot in axis *ax* (or
    create a new axis if `None`).  Plot poles and zeros in color
    *c*. Use the plot options *guide_opts* to style the unit circle
    and real and imaginary axis lines. Return the tuple containing the
    tuple of zeros, poles, and gain (see :func:`scipy.signal.tf2zpk`)
    and the axis *ax*.
    """
    if ax is None:
        ax = PL.subplot(111)
    z, p, k = SP.signal.tf2zpk(b, a)
    ax.add_patch(PL.Circle((0, 0), 1, fill=False, **guide_opts))
    ax.axhline(0, **guide_opts)
    ax.axvline(0, **guide_opts)
    ax.scatter(NP.real(z),
               NP.imag(z),
               marker=PL.matplotlib.markers.MarkerStyle('o', 'none'),
               facecolors='none',
               edgecolors=c)
    ax.scatter(NP.real(p),
               NP.imag(p),
               marker='x',
               color=c)
    xlim = PL.xlim()
    PL.xlim(xmin=max(xlim[0], -1.1))
    PL.xlim(xmax=max(xlim[1],  1.1))
    ylim = PL.ylim()
    PL.ylim(ymin=max(ylim[0], -1.1))
    PL.ylim(ymax=max(ylim[1],  1.1))
    ax.set_aspect('equal')
    PL.xlabel('Real axis')
    PL.ylabel('Imaginary axis')
    return (z, p, k), ax