# This Program is distributed under the terms of the MIT license.
# Author: Rui Sun
# Date: 2021-12-12
# Copyright: Rui Sun from SAA, SJTU
# Description: Task 2 - Numerical-Integration
# Environment: Python 3.9.5 64-bit
#              Numpy 1.20.3
#              Matplotlib 3.4.2

import numpy as np
import matplotlib.pyplot as plt
from numpy.lib.polynomial import roots

EPS = 1e-7
MAXSIZE = 200

# Romberg Integration
# \int_a^b{f(x)}\mathrm{d}x
def romberg(f, a, b):
    h = b - a
    R = np.zeros(MAXSIZE)
    R[0] = (h / 2) * (f(a) + f(b))
    for k in range(1, MAXSIZE):
        h /= 2
        R[k] = R[k - 1] / 2
        for j in range(1, 2**(k - 1) + 1):
            R[k] += h * f(a + (2 * j - 1) * h)
        if abs(R[k] - R[k - 1]) < EPS:
            return R[k]
    print("Error: Romberg Integration failed.")
    return 0

# Gauss-Legendre Integration
# \int_a^b{f(x)}\mathrm{d}x
def legendre(n, x):
    if n == 0:
        return 1.0
    elif n == 1:
        return x
    else:
        return ((2.0 * n - 1.0) * x * legendre(n - 1, x) - (n - 1.0) * legendre(n - 2, x)) / n

def dlegendre(n, x):
    if n == 0:
        return 0.0
    elif n == 1:
        return 1.0
    else:
        return (n / (x**2 - 1.0)) * (x * legendre(n, x) - legendre(n - 1, x))

def legendre_roots(polyorder):
    if polyorder < 2:
        print("Error: Polynomial order must be greater than 1.")
        return None
    else:
        roots = []
        for i in range(1, int(polyorder / 2) + 1):
            x = np.cos(np.pi * (i - 0.25) / (polyorder + 0.5))
            error = 10 * EPS**2
            while error > EPS**2:
                dx = -legendre(polyorder, x) / dlegendre(polyorder, x)
                x += dx
                error = abs(dx)
            roots.append(x)
        roots = np.array(roots)
        if polyorder % 2 == 0:
            roots = np.concatenate((-roots, roots[::-1]))
        else:
            roots = np.concatenate((-roots, [0], roots[::-1]))
        return roots

def gauss_legendre_weights(polyorder):
    w = []
    xs = legendre_roots(polyorder)
    w = 2.0 / ((1 - xs**2) * dlegendre(polyorder, xs)**2)
    return w, xs

def gauss_legendre(f, a, b):
    delta = 99999
    I = 0
    n = 1
    while delta > EPS:
        n += 1
        w, xs = gauss_legendre_weights(n)
        I_old = I
        I = (b - a) / 2 * np.sum(w * f((b - a) / 2 * xs + (b + a) / 2))
        delta = abs(I - I_old)
        if n > 1000:
            print("Error: Gauss-Legendre Integration failed.")
            return 0
    return I

def fa(x):
    return (x**2) * np.exp(x)

def fb(x):
    return np.exp(x) * np.sin(x)

def fc(x):
    return 4 / (1 + x**2)

def fd(x):
    return 1 / (1 + x)

def f(x):
    return np.exp(-x**2)

# main
print('Romberg Integration')
print('f(x) = x^2 e^x')
print('a = 0, b = 1')
print('I = ', romberg(fa, 0, 1))
print('\n')
print('f(x) = e^x sin(x)')
print('a = 1, b = 3')
print('I = ', romberg(fb, 1, 3))
print('\n')
print('f(x) = 4/(1+x^2)')
print('a = 0, b = 1')
print('I = ', romberg(fc, 0, 1))
print('\n')
print('f(x) = 1/(1+x)')
print('a = 0, b = 1')
print('I = ', romberg(fd, 0, 1))
print('\n')

print('Gauss-Legendre Integration')
print('f(x) = x^2 e^x')
print('a = 0, b = 1')
print('I = ', gauss_legendre(fa, 0, 1))
print('\n')
print('f(x) = e^x sin(x)')
print('a = 1, b = 3')
print('I = ', gauss_legendre(fb, 1, 3))
print('\n')
print('f(x) = 4/(1+x^2)')
print('a = 0, b = 1')
print('I = ', gauss_legendre(fc, 0, 1))
print('\n')
print('f(x) = 1/(1+x)')
print('a = 0, b = 1')
print('I = ', gauss_legendre(fd, 0, 1))
print('\n')

x = np.linspace(-5, 5, 1000)
y = f(x)
plt.title(r'f(x)=e^(-x^2)')
plt.grid('on')
plt.plot(x, y)

print('Romberg Integration')
print(f'I = {romberg(f, -5, 5)}')
print('Gauss-Legendre Integration')
print(f'I = {gauss_legendre(f, -5, 5)}')


import cv2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import pdb
import os
import skimage.io as io

from scipy.stats import pearsonr

# -------------------------- train_data.csv -------------------------------

# Read csv
features = pd.read_csv("data/train_data.csv", thousands=',')

# Drop first row
features = features.dropna(axis=0)

# Extract values of columns needed
revenue = features["Box_office"].values.astype(np.float)
imdb = features["imdbVotes"].values.astype(np.float)
imdbRating = features["imdbRating"].values.astype(np.float)
runtime = features["Runtime"].values.astype(np.int)
metascore = features["Metascore"].values.astype(np.float)
releaseMonth = features["Release_month"].values.astype(np.int)

# Evaluation Pearson r correlation
correlation, _ = pearsonr(imdb, revenue)

# Figure 1: Shows correlation between columns
plt.figure(1, figsize = (20, 7))
plt.subplot(2, 3, 1)
plt.subplots_adjust(wspace = 0.2, hspace = 0.5)
plt.scatter(imdb, revenue, s = 1, marker = "o", facecolor = "none", edgecolor = "blue")
plt.title("Revenue vs imdb Votes", fontsize=16)
plt.xlabel("imdb Votes", fontsize=14)
plt.ylabel("Revenue", fontsize=14)
plt.annotate(f"Pearson-R = {correlation:.2f}", (np.min(imdb), 0.98*np.max(revenue)), fontsize=12) # plot the value on the graph

# Evaluation Pearson r correlation
correlation2, _ = pearsonr(imdbRating, revenue)

# Figure 2: Shows correlation between columns
plt.subplot(2, 3, 2)
plt.scatter(imdbRating, revenue, s = 1, marker = "o", facecolor = "none", edgecolor = "blue")
plt.title("Revenue vs imdb Rating", fontsize=16)
plt.xlabel("imdb Rating", fontsize=14)
plt.ylabel("Revenue", fontsize=14)
plt.annotate(f"Pearson-R = {correlation2:.2f}", (np.min(imdbRating), 0.98*np.max(revenue)), fontsize=12) # plot the value on the graph

# Evaluation Pearson r correlation
correlation3, _ = pearsonr(runtime, revenue)

# Figure 2: Shows correlation between columns
plt.subplot(2, 3, 3)
plt.scatter(runtime, revenue, s = 1, marker = "o", facecolor = "none", edgecolor = "blue")
plt.title("Revenue vs Runtime", fontsize=16)
plt.xlabel("Runtime", fontsize=14)
plt.ylabel("Revenue", fontsize=14)
plt.annotate(f"Pearson-R = {correlation3:.2f}", (np.min(runtime), 0.98*np.max(revenue)), fontsize=12) # plot the value on the graph

# Evaluation Pearson r correlation
correlation4, _ = pearsonr(metascore, revenue)

# Figure 2: Shows correlation between columns
plt.subplot(2, 3, 4)
plt.scatter(metascore, revenue, s = 1, marker = "o", facecolor = "none", edgecolor = "blue")
plt.title("Revenue vs Metascore", fontsize=16)
plt.xlabel("Metascore", fontsize=14)
plt.ylabel("Revenue", fontsize=14)
plt.annotate(f"Pearson-R = {correlation4:.2f}", (np.min(metascore), 0.98*np.max(revenue)), fontsize=12) # plot the value on the graph

# Evaluation Pearson r correlation
correlation5, _ = pearsonr(releaseMonth, revenue)

# Figure 2: Shows correlation between columns
plt.subplot(2, 3, 5)
plt.scatter(releaseMonth, revenue, s = 1, marker = "o", facecolor = "none", edgecolor = "blue")
plt.title("Revenue vs Release Month", fontsize=16)
plt.xlabel("Release Month", fontsize=14)
plt.ylabel("Revenue", fontsize=14)
plt.annotate(f"Pearson-R = {correlation5:.2f}", (np.min(releaseMonth), 0.98*np.max(revenue)), fontsize=12) # plot the value on the graph

plt.show()

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


"""
The minimal path sum in the 5 by 5 matrix below, by starting in any cell in the
left column and finishing in any cell in the right column, and only moving up,
down, and right, is indicated in red and bold; the sum is equal to 994.

 A = np.array([  [131, 201, 630, 537, 805],
                 [673,  96, 803, 699, 732],
                 [234, 342, 746, 497, 524],
                 [103, 965, 422, 121,  37],
                 [18, 150, 111, 956, 331]  ]).T

Find the minimal path sum, in matrix.txt (right click and "Save Link/Target
As..."), a 31K text file containing a 80 by 80 matrix, from the left column to
the right column.

Solution comment: Solve column by column, each time only considering a (N x 2) matrix.
Best path either straight right, or any number of steps up or down followed by a right step.
If at any point the column sum going up/down exceeds the best known path, we can stop going
up/down.

Time complexity is O(N x N x (N/2 + N/2) = O(N^3) worst case, but
the up/down search will terminate much quicker than (N/2 + N/2) on average. Runs in ~0.23s.
"""

import numpy as np

A = np.loadtxt('p082_matrix.txt', delimiter=',')
B = np.zeros(A.shape[0])  # Buffer for the column being solved.

for j in reversed(range(A.shape[1]-1)):
    for i in range(A.shape[0]):
        c_best = A[i,j] + A[i,j+1]
        # Down search
        col_sum = A[i,j]
        for k in range(i+1, A.shape[0]):
            col_sum += A[k,j]
            if col_sum >= c_best:
                break
            c_best = min(c_best, col_sum + A[k,j+1])

        # Up search
        col_sum = A[i,j]
        for k in reversed(range(i)):
            col_sum += A[k,j]
            if col_sum >= c_best:
                break
            c_best = min(c_best, col_sum + A[k,j+1])

        B[i] = c_best
    A[:,j] = B

print(np.min(A[:,0]))


import numpy as np

'''
Function:  Normalization
Description: Normalize input data. For vector x, the normalization process is given by
            normalization(x) = (x - min(x))/(max(x) - min(x))
Input:  data        dataType: ndarray   description: input data
Output: normdata    dataType: ndarray   description: output data after normalization
'''

def Normalization(data):
    # get the max and min value of each column
    minValue = data.min(axis=0)
    maxValue = data.max(axis=0)
    diff = maxValue - minValue
    # normalization
    mindata = np.tile(minValue, (data.shape[0], 1))
    normdata = (data - mindata) / np.tile(diff, (data.shape[0], 1))
    return normdata

'''
Function:  Standardization
Description: Standardize input data. For vector x, the normalization process is given by
             Standardization(x) = x - mean(x)/std(x)
Input:  data            dataType: ndarray   description: input data
Output: standarddata    dataType: ndarray   description: output data after standardization
'''

def Standardization(data):
    # get the mean and the variance of each column
    meanValue = data.mean(axis=0)
    varValue = data.std(axis=0)
    standarddata = (data - np.tile(meanValue, (data.shape[0], 1))) / np.tile(varValue, (data.shape[0], 1))
    return standarddata


import numpy as np
from models.k_means import KMeans

class GMM:
    """Implementes Gaussian Mixture Model fitted with EM algorithm. Similar to
    K-means, iteratively adjusts the clusters to match better the points
    belonging to them and then recompute which points belong to what cluster.
    In this case the clusters are soft, each point has a likelihood for each
    possible clusters. Clusters are modeled ase multivariate gaussians. The
    model is fitted using the EM algorithm.

    Parameters
    ----------
    k : `int`, optional
        Number of clusters. Defaults to 2.

    max_iter : `int`, optional
        Max iterations to perform before the algorithm stops training if
        convergence is not achieved.

    th : `float`, optional
        Minimum change in the posterior probabilities `h` to continue training.
        When the change is smaller the training is stopped as the algorithm is
        considered to have converged. Defaylts to 1e-7.
    """

    def __init__(self, k=2, max_iter=100, th=1e-7):
        self.k = k
        self.max_iter = max_iter
        self.weights = None
        self.th = 1e-7

    def fit(self, X, re_init=True, verbose=False):
        """Fits `self.k` multivariate gaussians to `X` using EM algorithm.

        Parameters
        ----------
        X : `numpy.ndarray` (n_examples, n_features)
            Training data.

        re_init : `boolean`, optional
            Whether to reinitialize centroids. Defaults to True. If this is the
            first call to fit, centroids will be initialized eitherway.
        """

        # Initialize gaussians
        if re_init or (self.weights is None):
            self._init_gaussians(X)

        prev_h = None
        for i in range(self.max_iter):
            # Expectation
            h = self._expectation_step(X)

            # Maximization
            self._maximization_step(X, h)
            if (prev_h is not None
                and np.linalg.norm(h-prev_h) < self.th):
                # Converged
                break
            prev_h = h

    def predict(self, X):
        return self._expectation_step(X)

    def _expectation_step(self, X):
        (n_samples, n_features) = X.shape
        # Computes likelihood for each sample of each gaussian
        h = np.zeros((n_samples, self.k))
        for k in range(self.k):
            h[:, k] = self._multinomial_gaussian(
                    X,
                    self.means[k],
                    self.covariances[k])

            h[:, k] *= self.weights[k]

        h = h/np.sum(h, axis=1, keepdims=True)

        return h

    def _maximization_step(self, X, h):
        (n_samples, n_features) = X.shape
        # Update weights
        self.weights = (1./n_samples)*np.sum(h, axis=0)

        # Update gaussians
        for k in range(self.k):
            h_sum = np.sum(h[:, k])
            self.means[k] = np.sum(h[:, k, None]*X, axis=0)/h_sum

            diff = (X-self.means[k])
            self.covariances[k] = np.matmul(diff.T, h[:, k, None]*diff)/h_sum

    def _multinomial_gaussian(self, x, mean, variance):
        factor = 1./np.sqrt(np.linalg.det(variance) * (2*np.pi) ** self.k)
        diff = x - mean
        inv_var = np.linalg.pinv(variance)
        exp = np.exp(-0.5 * np.sum((diff @ inv_var) * diff, axis=1))

        return factor * exp

    def _init_gaussians(self, X):

        # Init gaussians using the result of running kmeans
        self.means, self.covariances = KMeans(k=self.k)._init_gmm(X)

        self.weights = [1./self.k]*self.k


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

def compare_hist_to_norm(data, bins=25):
    """

    :param data:
    :param bins:
    :return:
    """
    fig = plt.figure(figsize=(10, 5))

    mu, std = scipy.stats.norm.fit(data)

    plt.hist(data, bins=bins, density=True, alpha=0.6, color='purple', label="Données")

    # Plot le PDF.
    xmin, xmax = plt.xlim()
    X = np.linspace(xmin, xmax)

    plt.plot(X, scipy.stats.norm.pdf(X, mu, std), label="Normal Distribution")
    plt.plot(X, skewnorm.pdf(X, *skewnorm.fit(data)), color='black', label="Skewed Normal Distribution")

    mu, std = scipy.stats.norm.fit(data)
    sk = scipy.stats.skew(data)

    title2 = "Moments mu: {}, sig: {}, sk: {}".format(round(mu, 4), round(std, 4), round(sk, 4))
    plt.ylabel("Fréquence", rotation=90)
    plt.title(title2)
    plt.legend()
    #plt.show()
    pass

def compare_hist_to_norm_ax(x, data, bins=25):

    mu, std = scipy.stats.norm.fit(data)

    ax[x].hist(data, bins=bins, density=True, alpha=0.6, color='purple', label="Données")

    # Plot le PDF.
    xmin, xmax = plt.xlim()
    X = np.linspace(xmin, xmax)

    ax[x].plot(X, scipy.stats.norm.pdf(X, mu, std), label="Normal Distribution")
    ax[x].plot(X, skewnorm.pdf(X, *skewnorm.fit(data)), color='black', label="Skewed Normal Distribution")

    mu, std = scipy.stats.norm.fit(data)
    sk = scipy.stats.skew(data)

    title2 = "Moments mu: {}, sig: {}, sk: {}".format(round(mu, 4), round(std, 4), round(sk, 4))
    ax[x].ylabel("Fréquence", rotation=90)
    ax[x].title(title2)
    ax[x].legend()
    pass


import matplotlib.pyplot as plt
from numpy import random, std, pi, cos, sin, polyfit
from graph import *

def rand_walker_1d(sample_size:int, num_steps:int):
    walkers = [0 for _ in range(sample_size)]           # List of walkers with location
    std_devs = []
    means = []

    for _ in range(num_steps):                          # Changes position, num_steps times
        std_devs.append(std(walkers))
        means.append(sum(walkers)/len(walkers))
        for i in range(len(walkers)):
            walkers[i] += ((random.rand() * 3) - 1)     # Adds random number from -1 to 1
    return walkers, std_devs, means

def rand_walker_2d(sample_size:int, num_steps:int):
    """Simulates a population of walkers that move up
    to 1 unit in a random direction num_steps times
    """
    walkers = [[0,0] for _ in range(sample_size)]       # List of walkers with location
    std_devs = []
    for _ in range(num_steps):
        std_devs.append(std([dist(walker[0],walker[1]) for walker in walkers]))
        for i in range(len(walkers)):
            radius = random.rand()                      # Movement magnitude, [0, 1]
            theta = random.rand() * 2 * pi              # Movement angle, [0, two pi]
            walkers[i][0] += radius * cos(theta)        # Adds movement to x
            walkers[i][1] += radius * sin(theta)        # Adds movement to y
    return walkers, std_devs

if __name__ == "__main__":
    sample_size = 1000000
    num_steps = 100

    walkers, std_devs, means = rand_walker_1d(sample_size, num_steps)
    # scatter_walker(walkers)
    # print(std_devs)
    # std_by_steps(std_devs, num_steps, sample_size)
    # pos_hist(walkers=walkers, num_steps=num_steps, num_bins=100, dimensions=1, by_radius=True, density=1)
    mean_by_steps(means, num_steps, sample_size)


## module midpoint
''' yStop = integrate (F,x,y,xStop,tol=1.0e-6)
    Modified midpoint method for solving the
    initial value problem y' = F(x,y}.
    x,y   = initial conditions
    xStop = terminal value of x
    yStop = y(xStop)
    F     = user-supplied function that returns the
            array F(x,y) = {y'[0],y'[1],...,y'[n-1]}.
'''
import numpy as np
import math
def integrate(F,x,y,xStop,tol):

    def midpoint(F,x,y,xStop,nSteps):

  # Midpoint formulas
        h = (xStop - x)/nSteps
        y0 = y
        y1 = y0 + h*F(x,y0)
        for i in range(nSteps-1):
            x = x + h
            y2 = y0 + 2.0*h*F(x,y1)
            y0 = y1
            y1 = y2
        return 0.5*(y1 + y0 + h*F(x,y2))

    def richardson(r,k):
  # Richardson's extrapolation
        for j in range(k-1,0,-1):
            const = (k/(k - 1.0))**(2.0*(k-j))
            r[j] = (const*r[j+1] - r[j])/(const - 1.0)
        return

    kMax = 51
    n = len(y)
    r = np.zeros((kMax,n))
  # Start with two integration steps
    nSteps = 2
    r[1] = midpoint(F,x,y,xStop,nSteps)
    r_old = r[1].copy()
  # Increase the number of integration points by 2
  # and refine result by Richardson extrapolation
    for k in range(2,kMax):
        nSteps = 2*k
        r[k] = midpoint(F,x,y,xStop,nSteps)
        richardson(r,k)
      # Compute RMS change in solution
        e = math.sqrt(np.sum((r[1] - r_old)**2)/n)
      # Check for convergence
        if e < tol: return r[1]
        r_old = r[1].copy()
    print("Midpoint method did not converge")


# -*- coding: utf-8 -*-
"""
Created on Wed Sep 25 15:15:18 2019

@author: Sturla
"""
import numpy as np
import matplotlib.pyplot as plt
#from matplotlib import rc

T = 1000 #The total population
gamma = 0.20 #Probability og becomming immune

def beta(I : int) -> float:
    '''Calculates the new probability for each iteration.'''
    return 0.5*I/T

def increment_time(S : int, I : int, R : int):
    '''Runs one iteration of the process.'''
    #Pick the number of new infected and immune by a binomial distubution.
    new_infected = np.random.binomial(S, beta(I))
    new_immune = np.random.binomial(I, gamma)

    S -= new_infected
    R += new_immune
    I += (new_infected - new_immune)
    return S, I, R

def simulation() -> list:
    '''Simulates the markovchain using the given probabilities'''
    time_steps = []
    time_steps.append([950, 50, 0])
    for i in range(0, 200):
        S, I, R = increment_time(time_steps[i][0], time_steps[i][1], time_steps[i][2])
        time_steps.append([S, I, R])
    return time_steps

def simulation_max_infected(initial_conditions : list):
    '''
    Simulates the markov chain, and keeps track of the max number of
    infected, and the number uf iterations untill max is reached
    '''
    time_steps = []
    time_steps.append(initial_conditions)

    max_infected = initial_conditions[1]
    index = 0
    for i in range(0, 200):
        S, I, R = increment_time(time_steps[i][0], time_steps[i][1], time_steps[i][2])
        if I > max_infected:
            max_infected = I
            index = i
        elif I == 0:
           break
        time_steps.append([S, I, R])
    return max_infected, index

def calc_avrage_max():
    '''
    Simulates the process 1000 times, and returns the avarge max, and the
    avarge iterations untill max is reached.
    '''
    max_list = []
    time_list = []
    for i in range(1000):
        max_infected, time = simulation_max_infected([950, 50, 0])
        max_list.append(max_infected)
        time_list.append(time)
    return np.average(max_list), np.average(time_list)

max_infected, time_of_max = calc_avrage_max()

print("e)")
graph = np.array(simulation())
# use LaTeX fonts in the plot
#plt.rc('text', usetex=True)
#plt.rc('font', family='serif')

# plot
plt.plot(graph)
# set labels (LaTeX can be used)
#plt.title(r'\textbf{Mutual Information Feature Selection}', fontsize=11)
#plt.xlabel(r'\textbf{Time (days)}', fontsize=11)
#plt.ylabel(r'\textbf{People}', fontsize=11)
plt.ylabel('People')
plt.xlabel('Time (days)')
plt.title("The number of people in each state", fontdict={'fontname': 'Times New Roman', 'fontsize': 21}, y=1.03)
plt.show()
print("f)")
print("Max number of infected: " , max_infected)
print("Time untill max: " ,time_of_max)

Project 1/project1 problem 1 task d and e.py


from numpy import pi, arange, arctan2, sqrt, meshgrid, linspace, sin, cos, array, log, ones
from scipy import ndimage

def ConvertToCylindrical(array_in, x_min, x_max, y_min, y_max, theta_offset = 0.0, oversample_th = 2.0, oversample_r = 2.0):
    """Take an array in rectangular coordinates and transform into cylindrical
    (r,theta) coordinates.  Must specify axis limits (min and max) in real units
    of both axes.  As a side effect, this allows calculation of the center element ->
    (x0, y0) = (-x_min/x_stepsize, -y_min/y_stepsize)

    the spacing of the input mesh in the transformed variables is approximately:
    dr = (1/r) * (x dx + y dy)
    dtheta = 1/r^2 * sqrt(x^2 dy + y^2 dx)

    the output mesh is has a spacing of dr_min/oversample_r, and
    dtheta_min/oversample_th
    so that the output grid is bigger (larger array) than the input array, when
    oversample_r and oversample_th are greater than 1.

    At each pixel of the output array, a lookup pair of x, y is created
    that correspond to the r, th at that pixel.  The value of the input array
    at x, y is inserted into the output array (at r, th) via the scipy.ndimage function.

    Lookup pairs that are outside the x,y boundaries of the input array result in a zero
    being written at r,th (this occurs every time, as a rectangular r,th space maps onto
    a non-rectangular x,y space)

    A mask with the same dimensions as the output array is also generated, which has a
    value 1 everywhere the mapping was successful, and 0 where unsuccessful.

    Returns: data array in r,th space; mask; and boundaries of new r,th space
    """

    x_axis = linspace(x_min, x_max, array_in.shape[0])
    y_axis = linspace(y_min, y_max, array_in.shape[1])

    x_stepsize = float(x_max - x_min) / array_in.shape[0]
    y_stepsize = float(y_max - y_min) / array_in.shape[1]

    x,y = meshgrid(x_axis, y_axis)
    # meshgrid makes two new arrays with same dimensions as array_in,
    # but filled with x and y coordinates of each point instead of data

    r_in = sqrt(x**2 + y**2)
    theta_in = arctan2(y, x)
    # these are two more arrays with same dimensions as array_in,
    # but filled with the r, theta coordinates of each point of array_in

    dtheta_min = (1.0/r_in[r_in>0]**2 * sqrt(x[r_in>0]**2 * y_stepsize**2 + y[r_in>0]**2 * x_stepsize)).min() * 180.0/pi
    # dtheta is approximately 1/r^2 * sqrt(x^2 dy + y^2 dx)
    th_step = dtheta_min / oversample_th

    dr_min = (1.0/r_in[r_in>0] * ( abs(x[r_in>0] * x_stepsize) + abs(y[r_in>0] * y_stepsize) )).min()
    # dr is (1/r) * (x dx + y dy)
    r_step = dr_min / oversample_r

    th_out_axis = arange(theta_offset, theta_offset + 360.0 + th_step, th_step )
    r_out_axis = arange(r_in.min(), r_in.max(), r_step)

    th_out, r_out = meshgrid(th_out_axis, r_out_axis)

    x_lookup = ( r_out * cos(th_out*pi/180.0) - x_min ) / x_stepsize  # coordinates for looking up data in array_in
    y_lookup = ( r_out * sin(th_out*pi/180.0) - y_min ) / y_stepsize
    #return x_lookup, y_lookup, r_out, th_out

    data_mask = ones(r_out.shape, dtype=int)
    data_mask[x_lookup >= array_in.shape[0]] = 0
    data_mask[x_lookup < 0] = 0
    data_mask[y_lookup >= array_in.shape[1]] = 0
    data_mask[y_lookup < 0] = 0

    #x_lookup.clip(0)
    #y_lookup.clip(0)

    array_out = ndimage.map_coordinates(array_in, array([x_lookup, y_lookup]), order = 1)
    # ndimage.map_coordinates takes a source image, and a set of two arrays: the arrays hold lookup coordinates.
    # Each pixel of a new array (with dimensions equal to the lookup arrays) is set by looking at the pixel
    # in the source image with the coordinate pair specified.

    extent = [th_out.min(), th_out.max(), r_in.min(), r_in.max()]
    return array_out, data_mask, extent
    #self.qxpp.clip(0)
    #self.qzpp.clip(0)

if __name__ == '__main__':
    from pylab import imshow, show, xlabel, ylabel, colorbar, figure, title
    x, y = meshgrid(arange(-50., 150., 1), arange(-20., 30., 1))
    r = sqrt(x**2 + y**2)
    th = arctan2(y, x)
    d = sin(r*pi/25.0)**2
    #d = cos(th)**2 * 1.0/(r + 1.0)**2
    array_out, data_mask, extent = ConvertToCylindrical(d.T, -50, 150, -20, 30)
    # transposing the meshgrid because meshgrid(x,y) has shape (len(y), len(x))

    figure()
    imshow(array_out, aspect = 'auto', origin='lower', extent = extent)
    xlabel(r'$\theta ({}^{\circ})$', size='large')
    ylabel(r'$r$', size='large')
    title(r'$\sin^2(r)$ in cylindrical coords', size='large')
    colorbar()

    figure()
    imshow(d, origin='lower', extent=[-50,150,-20,30])
    xlabel(r'$x$', size='large')
    ylabel(r'$y$', size='large')
    title(r'$\sin^2(r)$ in rectangular coords', size='large')
    colorbar()

    a2, m2, e2 = ConvertToCylindrical(d.T, -50, 150, -20, 30, theta_offset=90.0)
    figure()
    imshow(a2, aspect = 'auto', origin='lower', extent=e2)
    xlabel(r'$\theta ({}^{\circ})$', size='large')
    ylabel(r'$r$', size='large')
    title(r'$\sin^2(r)$ in cylindrical coords with 90.0 deg offset', size='large')
    colorbar()
    show()


# find eigenvalue S, and corresponding eigenvector X, using Reighley quotient R(A,B)= x'Ax/x'Bx = X' S X / X'X
# Example:
# A = (x1 - x2)' * ( x1 - x2); % L2 normal, x's dimension is nxp, n = number of observations, p = dimensionality.
# B = cov([x1; x2]);
# [S,X] = ReighleyQuotient(A,B,'min',1)
#
# function [S,X]=ReighleyQuotient(A,B,ORDER,ORTH)
# %Reighley quotient R(A,B)= x'Ax/x'Bx = X' S X / X'X
# %find eigenvalue S, and corresponding eigenvector X
# %ORDER='min', minimim first, ascend order of S, ORDER='max', descend order of S
# %ORTH=1, orthogonalize eigenvectors.
# % by Jing Wang, jingwang.physics@gmail.com, 05/23/3017
#
# if ishermitian(A) && ishermitian(B)
#     [~,Sb,Vb]=svd(B);
#     %C=Vb*sqrt(Sb);
#     sbinv=1./sqrt(diag(Sb));
#     Sbinv=diag(sbinv);
#     D=Sbinv* Vb'*A*Vb*Sbinv;
#     [~,S,V]=svd(D);
#     X_=Vb*Sbinv*V;
#     IND=[];
#     for i=1:size(X_,2)
#         x=X_(:,i);
#         X_(:,i)=x./norm(x);
#         if norm(x)<1e6
#             IND=[IND;i];
#         end
#     end
#
#     X=X_(:,IND); % remove bad column, if it's rank deficient
#
#     if strcmpi(ORDER, 'min')
#         X=X(:,end:-1:1);
#     end
#
#     if ORTH
#         [X,~]=qr(X);
#     end
#
# else
#     disp('Error!A or B is not Hermitian.')
# end
#
# end

from numpy.linalg import svd, norm, qr
def ReighleyQuotient(A, B, ascending=True, orthogonalize=True, tol=1e6):
    """
    find eigenvalue S, and corresponding eigenvector X, that solves the
    Reighley equation R(A,B) = x'Ax/x'Bx = X' S X / X'X

    Parameters
    ----------
    A : matrix

    B : matrix

    ascending : bools
        Whether to order the eigenpairs by eigenvalue size with minimum first

    orthogonalize : bool, default True
        Whether to QR the matrix and return it orthogonalized.

    tol : float, default 1e6
        The highest value accepted for the norm of a given column.

    Returns
    -------
    S : singular values

    References
    ----------
    From the following article:

    Adapted from the article author's matlab code:
    https://www.mathworks.com/matlabcentral/fileexchange/66547-reighleyquotient-a-b-order-orth-
    """
    assert A == A.H and B == B.H # both are hermitian
    _, s, V = svd(B)
    C = V * np.sqrt(s)
    sinv = (1./np.sqrt(s.diag()))
    D = sinv * V.T * A * V * sinv

    new_s, new_V = svd(D)
    X_ = V*sinv*new_V
    IND = []
    for i in range(X_.shape[1]):
        x = X_[:,i]
        X_[:,i] = x/norm(x)
        if norm(x) < tol:
            IND.append(i)

    X = X_[:,IND]

    if ascending:
        X = X[:,::-1]
    if orthogonalize:
        X, _ = qr(X)

    return new_s, X


import numpy as np

# A Python3 program to find if 2 given line segments intersect or not
# This code is contributed by Ansh Riyal
# SOURCE: https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
# class Point:
#     def __init__(self, x, y):
#         self.x = x
#         self.y = y

def is_on_segment(p, q, r):
    # very very jank indexing
    if (
        (q[0] <= max(p[0], r[0]))
        and (q[0] >= min(p[0], r[0]))
        and (q[1] <= max(p[1], r[1]))
        and (q[1] >= min(p[1], r[1]))
    ):
        return True
    return False

def orientation(p, q, r):
    # to find the orientation of an ordered triplet (p,q,r)
    # function returns the following values:
    # 0 : Collinear points
    # 1 : Clockwise points
    # 2 : Counterclockwise
    # See https://www.geeksforgeeks.org/orientation-3-ordered-points/amp/
    # for details of below formula.
    val = (float(q[1] - p[1]) * (r[0] - q[0])) - (float(q[0] - p[0]) * (r[1] - q[1]))
    if val > 0:
        return 1  # Clockwise orientation
    elif val < 0:
        return 2  # Counterclockwise orientation
    else:
        return 0  # Collinear orientation

# The main function that returns true if
# the line segment 'p1q1' and 'p2q2' intersect.
def check_intersect(p1, q1, p2, q2):
    # Find the 4 orientations required for
    # the general and special cases
    o1 = orientation(p1, q1, p2)
    o2 = orientation(p1, q1, q2)
    o3 = orientation(p2, q2, p1)
    o4 = orientation(p2, q2, q1)

    # General case
    if (o1 != o2) and (o3 != o4):
        return True

    # Special Cases
    # p1 , q1 and p2 are collinear and p2 lies on segment p1q1
    if (o1 == 0) and is_on_segment(p1, p2, q1):
        return True
    # p1 , q1 and q2 are collinear and q2 lies on segment p1q1
    if (o2 == 0) and is_on_segment(p1, q2, q1):
        return True
    # p2 , q2 and p1 are collinear and p1 lies on segment p2q2
    if (o3 == 0) and is_on_segment(p2, p1, q2):
        return True
    # p2 , q2 and q1 are collinear and q1 lies on segment p2q2
    if (o4 == 0) and is_on_segment(p2, q1, q2):
        return True
    # If none of the cases
    return False

# SOURCE: https://stackoverflow.com/questions/20677795/how-do-i-compute-the-intersection-point-of-two-lines
def line_intersection(line1, line2):
    xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
    ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])

    # define local function
    def det(a, b):
        return a[0] * b[1] - a[1] * b[0]

    div = det(xdiff, ydiff)
    x, y = None, None

    if div != 0:
        d = (det(*line1), det(*line2))
        x = det(d, xdiff) / div
        y = det(d, ydiff) / div
    return x, y

# SOURCE: https://stackoverflow.com/questions/3252194/numpy-and-line-intersections
def get_intersect(p1, q1, p2, q2):
    """
    Returns the point of intersection of the lines passing through p1,q1 and p2,q2.
    p1: [x, y] a point on the FIRST LINE
    q1: [x, y] another point on the FIRST LINE
    p2: [x, y] a point on the SECOND LINE
    q2: [x, y] another point on the SECOND LINE
    """

    is_intersecting = check_intersect(p1, q1, p2, q2)
    intersect_pt = None
    if is_intersecting:
        # using this shaves off ~0.5s per 100iterations for the LiDAR code
        x, y = line_intersection((p1, q1), (p2, q2))
        intersect_pt = [x, y]

    # operations below are slow
    # if is_intersecting:
    #     s = np.vstack([p1, q1, p2, q2])  # s for stacked
    #     h = np.hstack((s, np.ones((4, 1))))  # h for homogeneous
    #     l1 = np.cross(h[0], h[1])  # get first line
    #     l2 = np.cross(h[2], h[3])  # get second line
    #     x, y, z = np.cross(l1, l2)  # point of intersection
    #     if z != 0:
    #         intersect_pt = [x / z, y / z]
    return intersect_pt

if __name__ == "__main__":
    # Driver program to test above functions:
    p1 = [1, 1]
    q1 = [10, 1]
    p2 = [1, 2]
    q2 = [10, 2]
    print(get_intersect(p1, q1, p2, q2))

    p1 = [10, 0]
    q1 = [0, 10]
    p2 = [0, 0]
    q2 = [10, 10]
    print(get_intersect(p1, q1, p2, q2))

    p1 = [-5, -5]
    q1 = [0, 0]
    p2 = [1, 1]
    q2 = [10, 10]
    print(get_intersect(p1, q1, p2, q2))


''' mbinary
#########################################################################
# File : interplotion.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-10-02  21:14
# Description:
#########################################################################
'''

#########################################################################
# File : interplotion.py
# Author: mbinary
# Mail: zhuheqin1@gmail.com
# Blog: https://mbinary.xyz
# Github: https://github.com/mbinary
# Created Time: 2018-05-18  09:29
# Description: 插值计算,有牛顿插值,拉格朗日插值,以及通过插值得到的多项式估计新的函数值
#########################################################################

import sympy
from collections import namedtuple
from functools import reduce
from operator import mul

X = sympy.Symbol ('x')
point = namedtuple('point',['x','y'])

class interplotion:
    def __init__(self,points):
        self.points  = [point(x,y) for x,y in points]
        self.xs= [i for i,j in points]
        self.poly,self.rem = self.newton(self.points,0,len(self.points)-1)

    def newton(self,li,a,b):
        '''li:[(x,f(x))...]'''

        qs = [li[0].y]

        def quoDiff(begin,end):
            if begin == end:return li[begin].y
            q = (quoDiff(begin+1,end)-quoDiff(begin,end-1))/(li[end].x-li[begin].x)
            if begin == a:qs.append(q)
            return q

        quoDiff(a,b)
        poly ,base = 0, 1
        for i,q  in enumerate(qs):
            poly += q*base
            base*= X-li[i].x
        return poly, base*qs[-1]
    def lagrange(self,points=None):
        xs = None
        if points is None:
            xs = self.xs
            points = self.points
        else: xs =[x for x,y in points]
        product = reduce(mul,[X-x  for x in xs],1)
        poly = 0
        for x,y in points:
            tmp  = product/(X-x)
            coef = y/(tmp.subs(X,x))
            poly+= coef *tmp
        return poly

    def predict(self,val,poly = None):
        if poly is None:poly = self.poly
        return poly.subs(X,val) #  note the func  subs

if __name__ == '__main__':
    f = interplotion([(81,9),(100,10),(121,11)])
    p = f.lagrange()
    print(p.subs(X,105))
    print(p)

    intor = interplotion([(0,11),(0.02,9),(0.04,7),(0.06,10)])
    p = intor.lagrange()
    print(p)
    res = intor.predict(0.08)
    print(res)


import numpy as np
from sklearn import model_selection
import logistic_regressor as lr
from sklearn import linear_model
import scipy.io
import plot_utils

######################################################################################
#   The sigmoid function                                                             #
#     Input: z: can be a scalar, vector or a matrix                                  #
#     Output: sigz: sigmoid of scalar, vector or a matrix                            #
#     TODO: 1 line of code expected                                                  #
######################################################################################

def sigmoid (z):
    sig = np.zeros(z.shape)
    # Your code here
    sig = 1 / (1 + np.exp(-z))
    # End your code

    return sig

######################################################################################
#   The log_features transform                                                       #
#     Input: X: a data matrix                                                        #
#     Output: a matrix with every element x replaced by 1 + log(x)                   #
#     TODO: 1 line of code expected                                                  #
######################################################################################

def log_features(X):
    logf = np.zeros(X.shape)
    # Your code here
    logf =  np.log(1+X)
    # End your code
    return logf

######################################################################################
#   The std_features transform                                                       #
#     Input: X: a data matrix                                                        #
#     Output: a matrix with every column with zero mean, unit variance               #
######################################################################################

def std_features(X):
    mu = np.mean(X,axis=0)
    sigma = np.std(X,axis=0)
    X_norm = (X - mu) / sigma
    return X_norm, mu, sigma

######################################################################################
#   The bin_features transform                                                       #
#     Input: X: a data matrix                                                        #
#     Output: a matrix with every element x replaced by 1 if x > 0 else 0            #
#     TODO: 1 line of code expected                                                  #
######################################################################################

def bin_features(X):
    tX = np.zeros(X.shape)
    # your code here
    tX[X > 0] = 1
    # end your code
    return tX

######################################################################################
#   The select_lambda_crossval function                                              #
#     Inputs: X: a data matrix                                                       #
#             y: a vector of labels                                                  #
#             lambda_low, lambda_high,lambda_step: range of lambdas to sweep         #
#             penalty: 'l1' or 'l2'                                                  #
#     Output: best lambda selected by crossvalidation for input parameters           #
######################################################################################

# Select the best lambda for training set (X,y) by sweeping a range of
# lambda values from lambda_low to lambda_high in steps of lambda_step
# pick sklearn's LogisticRegression with the appropriate penalty (and solver)

# 20-25 lines of code expected

# For each lambda value, divide the data into 10 equal folds
# using sklearn's cross_validation KFold function.
# Then, repeat i = 1:10:
#  1. Retain fold i for testing, and train logistic model on the other 9 folds
#  with that lambda
#  2. Evaluate accuracy of model on left out fold i
# Accuracy associated with that lambda is the averaged accuracy over all 10
# folds.
# Do this for each lambda in the range and pick the best one
#
def select_lambda_crossval(X,y,lambda_low,lambda_high,lambda_step,penalty):

    best_lambda = lambda_low

    # Your code here
    # Implement the algorithm above.
    num_folds = 10
    best_accuracy = 0
    kf = model_selection.KFold(n_splits = num_folds)
    for reg in np.arange(lambda_low, lambda_high, lambda_step):
        accuracy = 0;
        print "reg = ", reg
        for train_index, test_index in kf.split(X):
            X_train = X[train_index]
            y_train = y[train_index]
            X_test = X[test_index]
            y_test = y[test_index]
            if (penalty == "l2"):
                sk_logreg = linear_model.LogisticRegression(C=1.0/reg, solver='lbfgs',fit_intercept=False, penalty=penalty)
            elif (penalty == "l1"):
                sk_logreg = linear_model.LogisticRegression(C=1.0/reg, solver='liblinear',fit_intercept=False,penalty=penalty)
            else:
                raise ValueError("Incorrect penalty type! Penalty can only be l2 or l1.")
            sk_logreg.fit(X_train, y_train)
            y_pred = sk_logreg.predict(X_test)
            # y_pred = bin_features(X_test.dot(sk_logreg.coef_[0]))
            cur_accuracy= float(np.sum(y_pred == y_test)) / y_test.shape[0]
            # print "lambda = ", reg, ", accuracy = ", cur_accuracy
            accuracy += cur_accuracy
        accuracy = accuracy / num_folds
        if (accuracy > best_accuracy):
            best_accuracy = accuracy
            best_lambda = reg

    # end your code

    return best_lambda

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

def load_mat(fname):
  d = scipy.io.loadmat(fname)
  Xtrain = d['Xtrain']
  ytrain = d['ytrain']
  Xtest = d['Xtest']
  ytest = d['ytest']

  return Xtrain, ytrain, Xtest, ytest

def load_spam_data():
    data = scipy.io.loadmat('spamData.mat')
    Xtrain = data['Xtrain']
    ytrain1 = data['ytrain']
    Xtest = data['Xtest']
    ytest1 = data['ytest']

    # need to flatten the ytrain and ytest
    ytrain = np.array([x[0] for x in ytrain1])
    ytest = np.array([x[0] for x in ytest1])
    return Xtrain,Xtest,ytrain,ytest


#!/bin/python3

import math
import os
import random
import re
import sys
import numpy as np

"""
You are given a number of sticks of varying lengths. You will iteratively cut the sticks
into smaller sticks, discarding the shortest pieces until there are none left. At each
iteration you will determine the length of the shortest stick remaining, cut that length
from each of the longer sticks and then discard all the pieces of that shortest length.
When all the remaining sticks are the same length, they cannot be shortened so discard them.

Given the lengths of n sticks, print the number of sticks that are left before each iteration
until there are none left.

For example, there are n = 3 sticks of lengths arr = [1, 2, 3]. The shortest stick length
is 1, so we cut that length from the longer two and discard the pieces of length 1. Now our
lengths are arr = [1, 2]. Again, the shortest stick is of length 1, so we cut that amount
from the longer stick and discard those pieces. There is only one stick left, arr = [1], so
we discard that stick. Our lengths are answer = [ 3, 2, 1].

Link: https://www.hackerrank.com/challenges/cut-the-sticks/problem
"""

# Complete the cutTheSticks function below.
def cutTheSticks(arr):

    result = []
    while len(arr) > 0:
        result.append(len(arr))
        lengthOfCut = min(arr)

        # cat the sticks
        tmp = list(map(lambda x : x - lengthOfCut, arr))

        # remove the sticks
        arr = [x for x in tmp if x > 0]

    return result

if __name__ == '__main__':
    # sample case 1
    #n = 6
    #arr = [ 5, 4, 4, 2, 2, 8 ]

    # sample case 2
    n = 8
    arr = [ 1, 2, 3, 4, 3, 3, 2, 1 ]

    result = cutTheSticks(arr)
    print(np.array(result))


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

# # Método de punto fijo
# J.J
# ---
# Dado que se busca resolver $f(x) = 0$, la función $f$ puede ser reescrita como $f(x) = g(x) - x = 0$. El método de punto fijo está dado por las iteraciones:
#
# \begin{equation}
# x_{k+1} = g(x_{k}).
# \end{equation}
#
# El método converge a una raíz si los valores de $x_{k}$ en cada iteración cumplen $|g'(x)| \leq 1$.

# Ejemplo: $f(x) = 2x^{3} - 9x^{2} + 7x + 6 = 0$
# \begin{equation}
# x = \frac{1}{7} \{ -2x^{3} + 9x^{2} - 6 \}
# \end{equation}

# In[1]:

import numpy as np
from sympy import *
from sympy.utilities.lambdify import lambdify
import matplotlib.pyplot as plt
init_printing(use_unicode=True)

# In[2]:

#calcular la derivada de f
x = symbols('x')
funcion = 2*x**3 - 9*x**2 + 7*x + 6
gfuncion = (-2*x**3 + 9*x**2 - 6)/7 #escribir la función aqui
dgfuncion = diff(gfuncion, x)
print(str(dgfuncion))

# In[3]:

f = lambdify(x, funcion)
g = lambdify(x, gfuncion)
dg = lambdify(x, dgfuncion)

# In[4]:

X = np.linspace(-1, 4, 100)
plt.plot(X,dg(X), label = 'g´(x)')
plt.ylim(-1,1)
plt.legend()
plt.show()

# La desigualdad se cumple aproximadamente entre en los intervalos $[-0.44, 0.46]$ y $[2.5, 3.34]$, aun que en realidad, en el primer intervalo no converge.

# In[5]:

e = 0.0001 #error
maxit = 100 #iteraciones máximas

# In[6]:

def PuntoFijo(x0, func = g, error = e, iterations = maxit):
    it = 0
    while (abs(f(x0)) > e) and (it < maxit):
        it += 1
        xk = g(x0)
        x0 = xk
    return x0

# In[7]:

sol = PuntoFijo(2.6)
print(sol)

# In[8]:

plt.plot(X, f(X), label='f(x)')
plt.plot(sol,f(sol),'ro')
plt.legend()
plt.show()

# In[ ]:


# Based on
# https://www.teachme.codes/numpy-docs/Meshgrid-SimulationExample/code/
# https://scicomp.stackexchange.com/questions/33325/can-i-solve-a-model-in-gekko-with-black-box-simulated-annealing-or-ga-solvers

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

# define objective function
def f(x):
    x1 = x[0]
    x2 = x[1]
    obj = 0.2 + x1**2 + x2**2 - 0.1*math.cos(6.0*3.1415*x1) - 0.1*math.cos(6.0*3.1415*x2)
    return obj

# Start location
x_start = [0.8, -0.5]

# Design variables at mesh points
'''
i1 = np.arange(-1.0, 1.0, 0.01)
i2 = np.arange(-1.0, 1.0, 0.01)
x1m, x2m = np.meshgrid(i1, i2)
fm = np.zeros(x1m.shape)
for i in range(x1m.shape[0]):
    for j in range(x1m.shape[1]):
        fm[i][j] = 0.2 + x1m[i][j]**2 + x2m[i][j]**2 \
             - 0.1*math.cos(6.0*3.1415*x1m[i][j]) \
             - 0.1*math.cos(6.0*3.1415*x2m[i][j])
'''

# Design variables at mesh points
ns = 100
xs = np.arange(-1.0, 1.0, 1/ns)
ys = np.arange(-1.0, 1.0, 1/ns)
XG,YG = np.meshgrid(xs, ys)
ZG =  0.2 + xs**2 + ys**2\
       - 0.1*np.cos(6.0*np.pi*XG)\
       - 0.1*np.cos(6.0*np.pi*YG)
fm = ZG;

##################################################
# Simulated Annealing
##################################################
# Number of cycles
n = 50
# Number of trials per cycle
m = 50
# Number of accepted solutions
na = 0.0
# Probability of accepting worse solution at the start
p1 = 0.7
# Probability of accepting worse solution at the end
p50 = 0.001
# Initial temperature
t1 = -1.0/math.log(p1)
# Final temperature
t50 = -1.0/math.log(p50)
# Fractional reduction every cycle
frac = (t50/t1)**(1.0/(n-1.0))
# Initialize x
x = np.zeros((n+1,2))
x[0] = x_start
xi = np.zeros(2)
xi = x_start
na = na + 1.0
# Current best results so far
xc = np.zeros(2)
xc = x[0]
fc = f(xi)
fs = np.zeros(n+1)
fs[0] = fc
# Current temperature
t = t1
# DeltaE Average
DeltaE_avg = 0.0
np.random.seed(0)
for i in range(n):
    print('Cycle: ' + str(i) + ' with Temperature: ' + str(t))
    for j in range(m):
        # Generate new trial points
        xi[0] = xc[0] + random.random() - 0.5
        xi[1] = xc[1] + random.random() - 0.5
        # Clip to upper and lower bounds
        xi[0] = max(min(xi[0],1.0),-1.0)
        xi[1] = max(min(xi[1],1.0),-1.0)
        DeltaE = abs(f(xi)-fc)
        if (f(xi)>fc):
            # Initialize DeltaE_avg if a worse solution was found
            #   on the first iteration
            if (i==0 and j==0): DeltaE_avg = DeltaE
            # objective function is worse
            # generate probability of acceptance
            p = math.exp(-DeltaE/(DeltaE_avg * t))
            # determine whether to accept worse point
            if (random.random()<p):
                # accept the worse solution
                accept = True
            else:
                # don't accept the worse solution
                accept = False
        else:
            # objective function is lower, automatically accept
            accept = True
        if (accept==True):
            # update currently accepted solution
            xc[0] = xi[0]
            xc[1] = xi[1]
            fc = f(xc)
            # increment number of accepted solutions
            na = na + 1.0
            # update DeltaE_avg
            DeltaE_avg = (DeltaE_avg * (na-1.0) +  DeltaE) / na
    # Record the best x values at the end of every cycle
    x[i+1][0] = xc[0]
    x[i+1][1] = xc[1]
    fs[i+1] = fc
    # Lower the temperature for next cycle
    t = frac * t

# print solution
print('Best solution: ' + str(xc))
print('Best objective: ' + str(fc))

# Create a contour plot
plt.figure()
#CS = plt.contour(x1m, x2m, fm)
CS = plt.contour(XG, YG, fm)
# Label contours
plt.clabel(CS, inline=1, fontsize=10)
# Add some text to the plot
plt.title('Non-Convex Function')
plt.xlabel('x1')
plt.ylabel('x2')

plt.plot(x_start[0],x_start[1],'r-o', markersize=10) # initial point
plt.plot(x[:,0],x[:,1],'y-o')
pml.savefig('sim_anneal_contour.png')

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.plot(fs,'r.-')
ax1.legend(['Objective'])
ax2 = fig.add_subplot(212)
ax2.plot(x[:,0],'b.-')
ax2.plot(x[:,1],'g--')
ax2.legend(['x1','x2'])
pml.savefig('sim_anneal_iterations.png')

plt.show()


# kurtosis python
# https://www.google.com/search?q=kurtosis+python&oq=Kurtosis+python&aqs=chrome.0.0l4j0i22i30l6.1736j0j7&sourceid=chrome&ie=UTF-8
# https://en.wikipedia.org/wiki/Kurtosis

''' Statistical functions:
Kurtosis is the fourth central moment
divided by the square of the variance.
If Fisher’s definition is used, then 3.0
is subtracted from the result to give 0.0
for a normal distribution.

If bias is False then the kurtosis is
calculated using k statistics to eliminate
bias coming from biased moment estimators.
'''
# -----------------------------------
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kurtosis.html
# scipy part -----------------------------------

# from scipy.stats import norm, kurtosis
from scipy import stats
import matplotlib.pyplot as plt
import matplotlib.pylab as p
import numpy as np
import pandas as pd

'''
# # Discrete vs continuous distribution dataset
# data = stats.norm.rvs(size=1000, random_state=3)
# # reference point
# print(stats.kurtosis(data))
# # print(kurtosis(data, fisher=False))

x = np.linspace(-5, 5, 100)
ax = plt.subplot()
distnames = ['laplace', 'norm', 'uniform', 'cauchy', 'maxwell', 'logistic']
for distname in distnames:
    if distname == 'uniform':
        dist = getattr(stats, distname)(loc=-2, scale=4)
    else:
        dist = getattr(stats, distname)
    data = dist.rvs(size=1000)
    kur = stats.kurtosis(data, fisher=True)
    y = dist.pdf(x)
    ax.plot(x, y, label=f'{distname}, {round(kur, 3)}')
    ax.legend()
plt.show()
'''

# geeksforgeeks part -----------------------------------
x1 = np.linspace(-5, 5, 10000)
y1 = 1./(np.sqrt(2.*np.pi)) * np.exp(-.5*(x1)**2)  # normal distribution
# p.plot(x1, y1, '*')
# print(stats.kurtosis(y1))
# print(stats.kurtosis(y1, fisher=False))
# p.show()

# stackoverflow part -----------------------------------
x_ = np.random.normal(0, 2, 10000)
f, (ax1, ax2) = plt.subplots(1, 2)

# print(f'excess kurtosis of random norm dist(should be 0):\
# {stats.kurtosis(x_)}')
# print(f'skewness of random norm dist (should be 0): {stats.skew(x_)}')

# print(f'excess kurtosis of norm dist (should be 0): {stats.kurtosis(x1)}')
# print(f'skewness of norm dist (should be 0): {stats.skew(x1)}')

# ax1.hist(x_, bins='auto')
# ax1.set_title('probability density (random)')
# ax2.hist(y1, bins='auto')
# ax2.set_title('your dataset')

# plt.tight_layout()
# plt.show()

# pandas part -----------------------------------
# df = pd.read_csv('Data/nba.csv')
# df = pd.read_csv('Data/XAUNZD_Daily.csv')
# print(df.tail())

# # skewness along the index axis
# print(df.kurt(axis=0, skipna=True))

# # skewness of the data over the column axis
# print(df.kurt(axis=1, skipna=True))

# BONUS part -----------------------------------
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kstat.html
# https://mathworld.wolfram.com/Cumulant.html
# https://mathworld.wolfram.com/k-Statistic.html
'''
sample size increases, n-th moment and n-th k-statistic converge
In the case of the normal distribution, they converge to zero
'''
rndm = np.random.RandomState(1234)
# print(rndm)
for n in [2, 3, 4, 5, 6, 7]:
    # sample size increases
    x = rndm.normal(size=10**n)
    m, k = stats.moment(x, 3), stats.kstat(x, 3)
    print(f'{m}, {k}, {m-k}')


#!/usr/bin/python
# -*- coding: utf-8 -*-
# Pierre Haessig — July 2016
""" Matrix helper functions
"""

from __future__ import division, print_function, unicode_literals
import numpy as np

def block_toeplitz(c, r=None):
    '''
    Construct a block Toeplitz matrix, with blocks having the same shape

    Signature is compatible with ``scipy.linalg.toeplitz``

    Parameters
    ----------
    c : list of 2d arrays
        First column of the matrix.
        Each item of the list should have same shape (mb,nb)
    r : list of 2d arrays
        First row of the matrix. If None, ``r = conjugate(c)`` is assumed;
        in this case, if c[0] is real, the result is a Hermitian matrix.
        r[0] is ignored; the first row of the returned matrix is
        made of blocks ``[c[0], r[1:]]``.

    c and r can also be lists of scalars; if so they will be broadcasted
    to the fill the blocks

    Returns
    -------
    A : (len(c)*mb, len(r)*nb) ndarray
        The block Toeplitz matrix.

    Examples
    --------
    Compatible with ``scipy.linalg.toeplitz`` (but less optimized):
    >>> block_toeplitz([1,2,3], [1,4,5,6])
    array([[1, 4, 5, 6],
           [2, 1, 4, 5],
           [3, 2, 1, 4]])

    Regular usage:
    >>> I2 = np.eye(2)
    >>> block_toeplitz([1*I2,2*I2,3*I2], [1*I2,4*I2,5*I2,6*I2])
    array([[1, 0, 4, 0, 5, 0, 6, 0],
           [0, 1, 0, 4, 0, 5, 0, 6],
           [2, 0, 1, 0, 4, 0, 5, 0],
           [0, 2, 0, 1, 0, 4, 0, 5],
           [3, 0, 2, 0, 1, 0, 4, 0],
           [0, 3, 0, 2, 0, 1, 0, 4]])

    Usage with broadcasting of scalar blocks:
    >>> block_toeplitz([1*I2,2*I2,3*I2], [1,4,5,6])
    array([[1, 0, 4, 4, 5, 5, 6, 6],
           [0, 1, 4, 4, 5, 5, 6, 6],
           [2, 0, 1, 0, 4, 4, 5, 5],
           [0, 2, 0, 1, 4, 4, 5, 5],
           [3, 0, 2, 0, 1, 0, 4, 4],
           [0, 3, 0, 2, 0, 1, 4, 4]])
    '''
    c = [np.atleast_2d(ci) for ci in c]
    if r is None:
        r = [np.conj(ci) for ci in c]
    else:
        r = [np.atleast_2d(rj) for rj in r]

    mb,nb = c[0].shape
    dtype = (c[0]+r[0]).dtype
    m = len(c)
    n = len(r)

    A = np.zeros((m*mb, n*nb), dtype=dtype)

    for i in range(m):
        for j in range(n):
            # 1. select the Aij block from c or r:
            d = i-j
            if d>=0:
                Aij = c[d]
            else:
                Aij = r[-d]
            # 2. paste the block
            A[i*mb:(i+1)*mb, j*mb:(j+1)*mb] = Aij

    return A


import torch
import dgl
import numpy as np
import networkx as nx
import scipy.sparse as sp
import matplotlib.pyplot as plt

INF = 20211120 #一个较大的数，graph_mat[i][j]=INF表示i不可以到达j

class FloydWarshall:
    def __init__(self, graph_mat) -> None:
        self.graph_mat = graph_mat # 图的邻接矩阵

    def shortest_path(self):
        m, n = len(self.graph_mat), len(self.graph_mat[0])
        distance_mat = self.graph_mat.copy()
        path = [[None] * n for _ in range(m)] # 记录路径
        for k in range(m):
            for i in range(m):
                for j in range(n):
                    if distance_mat[i][k]+distance_mat[k][j] < distance_mat[i][j]:
                        distance_mat[i][j] = distance_mat[i][k]+distance_mat[k][j]
                        path[i][j] = k
        return distance_mat, path
# 递归
# def get_nodes_edges_recursion(paths, i, j):
#         if i == j:
#             return [i], []
#         else:
#             if paths[i][j] == None:
#                 return [j], [(i, j)]
#             else:
#                 left_nodes, left_edges = get_nodes_edges(paths, i, paths[i][j])
#                 right_nodes, right_edges = get_nodes_edges(paths, paths[i][j], j)
#         return left_nodes+right_nodes, left_edges+right_edges

def get_nodes_edges(paths, i, j):
    pass_nodes = [i, j]
    pass_edges = []
    while paths[i][j] != None:
        j = paths[i][j]
        pass_nodes.insert(1, j)
        pass_edges.append((j, pass_nodes[2]))
    pass_edges.append((i, j))
    return pass_nodes, pass_edges[::-1]

def draw(sp_mat, color_nodes, color_edges):
    '''画一张图，并给指定的节点和边着色
    Parameters
    ----------
    sp_mat : scipy.sparse.spmatrix
    color_nodes : list, e.g. [0, 1, 2, ...]
        指定着色的节点
    color_edges : list, e.g. [(0, 1), (2, 5), ...]
        指定着色的边

    Returns
    -------
    None
    '''

    G = dgl.from_scipy(sp_mat, eweight_name='w') # 注意：dgl.from_scipy()默认为有向多重图
    # print(type(G))
    nx_multi_G = dgl.to_networkx(G, edge_attrs='w').to_undirected() # 变为无向简单图
    nx_G = nx.Graph(nx_multi_G)
    # print(nx_G.edges(data=True))
    edge_labels = nx.get_edge_attributes(nx_G, 'w')
    # tensor.item() tensor(0.)->0(tensor->int)
    edge_labels = { (key[0],key[1]): edge_labels[key].item() for key in edge_labels }
    edges = list(nx_G.edges)
    num_nodes = nx_G.number_of_nodes()
    num_edges = nx_G.number_of_edges()
    node_color = ['b'] * num_nodes
    edge_color = ['b'] * num_edges

    for i in color_nodes:
        node_color[i] = 'r'

    for i in range(num_edges):
        u, v = edges[i][0], edges[i][1]
        if (u, v) in set(color_edges) or (v, u) in set(color_edges):
            edge_color[i] = 'r'
    pos = nx.circular_layout(nx_G)
    plt.title('Undigraph: Shortest Path')
    nx.draw(nx_G, pos, with_labels=True, node_color=node_color, edge_color=edge_color)
    nx.draw_networkx_edge_labels(nx_G, pos, edge_labels=edge_labels)
    plt.savefig('floyd_warshall.png', format='PNG')
    plt.show()

def main():
    row = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4])
    col = np.array([1, 2, 2, 3, 4, 3, 4, 5, 5])
    data = np.array([1, 12, 9, 3, 5, 4, 13, 15, 4])

    count_node = 6
    sp_mat = sp.coo_matrix((data, (row, col)), shape=(count_node, count_node))
    graph_mat = sp_mat.toarray()
    # 无向图
    for i in range(len(graph_mat)):
        for j in range(i):
            if graph_mat[i][j] == 0 and graph_mat[j][i] == 0:
                graph_mat[i][j] = graph_mat[j][i] = INF
            else:
                graph_mat[i][j] += graph_mat[j][i]
                graph_mat[j][i] = graph_mat[i][j]

    distance_mat, paths = FloydWarshall(graph_mat).shortest_path()
    print(distance_mat)
    print(paths)

    for i in range(count_node):
        for j in range(i+1, count_node):
            print('{}->{}: {} | {}'.format(i, j, get_nodes_edges(paths, i, j), distance_mat[i][j]))

    start_node, end_node = 0, 5 # 开始节点，结束节点
    pass_nodes, pass_edges = get_nodes_edges(paths, start_node, end_node)
    '''使用get_nodes_edges_recursion注意添加开始节点
    '''
    # pass_nodes, pass_edges = get_nodes_edges_recursion(paths, start_node, end_node)
    # pass_nodes.insert(0, start_node)
    draw(sp_mat, pass_nodes, pass_edges)
if __name__ == '__main__':
    main()

import numpy,import scipy,import networkx


"""
Provides convenient, but non-vital utilities.
"""

import numpy as np

def N_to_C(N):
    """
    Computes the number of connections for a network with N regions.

    Arguments
    ---------
    N : 2 <= int
        Number of regions.

    Returns
    -------
    C : 1 <= int
        Number of connections.
    """
    return N * (N - 1) / 2

def C_to_N(C):
    """
    Computes the number of regions for a network with C connections.

    Arguments
    ---------
    C : 1 <= int
        Number of connections.

    Returns
    -------
    N : 1 <= int
        Number of regions.
    """
    N = (np.sqrt(8 * C + 1) - 1) / 2 + 1
    return N

def nm_to_c(n, m):
    """
    Converts a pair of region indices (n, m) to a connection index.

    Arguments
    ---------
    n : 0 <= int
        First region index.
    m : n < int
        Second region index.

    Returns
    -------
    c : 0 <= int < N * (N - 1) / 2
        Connection index.

    Notes
    -----
    N is the total number of regions.
    """
    return N_to_C(n) + m

def c_to_nm(c):
    """
    Converts a connection index to a pair of region indices (n, m).

    Arguments
    ---------
    c : 0 <= int < N * (N - 1) / 2
        Connection index.

    Returns
    -------
    n : 0 <= int
        First region index.
    m : n < int
        Second region index.

    Notes
    -----
    N is the total number of regions.
    """
    n = np.floor((np.sqrt(8 * c + 1) - 1) / 2) + 1
    m = c - N_to_C(n)
    return (n, m)


from time import perf_counter
import numpy as np
from matplotlib import pyplot as plt

#returns the minimum of a unidimensional unimodal function using Newton Rapson method
def Newton_Rapson(f,fp, fpp, a, e = 0.1, plot=False):
    t = perf_counter()
    A = []
    k = a
    while abs(fp(k)) > e :
        k = k - fp(k)/fpp(k)
        if plot :
            A.append(k)
    t = perf_counter() - t
    print("time execution: ", t)
    if plot :
        X = np.linspace(a,2*k-a,1000)
        plt.plot(X,f(X))
        plt.plot(k,f(k),"s",label="optimum")
        for u in A:
            plt.plot(u,f(u),"o")
        plt.legend()
        plt.show()
    return k

#returns the minimum of a unidimensional unimodal function using Quasi Newton method
def Quasi_Newton(f, a, s = 0.01, e = 0.1, plot=False):
    t = perf_counter()
    A = []
    k = a
    dev = abs((f(k + s) - f(k - s))/(2 * s))
    while  dev > e:
        if plot :
            A.append(k)
        x = f(k + s)
        y = f(k - s)
        z = f(k)
        k = k - ((s * (x - y))/(2 * (x - 2 * z + y)))
        dev = abs((f(k + s) - f(k - s))/(2 * s))
    t = perf_counter() - t
    print("time execution: ", t)
    if plot :
        X = np.linspace(a,2*k-a,1000)
        plt.plot(X,f(X))
        for u in A:
            plt.plot(u,f(u),"o")
        plt.plot(k,f(k),"s",label="optimum")
        plt.legend()
        plt.show()
    return k

#returns the minimum of a unidimensional function usingthe Secant method
def Secant_Method(f, fp, lamda, s = 0.01, e = 0.01, plot=False):
    A = []
    t = perf_counter()
    a = lamda
    b = a + s
    while fp(s) < 0:
        a = s
        s *= 2
    b = s
    k = a - ((fp(a) * (b - a)) / (fp(b) - fp(a)))
    while abs(fp(k)) > e:
        if plot :
            A.append(k)
        if fp(k) >= 0 :
            b = k
        else : a = k
        k = a - ((fp(a) * (b - a)) / (fp(b) - fp(a)))
    t = perf_counter() - t
    print("time execution: ", t)
    if plot :
        X = np.linspace(lamda,2*k-lamda,1000)
        plt.plot(X,f(X))
        for u in A:
            plt.plot(u,f(u),"o")
        plt.plot(k,f(k),"s",label="optimum")
        plt.legend()
        plt.show()
    return k


'''
Aims:
To perform a random search for a given problem, to compute a quality measure for the
solution candidates, to make some statistical analysis to a sample set of possible solutions.
Task:
Develop an application in python that has the following functionalities:
1. Randomly creates possible solutions for your assigned problem (Random Candidate
Solution Generator) (25p).
2. Check if a candidate to the solution is indeed a viable solution (25p).
3. Assigns a measure of quality (a positive value) to a candidate solution - where zero
marks a correct one and, as the candidate is more and more farther from the correct
solution the number grows (Fitness Function) (25p).
4. For a sample set (of size n) of random generated solutions, the mean and the standard
deviation of their quality measures is computed (25p)

11. Caravan
A caravan of n camels is traveling through desert in a single line. To break the monotony
of the long traveling days, each other day the camels are settled so it doesn't see the
same camel in front of her before. Generate possibilities to arrange the camels, knowing
how were place in the first day

Solution:
    - initially, suppose the camles were arranged
        0, 1, 2, .. n - 1 (so it's easier)

    - A candidate solution is any possible permutation of
        - the camels (no need for check if a solution is valid)

    - A fitness function can be:
        - nr of camels - nr of camels that see another camel in from - 1
'''

import numpy
import random
import matplotlib.pyplot as pyplot

def generate_camels(n):
    x = range(n)
    random.shuffle(x)
    return x

def fitness_function(p):
    cnt = len(p) - 1
    for i in range(len(p) - 1):
        if p[i] + 1 != p[i + 1]:
            cnt -= 1
    return cnt

def generate_samples(n, m):
    samples = [generate_camels(n) for _ in range(m)]
    fitness = [fitness_function(x) for x in samples]
    print("\n".join([str(samples[i]) + " fitness = " + str(fitness[i]) for i in range(len(samples))]))
    pyplot.hist(fitness)
    pyplot.draw()
    print("mean: %.6f" % numpy.mean(fitness))
    print("std dev: %.6f" % numpy.std(fitness))
    pyplot.show()

def main():
    n = int(input("number of camles: = "))
    m = int(input("sample size: = "))
    generate_samples(n, m)

main()


from random import randint
from tempfile import TemporaryFile

import numpy as np

def _inPlaceQuickSort(A, start, end):
    count = 0
    if start < end:
        pivot = randint(start, end)
        temp = A[end]
        A[end] = A[pivot]
        A[pivot] = temp

        p, count = _inPlacePartition(A, start, end)
        count += _inPlaceQuickSort(A, start, p - 1)
        count += _inPlaceQuickSort(A, p + 1, end)
    return count

def _inPlacePartition(A, start, end):

    count = 0
    pivot = randint(start, end)
    temp = A[end]
    A[end] = A[pivot]
    A[pivot] = temp
    newPivotIndex = start - 1
    for index in range(start, end):

        count += 1
        if A[index] < A[end]:  # check if current val is less than pivot value
            newPivotIndex = newPivotIndex + 1
            temp = A[newPivotIndex]
            A[newPivotIndex] = A[index]
            A[index] = temp

    temp = A[newPivotIndex + 1]
    A[newPivotIndex + 1] = A[end]
    A[end] = temp
    return newPivotIndex + 1, count

outfile = TemporaryFile()
p = 100  # 1000 elements are to be sorted

mu, sigma = 0, 1  # mean and standard deviation
X = np.random.normal(mu, sigma, p)
np.save(outfile, X)
print("The array is")
print(X)

outfile.seek(0)  # using the same array
M = np.load(outfile)
r = len(M) - 1
z = _inPlaceQuickSort(M, 0, r)

print(
    "No of Comparisons for 100 elements selected from a standard normal distribution"
    "is :"
)
print(z)


"""

https://lpsa.swarthmore.edu/Root_Locus/RootLocusWhy.html

"""

import numpy as np
import matplotlib.pyplot as plt
from sympy.abc import *
from sympy.integrals import inverse_laplace_transform
from sympy.solvers import solve
from sympy import *

def eval_transfer_function(G, R, K0, t0, t1):
    G = G.subs(K, K0)
    R = R.subs(K, K0)
    C = inverse_laplace_transform(G*R, s, t)
    x = np.linspace(t0, t1, 100)
    y = np.array([C.subs(t, ts).evalf().subs(0, 1) for ts in x])
    y = np.array([re(ys) for ys in y])
    return (x, y)

"""

Assume transfer function is
G(s) = 1/(s*(s+3))

In a closed-loop feedback system with gain K
we have the following expression
H(s) = C(s)/R(s) = K*G(s) / (1 + K*G(s))

where C(s) is the output and R(s) is the input

Evaluating H(s) gives us
H(s) = K/(s**2 + 3*s + K)

We can control the gain K so we can vary it and look at the output

The input we will feed in this case is a step response (laplace transform is 1/s)

Since it is time consuming to try various K to see what works best, we can find K
another way

Solve for the roots of the poles
For the function

s**2 + 3*s + K gives us the characteristic roots
s = -3/2 +- sqrt(9 - 4K)/2
9 > 4K is overdamped (real roots)
9 < 4K is underdamped (complex roots)
9 = 4K is critically damped
Say we want critical damping, we solve for K to be 4.5

"""
D = s**2 + 3*s + K
G1 = K/D
R1 = 1/s
x1, y1 = eval_transfer_function(G1, R1, 1, 0, 10)
x2, y2 = eval_transfer_function(G1, R1, 10, 0, 10)
x3, y3 = eval_transfer_function(G1, R1, 100, 0, 10)
x4, y4 = eval_transfer_function(G1, R1, 4.5, 0, 10)

print("Roots", solve(D, s))

plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.figure(1)
plt.plot(x1, y1, label='K=1')
plt.plot(x2, y2, label='K=10')
plt.plot(x3, y3, label='K=100')
plt.plot(x4, y4, label='K=4.5')
plt.legend(loc='best')
plt.savefig('simple-gain.png')
plt.show()


#!/usr/bin/env python

import math
import numpy as np

def unitized(r):
    v = np.copy(r)
    nrm = np.linalg.norm(v)
    if math.isclose(nrm, 0.0, rel_tol=1e-14):
        return v
    else:
        return v/np.linalg.norm(v)

def unitize(r):
    r /= np.linalg.norm(r)
    return r

def is_unitized(r):
    return math.isclose(np.linalg.norm(r), 1.0, rel_tol=1e-12)

def perm_tensor():
    '''
    This function returns the permutation tensor.
    '''
    epsilon = np.zeros((3,3,3))
    epsilon[1,2,0] =  1.0
    epsilon[2,1,0] = -1.0
    epsilon[0,2,1] = -1.0
    epsilon[2,0,1] =  1.0
    epsilon[0,1,2] =  1.0
    epsilon[1,0,2] = -1.0
    return epsilon

def cross_mat(r):
    mat = np.zeros((3,3))
    mat[0,1] = -r[2]
    mat[0,2] = r[1]
    mat[1,0] = r[2]
    mat[1,2] = -r[0]
    mat[2,0] = -r[1]
    mat[2,1] = r[0]
    return mat

def decomp_LTL(A, overwrite=False, zero_upper=True, out=None):
    m, n = A.shape
    assert m == n
    if overwrite:
        L = A
    else:
        if out is not None:
            assert n,n == out.shape
            out[:,:] = 0.0
            L = out
        else:
            L = np.zeros((n,n))

    for i in range(n-1,-1,-1):
        L[i,i] = math.sqrt(A[i,i] - np.dot(L[i+1:,i],L[i+1:,i]))
        for j in range(i):
            L[i,j] = (A[i,j] - np.dot(L[i+1:,i], L[i+1:,j]))/L[i,i]

    if overwrite and zero_upper:
        for i in range(n):
            for j in range(i+1,n):
                L[i,j] = 0.0
    return L


# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return np.power(x, 2)

def d_f_1(x):
    return 2.0*x

def d_f_2(f, x, delta=1e-4):
    return (f(x+delta) - f(x-delta)) / (2*delta)

def gradient_descent():
    """梯度下降求最小值
    """

    data = np.arange(-10, 11)
    plt.plot(data, f(data))
    plt.show()

    learning_rate = 0.1
    epochs = 30

    x_init = 10.0
    x = x_init
    for i in range(epochs):
        d_f_x = d_f_1(x)
        # d_f_x = d_f_2(f, x)
        x = x - learning_rate * d_f_x
        print(x)

    print('initial x =', x_init)
    print('arg min f(x) of x =', x)
    print('f(x) =', f(x))

if __name__ == '__main__':
    gradient_descent()


import numpy as np
import numpy.linalg as la
import numpy.polynomial.polynomial as poly
import matplotlib.pyplot as plt

# read data
data = np.loadtxt('data/whData.dat', dtype=np.object)

# Reading and storing columns 0 and 1 and finally converted to numpy.float array
data = data[:, 0:2].astype(np.float)

# Removing outliers
data = data[data[:, 0] > 0]

# create weight vector for train data
wgt = np.copy(data[:, 0])

# create height vector for train data
hgt = np.copy(data[:, 1])

xmin = hgt.min() - 15
xmax = hgt.max() + 15
ymin = wgt.min() - 15
ymax = wgt.max() + 15

def plot_data_and_fit(h, w, x, y):
    plt.plot(h, w, 'ko', x, y, 'r-')
    plt.xlim(xmin, xmax)
    plt.ylim(ymin, ymax)
    plt.show()

def trsf(x):
    return x / 100.

n = 10
x = np.linspace(xmin, xmax, 100)

# method1:
# regression using ployfit
c = poly.polyfit(hgt, wgt, n)
y = poly.polyval(x, c)
plot_data_and_fit(hgt, wgt, x, y)

# method2:
# regression using the Vandermonde matrix and pinv
X = poly.polyvander(hgt, n)
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(x, n), c)
plot_data_and_fit(hgt, wgt, x, y)

# method3:
# regression using the Vandermonde matrix and lstsq
X = poly.polyvander(hgt, n)
c = la.lstsq(X, wgt)[0]
y = np.dot(poly.polyvander(x, n), c)
plot_data_and_fit(hgt, wgt, x, y)

# method4:
# regression on transformed data using the Vandermonde
# matrix and either pinv or lstsq
X = poly.polyvander(trsf(hgt), n)
c = np.dot(la.pinv(X), wgt)
y = np.dot(poly.polyvander(trsf(x), n), c)
plot_data_and_fit(hgt, wgt, x, y)


import numpy as np

class Loss(object):

    def loss(self, y, h_x):
        return 0

    def loss_gradient(self, y, h_x):
        return 0

class LMS(Loss):

    def loss(self, y, h_x):
        return (y - h_x) ** 2

    def loss_gradient(self, y, h_x):
        return h_x - y

class SVM(Loss):

    def loss(self, y, h_x):
        return max(0, 1 - y * h_x)

    def loss_gradient(self, y, h_x):
        if abs(h_x) < 1:
            return -y
        return 0


import matplotlib.pyplot as plt
import numpy as np

N = 8
plt.figure(1, figsize=(9.5, 6))
for k in range(N):
	s = np.exp(-1j*2*np.pi*k/N*np.arange(N))
	plt.subplot(N/2, 2, k+1)
	plt.plot(np.real(s), 'b', lw=1.5)
	plt.axis([0,N-1,-1.5,1.5])
	plt.title(r"$s^{*}_{%s}$"%(k), fontsize=18)
	plt.subplot(N/2, 2, k+1)
	plt.plot(np.imag(s), 'g', lw=1.5)
	plt.axis([0,N-1,-1.5,1.5])

plt.tight_layout()
plt.savefig('complex-sinewaves.png')
plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Jul  8 15:33:55 2021

@author: alessandro
"""

import numpy as np
import numpy.linalg as npl

def matrice(a): return np.array([1, -1, 2, -1, 6, 1, 2, 1, a]).reshape((3, 3))

AS = [matrice(a) for a in range(6, 11)]

# a)
normeinf = [npl.norm(A, np.inf) for A in AS]
print(normeinf)

# b)
massimo = max(normeinf)
indice = 6 + normeinf.index(massimo)
print(f"Norma massima = {massimo} in indice {indice}")

# c)
normeuno = [npl.norm(A, 1) for A in AS]
print(normeuno)
minimo = min(normeuno)
indice = 6 + normeuno.index(minimo)
print(f"Norma minima = {minimo} in indice {indice}")

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


import numpy as np
import unittest
import aiml.lr as lr

class TestLinearRegression(unittest.TestCase):
    def test_compute_cost(self):
        """Testing Linear Regression compute_cost() function. Expected results were given from Octave"""
        x = np.array([[1.0,  0.13000986907454054053, -0.22367518716859130512],
                      [1.0, -0.50418983822317686716, -0.22367518716859130512]])
        y = np.array([[399900],
                      [329900]])

        theta = np.zeros(shape=(3, 1))
        expected_j = 67188505000.0
        j = lr.compute_cost(x, y, theta)
        self.assertAlmostEqual(j, expected_j)

        theta = np.ones(shape=(3, 1))
        expected_j = 67188278890.0
        j = lr.compute_cost(x, y, theta)
        self.assertAlmostEqual(j, expected_j, places=0)

        theta[0, 0] = 89597.909542
        theta[1, 0] = 139.210674
        theta[2, 0] = -8738.019112
        expected_j = 37977534204.0
        j = lr.compute_cost(x, y, theta)
        self.assertAlmostEqual(j, expected_j, places=0)

        theta[0, 0] = 335910.396042
        theta[1, 0] = 100867.715540
        theta[2, 0] = 2874.680525
        expected_j = 1180860698
        j = lr.compute_cost(x, y, theta)
        self.assertAlmostEqual(j, expected_j, places=1)


import numpy as np
import matplotlib.pyplot as plt

def f1(x, y):
    """ Bottom boundary
    """
    return 0

def f2(x, y):
    """ Left boundary
    """
    return 0

def f3(x, y):
    """ Right boundary
    """
    return 0

def f4(x, y):
    """ Top boundary
    """
    return 10 * np.sin(np.pi * x)

def save_fig(x, y, U, file_name):
    """ Save the figure of the approxiamte solution.

    Args:
        x: ndarray, the split of x interval
        y: ndarray, the split of y interval
        U: ndarray, the value of the coordinates
        file_name: string,  the picture name to be saved
    """
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    X, Y = np.meshgrid(x, y)
    ax.plot_surface(X, Y, U)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    ax.set_title('Approximate solution of Laplace equation by nine-points')
    plt.savefig(file_name)

def nine_points_difference_scheme(x_inte, y_inte, M, N, func1, func2, func3, func4):
    """ Solve Laplace equation by nine points difference scheme.

    Args:
        x_inte: list/ndarray, boundary of x
        y_inte: list/ndarray, boundary of y
        M: int, number of points in x-axis
        N: int, number of points in y-axis
        func1: function object, bottom boundary
        func2: function object, left boundary
        func3: function object, right boundary
        func4: function object, top boundary
    """
    # cofficients matrix
    A1 = np.diag(-20*np.ones(N-1)) + np.diag(4*np.ones(N-2), 1) + np.diag(4*np.ones(N-2), -1)
    A2 = np.diag(np.ones(N-2), 1) + np.diag(np.ones(N-2), -1) + np.diag(4*np.ones(N-1))
    A = np.kron(np.diag(np.ones(N-2), -1), A2) + np.kron(np.diag(np.ones(N-2), 1), A2)+ np.kron(np.diag(np.ones(N-1)), A1)

    x = np.linspace(x_inte[0], x_inte[1], M+1)
    y = np.linspace(y_inte[0], y_inte[1], N+1)
    # boundary condition
    b = np.zeros((M-1, N-1))
    for i in range(M-1):
        for j in range(N-1):
            if i == 0:
                if j == 0:
                    b[i, j] = -func1(x[i+2], y[j]) - 4*func1(x[i+1], y[j]) - func1(x[i], y[j]) - 4*func2(x[i], y[j+1]) - func2(x[i], y[j+2])
                elif j == N-2:
                    b[i, j] = -func2(x[i], y[j]) - 4*func2(x[i], y[j+1]) - func2(x[i], y[j+2]) - 4*func4(x[i+1], y[j+2]) - func4(x[i+2], y[i+2])
                else:
                    b[i, j] = -func2(x[i], y[j]) - 4*func2(x[i], y[j+1]) - func2(x[i], y[j+2])
            elif i == N-2:
                if j == 0:
                    b[i, j] = -func1(x[i], y[j]) - 4*func1(x[i+1], y[j]) - func1(x[i+2], y[j]) - 4*func3(x[i+2], y[i+1]) - func3(x[i+2], y[i+2])
                elif j == N-2:
                    b[i, j] = -func3(x[i+2], y[j]) - 4*func3(x[i+2], y[j+1]) - func3(x[i+2], y[j+2]) - 4*func4(x[i+1], y[j+2]) - func4(x[i], y[j+2])
                else:
                    b[i, j] = -func3(x[i+2], y[j]) - 4*func3(x[i+2], y[j+1]) - func3(x[i+2], y[j+2])
            else:
                if j == 0:
                    b[i, j] = -func1(x[i], y[j]) - 4*func1(x[i+1], y[j]) - func1(x[i+2], y[j])
                elif j == N-2:
                    b[i, j] = -func4(x[i], y[j+2]) - 4*func4(x[i+1], y[j+2]) - func4(x[i+2], y[j+2])
                else:
                    b[i, j] = 0

    U = (np.linalg.inv(A) @ b.T.reshape(-1, 1)).reshape(M-1, N-1)

    # show approximate solution
    x1 = np.arange(x_inte[0]+(x_inte[1]-x_inte[0])/M, x_inte[1], (x_inte[1]-x_inte[0])/M)
    y1 = np.arange(y_inte[0]+(y_inte[1]-y_inte[0])/N, y_inte[1], (y_inte[1]-y_inte[0])/N)
    save_fig(x1, y1, U, 'figure_nine_points.png')

if __name__ == '__main__':
    x_inte = y_inte = [0, 1]
    M = N = 100
    nine_points_difference_scheme(x_inte, y_inte, M, N, f1, f2, f3, f4)


"""
super fast single thread numpy implementation
calculates all primes in the first n natural numbers
based on that all primes greater than 3 are either 2k-1 or 2k+1 (k>0)
author: Perry Deng pxdeng@pm.me
date: 02.15.19
"""

import numpy as np
import math

def calculate_primes(n):
  """
  calculates all primes in the first n natural numbers
  based on that all primes greater than 3 are either 2k-1 or 2k+1 (k>0),
  that square roots of primes cannot be factored by primes smaller than themselves,
  and that the number of primes in the first n integers can be approximated by
  n / ln(n)
  :param n: first n natural numbers
  :return: numpy array of primes in first n natural numbers
  """
  largest = (n - 1) // 6 # number of possible values of 2k +- 1 up to n
  temp = (np.arange(1, largest + 1, dtype=np.uint32)) * 6 # [1, 2, ..., largest]
  candidates =np.empty((largest, 2), dtype=np.uint32)
  candidates[:, 0] = temp - 1
  candidates[:, 1] = temp + 1
  candidates = candidates.flatten() # all values of 2k +- 1 up to n
  total_candidates = candidates.shape[0]
  prime_theorem_divisor = math.log(n) / 1.25
  primes = np.empty(int(n // prime_theorem_divisor), dtype=np.uint32)
  primes[0] = 2
  primes[1] = 3
  num_primes = 2
  up_to = 0
  for i in range(total_candidates):
    candidate = candidates[i]
    while primes[up_to] < math.sqrt(candidate):
      up_to += 1
    remainders = np.mod(candidate, primes[0:up_to + 1])
    prime = np.all(remainders) # true if does not contain 0
    if prime:
      primes[num_primes] = candidate
      num_primes += 1
  return primes[0:num_primes]


import numpy as np

def affine_forward(x, w, b):
  """
  Computes the forward pass for an affine (fully-connected) layer.

  The input x has shape (N, d_1, ..., d_k) and contains a minibatch of N
  examples, where each example x[i] has shape (d_1, ..., d_k). We will
  reshape each input into a vector of dimension D = d_1 * ... * d_k, and
  then transform it to an output vector of dimension M.

  Inputs:
  - x: A numpy array containing input data, of shape (N, d_1, ..., d_k)
  - w: A numpy array of weights, of shape (D, M)
  - b: A numpy array of biases, of shape (M,)

  Returns a tuple of:
  - out: output, of shape (N, M)
  - cache: (x, w, b)
  """

  # ================================================================ #
  # YOUR CODE HERE:
  #   Calculate the output of the forward pass.  Notice the dimensions
  #   of w are D x M, which is the transpose of what we did in earlier
  #   assignments.
  # ================================================================ #
  x_shapes = x.shape
  D = np.prod(x_shapes[1:])
  N = x_shapes[0]
  X = x.reshape(N,D)
  out = X@w+b
  # ================================================================ #
  # END YOUR CODE HERE
  # ================================================================ #

  cache = (x, w, b)
  return out, cache

def affine_backward(dout, cache):
  """
  Computes the backward pass for an affine layer.

  Inputs:
  - dout: Upstream derivative, of shape (N, M)
  - cache: Tuple of:
    - x: A numpy array containing input data, of shape (N, d_1, ..., d_k)
    - w: A numpy array of weights, of shape (D, M)
    - b: A numpy array of biases, of shape (M,)

  Returns a tuple of:
  - dx: Gradient with respect to x, of shape (N, d1, ..., d_k)
  - dw: Gradient with respect to w, of shape (D, M)
  - db: Gradient with respect to b, of shape (M,)
  """
  x, w, b = cache
  dx, dw, db = None, None, None

  # ================================================================ #
  # YOUR CODE HERE:
  #   Calculate the gradients for the backward pass.
  # Notice:
  #   dout is N x M
  #   dx should be N x d1 x ... x dk; it relates to dout through multiplication with w, which is D x M
  #   dw should be D x M; it relates to dout through multiplication with x, which is N x D after reshaping
  #   db should be M; it is just the sum over dout examples
  # ================================================================ #
  x_shapes = x.shape
  D = np.prod(x_shapes[1:])
  N = x_shapes[0]
  x_reshape = x.reshape(N,D)
  dx = (dout@w.T).reshape(x_shapes)
  dw = x_reshape.T@dout
  db = dout.T@np.ones((N,))
  # ================================================================ #
  # END YOUR CODE HERE
  # ================================================================ #

  return dx, dw, db

def relu_forward(x):
  """
  Computes the forward pass for a layer of rectified linear units (ReLUs).

  Input:
  - x: Inputs, of any shape

  Returns a tuple of:
  - out: Output, of the same shape as x
  - cache: x
  """
  # ================================================================ #
  # YOUR CODE HERE:
  #   Implement the ReLU forward pass.
  # ================================================================ #
  out = (x>0)*x
  # ================================================================ #
  # END YOUR CODE HERE
  # ================================================================ #

  cache = x
  return out, cache

def relu_backward(dout, cache):
  """
  Computes the backward pass for a layer of rectified linear units (ReLUs).

  Input:
  - dout: Upstream derivatives, of any shape
  - cache: Input x, of same shape as dout

  Returns:
  - dx: Gradient with respect to x
  """
  x = cache

  # ================================================================ #
  # YOUR CODE HERE:
  #   Implement the ReLU backward pass
  # ================================================================ #
  dx = dout*(x>0)
  # ================================================================ #
  # END YOUR CODE HERE
  # ================================================================ #

  return dx

def batchnorm_forward(x, gamma, beta, bn_param):
  """
  Forward pass for batch normalization.

  During training the sample mean and (uncorrected) sample variance are
  computed from minibatch statistics and used to normalize the incoming data.
  During training we also keep an exponentially decaying running mean of the mean
  and variance of each feature, and these averages are used to normalize data
  at test-time.

  At each timestep we update the running averages for mean and variance using
  an exponential decay based on the momentum parameter:

  running_mean = momentum * running_mean + (1 - momentum) * sample_mean
  running_var = momentum * running_var + (1 - momentum) * sample_var

  Note that the batch normalization paper suggests a different test-time
  behavior: they compute sample mean and variance for each feature using a
  large number of training images rather than using a running average. For
  this implementation we have chosen to use running averages instead since
  they do not require an additional estimation step; the torch7 implementation
  of batch normalization also uses running averages.

  Input:
  - x: Data of shape (N, D)
  - gamma: Scale parameter of shape (D,)
  - beta: Shift paremeter of shape (D,)
  - bn_param: Dictionary with the following keys:
    - mode: 'train' or 'test'; required
    - eps: Constant for numeric stability
    - momentum: Constant for running mean / variance.
    - running_mean: Array of shape (D,) giving running mean of features
    - running_var Array of shape (D,) giving running variance of features

  Returns a tuple of:
  - out: of shape (N, D)
  - cache: A tuple of values needed in the backward pass
  """
  mode = bn_param['mode']
  eps = bn_param.get('eps', 1e-5)
  momentum = bn_param.get('momentum', 0.9)

  N, D = x.shape
  running_mean = bn_param.get('running_mean', np.zeros(D, dtype=x.dtype))
  running_var = bn_param.get('running_var', np.zeros(D, dtype=x.dtype))

  out, cache = None, None
  if mode == 'train':

    # ================================================================ #
    # YOUR CODE HERE:
    #   A few steps here:
    #     (1) Calculate the running mean and variance of the minibatch.
    #     (2) Normalize the activations with the running mean and variance.
    #     (3) Scale and shift the normalized activations.  Store this
    #         as the variable 'out'
    #     (4) Store any variables you may need for the backward pass in
    #         the 'cache' variable.
    # ================================================================ #

    #(1)
    x_bar = np.mean(x, axis=0)
    sigma2_x = np.var(x,axis=0)
    running_mean = momentum * running_mean + (1 - momentum) * x_bar
    running_var  = momentum * running_var  + (1 - momentum) * sigma2_x

    #(2)
    x_hat = x - x_bar
    x_hat = x_hat/np.sqrt(sigma2_x+eps)

    #(3)
    out = gamma*x_hat + beta

    #(4)
    cache = {}
    cache['xhat'] = x_hat
    cache['gamma']= gamma
    cache['sigma2'] = sigma2_x
    cache['eps'] = eps
    cache['xbar'] = x_bar
    cache['x'] = x
    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #

  elif mode == 'test':

    # ================================================================ #
    # YOUR CODE HERE:
    #   Calculate the testing time normalized activation.  Normalize using
    #   the running mean and variance, and then scale and shift appropriately.
    #   Store the output as 'out'.
    # ================================================================ #

    x_hat = x - running_mean
    x_hat = x_hat/np.sqrt(running_var+eps)

    out = gamma*x_hat + beta

    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #

  else:
    raise ValueError('Invalid forward batchnorm mode "%s"' % mode)

  # Store the updated running means back into bn_param
  bn_param['running_mean'] = running_mean
  bn_param['running_var'] = running_var

  return out, cache

def batchnorm_backward(dout, cache):
  """
  Backward pass for batch normalization.

  For this implementation, you should write out a computation graph for
  batch normalization on paper and propagate gradients backward through
  intermediate nodes.

  Inputs:
  - dout: Upstream derivatives, of shape (N, D)
  - cache: Variable of intermediates from batchnorm_forward.

  Returns a tuple of:
  - dx: Gradient with respect to inputs x, of shape (N, D)
  - dgamma: Gradient with respect to scale parameter gamma, of shape (D,)
  - dbeta: Gradient with respect to shift parameter beta, of shape (D,)
  """
  dx, dgamma, dbeta = None, None, None

  # ================================================================ #
  # YOUR CODE HERE:
  #   Implement the batchnorm backward pass, calculating dx, dgamma, and dbeta.
  # ================================================================ #
  N,D = dout.shape
  dbeta = np.ones(N,)@dout
  dgamma = np.ones(N,)@(dout*cache['xhat'])
  dxhat = dout*cache['gamma']
  xc = cache['x']-cache['xbar']
  da = 1/(np.sqrt(cache['sigma2']+cache['eps']))*dxhat
  dsigma2 = np.ones(N,)@((-0.5*1/np.power(cache['sigma2']+cache['eps'],1.5))*(xc)*dxhat)
  du =  -1/(np.sqrt(cache['sigma2']+cache['eps']))*(np.ones(N,)@dxhat) - dsigma2*(2/N**2)*(np.ones(N,)@(xc))
  dx = da +(2/N)*(cache['x'] - cache['xbar'])*dsigma2 +(1/N)*du
  # ================================================================ #
  # END YOUR CODE HERE
  # ================================================================ #

  return dx, dgamma, dbeta

def dropout_forward(x, dropout_param):
  """
  Performs the forward pass for (inverted) dropout.

  Inputs:
  - x: Input data, of any shape
  - dropout_param: A dictionary with the following keys:
    - p: Dropout parameter. We drop each neuron output with probability p.
    - mode: 'test' or 'train'. If the mode is train, then perform dropout;
      if the mode is test, then just return the input.
    - seed: Seed for the random number generator. Passing seed makes this
      function deterministic, which is needed for gradient checking but not in
      real networks.

  Outputs:
  - out: Array of the same shape as x.
  - cache: A tuple (dropout_param, mask). In training mode, mask is the dropout
    mask that was used to multiply the input; in test mode, mask is None.
  """
  p, mode = dropout_param['p'], dropout_param['mode']
  if 'seed' in dropout_param:
    np.random.seed(dropout_param['seed'])

  mask = None
  out = None

  if mode == 'train':
    # ================================================================ #
    # YOUR CODE HERE:
    #   Implement the inverted dropout forward pass during training time.
    #   Store the masked and scaled activations in out, and store the
    #   dropout mask as the variable mask.
    # ================================================================ #
    mask = (np.random.rand(*x.shape) > p) / (1-p)
    out = x*mask

    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #

  elif mode == 'test':

    # ================================================================ #
    # YOUR CODE HERE:
    #   Implement the inverted dropout forward pass during test time.
    # ================================================================ #

    out =x

    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #

  cache = (dropout_param, mask)
  out = out.astype(x.dtype, copy=False)

  return out, cache

def dropout_backward(dout, cache):
  """
  Perform the backward pass for (inverted) dropout.

  Inputs:
  - dout: Upstream derivatives, of any shape
  - cache: (dropout_param, mask) from dropout_forward.
  """
  dropout_param, mask = cache
  mode = dropout_param['mode']

  dx = None
  if mode == 'train':
    # ================================================================ #
    # YOUR CODE HERE:
    #   Implement the inverted dropout backward pass during training time.
    # ================================================================ #

    dx = mask*dout

    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #
  elif mode == 'test':
    # ================================================================ #
    # YOUR CODE HERE:
    #   Implement the inverted dropout backward pass during test time.
    # ================================================================ #

    # We should not be doing backprop at test time so we can pass here
    pass

    # ================================================================ #
    # END YOUR CODE HERE
    # ================================================================ #
  return dx

def svm_loss(x, y):
  """
  Computes the loss and gradient using for multiclass SVM classification.

  Inputs:
  - x: Input data, of shape (N, C) where x[i, j] is the score for the jth class
    for the ith input.
  - y: Vector of labels, of shape (N,) where y[i] is the label for x[i] and
    0 <= y[i] < C

  Returns a tuple of:
  - loss: Scalar giving the loss
  - dx: Gradient of the loss with respect to x
  """
  N = x.shape[0]
  correct_class_scores = x[np.arange(N), y]
  margins = np.maximum(0, x - correct_class_scores[:, np.newaxis] + 1.0)
  margins[np.arange(N), y] = 0
  loss = np.sum(margins) / N
  num_pos = np.sum(margins > 0, axis=1)
  dx = np.zeros_like(x)
  dx[margins > 0] = 1
  dx[np.arange(N), y] -= num_pos
  dx /= N
  return loss, dx

def softmax_loss(x, y):
  """
  Computes the loss and gradient for softmax classification.

  Inputs:
  - x: Input data, of shape (N, C) where x[i, j] is the score for the jth class
    for the ith input.
  - y: Vector of labels, of shape (N,) where y[i] is the label for x[i] and
    0 <= y[i] < C

  Returns a tuple of:
  - loss: Scalar giving the loss
  - dx: Gradient of the loss with respect to x
  """

  probs = np.exp(x - np.max(x, axis=1, keepdims=True))
  probs /= np.sum(probs, axis=1, keepdims=True)
  N = x.shape[0]
  loss = -np.sum(np.log(probs[np.arange(N), y])) / N
  dx = probs.copy()
  dx[np.arange(N), y] -= 1
  dx /= N
  return loss, dx


# Numerical Dynamics in Three Dimensions

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

# Defining Variables
G = 6.67e-11
M = 6.42e23
R = 3.3895e6
m = 100

# simulation time, timestep and time
t_max = 100000
dt = 100
t_array = np.arange(0, t_max, dt)

# initialise empty lists to record trajectories
position_matrix = np.zeros(shape=(len(t_array),3))
velocity_matrix = np.zeros(shape=(len(t_array),3))

# Initial Conditions
x0 = 0
y0 = 1e7
z0 = 0
# Scenario 1
#vx = 0
# Scenario 2
vx = np.sqrt((G*M)/y0)
# Scenario 3
#vx = 2500
# Scenario 4
#vx = np.sqrt((2*G*M)/y0)
vy = 0
vz = 0

# 3-element numpy matrices
position_matrix[0] = ([0, 1e7, 0])
velocity_matrix[0] = ([np.sqrt((G*M)/np.linalg.norm(position_matrix[0])), 0, 0])
position_matrix[1] = position_matrix[0] + dt*velocity_matrix[0] + 0.5*dt*dt*(-G*M*position_matrix[0]/math.pow(np.linalg.norm(position_matrix[0]), 3))

for t in t_array:
    for i in range ( 1, len(t_array) - 1 ) :
        if ( np.linalg.norm(position_matrix[i]) >= R  ) :

            # calculate new position and velocity
            acceleration = (-G*M*position_matrix[i]/math.pow(np.linalg.norm(position_matrix[i]), 3))
            position_matrix[i+1] = ( 2 * position_matrix[i] ) - position_matrix[i-1] + ((dt**2) * acceleration)
            velocity_matrix[i+1] = (position_matrix[i+1] - position_matrix[i]) / ( dt )
            i += 1

        else:
            break

position_y_final = []
position_x_final = []

for i in position_matrix :
    position_y_final.append(i[1])
    position_x_final.append(i[0])

# Scenario 1 : Straight Down Descent
# Set graph to altitude (y) against time
# Set vx variable to 0
"""
plt.figure(1)
plt.clf()
plt.xlabel('time (s)')
plt.grid()
plt.plot(t_array, position_y_final, label='altitude (m)')
plt.legend()
plt.show()

"""

# Scenario 2 : Circular Orbit
# Set graph to y-coordinate against x-coordinate
# Set vx variable to np.sqrt((G*M)/y0)

# Scenario 3 : Elliptical Orbit
# Set graph to y-coordinate against x-coordinate
# Set vx variable to anywhere in between Scenarios 2 and 4

# Scenario 4 : Hyperbolic Escape
# Set graph to y-coordinate against x-coordinate
# Set vx variable to np.sqrt((2*G*M)/y0)

plt.figure(2)
plt.clf()
plt.xlabel('y-coordinate (m)')
plt.grid()
plt.plot(position_y_final, position_x_final, label='x-coordinate (m)')
plt.legend()
plt.show()


from scipy.stats.distributions import chi2

#
# def ipte_formula(iterations_or_ipte, number_of_incidents, confidence):
#     chi_square_inverse_right_tailed = chi2.ppf(confidence, df=2 * (number_of_incidents + 1))
#     return chi_square_inverse_right_tailed * (1000 / (iterations_or_ipte * 2))
#

def calculate_iterations_required(required_ipte, number_of_incidents, confidence=0.9):
    chi_square_inverse_right_tailed = chi2.ppf(confidence, df=2 * (number_of_incidents + 1))
    return chi_square_inverse_right_tailed * (1000 / (required_ipte * 2))
    # return ipte_formula(required_ipte, number_of_incidents, 0.9)

def calculate_ipte(number_of_iterations, number_of_incidents, confidence=0.9):
    chi_square_inverse_right_tailed = chi2.ppf(confidence, df=2 * (number_of_incidents + 1))
    return chi_square_inverse_right_tailed * (1000 / (number_of_iterations * 2))

# Test
# def test_util(number_of_incidents=0, number_of_iterations=576, confidence_interval=0.9, required_ipte=4.0):
#     print("Number of incidents=", number_of_incidents)
#     print("Total iterations=", number_of_iterations)
#     print("Confidence Interval(2 sided)=", confidence_interval)
#     ipti = calculate_ipte(number_of_iterations, number_of_incidents)
#     number_of_iterations_required = calculate_iterations_required(required_ipte, number_of_incidents)
#     print("IPTI: ", ipti, " \nNumber of iterations required to get this IPTI: ", number_of_iterations_required)
# test_util()