def circumsphere(vertices):
    '''
    @param vertices: an array of simplices
    @returns: radius of circumsphere, coordinates of circumsphere
    @rtype: tuple
    '''

    # based on https://westy31.home.xs4all.nl/Circumsphere/ncircumsphere.htm and
    # https://codereview.stackexchange.com/questions/77593/calculating-the-volume-of-a-tetrahedron

    from scipy.spatial import distance

    # distances
    squared_dists = distance.pdist(vertices, metric='sqeuclidean')
    n = distance.num_obs_y(squared_dists)

    # add ones and a zero to make a Cayley-Menger matrix.
    squared_dists_mat = distance.squareform(squared_dists)
    with_border = np.insert(np.insert(squared_dists_mat, 0, values=1, axis=1), 0, values=1, axis=0)
    np.fill_diagonal(with_border, 0)

    #the first diagonal element of its inverse holds -2*r*r
    #and first row / first column hold barycentric coordinates of the sphere
    inv = np.linalg.inv(with_border)
    r = math.sqrt(inv[0][0] / -2)
    barycentric_coodinates = inv[1:, 0]
    return r, bary2cart(vertices, barycentric_coodinates)

def bary2cart(simplex, point):
    simplex, point = np.asarray(simplex), np.asarray(point)
    return np.dot(simplex.T, point)

def check_point_in_sphere(sphere, r, point):
    '''
    @param sphere: coodinates of a shpere
    @type sphere: list
    @param r: raduius of a sphere
    @type r: float
    @param point: coordinates of a point to check
    @type point: list
    @returns: boolean value
    @rtype: bool
    '''
    sphere, point = np.asarray(sphere), np.asarray(point)
    if np.sum((sphere - point)**2) <= r ** 2:
        return True
    else:
        return False
'''
Example:
pentachoron = [[1, 1, 1, -1.0 / math.sqrt(5)], [1, -1, -1, -1.0 / math.sqrt(5)], [-1, 1, -1, -1.0 / math.sqrt(
    5)], [-1, -1, 1, -1.0 / math.sqrt(5)], [0, 0, 0, math.sqrt(5) - 1.0 / math.sqrt(5)]]
tetrahedron = [[1, 1, 1], [1, -1, -1], [-1, 1, -1], [-1, -1, 1]]
triangle = [(3, 3), (1, 3), (1, 1)]

print circumsphere(pentachoron)
print circumsphere(tetrahedron)
print circumsphere(triangle)'''


# %%
from pylab import *
from scipy.linalg import lstsq
from scipy.special import jn

# %% [markdown]
# ##### Constants

# %%
N = 101  # no of data points
K = 9    # no of sets of data with varying noise

A_true, B_true = 1.05, -0.105 # true values of A and B

DATAFILE = "fitting.dat"

# %% [markdown]
# ### 1. Generate the data points

# %%
""" run generate_data.py to generate the data """

# %% [markdown]
# ### 2. Load data

# %%
raw_data = loadtxt(DATAFILE)

Time = raw_data[:, 0]
F = raw_data[:, 1:]

# %% [markdown]
# ### 3. The function and the noise

# %%
def g(t, A=A_true, B=B_true):
    return A * jn(2, t) + B * t

F_true = g(Time)
Sigma = logspace(-1, -3, K)  # vector of stdevs of noise

# %% [markdown]
# ### 4. Plot the data

# %%
figure(figsize=(9, 7))
grid(True)
title("Q4: Data to be fitted to theory", size=16)
xlabel("$t$   $\longrightarrow$", size=16)
ylabel("$f(t)+noise$   $\longrightarrow$", size=16)
plot(Time, F)
plot(Time, F_true, color='black', lw=2)
legend([f"$\sigma_{i + 1}$ = {s:.3f}" for i, s in enumerate(Sigma)] + ["True Value"])
show()

# %% [markdown]
# ### 5. Plot the first column with error bars

# %%
figure(figsize=(9, 7))
grid(True)
title("Q5: Data points for $\sigma = 0.10$ along with exact function", size=16)
xlabel("$t$   $\longrightarrow$", size=16)
ylabel("$f(t)+noise$   $\longrightarrow$", size=16)
errorbar(Time[::5], F[::5, 0], Sigma[0], fmt="ro")
plot(Time, F_true, color='black', lw=2)
legend(["$f(t)$", "Errorbar"])
show()

# %% [markdown]
# ### 6. Confirm that the two vectors are equal

# %%
M = c_[jn(2, Time), Time]
assert allclose(F_true.reshape(N, 1), matmul(M, [[A_true], [B_true]]))

# %% [markdown]
# ### 7. Mean Squared Error for various A and B

# %%
# 0 to 2 in steps of 0.1 (including endpoint)
numA = int((2 - 0) / 0.1) + 1
A = linspace(0, 2, numA)

# -0.2 to 0 in steps of 0.01 (including endpoint)
numB = int((0 - -0.2) / 0.01) + 1
B = linspace(-0.2, 0, numB)

eps = zeros((numA, numB))
for i in range(numA):
    for j in range(numB):
        eps[i][j] = mean((F[:, 0] - g(Time, A[i], B[j])) ** 2)

# %% [markdown]
# ### 8. Plot the MSE

# %%
figure(figsize=(9, 7))
grid(True)
title("Q8: Contour plot of $\epsilon_{ij}$", size=16)
xlabel("$A$   $\longrightarrow$", size=16)
ylabel("$B$   $\longrightarrow$", size=16)
clabel(contour(A, B, eps, 15))
plot([A_true], [B_true], "ro")
annotate("Exact location", xy=(A_true, B_true), size=16)
show()

# %% [markdown]
# ### 9. Obtain best estimate of A and B

# %%
print("Best estimate:   A = {}, B = {}".format(*lstsq(M, F[:, 0])[0]))

# %% [markdown]
# ### 10. Plot the error in A and B for different stdev of noise

# %%
Aerr, Berr = abs(lstsq(M, F)[0] - [[A_true], [B_true]])

figure(figsize=(9, 7))
grid(True)
title("Q10: Variation of error with noise", size=16)
xlabel("$Noise$ $standard$ $deviation$   $\longrightarrow$", size=16)
ylabel("$Error$   $\longrightarrow$", size=16)
plot(Sigma, Aerr, 'o', linestyle="dashed")
plot(Sigma, Berr, 'o', linestyle="dashed")
legend(["Aerr", "Berr"])
show()

# %% [markdown]
# ### 11. Replot using log-log scale

# %%
figure(figsize=(9, 7))
grid(True)
title("Q11: Variation of error with noise", size=16)
xlabel("$\sigma_n$   $\longrightarrow$", size=16)
ylabel("$Error$   $\longrightarrow$", size=16)
xscale("log")
yscale("log")
errorbar(Sigma, Aerr, Sigma, fmt="o")
errorbar(Sigma, Berr, Sigma, fmt="o")
legend(["Aerr", "Berr"])
show()


import numpy as np

# linear normalization
def linear_normalization(matrix, types):
    """
    Normalize decision matrix using linear normalization method.

    Parameters
    -----------
        matrix : ndarray
            Decision matrix with m alternatives in rows and n criteria in columns
        types : ndarray
            Criteria types. Profit criteria are represented by 1 and cost by -1.

    Returns
    --------
        ndarray
            Normalized decision matrix

    Examples
    ----------
    >>> nmatrix = linear_normalization(matrix, types)
    """

    x_norm = np.zeros(np.shape(matrix))
    x_norm[:, types == 1] = matrix[:, types == 1] / (np.amax(matrix[:, types == 1], axis = 0))
    x_norm[:, types == -1] = np.amin(matrix[:, types == -1], axis = 0) / matrix[:, types == -1]
    return x_norm

# min-max normalization
def minmax_normalization(matrix, types):
    """
    Normalize decision matrix using minimum-maximum normalization method.

    Parameters
    -----------
        matrix : ndarray
            Decision matrix with m alternatives in rows and n criteria in columns
        types : ndarray
            Criteria types. Profit criteria are represented by 1 and cost by -1.

    Returns
    --------
        ndarray
            Normalized decision matrix

    Examples
    ----------
    >>> nmatrix = minmax_normalization(matrix, types)
    """

    x_norm = np.zeros((matrix.shape[0], matrix.shape[1]))
    x_norm[:, types == 1] = (matrix[:, types == 1] - np.amin(matrix[:, types == 1], axis = 0)
                             ) / (np.amax(matrix[:, types == 1], axis = 0) - np.amin(matrix[:, types == 1], axis = 0))

    x_norm[:, types == -1] = (np.amax(matrix[:, types == -1], axis = 0) - matrix[:, types == -1]
                           ) / (np.amax(matrix[:, types == -1], axis = 0) - np.amin(matrix[:, types == -1], axis = 0))

    return x_norm

# max normalization
def max_normalization(matrix, types):
    """
    Normalize decision matrix using maximum normalization method.

    Parameters
    -----------
        matrix : ndarray
            Decision matrix with m alternatives in rows and n criteria in columns
        types : ndarray
            Criteria types. Profit criteria are represented by 1 and cost by -1.

    Returns
    --------
        ndarray
            Normalized decision matrix

    Examples
    ----------
    >>> nmatrix = max_normalization(matrix, types)
    """

    maximes = np.amax(matrix, axis = 0)
    matrix = matrix / maximes
    matrix[:, types == -1] = 1 - matrix[:, types == -1]
    return matrix

# sum normalization
def sum_normalization(matrix, types):
    """
    Normalize decision matrix using sum normalization method.

    Parameters
    -----------
        matrix : ndarray
            Decision matrix with m alternatives in rows and n criteria in columns
        types : ndarray
            Criteria types. Profit criteria are represented by 1 and cost by -1.

    Returns
    --------
        ndarray
            Normalized decision matrix

    Examples
    ----------
    >>> nmatrix = sum_normalization(matrix, types)
    """

    x_norm = np.zeros((matrix.shape[0], matrix.shape[1]))
    x_norm[:, types == 1] = matrix[:, types == 1] / np.sum(matrix[:, types == 1], axis = 0)
    x_norm[:, types == -1] = (1 / matrix[:, types == -1]) / np.sum((1 / matrix[:, types == -1]), axis = 0)

    return x_norm

# vector normalization
def vector_normalization(matrix, types):
    """
    Normalize decision matrix using vector normalization method.

    Parameters
    -----------
        matrix : ndarray
            Decision matrix with m alternatives in rows and n criteria in columns
        types : ndarray
            Criteria types. Profit criteria are represented by 1 and cost by -1.

    Returns
    --------
        ndarray
            Normalized decision matrix

    Examples
    -----------
    >>> nmatrix = vector_normalization(matrix, types)
    """

    x_norm = np.zeros((matrix.shape[0], matrix.shape[1]))
    x_norm[:, types == 1] = matrix[:, types == 1] / (np.sum(matrix[:, types == 1] ** 2, axis = 0))**(0.5)
    x_norm[:, types == -1] = 1 - (matrix[:, types == -1] / (np.sum(matrix[:, types == -1] ** 2, axis = 0))**(0.5))

    return x_norm


import numpy as np
from sklearn.metrics import mean_squared_error
import sklearn.metrics

#
# Normalized Discounted Cumulative Gain metric
#
def ndcg_score(y_true, y_pred, k=5):
    """Normalized discounted cumulative gain (NDCG) at rank k

    This specific score function operates under the assumption that the
    relevance for the correct label is 1 and the relevance for all other labels
    is 0.

    Parameters
    ----------
    y_true : array-like, shape = [n_samples,]
        Ground truth (true relevance labels). These must be encoded to integer
        values, by using LabelEncoder, for example.

    y_pred : array-like, shape = [n_samples, n_classes]
        Probability predictions for each class.

    k : int
        Rank.

    Returns
    -------
    NDCG @k : float
    """
    y_pred_topk = np.fliplr(np.argsort(y_pred))[:,:k]
    pos = np.where(np.sum(y_pred_topk==y_true[:,None],1) > 0,
                 np.argmax(y_pred_topk==y_true[:,None],1),
                 np.nan)
    scores = [1.0/np.log2((i+1)+1) if not np.isnan(i) else 0 for i in pos]
    return np.mean(scores)

ndcg_scorer = sklearn.metrics.make_scorer(ndcg_score,
    greater_is_better=True, needs_proba=True)

#
# Root mean squared log error
#

def rmsle_score(y_true, y_pred, **kwargs):
    return np.sqrt(mean_squared_error(np.log(y_pred + 1), np.log(y_true + 1),
        **kwargs))

rmsle_scorer = sklearn.metrics.make_scorer(rmsle_score,
    greater_is_better=False, needs_proba=False)


#!/usr/bin/env python3
# coding=utf-8

import numpy as np

## Function to get the givens_rotation_Qk matrix for givens rotation
def givens_rotation_Qk(k,A):
    Q = np.eye(len(A))
    alfa_k = A[k,k]
    beta_k = A[k+1,k]
    ck = alfa_k/(np.sqrt((alfa_k**2)+(beta_k**2)))
    sk = -(beta_k)/(np.sqrt((alfa_k**2)+(beta_k**2)))
    Q[k,k] = ck
    Q[k,k+1] = -sk
    Q[k+1,k] = sk
    Q[k+1,k+1] = ck
    return Q

## Function which returns a matrix after a givens rotation
def QR_fatoration(A):
    R = A
    matrix_i_size = len(A)
    Q =np.eye(matrix_i_size)
    Q_iteration_size = matrix_i_size - 1
    for i in range (0, Q_iteration_size,1):
        Q = Q@np.transpose(givens_rotation_Qk(i,R))
        R = givens_rotation_Qk(i,R)@R
    return [R,Q]

def wilkinson_heuristics(A,n):
    get_sgnd = lambda d: 1 if d >= 0 else -1
    alfa_ant = A[n-2,n-2]
    alfa = A[n-1,n-1]
    beta = A[(n-2)+1,n-2]
    dk = (alfa_ant - alfa)/2
    uk = alfa + dk - get_sgnd(dk)*(np.sqrt((dk**2)+(beta**2)))
    return [uk,beta]

def QR_algorithm(A, erro = 1/1000000, spectral_shift = True):
    #round_parameter = len(str(int(1/erro)))
    A = A.copy()
    get_uk = lambda A,n,k,spectral_shift: wilkinson_heuristics(A,n)[0] if ((k > 0) and (spectral_shift == True)) else 0
    V = I = np.eye(len(A))
    k = 0
    for m in range(len(A),1,-1):
        beta = wilkinson_heuristics(A,m)[1]
        while(abs(beta)>erro):
            uk = get_uk(A,m,k,spectral_shift)
            R,Q = QR_fatoration(A - (uk*I))
            A = R@Q + uk*I
            V = V@Q
            k = k + 1
            beta = wilkinson_heuristics(A,m)[1]
        A = np.matrix.round(A,6) # A = np.matrix.round(A,round_parameter - 1)
    lamb = A
    return [V,lamb,k]

def test_qr_fatoration():
    #exemple 1:
    A = np.array([[2,1,0,0],
                [1,2,1,0],
                [0,1,2,1],
                [0,0,1,2]])

    R = QR_fatoration(A)[0]
    Q = QR_fatoration(A)[1]
    print("R = ", R)
    print("Q = ", Q)

def test_qr_algorithm():
    #exemple 1:
    A = np.array([[2,1,0,0],
                [1,2,1,0],
                [0,1,2,1],
                [0,0,1,2]])
    print("test QR_algorithm with spectral_shift")
    V,lamb,k = QR_algorithm(A)
    print("V = \n", V)
    print("lamb = \n",lamb)
    print("k shift = ", k)
    new_A = V@lamb@np.transpose(V)
    #new_A = np.matrix.round(new_A,6)
    print("\n")
    print("A = \n", A)
    print("V Λ V_transposto = \n", new_A)

    print("\n\n")

    print("test QR_algorithm without spectral_shift")
    V,lamb,k = QR_algorithm(A,spectral_shift = False)
    print("V = \n", V)
    print("lamb = \n",lamb)
    print("k = ", k)
    new_A = V@lamb@np.transpose(V)
    #new_A = np.matrix.round(new_A,6)
    print("\n")
    print("A = \n", A)
    print("V Λ V_transposto = \n", new_A)

if __name__ == "__main__":
    try:
        while True:
            test = input("Do you want to test the QR_algorithm(1) or QR_fatoration(0): ")
            if (test == "1"):
                test_qr_algorithm()
                print("\n")
            elif (test == "0"):
                test_qr_fatoration()
                print("\n")
            else:
                print("your input isn't valid \nplease, try again\n")

    except KeyboardInterrupt:
        print("\n Better luck next time")


import random
import math
from typing import Optional

import numpy as np
import matplotlib.pyplot as plt
from qiskit import QuantumCircuit, Aer, transpile, assemble
from qiskit.visualization import plot_histogram
from sympy import Rational
from sympy.ntheory.continued_fraction import continued_fraction, continued_fraction_convergents

from qft import qft
from elementary import ax_modM

def shor(M: int, a: Optional[int] = None, N_len: Optional[int] = None, show_hist: bool = True, use_only_period: bool = False):
    if a is None:
        random.randint(2, M - 1)
    gcd = math.gcd(a, M)
    if gcd != 1:
        print(f'Answer is found in only classical computation: {gcd}')
        return gcd

    if N_len is None:
        N_len = int(np.ceil(np.log2(M ** 2)))
    N = 2 ** N_len
    qc = QuantumCircuit(10 * N_len - 2, N_len)

    qc.h(range(N_len))

    qc.append(ax_modM(a=a, M=M, N_len=N_len), range(10 * N_len - 2))

    qc.append(qft(n=N_len), range(N_len))

    qc.measure(range(N_len), range(N_len))

    backend = Aer.get_backend('aer_simulator_matrix_product_state')#('aer_simulator')
    qc = transpile(qc, backend)
    job = backend.run(qc, shots=10000)
    hist = job.result().get_counts()

    if show_hist:
        plot_histogram(hist)
        plt.show()

    print(sorted(hist.items(), key=lambda x: x[1], reverse=True))
    y_list = []
    for measured_key, _ in sorted(hist.items(), key=lambda x: x[1], reverse=True):
        y = int(measured_key[-N_len:], 2)
        if y == 0:
            continue

        for fraction in continued_fraction_convergents(continued_fraction(Rational(y, N))):
            maybe_r = fraction.denominator
            if maybe_r != 1 and maybe_r < M and a ** maybe_r % M == 1:
                if use_only_period:
                    return maybe_r

                if maybe_r % 2 == 1 or (a ** (maybe_r // 2) + 1) % M == 0:
                    continue
                gcd = math.gcd(a ** (maybe_r // 2) + 1, M)
                if gcd != 1:
                    return gcd
                gcd = math.gcd(a ** (maybe_r // 2) - 1, M)
                if gcd != 1:
                    return gcd

    print('gcd was not found?!')

if __name__ == '__main__':
    print(shor(M=8, a=3))
    #print(shor(M=57, a=5))
    #print(shor(M=7, a=3, N_len=3, use_only_period=True))
    #print(shor(M=7, a=3, use_only_period=True))


"""
  Name     : c10_36_put_call_ratio_add_trend.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""

import scipy as sp
import pandas as pd
from matplotlib.pyplot import *
import matplotlib.pyplot as plt
from datetime import datetime
import statsmodels.api as sm
#
data=pd.read_csv('c:/temp/totalpc.csv',skiprows=2,index_col=0,parse_dates=True)
data.columns=('Calls','Puts','Total','Ratio')
begdate=datetime(2013,6, 1)
enddate=datetime(2013,12,31)
data2=data[(data.index>=begdate) & (data.index<=enddate)]
x=data2.index
y=data2.Ratio
x2=range(len(x))
x3=sm.add_constant(x2)
model=sm.OLS(y,x3)
results=model.fit()

#print results.summary()
alpha=round(results.params[0],3)
slope=round(results.params[1],3)
y3=alpha+sp.dot(slope,x2)
y2=sp.ones(len(y))
title('Put-call ratio with a trend')
xlabel('Date')
ylabel('Put-call ratio')
ylim(0,1.5)
plot(x, y, 'b-')
plt.plot(x, y2,'r-.')
plot(x,y3,'y+')
plt.figtext(0.3,0.35,'Trend: intercept='+str(alpha)+',slope='+str(slope))
show()


import scipy
from scipy import signal
import numpy as np
import cv2
from matplotlib import pyplot as plt
import os
import matplotlib.colors as colors

def read_img(path):
    return cv2.imread(path, 0)

def save_img(img, path):
    cv2.imwrite(path,img)
    print(path, "is saved!")

def display_img(img):
    plt.imshow(img, cmap='gray', interpolation='bicubic')
    plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis
    plt.show()

def convolve(image, kernel):
    # Return the convolution result: image * kernel.
    # Input- image: H x W
    #        kernel: h x w
    # Output- convolve: H x W
    output = signal.convolve2d(image, kernel, boundary='symm', mode = 'same')
    # TODO: You can use the function scipy.signal.convolve2d().
    return output

def edge_detection(image):
    # Return the gradient magnitude of the input image
    # Input- image: H x W
    # Output- grad_magnitude: H x W

    # TODO: Fix kx, ky
#    kx = 0.5*np.array([[0,0,0],[1,0,-1],[0,0,0]])  # 1 x 3
#    ky = 0.5*np.array([[0,1,0],[0,0,0],[0,-1,0]])  # 3 x 1
    kx = 0.5*np.array([[1,0,-1]])
    ky = 0.5*np.array([[1],[0],[-1]])

    Ix = convolve(image, kx)
    Iy = convolve(image, ky)

    # TODO: Use Ix, Iy to calculate grad_magnitude
    grad_magnitude = np.sqrt(Ix**2 + Iy**2)

    return grad_magnitude, Ix, Iy

def sobel_operator(image):
    # Return Gx, Gy, and the gradient magnitude.
    # Input- image: H x W
    # Output- Gx, Gy, grad_magnitude: H x W

    # TODO: Use convolve() to complete the function
    Gx, Gy, grad_magnitude = None, None, None
    kx = np.array([[1,0,-1],[2,0,-2],[1,0,-1]])  # 1 x 3
    ky = np.array([[1,2,1],[0,0,0],[-1,-2,-1]])  # 3 x 1

    Gx = convolve(image, kx)
    Gy = convolve(image, ky)

    grad_magnitude = np.sqrt(Gx**2 + Gy**2)
    return Gx, Gy, grad_magnitude

def steerable_filter(image, angles=[0, np.pi/6, np.pi/3, np.pi/2, np.pi*2/3, np.pi*5/6]):
    # Given a list of angels used as alpha in the formula,
    # return the corresponding images based on the formula given in pdf.
    # Input- image: H x W
    #        angels: a list of scalars
    # Output- results: a list of images of H x W
    # You are encouraged not to use sobel_operator() in this function.

    # TODO: Use convolve() to complete the function
    output = []
    for i in range(len(angles)):
        kernal = kernal_steerable_filter(angles[i])
        output.append(convolve(image, kernal))
    return output

def kernal_steerable_filter(alpha):
    return np.array([[np.cos(alpha)+np.sin(alpha), 2*np.sin(alpha), -np.cos(alpha)+np.sin(alpha)],
                      [2*np.cos(alpha), 0 , -2*np.cos(alpha)],
                      [np.cos(alpha)-np.sin(alpha), -2*np.sin(alpha), -np.cos(alpha)-np.sin(alpha)]])

def image_patches(image, patch_size=(16,16)):
    # Given an input image and patch_size,
    # return the corresponding image patches made
    # by dividing up the image into patch_size sections.
    # Input- image: H x W
    #        patch_size: a scalar tuple M, N
    # Output- results: a list of images of size M x N

    # TODO: Use slicing to complete the function
    if (len(image.shape)==2):
        m,n = image.shape
    else:
        m, n, _ = image.shape
    h_num = m//patch_size[0]
    w_num = n//patch_size[1]
    output = []
    for i in range(h_num):
        for j in range(w_num):
            h_start, h_end = i*patch_size[0], (i+1)*patch_size[0]
            w_start, w_end = j*patch_size[1], (j+1)*patch_size[1]
            if (len(image.shape)==2):
                output.append(image[h_start:h_end, w_start:w_end])
            else:
                output.append(image[h_start:h_end, w_start:w_end, :])
    return output

def gaussian(x,y,sigma):
    return 1/(2*np.pi*sigma)*np.exp(-(x**2+y**2)/(2*sigma))

def gaussian_kernal(sigma, kernal_size=(3,3)):
    offset_h=kernal_size[0]//2
    offset_w=kernal_size[1]//2
    result = np.ones(kernal_size)
    for i in range(kernal_size[0]):
        for j in range(kernal_size[1]):
            result[i,j] = gaussian(i-offset_h, j-offset_w, sigma)
    return result

def gaussian1d(x, sigma):
    return 1/np.sqrt(2*np.pi*sigma) * np.exp(-x**2/(2*sigma))

def gaussian1d_prime(x, sigma):
    return -1*x/(sigma*np.sqrt(2*np.pi*sigma)) * np.exp(-x**2/(2*sigma))

def gaussian1d_prime_prime(x, sigma):
    return -1/(sigma*np.sqrt(2*np.pi*sigma)) * (np.exp(-x**2/(2*sigma))-x**2/sigma*np.exp(-x**2/(2*sigma)))

def main():
    # The main function
    ########################
    img = read_img('./grace_hopper.png')

    ##### Image Patches #####
    if not os.path.exists("./image_patches"):
        os.makedirs("./image_patches")

    # Q1
    patch_size = (16,16)
    patches = image_patches(img, patch_size)
    # TODO choose a few patches and save them
    chosen_patches = patches[200];
    save_img(chosen_patches, "./image_patches/q1_patch.png")
#    display_img(chosen_patches)

    # Q2: No code

    ##### Gaussian Filter #####
    if not os.path.exists("./gaussian_filter"):
        os.makedirs("./gaussian_filter")

    # Q1: No code

    # Q2

    # TODO: Calculate the kernel described in the question.  There is tolerance for the kernel.
    sigma = 1/(2*np.log(2))
    kernel_gaussian = gaussian_kernal(sigma,(3,3))

    filtered_gaussian = convolve(img, kernel_gaussian)
    save_img(filtered_gaussian, "./gaussian_filter/q2_gaussian.png")

    # Q3
    edge_detect, _, _ = edge_detection(img)
    save_img(edge_detect, "./gaussian_filter/q3_edge.png")
    edge_with_gaussian, _, _ = edge_detection(filtered_gaussian)
    save_img(edge_with_gaussian, "./gaussian_filter/q3_edge_gaussian.png")
#    display_img(edge_detect)
    print("Gaussian Filter is done. ")

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

    ##### Sobel Operator #####
    if not os.path.exists("./sobel_operator"):
        os.makedirs("./sobel_operator")

    # Q1: No code

    # Q2
    Gx, Gy, edge_sobel = sobel_operator(img)
    save_img(Gx, "./sobel_operator/q2_Gx.png")
    save_img(Gy, "./sobel_operator/q2_Gy.png")
    save_img(edge_sobel, "./sobel_operator/q2_edge_sobel.png")

    # Q3
    steerable_list = steerable_filter(img)
    for i, steerable in enumerate(steerable_list):
        save_img(steerable, "./sobel_operator/q3_steerable_{}.png".format(i))

    print("Sobel Operator is done. ")
    ########################

    #####LoG Filter#####
    if not os.path.exists("./log_filter"):
        os.makedirs("./log_filter")

    # Q1
    kernel_LoG1 = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]])
    kernel_LoG2 = 0.04*np.array([
        [0, 0, 3, 2, 2, 2, 3, 0, 0],
        [0, 2, 3, 5, 5, 5, 3, 2, 0],
        [3, 3, 5, 3, 0, 3, 5, 3, 3],
        [2, 5, 3, -12, -23, -12, 3, 5, 2],
        [2, 5, 0, -23, -40, -23, 0, 5, 2],
        [2, 5, 3, -12, -23, -12, 3, 5, 2],
        [3, 3, 5, 3, 0, 3, 5, 3, 3],
        [0, 2, 3, 5, 5, 5, 3, 2, 0],
        [0, 0, 3, 2, 2, 2, 3, 0, 0]
    ])
    filtered_LoG1 = convolve(img, kernel_LoG1)
    save_img(filtered_LoG1, "./log_filter/q1_LoG1.png")
    filtered_LoG2 = convolve(img, kernel_LoG2)
    save_img(filtered_LoG2, "./log_filter/q1_LoG2.png")

    print(img.shape)
    # Q2: No code
#    sigma = 1/(2*np.log(2))
    sigma = 2
    sigma1 = sigma/2.5
    sigma2 = sigma*2.5
    x = np.linspace(-10,10,200)
    y = gaussian1d_prime_prime(x, sigma)
    y1 = gaussian1d(x, sigma1)
    y2 = gaussian1d(x, sigma2)
#    plt.figure()
#    plt.plot(x,sigma*y,'b',label = 'LOG')
#    plt.plot(x, (y2-y1),'r', label = 'DoG')
#    plt.legend()

    print("LoG Filter is done. ")
    ########################

if __name__ == "__main__":
    main()


from math import factorial
import numpy as np

def pretty_polynomial(polynomial):
    """
    Takes a list of coefficients (must be in ascending powers of x) and produces a 'pretty' output.
    :param polynomial: the list of coefficients of a polynomial
    :return: a string of the polynomial in a more readable format.
    """
    s = ''
    for i in range(1, len(polynomial)):
        if polynomial[i] > 0:
            s += ' + ' + str(polynomial[i]) + 'x^' + str(i)
        elif polynomial[i] < 0:
            s += '  ' + str(polynomial[i]) + 'x^' + str(i)

    # If the constant is nonzero, prepend it to the string. Otherwise, get rid of the '+'.
    if polynomial[0]:
        s = str(polynomial[0]) + s
    else:
        s = s[2:]
    return s

def legendre_polynomial(n: int):
    """
    Calculate the coefficients of the nth order Legendre polynomial in x, using
    the Rodrigues formula: P_n(x) = 1/(2^n n!) (d/dx)^n [(x^2 - 1)^n].

    We will treat polynomials as lists in python, where the index in the list corresponds to the power
    of x, so the element in the list contains the coefficient of x^i. Thus our polynomials will be
    written in ascending powers of x, somewhat contrasting convention. All our operations will therefore
    be reduced to list methods.

    :param n: the order of the Legendre polynomial whose coefficients are to be determined
    :return: a list of coefficients in ascending powers of x.
    """
    # 1. Expand (x^2 - 1) ^ n with the binomial theorem.
    expansion = [None] * (n + 1)
    for i in range(len(expansion)):
        expansion[i] = (-1)**(n - i) * factorial(n) / (factorial(i) * factorial(n - i))

    # Because the brackets contain x^2, the expansion will only have even powers of x.
    # However, we need the odd powers too (which are all zero). 2n + 1 terms in total.
    coeffs = [None] * (2*n + 1)
    coeffs[::2] = expansion
    coeffs[1::2] = [0] * n

    # 2. Differentiate n times. Differentiating is the same as multiplying each element
    # by its index (remember this is the power of x), then deleting the first term in the list.
    for _ in range(n):
        coeffs = [i * coeffs[i] for i in range(1, len(coeffs))]

    # Don't forget the normalising constant in the Rodrigues formula.
    # The below code is the same as [x / (2**n * factorial(n)) for x in coeffs].
    return list(map(lambda x: x / (2**n * factorial(n)), coeffs))

def legendre_representation(poly):
    """
    Any polynomial can be written in terms of Legendre polynomials.
    :param poly: A list or np array of coefficients of the polynomial
    :return: A list of coefficients of the Legendre polynomials,
    e.g [3, 1, 0, 4] <=> 3P_0(x) + P_1(x) + 4P_3(x)
    """
    if not isinstance(poly, np.ndarray):
        poly = np.array(poly)
    n = len(poly) - 1
    legendre_coefficients = [0] * (n + 1)

    while n >= 0:
        Pn = legendre_polynomial(n)
        legendre_coefficients[n] = poly[n]/Pn[n]
        if n == len(poly) - 1:
            poly = poly - [legendre_coefficients[n] * x for x in Pn]
        else:
            poly[:n+1] = poly[:n+1] - [legendre_coefficients[n] * x for x in Pn]
        n -= 1

    return legendre_coefficients


#simple lp

import numpy as np
import scipy.sparse as sparse
import scipy.sparse.linalg as linalg
# min cx
# x >= 0
# Ax = b

def newtonDec(df, dx):
	return np.dot(df,dx)

# assumes that x + alpha*dx can be made positive
def linesearch(x, dx):
   alpha = 1.
   while not np.all( x + alpha*dx > 0):
   		alpha *= 0.1
   return alpha

# min cx

def solve_lp2(A, b, c, gamma, xstart=None):
	#x = np.ones(A.shape[1])
	#lam = np.zeros(b.shape)
	xsize = A.shape[1]
	if xstart is not None:
		x = xstart
	else:
		#xlam = np.ones(xsize + b.size)
		x = np.ones(xsize) # xlam[:xsize]
		#lam = xlam[xsize:]
	while True :
		print("Iterate")
		H = sparse.bmat( [[ sparse.diags(gamma / x**2)   ,   A.T ],
		                  [ A  ,                         0 ]]  )

		dfdx = c - gamma / x #+  A.T@lam
		dfdlam = A@x - b
		df = np.concatenate((dfdx, dfdlam))#np.zeros(b.size))) # dfdlam))
		#np.concatenate( , A@x - b)
		dxlam = linalg.spsolve(H,df)
		dx = - dxlam[:xsize]
		lam = dxlam[xsize:]

		alpha = linesearch(x,dx)
		x += alpha * dx
		#lam += dlam
		if newtonDec(dfdx,dx) >= -1e-10:
			print("stop")
			break

	return x, lam

def solve_lp(A,b,c, xstart=None):
	gamma = 1.0
	xsize = A.shape[1]
	x = np.ones(xsize)
	for i in range(8):
		x, lam = solve_lp2(A, b, c, gamma, xstart=x)
		gamma *= 0.1
	return x, lam

N = 12
A = np.ones(N).reshape(1,-1)
b = np.ones(1)*2
c = np.zeros(N)
c[0] = -1

#print(solve_lp(A,b,c, 0.000001))
print(solve_lp(A,b,c))

def BB(A, b, c, best, xhint = None):
	picked = np.zeros(xsize)
	picked[pickvar] = 1
	Anew = sparse.hstack((A, picked))
	bnew = np.concatenate((b,choice))
	x, lam =
	np.dot(c,x)
	if lp_solve(Anew, bnew, c) < best:
		best, x = BB(Anew, bnew , c, best, xhint)
	return best, x

'''
#min  cx + gamma * ln(x)
# s.t. Ax = b

# cx + gamma * ln(x) + lambda (Ax - b)

#gradient
delx = c + gamma * 1/x + lambda A
dellam = Ax - b
# hess
dlx = A
dxl = A.T
dxx = - gamma (1/x**2)

H @ (x l) = (delx dell)
'''


import sys
import scipy.io as sio
from pprint import pprint
import matplotlib.pyplot as plt
import numpy as np
from sympy import *
from scipy.optimize import newton

x = Symbol('x')
y = 2* (x**6) + 3 *(x**4) - 10 *(x**3) + 12 * (x**2) - 60 * x

def dx(y, x, x0):
	f = lambdify(x, y, 'numpy')
	return abs(f(np.array(x0)))

def f(x):
    return 2* (x**6) + 3 *(x**4) - 10 *(x**3) + 12 * (x**2) - 60 * x

def df(x):
    return 12 * (x**5) + 12 * (x**3) -30 * (x**3) + 24 * (x**2) - 60

e = 1e-8
x0 = 1
delta = dx(y, x, x0)
x_pred = []
y_pred = []
x_pred.append(x0)
y_pred.append(f(x0))

while delta > e:
	x0 = x0 - f(x0)/df(x0)
	delta = dx(y, x, x0)
	x_pred.append(x0)
	y_pred.append(f(x0))

print('Root: ', x0)
print('f(x): ', f(x0))

xn = newton(f, 1, df, tol=e)
print('Root with scipy newton: ', xn)
print('f(x) with scipy newton: ', f(xn))

plt.figure(figsize=(10, 8))
plt.title("Newton steps", fontsize=16)
plt.scatter(x_pred, y_pred, color = "b")
plt.xlabel('x', fontsize=14)
plt.ylabel('f(x)', fontsize=14)
plt.grid(True)
plt.show()

import numpy,import scipy,from scipy,from sympy


"""
Susceptible-Infected-Recovered (SIR) Model
without demographics (births/deaths) with mortality

References:

* Modeling Infectious Diseases in Humans and Animals,
  M. J. Keeling and P. Rohani,
  Princeton University Press,
  2008
"""

import numpy as np

from scipy import integrate

from matplotlib import pyplot as plt

# Total UK population (2019 estimate)
N = 67545757

def SIR(t, y, R0, gamma, m):
    """
    SIR ODEs

    Parameters
    ----------
    t: double
        Current time
    y: np.ndarray
        Current state
    R0: double
        Basic reproductive ratio
    m: double
        Mortality rate

    Notes
    -----
    Deaths are included in dR/dt (recovered rate) instead of dI/dt (infected rate);
    this is to simulate a delayed death after infection (incubation period).
    For this reason the infected rate is not influenced by the death rate.
    """

    assert 0 <= m <= 1

    # Changes in S, I and R do not depend on R
    S, I = y[0], y[1]

    # Gamma and beta are related by R0
    beta = gamma * R0

    dSdt = -beta * I * S
    dIdt = beta * I * S - gamma * I
    dRdt = gamma * I - m * gamma * I
    dDdt = m * gamma * I  # Deaths

    return np.array([dSdt, dIdt, dRdt, dDdt])

def solve_SIR(I0, tint, R0, gamma, m):
    """
    Solve system of SIR ODEs

    Parameters
    ----------
    I0: int
        Initial number of infected people
    tint: Tuple[double]
        Time interval
    R0: double
        Basic reproductive ratio
    m: double
        Mortality rate
    """

    # Initial susceptible and infected people as population fraction
    S0 = (N - I0) / N
    I0 = I0 / N

    y0 = np.array([S0, I0, 0, 0])

    sir = integrate.solve_ivp(
        lambda t, y: SIR(t, y, R0, gamma, m if m is not None else 0.0),
        tint,
        y0,
        rtol=1e-12,
        atol=1e-12,
    )

    # Check conservation of people
    assert np.allclose(sir.y.sum(axis=0), S0 + I0)

    return sir

def plot_sir(I0, tint, R0, gamma, m=None, tag=None):
    """
    Plot SIR model

    Parameters
    ----------
    I0: int
        Initial number of infected people
    tint: Tuple[double]
        Time interval
    R0: double
        Basic reproductive ratio
    m: double (optional)
        Mortality rate
    tag: str
        Plot tag
    """

    sir = solve_SIR(I0, tint, R0, gamma, m)

    fig = plt.figure()

    plt.plot(sir.t, sir.y[0], label="Susceptible")
    plt.plot(sir.t, sir.y[1], label="Infected")
    plt.plot(sir.t, sir.y[2], label="Recovered")

    if m is not None:
        plt.plot(sir.t, sir.y[3], label="Dead")
    plt.legend()

    plt.title(f"SIR Model ($R_0$  = {R0:.2f} {f', m = {m}' if m is not None else ''})")
    plt.xlabel("Time")
    plt.ylabel("Fraction of Population")

    if tag is None:
        tag = "simple" if m is None else "mortality"
    plt.savefig(f"plots/SIR_{tag}.pdf")
    plt.close(fig)

    return sir.t, sir.y

def plot_infected(I0, tint, R0, gamma, m=None):
    """
    Plot fraction of infected people (SIR model) for different values of R0

    Parameters
    ----------
    I0: int
        Initial number of infected people
    tint: Tuple[double]
        Time interval
    R0: List[double]
        Basic reproductive ratio
    m: double
        Mortality rate
    """

    fig = plt.figure()

    for r0 in R0:
        sir = solve_SIR(I0, tint, r0, gamma, m)

        plt.plot(sir.t, sir.y[1], label=f"$R_0$  = {r0:.2f}")

    plt.legend()
    plt.title(f"SIR Model (Infected)")
    plt.xlabel("Time")
    plt.ylabel("Fraction of Infected Population")

    tag = "simple" if m is None else "mortality"
    plt.savefig(f"plots/SIR_{tag}_R.pdf")
    plt.close(fig)

# Number of infected people in the UK (13/03/2020)
i0 = 1
tint = (0, 40)

# No mortality
plot_sir(I0=i0, tint=tint, R0=2, gamma=1)

# 2.5% mortality
plot_sir(I0=i0, tint=tint, R0=2, gamma=1, m=0.025)

# No mortality
plot_infected(I0=i0, tint=tint, R0=[1.5, 2.0, 2.5, 3.0, 3.5], gamma=1)


# coding: utf-8

# # Pysius - a Python solver for Blasius equation

# In[1]:

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

# Let $f(\eta)$ be the non-dimensional stream function, with $\eta$ being the similarity variable. Blasius equation reads:
#
# $$f''' + \frac{1}{2}ff'' = 0$$
#
# This is a third-order ODE, that can be thus cast to a system of 3 first-order ODEs:
#
# $$\begin{cases}
# f' = u\\
# u'  = \xi\\
# \xi' = -\frac{1}{2}f\xi
# \end{cases}$$
#
# the first two rows representing de-facto the definitions of the additional variables $f$ and $\xi$. Boundary conditions are:
#
# $$f(0)=0$$
# $$u(0)=0$$
# $$\lim_{\eta \to \infty}u(\eta)=\int_0^\infty \xi d\eta = 1$$
#
# A complete set of initial conditions is not available (the value of $\xi$ at $\eta=0$ is not provided). This makes it impossible to solve the equation with an $\eta$-marching scheme (meaning, starting from initial conditions towards higher values of eta), hence they need to be solved nonlinearly. Also, the third condition can be either written as a condition on $u$ or an integral condition on $\xi$; the first option will be used in this script (although the same result can be obtained with the latter).

# The theoretical domain would be $\eta\in[0,\infty)$; a discretisation is needed. Here, $\infty$ is approximated with a high enough value `eta_max`, while the parameter `N` indicates  the number of nodes on which the function is evaluated (including extremes, so including $0$ and `eta_max`. Finally `deta` is the spacing between nodes.
#
# _Hint: try starting from a low number of nodes and a low value for_ `eta_max` _and gradually increase them. Do this until no substantial change in the final solution is observed._

# In[2]:

eta_max = 20 # extreme of domain
N = 1000 # number of nodes

deta = eta_max / (N-1)

# Next up, it has to be decided how to store the unknowns in memory. There are three variables, $f$, $u$ and $\xi$, and $N$ nodes - which adds up to $3N$ unknowns (corresponding to the value of each variable on each node). All of them are stored in a one-dimensional array $y$ of size $3N$:

# In[3]:

y = np.zeros(3*N)

# It is conventionally decided that the first N elements of `y` represent $\xi$ at each of the nodes, namely:
# ```python
# xi = y[0:N] # where xi[n-1] represents xi at the n-th node
# ```
# notice that, when using Python's slicing `0:N`, the first extreme ($0$) is inclusive, the second ($N$) is not. The other variables just follow:
# ```python
# u = y[N:(2*N)]
# f = y[(2*N):(3*N)]
# ```

# Using a forward-Euler discretisation, the equation can be evaluated at each node $n$ as:
#
# $$
# \left(
# \begin{bmatrix}
# \xi_{n+1}\\
# u_{n+1}\\
# f_{n+1}
# \end{bmatrix} -
# \begin{bmatrix}
# \xi_{n}\\
# u_{n}\\
# f_{n}
# \end{bmatrix}
# \right) \frac{1}{\Delta \eta} +
# \begin{bmatrix}
# \frac{1}{2}\xi_{n}f_n\\
# -\xi_{n}\\
# -u_{n}
# \end{bmatrix} = 0
# $$
#
# Notice that such equation cannot be written for $n=N$ (the last cell), as it would require informations from the unexistent cell $N+1$. Therefore, $3(N-1)$ equations can be written on all the other nodes; the remaining 3 equations are provided by boundary conditions, so that the number of equations matches the one of unknowns.
#
# This can be written as a whole as:
#
# $$
# Ay + b(y) = 0
# $$
#
# where $A$ is a matrix, vector $b$ is a function of y. The whole left hand side is thus a vector, where the arrangement of rows is arbitrary; here it is performed so that:
# - the first $N-1$ rows represent the discretised Blasius equation for $\xi$
# - the next row represents the boundary contition for $u(0) = 0$
# - the next $N-1$ rows represent the discretised Blasius equation for $u$
# - the next row represents the boundary condition for $u(\eta\to\infty)$
# - the next row is the boundary condition for $f(0)$
# - the final $N-1$ rows represent the discretised Blasius equation for $f$

# In[4]:

# Keep in mind that when slicing or using "range", the first bound is inclusive
# while the second is not!
# In this way, for instance, range(1,11) produces an array of numbers from 1 to 10,
# which has size 11-1 = 10.

A = np.zeros((3*N, 3*N))

# Blasius equation for xi (derivative of xi)
for ii in range(N-1):
    A[ii,ii] = -1/deta
    A[ii,ii+1] = 1/deta

# boundary condition for u(0)
A[N-1, N] = 1

# Blasius equation for u (derivative of u)
for ii in range(N,2*N-1):
    A[ii,ii] = -1/deta
    A[ii,ii+1] = 1/deta

# boundary conditions for u at etamax ~ infinity
A[2*N-1,2*N-1] = 1

# boundary condition for f(0)
A[2*N,2*N] = 1

# Blasius equation for f (derivative of f)
for ii in range(2*N+1, 3*N):
    A[ii,ii-1] = -1/deta
    A[ii,ii] = 1/deta

# In[5]:

# now, a function returning vector b is defined

def b(y):

    result = np.zeros(3*N)

    # Blasius equation for xi (derivative of xi)
    for ii in range(N-1):
        result[ii] = y[ii]*y[2*N+ii]/2

    # Blasius equation for u (derivative of u)
    for ii in range(N,2*N-1):
        result[ii] = - y[ii-N]

    # boundary conditions for u at etamax ~ infinity
    result[2*N-1] = -1

    # Blasius equation for f (derivative of f)
    for ii in range(2*N+1, 3*N):
        result[ii] = -y[ii-1-N]

    return result

# In[6]:

# Jacobi's matrix for b; this will come in handy later

def db(y):

    result = np.zeros((3*N,3*N))

    # Blasius equation for xi (derivative of xi)
    for ii in range(N-1):
        result[ii,2*N+ii] = y[ii]/2
        result[ii,ii] = y[2*N+ii]/2

    # Blasius equation for u (derivative of u)
    for ii in range(N,2*N-1):
        result[ii,ii-N] = - 1

    # Blasius equation for f (derivative of f)
    for ii in range(2*N+1, 3*N):
        result[ii,ii-1-N] = -1

    return result

# We now have a non-linear equation in the form:
#
# $$ F(y) = Ay + b(y) = 0$$
#
# this can be solved with a Newton-Raphson scheme starting from an initial guess `y0`:
#
# $$ y^{\,k+1} = y^{\,k} - J^{-1}(y^{\,k})\, F(y^{\,k}) $$
#
# where $J$ is the Jacobi's matrix of $F$, while $k$ denotes the iteration of the algorithm. Iterations are stopped when a maximum of iterations `KMAX` is reached or when the infinity norm of the vector of the change between iterations $||y^{\,k+1} - y^{\,k}||_\infty$ is below a threshold value `TOL`.

# In[7]:

# define F and the jacobian J
F = lambda yy : A.dot(yy) + b(yy)
J = lambda yy : A + db(yy)

# In[8]:

# initial condition (linear profiles which respect B.C.)
y0 = np.zeros(3*N)
y0[0:N] = 0.5*np.linspace(1.0,0.0,num=N)*deta
y0[N:2*N] = np.linspace(0,1,num=N)
y0[2*N:3*N] = np.linspace(0,1,num=N)

# In[9]:

KMAX = 100 # maximum number of iterations
TOL = 1e-10 # tolerance

exit4it = True
for ii in range(KMAX):
    dy = - np.linalg.solve(J(y0),F(y0))
    y = y0 + dy
    y0 = y
    print('Iteration {}, maximum absolute value of residual: {}'.format(ii+1,max(abs(F(y)))))
    if max(abs(dy)) < TOL:
        exit4it = False
        print()
        print('Algorithm terminated due to satisfactory residual (number of iterations: {}).'.format(ii+1))
        break
if exit4it:
    print()
    print('Warning: algorithm was terminated for too many iterations;')
    print('converngence might have not been achieved.')

# Now, the solution is extracted and plotted:

# In[10]:

eta = np.linspace(0,eta_max,num=N)
xi = y[0:N]
u = y[N:(2*N)]
f = y[(2*N):(3*N)]

# In[11]:

fig, ax = plt.subplots()
ax.plot(eta,f)
ax.plot(eta,u)
ax.plot(eta,xi)
ax.plot(eta,eta*u-f)
ax.set_xlabel('$\eta$')
ax.set_xlim([0,10])
ax.set_ylim([-0.1,2])
ax.grid()
ax.legend(['$f$', '$u$', '$\\xi$', '$\eta u - f$'])

# # Postprocessing

# Now, the streamlines associated to the Blasius solution are plotted in a $x,z$ plane; these correspond to the isocontours of the dimensional stream function $\psi$. It is thus necessary to first find the values of $f$ in real space (as a function of $x$ and $y$). To do so, a mesh is created; then, the value of $\eta$ corresponding to each couple $(x,y)$ is calculated:
#
# $$ \eta = y\sqrt{\frac{u_\infty}{\nu x}} $$
#
# Knowing $\eta$, it is possible to find the value of $f$ for each $(x,y)$ by interpolation of the Blasius solution; hence, it is also possible to calculate the dimensional stream function $\psi$:
#
# $$ \psi = f\sqrt{\nu u_\infty x} $$

# In[12]:

# first off: define u_inf and nu
# unitary values are arbitrarily chosen
u_inf = 1
nu = 1

# In[13]:

# function that returns eta from x and y
get_eta = lambda x,y : y / math.sqrt(nu*x/u_inf)

# When creating a mesh, one needs to be careful: $x=0$ is __outside__ of the domain for Blasius boundary layer (also, the solution is discontinuous there). Moreover, a value $x=0$ would make $\eta$ undefined (see its definition).

# In[14]:

# mesh settings
x_min = 0.05; x_max = 1 # bounds for x
y_max = 1; # bounds for y (lower bound is assumed to be 0)
nox = 30; noy = 30 # number of points in each direction

# generate mesh
if get_eta(x_min, y_max) > eta_max:
    print('Warning: requested mesh exceeds the calculated values of eta.')
x, y = np.meshgrid(np.linspace(x_min,x_max,num=nox), np.linspace(0,y_max,num=noy))

# In[15]:

# calculate stream function associated to each x, y
psi = np.empty_like(x)
for ii in range(noy):
    for jj in range(nox):
        current_eta = get_eta(x[ii,jj], y[ii,jj])
        psi[ii,jj] = np.interp(current_eta, eta, f) * math.sqrt(nu*u_inf*x[ii,jj])

# In[16]:

fig, ax = plt.subplots()
ax.contour(x,y,psi,levels=[0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16])
ax.set_title('Streamlines')
ax.set_xlabel('x')
ax.set_ylabel('y')

# And finally, the non-dimensional velocity field can be found as:
#
# $$ u_x = u_\infty \, f' $$
#
# $$ u_y = \frac{1}{2}\sqrt{\frac{\nu u_\infty}{x}} \, \left(\eta\, f' -f \right) $$
#
# _Notice that this leads to an infinite value of $u_y$ in the limit for $x \to 0$._

# In[17]:

# mesh is here redefined to have better looking graphs
nox = math.floor(nox/4) # number of points in x is divided by 4
noy = math.floor(noy/1.5) # number of points in y is divided by 1.5
x, y = np.meshgrid(np.linspace(x_min,x_max,num=nox), np.linspace(0,y_max,num=noy))

# calculate velocity field associated to each x, y
ux = np.empty_like(x)
uy = np.empty_like(x)
for ii in range(noy):
    for jj in range(nox):
        current_eta = get_eta(x[ii,jj], y[ii,jj])
        ux[ii,jj] = np.interp(current_eta, eta, u) * u_inf
        uy[ii,jj] = (current_eta*np.interp(current_eta, eta, u) - np.interp(current_eta, eta, f)) * math.sqrt(nu*u_inf/x[ii,jj])/2

# In[18]:

fig, ax = plt.subplots()
ax.quiver(x,y,ux,uy)
ax.set_title('Velocity field')
ax.set_xlabel('x')
ax.set_ylabel('y')

# Again, the high values of $u_y$ towards $x \to 0$ are a peculiarity of Blasius' solution; this is a direct consequence of the similarity. The $u_x$ velocity component is assumed to be uniform and equal to $u_\infty$ for $x\leq0$ (as the external solution is assumed to have such shape); in other words, for $x=0$ and $\forall y$, $u_x = u_\infty$. For $x>0$, on the other hand, $u_x$ is given by a self similar solution for the boundary layer; the only way to satisfy both these conditions is to have a zero-thickness of the boundary layer in $x=0$, which also makes sense on a physical standpoint. As $x=0$ is approached, the y-profile of the self similar solution for $u_x$ becomes increasingly flat with an almost constant value of $u_\infty$, as a consequence of the thinner and thinner boundary layer. This can be clearly observed below:

# In[19]:

x, y = np.meshgrid(np.linspace(0.01,x_max,num=nox), np.linspace(0,y_max,num=noy))
ux = np.empty_like(x)
uy = np.empty_like(x)
for ii in range(noy):
    for jj in range(nox):
        current_eta = get_eta(x[ii,jj], y[ii,jj])
        ux[ii,jj] = np.interp(current_eta, eta, u) * u_inf

fig, ax = plt.subplots()
ax.quiver(x,y,ux,0)
ax.set_title('x-component of velocity field')
ax.set_xlabel('x')
ax.set_ylabel('y')

plt.show()

# However, the fact that the boundary layer thickness (from now on indicated with $\delta(x)$) tends to 0 for $x \to 0$ also means that $\eta$ becomes singular there, as it can be written as:
#
# $$ \eta = \frac{y}{\delta(x)} $$
#
# thus $\lim_{x \to 0} \eta = \infty$. Similarly, also the vertical velocity component $u_y$ becomes singular as the term $1/\sqrt{x}$ diverges for $x \to 0$, while the term $\left(\eta\, f' -f \right)$ converges to a constant for $\eta \to \infty$:
#
# $$ u_y = \frac{1}{2}\sqrt{\frac{\nu u_\infty}{x}} \, \left(\eta\, f' -f \right) $$
#
#
# Another issue with the vertical velocity component is that, for any $x$ and for $y \to \infty$, non-zero values are observed due to the term $\left(\eta\, f' -f \right)$ (actually, $u_y$ becomes larger and larger moving away from the wall, until an asymptotic value is found); this does not match the imposed external, irrotational flow, which is assumed to be:
#
# $$\mathbf{U}_{ext} = u_\infty\hat{\mathbf{x}} + 0\,\hat{\mathbf{y}}$$
#
# and hence has a null vertical component. Be aware that, despite the mismatch, Blasius solution is mathematically correct; a possible explanation for the incongruence resides in the non-physical choice of external velocity $\mathbf{U}_{ext}$. This has been calculated by solving Euler's equations with non penetration boundary conditions applied at the plate; meaning, the presence of the boundary layer is not taken into account. In fact, the external solution must phisically be aware of the boundary layer; this can be done numerically by iteratively modifying the external solution with the associated boundary layer one, then calculating a new boundary layer solution. In other words:
# - calculate boundary layer solution associated to external solution;
# - update external solution (which is, calculate a new one) so that it accounts for the presence of the boundary layer previously calculated;
# - repeat until convergence (if convergence is ever obtained!).

# In[ ]:


"""
Functions to sample zero-centered nx x ny random vector with exponential spatial covariance
See https://math.stackexchange.com/questions/163470/generating-correlated-random-numbers-why-does-cholesky-decomposition-work
"""
import argparse

import numpy
from scipy.linalg import cholesky
from scipy.spatial.distance import cdist

def exponential_covariance(distance, length, sigma):
    return numpy.exp(-distance/numpy.float(length)) * sigma**2

def build_covariance_matrix(nx, ny, length, sigma, lx=1.0, ly=1.0):
    dx, dy = lx/nx, ly/ny
    x, y = numpy.meshgrid((numpy.arange(nx)+.5)*dx, (numpy.arange(ny)+.5)*dy)
    coords = list(zip(x.ravel(), y.ravel()))
    distance_matrix = cdist(coords, coords)
    covariance_matrix = exponential_covariance(distance_matrix, length, sigma)
    return covariance_matrix

def generate(nx, ny, length, sigma, lx=1.0, ly=1.0):
    """ generate single realization """
    chol = _chol(nx, ny, length, sigma, lx, ly)
    u = numpy.random.randn(ny, nx).ravel()
    v = chol.dot(u).reshape(ny, nx)
    return v

def batch_generate(nx, ny, length, sigma, lx=1.0, ly=1.0, sample_size=1):
    """ generate multiple realizations """
    chol = _chol(nx, ny, length, sigma, lx, ly)
    ubatch = numpy.random.randn(ny, nx, sample_size).reshape(ny*nx, sample_size)
    vbatch = chol.dot(ubatch)
    vbatch = vbatch.T.reshape(sample_size, ny, nx)
    return vbatch

def _chol(nx, ny, length, sigma, lx, ly):
    covariance_matrix = build_covariance_matrix(nx, ny, length, sigma, lx, ly)
    chol = cholesky(covariance_matrix, lower=True)
    return chol

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--seed', type=int, default=42)
    parser.add_argument('--outfile', default='tmp.npy', help='output filename')
    parser.add_argument('--grid_size', nargs=2, type=int, default=[64, 64], help='resolution of the grid')
    parser.add_argument('--domain_size', nargs=2, type=float, default=[1.0, 1.0], help='default is a unit square')
    parser.add_argument('--length', type=float, default=1.0, help='length scale of exponential covariance')
    parser.add_argument('--sigma', type=float, default=1.0, help='amplitude of exponential covariance')
    parser.add_argument('--sample_size', type=int, default=10)
    args = parser.parse_args()

    numpy.random.seed(args.seed)

    nx, ny = args.grid_size
    lx, ly = args.domain_size

    data = batch_generate(nx, ny, args.length, args.sigma, lx, ly, args.sample_size)
    numpy.save(args.outfile, data)

    print('Generated data saved at {}'.format(args.outfile))


'''
几何中夹角余弦可用来衡量两个向量方向的差异，机器学习中借用这一概念来衡量样本向量之间的差异。

1.二维空间向量的夹角余弦相似度
'''
import numpy as np

def cosn(a, b):
    """
    n维夹角余弦
    """
    sum1 = sum2 = sum3 = 0
    for i in range(len(a)):
        sum1 += a[i] * b[i]
        sum2 += a[i] ** 2
        sum3 += b[i] ** 2
    cos = sum1 / (np.sqrt(sum2) * np.sqrt(sum3))
    return cos

print('a,b 多维夹角余弦距离：', cosn((1, 1, 1, 1), (2, 2, 2, 2)))

def cosn2(a, b):
    """
    n维夹角余弦, 不使用循环
    """
    A, B = np.array(a), np.array(b)
    sum1 = sum(A * B)
    sum2 = np.sqrt(np.sum(A ** 2))
    sum3 = np.sqrt(np.sum(B ** 2))
    cos = sum1 / (sum2 * sum3)
    return cos

print('a,b 多维夹角余弦距离：', cosn2((1, 1, 1, 1), (2, 2, 2, 2)))

print('a,b 二维夹角余弦距离：', cosn((0, 2), (2, 0)))

print(np.pi / 3)
print(np.sin(np.pi / 3))
print(355 / 113)


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

non_decimal = re.compile(r'[^\d]+')

df = pd.read_csv('./data/moore.csv', delimiter='\t', header=None)
x = df[2].apply(
    lambda v: non_decimal.sub('', v.split('[')[0])
)
y = df[1].apply(
    lambda v: non_decimal.sub('', v.split('[')[0])
)

x = x.values.astype(np.int)
y = y.values.astype(np.int)

plt.scatter(x, y)
plt.show()

# Transform y to be more like linear
y = np.log(y)
plt.scatter(x, y)
plt.show()

denominator = x.dot(x) - x.mean() * x.sum()

a = (x.dot(y) - y.mean() * x.sum()) / denominator
b = (y.mean() * x.dot(x) - x.mean() * x.dot(y)) / denominator

y_hat = a * x + b

plt.scatter(x, y)
plt.plot(x, y_hat)
plt.show()

d1 = y - y_hat
d2 = y - y.mean()
r2 = 1 - d1.dot(d1) / d2.dot(d2)
print("a:", a, "b", b)
print('R2', r2)

# log(tc) = a * year + b
# tc = exp(b) * exp(a * year)
# Time to double
# 2*tc = 2 * exp(b) * exp(a * year)
#      = exp(ln(2)) * exp(b) * exp(a * year)
#      = exp(b) * exp(a * year * ln(2))
# exp(b) * exp(a * year2) = exp(b) * exp(a * year1 + ln2)
# a * year2 = a * year1 + ln2
# year2 = year1 + ln2/a
print('time to double:', np.log(2) / a, 'years')


from numpy import *

#points is array of row of data sets

def compute_error_for_given_points(b, m, points):
	totalError = 0
	# i is the row of the data sets
	for i in range(0, len(points)):
		x = points[i, 0]
		y = points[i, 1]
		# **2 means square
		totalError += (y - (m*x + b))**2

	return totalError / float(len(points))

def step_gradient(b_current, m_current, points, learning_rate):
	#gradient descent
	b_gradient = 0
	m_gradient = 0
	#N is number of points
	N = float(len(points))

	#we are gonna up date b and m over time
	for i in range(0,len(points)):
		x = points[i, 0]
		y = points[i, 1]
		b_gradient += -(2/N) * (y - ((m_current * x) + b_current))
		m_gradient += -(2/N) * x * (y - ((m_current * x) + b_current))
	new_b = b_current - (learning_rate * b_gradient)
	new_m = m_current - (learning_rate * m_gradient)
	return [new_b, new_m]

def gradient_descent_runner(points, starting_b, starting_m, learning_rate, num_iterations):
	b = starting_b
	m = starting_m

	for i in range(num_iterations):
		b, m = step_gradient(b, m, array(points), learning_rate)

	return [b,m]

def run():
	#data sets will be separated by a comma like an x and y pair
	points = genfromtxt('data.csv', delimiter=',')

	#hyperparameters
	learning_rate = 0.0001

	#y = mx + b (slope formula)
	initial_b = 0
	initial_m = 0
	num_iterations = 1000

	print "Before gradient descent with b = {0}, m = {1}, error = {2}".format(initial_b, initial_m, compute_error_for_given_points(initial_b, initial_m, points))

	[b, m] = gradient_descent_runner(points,initial_b, initial_m, learning_rate, num_iterations)

	print "After gradient descent with b = {0}, m = {1}, error = {2}".format(b, m, compute_error_for_given_points(b, m, points))

if __name__ == '__main__':
	run()


from sympy import symbols, solve, diff, pprint, integrate, ln, lambdify
import matplotlib.pyplot as plt
import numpy as np
import math

# An oil tanker is leaking oil at a rate given in barrels per hour by the function shown below,
# where t is the time in hours after the tanker hits a hidden rock

t = symbols( 't' )
dL = 76 * ln( t + 1 ) / ( t + 1 )

# Time in hours, first day
a, b = 0, 24
day1 = integrate( dL, ( t, a, b ) ).evalf()

round( day1 ) # Round to three decimal places as needed.

solve( integrate( dL, t ), t )

# Time in hours, first day
a, b = 24, 48
day2 = integrate( dL, ( t, a, b ) ).evalf()

round( day2 ) # Round to three decimal places as needed.

# Time in hours, first day
a, b = 10000 * 24, 10001 * 24
day11 = integrate( dL, ( t, a, b ) ).evalf()

round( day11 ) # Round to three decimal places as needed.

# What is the leak doing?
g_xlim = [ 1, 100 ]
g_ylim = [ -5, 15 ]

lam_l = lambdify( t, integrate( dL, t ), np )

x_vals = np.linspace( g_xlim[0], g_xlim[1], 1000, endpoint=True )
y_vals = lam_l( x_vals )
plt.plot( x_vals, y_vals )
plt.show()


# -*- coding: utf-8 -*-
"""
Created on Thu Dec  2 19:35:06 2021

@author: Oliver
"""

"""Linear Algebra Numerical Solving Methods"""

"""Gauss Elimination"""

import numpy as np

def linearsolver(A,b):
    n = len(A)
    #Initialise solution vector as an empty array
    x = np.zeros(n)
    #Join A and use concatenate to form an augmented coefficient matrix
    M = np.concatenate((A,b.T), axis=1)
    for k in range(n):
        for i in range(k,n):
                if abs(M[i][k]) > abs(M[k][k]):
                    M[[k,i]] = M[[i,k]]
                else:
                    pass
                    for j in range(k+1,n):
                        q = M[j][k] / M[k][k]
                        for m in range(n+1):
                            M[j][m] += -q * M[k][m]
    #Python starts indexing with 0, so the last element is n-1
    x[n-1] =M[n-1][n]/M[n-1][n-1]
    #We need to start at n-2, because of Python indexing
    for i in range (n-2,-1,-1):
        z = M[i][n]
        for j in range(i+1,n):
            z = z - M[i][j]*x[j]
        x[i] = z/M[i][i]
    return x

#Initialise the matrices to be solved.
A=np.array([[10., 15., 25],[4., 5., 6],[25, 3, 8]])
b=np.array([[34., 25., 15]])
print(f'Gauss Elimination: {linearsolver(A,b)}')

"""Gaussian Elimination with Partial Pivoting"""
def column(m, c):
    return [m[i][c] for i in range(len(m))]

def row(m, r):
    return m[r][:]

def height(m):
    return len(m)

def width(m):
    return len(m[0])

def print_matrix(m):
    for i in range(len(m)):
        print(m[i])

def gaussian_elimination_with_pivot(m):
# forward elimination
    n = height(m)
    for i in range(n):
        pivot(m, n, i)
        for j in range(i+1, n):
            m[j] = [m[j][k] - m[i][k]*m[j][i]/m[i][i] for k in range(n+1)]
    if (m[n-1][n-1]) == 0:
        raise ValueError('No unique solution')
    # backward substitution
    x = [0] * n
    for i in range(n-1, -1, -1):
        s = sum(m[i][j] * x[j] for j in
        range(i, n))
        x[i] = (m[i][n] - s) / m[i][i]
    return x

def pivot(m, n, i):
    max = -1e100
    for r in range(i, n):
        if max < abs(m[r][i]):
            max_row = r
            max = abs(m[r][i])
        m[i], m[max_row] = m[max_row], m[i]

if __name__ == '__main__':
    #m = [[0,-2,6,-10], [-1,3,-6,5], [4,-12,8,12]]
    #m = [[1,-1,3,2], [3,-3,1,-1], [1,1,0,3]]
    m = [[1,-1,3,2], [6,-6,2,-2], [1,1,0,3]]
    print(f'Guassian pivot:{gaussian_elimination_with_pivot(m)}')


"""
E14_ode_coupled.py

Solving coupled ODEs (Lorentz Attractor)
charles stanier
charles.stanier@gmail.com
Oct 2, 2019

See about the Lorentz Attractor at https://en.wikipedia.org/wiki/Lorenz_system

The behavior of the system depends on the parameters rho, beta, and sigma
It is a coupled nonlinear system of 3 ODEs

derivative function and driver in same file
defining problem parameters as a dictionary
in the driver and passing that to the derivative
scipy.integrate.solve_ivp does not permit passing of
additional arguments, so we use the awkward lambda
construction per https://github.com/scipy/scipy/issues/8352

this will be fixed with scipy version 1.4 but it has not
yet been released

This passing of model parameters through a dictionary
is a good practice to make  your code readable
and keep all of your model specifications in one place.

for engineering problems, you can add notes and/or units to the pinfo dictionary
as well as error codes.  This can keep you organized and minimize chance of mistakes

Log of changes: none so far

"""

import numpy as np
from scipy.integrate import solve_ivp
import pylab as pl

def lorentz_deriv(t, state_vec, pinfo):
  x, y, z = state_vec  # unpack the state vector
  # unpack the problem parameters
  rho = pinfo['rho']
  beta = pinfo['beta']
  sigma = pinfo['sigma']
  dxdt = sigma * (y - x)
  dydt = x * (rho - z) - y
  dzdt = x * y - beta * z
  return [ dxdt, dydt, dzdt ]   # derivatives

# OK here is the driver

# dictionary with problem parameters
pinfo = {  "rho" :   28,
           "sigma":  10,
           "beta"  : 8/3,
           "tspan" : [0, 100],
           "init_state_vec": [ 1, 1, 1 ],  # initial x, y, z
           "npoints": 1E4 }  # set to None to use default evaluation points

# initial condition
init_cond = pinfo['init_state_vec']
tspan = pinfo['tspan']

# if a number of points has been declared then use it
try:
    tvals = np.linspace( tspan[0], tspan[1], pinfo['npoints'] )
except:
    tvals = None

# calling the ODE solver
soltn = solve_ivp( fun=lambda t, svec : lorentz_deriv(t,svec,pinfo), t_eval = tvals, t_span = tspan, y0=init_cond)

# extracting the results
t_plot = soltn.t # time values to plot
x_plot = soltn.y[0,:] # x variable from lorentz
y_plot = soltn.y[1,:] # y variable from lorentz
z_plot = soltn.y[2,:] # z variable from lorentz

# plot the results
pl.plot(t_plot,x_plot,color='black')
pl.plot(t_plot,y_plot,color='red')
pl.plot(t_plot,z_plot,color='blue')
pl.xlabel('time')
pl.ylabel('x, y, z')
pl.legend( [ 'x','y','z' ])
pl.show()

# making a 3D plot
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(x_plot,y_plot,z_plot)
plt.show()


from sympy import symbols, sin, cos, pi, latex, pprint
from sympy.diffgeom import Manifold, Patch, CoordSystem
from sympy.simplify import simplify

from common1 import plot_latex

r, theta = symbols('r, theta')
x, y = symbols('x, y')
m = Manifold('M', 2)
# 定义一个patch
patch = Patch('P', m)
# 为这个patch建立坐标系，一个是笛卡尔，一个是极坐标
rect: CoordSystem = CoordSystem('rect', patch)
polar = CoordSystem('polar', patch)
# print(rect in patch.coord_systems)
# 建立两个坐标系之间的转换关系，逆变换是自动的。
# 这个地方，如果笛卡尔是3维，另一个是2维曲面（但是也用u,v，不用极坐标，那会怎么样呢？）
polar.connect_to(rect, [r, theta], [r*cos(theta), r*sin(theta)])
# t = polar.coord_tuple_transform_to(rect, [1, pi])
# 极坐标存在奇点，r = 0时，其他怎么取都是0

t = polar.coord_tuple_transform_to(rect, [0, pi])
print(t)
t = polar.coord_tuple_transform_to(rect, [2, pi/2])
print(t)
t = rect.coord_tuple_transform_to(polar, [0, 2])
print(t)

# 雅克比矩阵。极坐标到笛卡尔坐标系的变换矩阵函数，在每个点，是可以求出一个具体的矩阵的
# 但整体来说是一个函数。
m = polar.jacobian(rect, [r, theta])
print(m)
plot_latex(latex(m))
# 笛卡尔坐标系到笛卡尔坐标系的雅克比矩阵是单位矩阵
m = rect.jacobian(rect, [x, y])
# plot_latex(latex(m))

p = rect.point([3, 2])
# base_vector返回一个向量场。给定一个点，会返回一个向量？
# v_x = rect.base_vector(0)
# v_y = rect.base_vector(1)
# pprint(v_x(p), v_y(p))

# 返回标量场。标量场的意思是取一个点，返回一个标量值。x y轴可以视为两个天然的标量场，但应该开可以返回其他标量场
x_scalar_field = rect.coord_function(0)

# 返回横坐标
print(x_scalar_field(p))

# base_oneform返回的又是什么？
# pprint(rect.base_oneform(0))


import numpy as np

try:
    import QENSmodels
except ImportError:
    print('Module QENSmodels not found')

def lorentzian(x, scale=1.0, center=0.0, hwhm=1.0):
    r""" Lorentzian model

    Parameters
    ----------
    x: float or list or :class:`~numpy:numpy.ndarray`
        domain of the function

    scale: float
        scale factor. Default to 1.

    center: float
        center of peak. Default to 0.

    hwhm: float
        Half Width at Half Maximum. Default to 1.

    Return
    ------
    float or :class:`~numpy:numpy.ndarray`
        output number or array

    Examples
    --------
    >>> round(lorentzian(1, 1, 1, 1), 3)
    0.318

    >>> round(lorentzian(3., 2., 2., 5.), 3)
    0.122

    >>> result = lorentzian([1, 3.], 1., 1., 1.)
    >>> round(result[0], 3)
    0.318
    >>> round(result[1], 3)
    0.064

    Notes
    -----
    * A Lorentzian function is defined as

    .. math::

       \text{Lorentzian}(x, \text{scale}, \text{center}, \text{hwhm}) =
       \frac{\text{scale}}{\pi} \frac{\text{hwhm}}
       {(x-\text{center})^2+\text{hwhm}^2}

    * Note that the maximum of a Lorentzian is
      :math:`\text{Lorentzian}(\text{center}, \text{scale}, \text{center},
      \text{hwhm})=\frac{\text{scale}}{\pi \text{hwhm}}`.

    * **Equivalence between different implementations**
      ``Lorentzian`` corresponds to the following implementations in
      `Mantid
      <http://docs.mantidproject.org/nightly/fitfunctions/Lorentzian.html>`__
      and
      `DAVE <https://www.ncnr.nist.gov/dave/documentation/pandoc_DAVE.pdf>`__

      +------------------+-----------------+------------------+
      | QENSmodels       | Mantid          |  DAVE            |
      +==================+=================+==================+
      | ``Lorentzian``   | ``Lorentzian``  |  ``Lorentzian``  |
      +------------------+-----------------+------------------+
      | ``scale``        | Amplitude       |  A               |
      +------------------+-----------------+------------------+
      | ``center``       | PeakCentre      |  :math:`x_0`     |
      +------------------+-----------------+------------------+
      | ``hwhm``         | FWHM /2         | W/2              |
      +------------------+-----------------+------------------+

    """
    # Input validation
    x = np.asarray(x)

    if hwhm == 0:
        model = QENSmodels.delta(x, scale, center)
    else:
        model = scale * hwhm / ((x - center)**2 + hwhm**2) / np.pi

    return model

if __name__ == "__main__":
    import doctest
    doctest.testmod()


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

readFilePath = r'C:\Users\Adarsh\Downloads\18100006-eng\ml_18100006.csv'

def estimate_coef(x, y):
    n = np.sign(x)
    m_x = np.mean(x)
    m_y = np.mean(y)
#    x = x.reshape((1, -1))
#    y = y.reshape(1,-1)
    SS_xx = 0
    SS_xy = 0
    SS_xy = np.sum(y * x - n * m_y * m_x)
    SS_xx = np.sum(x * x - n * m_x * m_x)

    #for i in range(1, (n-1)):
        #SS_xy = SS_xy + (y[i]*x[i] - n*m_y*m_x)
        #SS_xx = SS_xx+ (x[i]*x[i] - n*m_x*m_x)
    # calculating regression coefficients
    b_1 = SS_xy / SS_xx
    b_0 = m_y - b_1 * m_x
    return (b_0, b_1)

def plot_regression_line(x, y, b):
	# plotting the actual points as scatter plot
	plt.scatter(x, y, color = "m",
			marker = "o", s = 30)

	# predicted response vector
	y_pred = b[0] + b[1]*x

	# plotting the regression line
	plt.plot(x, y_pred, color = "g")

	# putting labels
	plt.xlabel('x')
	plt.ylabel('y')

	# function to show plot
	plt.show()

def main():
#    food = []
 #   transport = []
  #  shelter = []
   # all_items = []
    #months_count = []
    # row1 = ['date', 'Product Groups', 'Consumer Price Index']

    food = np.array()
    shelter = np.array()
    transport = np.array()
    all_items = np.array()
    months_count =np.array()
    with open(readFilePath, 'r', newline='') as readFile:
        # next(readFile)  # Skip over header in input file.
        readCSV = csv.reader(readFile, delimiter=',')

        i = 1.0
        for row in readCSV:
            if (row[1] in ('All-items')):
                all_items.append(row[2])
                months_count.append(i)
            elif (row[1] in ('Food')):
                food.append(row[2])
            elif (row[1] in ('Shelter')):
                shelter.append(row[2])
            elif (row[1] in ('Transportation')):
                transport.append(row[2])

            i = i+1.0
    all_items = [float(i) for i in all_items]
    print(all_items)

    #all_items = np.asarray(all_items)
    food = np.asarray(food)
    shelter = np.asarray(shelter)
    transport = np.asarray(transport)

    #print(months_count)
    b = estimate_coef(months_count,all_items)
    plot_regression_line(months_count,all_items,b)

if __name__ =="__main__":
    main()


import numpy as np
import numpy.linalg as la
from io import StringIO

def print_mat(mat):

    stream = StringIO()
    np.savetxt(stream, mat, fmt="%.3f")
    print( stream.getvalue() )

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

def get_convergent_vector(L, r_0, threshold):

    '''
    :param L: transition matrix
    :param r_0: initial vector
    :param threshold: parameter for convergence condition
    :return: convergent vector
    '''

    r_cur = r_0

    while True:

        r_next = np.matmul(L, r_cur)

        if la.norm(r_next - r_cur) < threshold:
            # check convergence condition is met or not
            break

        r_cur = r_next

    return r_cur

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

# transition matrix L
L_without_damping = np.array([
    [0,   1/2, 1/3, 0, 0,   0,   0 ],
    [1/3, 0,   0,   0, 1/2, 0,   0 ],
    [1/3, 1/2, 0,   1, 0,   1/3, 0 ],
    [1/3, 0,   1/3, 0, 1/2, 1/3, 0 ],
    [0,   0,   0,   0, 0,   0,   0 ],
    [0,   0,   1/3, 0, 0,   0,   0 ],
    [0,   0,   0,   0, 0,   1/3, 1 ],
])

h, w = L_without_damping.shape

if h != w:
    raise Exception('transition matrix should be a square matrix.')

n = h

# damping factor
d = 0.5

L_with_damping = L_without_damping * d + (1-d)/n * np.ones(n)

# initial vector for r
r_0 = ( np.ones(n) / n ) * 100.0

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

print_mat(L_without_damping)

result_without_damping = get_convergent_vector(L_without_damping, r_0, threshold=0.01)
print_mat(result_without_damping)

result_with_damping = get_convergent_vector(L_with_damping, r_0, threshold=0.01)
print_mat(result_with_damping)


from math import radians, cos, sin
import numpy as np
from numpy.linalg import inv

def rotation_matrix(theta):
    """Generates a 2-d rotation matrix.

    .. math::
        \\begin{pmatrix} \\cos\\theta & -\\sin\\theta \\\\ \\sin\\theta & \\
        \\cos\\theta \\end{pmatrix}

    Parameters
    ----------
    theta : float
        Angle of rotation in degrees.

    Returns
    -------
    ndarray
        A 2-d rotation matrix.

    """
    theta = radians(theta)
    matrix = np.array([
        [cos(theta), -sin(theta)],
        [sin(theta), cos(theta)]
    ])
    return matrix

def reflection_matrix(orientation=90.):
    """Generates a 2-d reflection matrix.

    .. math::
        \\begin{pmatrix} \\cos 2\\theta & \\sin 2\\theta \\\\ \\sin 2\\theta \\
        & -\\cos 2\\theta \\end{pmatrix}

    Parameters
    ----------
    orientation : float, optional
        Angle line of reflection makes to the x-axis in degrees.

    Returns
    -------
    ndarray
        A 2-d reflection matrix.

    """
    orientation = radians(orientation)
    return np.array([
        [cos(2 * orientation), sin(2 * orientation)],
        [sin(2 * orientation), -cos(2 * orientation)]
    ])

def check_orthogonal(matrix):
    """Checks if `matrix` is orthogonal by equating the inverse and transpose.

    Parameters
    ----------
    matrix : array_like
        An array representing a matrix.

    Returns
    -------
    bool
        True if the matrix is orthogonal, False otherwise.

    """
    matrix_t = np.transpose(matrix)
    matrix_i = inv(matrix)

    if not np.all(np.isclose(matrix_t, matrix_i)):
        return False
    return True

def get_point_group_transformation_matrix(matrix_type, rotation_or_matrix):
    """Generates a matrix from the input

    Parameters
    ----------
    matrix_type : function
        Any function able to return an orthogonal matrix.
    rotation_or_matrix : int, float, array_like
        An object to convert into a matrix. If an int or a float, this will be
        passed to the `matrix_type` creator. If a matrix, it will be checked
        for orthogonality.

    Returns
    -------
    ndarray
        A matrix representing the specified transformation.

    """
    matrix = None
    if matrix_type == "rotation":
        matrix_type = rotation_matrix
    elif matrix_type == "reflection":
        matrix_type = reflection_matrix

    if isinstance(rotation_or_matrix, float) or isinstance(rotation_or_matrix,
                                                           int):
        matrix = matrix_type(rotation_or_matrix)
    elif isinstance(rotation_or_matrix, np.ndarray):
        matrix = rotation_or_matrix
    if not check_orthogonal(matrix):  # Simple check to see if the matrix is a valid rotation matrix.
        raise ValueError(
            "Not a valid point group transformation matrix (non-orthogonal).")
    assert matrix is not None
    return matrix

def get_rotation_matrix(rotation):
    return get_point_group_transformation_matrix("rotation", rotation)

def get_reflection_matrix(orientation):
    return get_point_group_transformation_matrix("reflection", orientation)


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

# In[1]:

import scipy
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# In[2]:

housing_data = pd.read_csv('datasets/house_data_processed.csv')

housing_data.head()

# In[3]:

housing_data.shape

# In[4]:

plt.figure(figsize=(12, 8))

sns.boxplot(x='MEDV', data=housing_data, orient='v')

plt.show()

# In[5]:

plt.figure(figsize=(12, 8))

sns.distplot(housing_data['MEDV'], rug=True, hist=False)

plt.show()

# In[6]:

mean = np.mean(housing_data['MEDV'])
std = np.std(housing_data['MEDV'])

# In[7]:

mean, std

# #### For 68% confidence Interval

# In[8]:

conf_int_low, conf_int_high = scipy.stats.norm.interval(0.68, loc=mean, scale=std)

conf_int_low, conf_int_high

# In[9]:

plt.figure(figsize=(12, 8))

sns.distplot(housing_data['MEDV'], rug=True, kde=True, hist=False)

plt.stem([mean],
         [0.06], linefmt = 'C1',
         markerfmt = 'C1', label = 'mean', use_line_collection=True)

plt.stem([conf_int_low],
         [0.06], linefmt = 'C2',
         markerfmt = 'C2', label = '95% CI High', use_line_collection=True)

plt.stem([conf_int_high],
         [0.06], linefmt = 'C3',
         markerfmt = 'C3', label = '95% CI Low', use_line_collection=True)

plt.xlabel('MEDV')
plt.legend()
plt.show()

# ### For 90% confidence interval

# In[10]:

conf_int_low, conf_int_high = scipy.stats.norm.interval(0.90, loc=mean, scale=std)

conf_int_low, conf_int_high

# In[11]:

plt.figure(figsize=(12, 8))

sns.distplot(housing_data['MEDV'], rug=True, kde=True, hist=False)

plt.stem([mean],
         [0.06], linefmt = 'C1',
         markerfmt = 'C1', label = 'mean', use_line_collection=True)

plt.stem([conf_int_low],
         [0.06], linefmt = 'C2',
         markerfmt = 'C2', label = '95% CI High', use_line_collection=True)

plt.stem([conf_int_high],
         [0.06], linefmt = 'C3',
         markerfmt = 'C3', label = '95% CI Low', use_line_collection=True)

plt.xlabel('MEDV')
plt.legend()
plt.show()

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:

# In[ ]:


#!/usr/bin/env python3
## source: https://machinelearningmastery.com/singular-value-decomposition-for-machine-learning/

from numpy import array
from numpy import diag
from numpy import dot
from numpy import zeros
from scipy.linalg import svd

# Singular-value decomposition
def convert_to_svd(matrix):
    U, s, VT = svd(matrix)
    return U,s,VT

# Reconstruct SVD
def reconstruct_source_from_svd(U,s,VT, row_size, col_size, truncate=False, n_elements=2):
    """
    ## truncate,n_elements flow is also available via TruncatedSVD
    from sklearn.decomposition import TruncatedSVD

    # svd
    svd = TruncatedSVD(n_components=2)
    svd.fit(A)
    result = svd.transform(A)
    print(result)
    """
    # create m x n Sigma matrix
    Sigma = zeros((row_size, col_size))
    if row_size == col_size:
        Sigma = diag(s)
    elif row_size < col_size:
        # populate Sigma with m x m diagonal matrix
        Sigma[:row_size, :row_size] = diag(s)
    elif row_size > col_size:
        # populate Sigma with n x n diagonal matrix
        Sigma[:col_size, :col_size] = diag(s)
    if truncate == True:
        Sigma = Sigma[:, :n_elements]
        VT = VT[:n_elements, :]
        # transform
        T = U.dot(Sigma)
        print(T)
        T = A.dot(VT.T)
        print(T)
    # reconstruct matrix
    return U.dot(Sigma.dot(VT))

if __name__ == "__main__":
    # define main data matrix
    A = array([
        [1, 200, 3, 4],
        [3, 400, 500, 6],
        [500, 6, 7, 800],
    ])
    print("Main Matrix:\n%s" % A)
    print("rows: %s, cols: %s" % (A.shape[0], A.shape[1]))
    U,s,VT = convert_to_svd(A)
    print("\nSVD:\n%s" % s)
    print("%s singular-values" % len(s))
    ReA = reconstruct_source_from_svd(U,s,VT, 3, 4)
    print("\nReconstructed Matrix:\n %s" % A)


# merge parts of array a
# lower part: p to q
# upper part: q+1 to r
def merge(a, p, q, r):
    # number of elements in lower part
    n1 = q - p + 1
    # number of elements in upper part
    n2 = r - q

    # we now create new arrays and fill them with elements
    # from upper and lower parts of a
    L = [float('-inf')] * n1
    R = [float('-inf')] * n2

    l_index = 0
    for i in range(p, q + 1):
        L[l_index] = a[i]
        l_index += 1

    r_index = 0
    for i in range(q + 1, r + 1):
        R[r_index] = a[i]
        r_index += 1

    # to iterate over L
    i = 0
    # to iterate over R
    j = 0
    # to iterate over a
    k = p

    for k in range(p, r + 1):
        # break the loop if one the arrays no longer has elements
        # in which case we need to fill A with the elements remaining in the other array
        if i >= len(L) or j >= len(R):
            break

        if L[i] <= R[j]:
            a[k] = L[i]
            i += 1
        else:
            # R[j] > L[i]
            a[k] = R[j]
            j += 1

    # filling a with whatever elements are left in either arrays
    while i < len(L):
        a[k] = L[i]
        i += 1
        k += 1

    while j < len(R):
        a[k] = R[j]
        j += 1
        k += 1

# Runtime Average-case: Theta(n lgn)
# Runtime Best-case: Theta(n lgn)
# Runtime Worst-case: Theta(n lgn)
# In Place: No
# Stable: Yes
def merge_sort(a, p, r):
    # ie if array is not empty
    if p < r:
        # q is the middle element so we're splitting the array in half
        q = int((p + r) / 2)

        merge_sort(a, p, q)
        merge_sort(a, q + 1, r)

        merge(a, p, q, r)

a = [10, 4, 6, 8, 9, 3, 5, 1]

merge_sort(a, 0, len(a) - 1)

# from numpy import random
#
# for i in range(0, 100):
#     a = random.randint(100, size=100)
#     b = a.copy()
#
#     a = sorted(a)
#     merge_sort(b, 0, len(b) - 1)
#
#     identical = True
#
#     for j in range(0, len(a)):
#         if a[j] != b[j]:
#             identical = False
#             break
#
#     if identical:
#         print("Arrays are identical")
#     else:
#         print("Arrays are not identical")


# Logistic regression
#%%
# Importing libraries
import numpy as np
import random
from matplotlib import pyplot as plt

#%%
class LogisticRegression():
    def __init__(self):
        self.w = np.random.rand(1,1)
        self.b = np.random.rand(1,1)
        self.J = 0

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

    def __step(self, w, b, X, y, alpha, m, print_params=False):
        """ Implements one step of backpropagation """
        if print_params:
            print("w.shape:",w.shape)
            print("b.shape:", b.shape)
            print("X.shape:", X.shape)
            print("y.shape:", y.shape)
        Z = np.dot(w, X) + b
        # print("Z.shape:", Z.shape)
        A = self.__sigmoid(Z)
        # print("A.shape:", A.shape)
        dZ = A - y
        # print("dZ.shape:", dZ.shape)
        dw = np.dot(dZ, X.T) / m
        db = np.sum(dZ) / m
        w = w - alpha * dw
        b = b - alpha * db
        J = np.sum(-y * np.log(A) - (1-y) * np.log(1-A)) / m
        return w, b, J

    def train(self, X, y, print_params=False):
        """ Trains logsitic regression model - X is N x M matrix and y is 1 x M matrix """
        alpha = 0.01
        m = 1000
        for i in range(100000):
            self.w, self.b, self.J = self.__step(self.w, self.b, X, y, alpha, m)
            if print_params:
                print("J:", self.J)
                print("w:", self.w, "b:", self.b)
                print("========")

    def predict(self, x_tst):
        """ Returns the prediction of the input x_tst - x_tst should be 1 x N vector """
        return self.__sigmoid(np.dot(self.w, x_tst) + self.b)

#%%
# Generating training data
x = np.linspace(1, 10, 1000)[:, np.newaxis].T
y = np.hstack((np.zeros((1,500)), np.ones((1,500))))

# Adding some randomness
y[0,random.randint(0,500)] = 1
y[0,random.randint(500,1000)] = 0
print("X is", x.shape)
print("y is", y.shape)

#%%
# Creating and training the model
model = LogisticRegression()
model.train(x, y)

#%%
# Generating a test example
x1 = np.array([[0.05]])
# Predicting the output
y1 = model.predict(x1)
print("Prediction of", x1, " is", y1)

#%%
# Generating predictions for all input examples X
x_test = np.linspace(1, 10, 100)[:,np.newaxis].T
y_p = model.predict(x_test)

#%%
# Plotting training data
plt.figure(0)
plt.plot(x, y, "r+")
# plt.show()
# Plotting predictions
print("x is", x.shape, "and y_p is", y_p.shape)
print("max of y_p:", np.max(y_p))
plt.plot(x_test, y_p, "bo")
plt.show()


#	...................................................................................
'''
author: Palash Nandi.
'''
#	...................................................................................

import math
import random
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from collections import Counter
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
import seaborn as sns
import matplotlib.pyplot as plt
from tqdm import tqdm
from numpy import linalg as eigen_decomp

import read_dataset as rd
#	.....................................
def check_ratios(x):
    sum_ = np.sum(x)
    _ = [ i/sum_ for i in x]
    _.sort(reverse=True)

    print(f'The normalized variances are: {_}')

# 	.....................................
def PCA_from_scratch_linalg(df):
	print(f'PCA from scratch using linalg of Numpy')

	mean_arr = df.mean(axis = 0).to_numpy()
	X = np.array(df) - mean_arr
	X_T = X
	X = X.T
	# print(f'X: {X.shape}')
	# print(f'X_T: {X_T.shape}')

	covarience_matrix = np.matmul(X, X_T) / X.shape[1]

	print(f'X: {X.shape}, X_T: {X_T.shape}, cov_mat: {covarience_matrix.shape}\n')
	# print(covarience_matrix)

	lambdas, e_vecs = eigen_decomp.eig(covarience_matrix)
	# print(lambs)
	# Numpy returns the eigen vectors column-wise
	print(f'\nEigen vectors are:\n{np.transpose(e_vecs)}\n')
	check_ratios(lambdas)

# 	.....................................
def PCA_from_scratch_SVD(df):
	print(f'\n\nPCA from scratch using SVD of Numpy')
	mean_arr = df.mean(axis = 0).to_numpy()
	X = np.array(df) - mean_arr
	X_T = X
	X = X.T
	# print(f'X: {X.shape}')
	# print(f'X_T: {X_T.shape}')
	covarience_matrix = np.matmul(X, X_T) / X.shape[1]
	print(f'X: {X.shape}, X_T: {X_T.shape}, cov_mat: {covarience_matrix.shape}\n')
	# print(covarience_matrix)

	u, s, vh = np.linalg.svd(X, full_matrices=True)
	# print(f'u: {u.shape}, s: {s.shape}, vh: {vh.shape}')
	e_vec = []
	for eigenvector in np.transpose(u):
	    e_vec.append(np.dot(eigenvector.T, np.dot(covarience_matrix, eigenvector)))

	# Numpy returns the eigen vectors row-wise
	print(f'\nEigen vectors are:\n{np.transpose(u)}\n')
	check_ratios(e_vec)

# 	.....................................
def PCA_from_scratch_sklearn(df):
	#  PCA needs df in (row_number, features) format
	print(f'\n\nPCA from sklearn')

	eigenvalue_list = []
	mean_arr = df.mean(axis = 0).to_numpy()
	X = np.array(df) - mean_arr
	X_T = X
	X = X.T
	pca = PCA(n_components=X.shape[0])
	pca.fit(X_T)

	# print(pca.explained_variance_ratio_)
	# print(pca.singular_values_)
	# print(pca.components_.shape)

	for eigenvalue, eigenvector in zip(pca.explained_variance_ratio_, pca.components_):
	    eigenvalue_list.append(eigenvalue)

	print(f'\nEigen vectors are:\n{pca.components_}\n')
	print(f'Eigen values: {eigenvalue_list}')

#	.....................................
# dataset_path = 'iris_dataset.csv'
# dataset_path = 'cancer_data.csv'
# dataset_path = 'mall_customer_dataset.csv'
dataset_path = 'wine_quality_dataset.csv'

print('\n\n\n')

df = rd.read_dataset(dataset_path)
PCA_from_scratch_linalg(df)
PCA_from_scratch_SVD(df)
PCA_from_scratch_sklearn(df)

print('\n\n\n')


import numpy

# initialize two array
x = numpy.array([[1, 2], [3, 4]], dtype=numpy.float64)
y = numpy.array([[3, 4], [5, 6]], dtype=numpy.float64)

print('Print the two matrices')
print('X = \n', x)
print('Y = \n', y)

# Elementwise sum; both produce the array
print('\nElementwise addition of two matrices: ( X + Y of Matlab )')
print('Add using add operator: \n', x + y)
print('Add using add function: \n', numpy.add(x, y))

# Elementwise difference; both produce the array
print('\nElementwise subtraction of two matrices: ( X - Y of Matlab )')
print('Subtract using operator: \n', x - y)
print('Subtract using function: \n', numpy.subtract(x, y))

# Elementwise product; both produce the array
print('\nElementwise Multiplication of two matrices: ( X .* Y of Matlab )')
print('Multiply using operator: \n', x * y)
print('Multiply using function: \n', numpy.multiply(x, y))

# Elementwise division; both produce the array
print('\nElementwise division of two matrices: ( X ./ Y of Matlab )')
print('Division using operator: \n', x / y)
print('Division using function: \n', numpy.divide(x, y))

# Elementwise square root; produces the array
print('\nSquare root each element of X matrix\n', numpy.sqrt(x))

# Matrix Multiplication
print('\nMatrix Multiplication of two matrices: ( X * Y of Matlab )')
print(x.dot(y))


#!/usr/bin/env python

'''

@Author: Balasubramanyam Evani
Manipal University Jaipur

Visualization helper script

'''

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib import cm
import scipy.interpolate as interp

##### Objective functions

def f_M(X , Y):
    return -1.0 * ((np.sin(X) * np.power( np.sin( (X**2) / np.pi ) , 20)) + (np.sin(Y) * np.power( np.sin( (2 * Y**2) / np.pi ) , 20)))

def f_R(X, Y):
    return (1 - X)**2 + 100*(Y - X**2)**2

def f_S(X, Y):
    return X**2 + Y**2

def f_A(X, Y):
    return -20 * np.exp(-0.20 * np.sqrt(0.5*(X**2 + Y**2))) - np.exp(0.5*(np.cos(2*np.pi*X) + np.cos(2*np.pi*Y))) + 20 + np.e

####### Surface Plots

def Visualization_Michalewicz():

    X = np.linspace(0 , np.pi , 100)
    Y = np.linspace(0 , np.pi , 100)
    X,Y = np.meshgrid(X , Y)
    Z = f_M(X , Y)
    plt.figure(1)
    ax = plt.axes(projection='3d')
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,linewidth=0, antialiased=False)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')

def Visualization_Rosenbrock():

    X, Y = np.meshgrid(np.linspace(-1.3, 1.3, 31), np.linspace(-0.9, 1.7, 31))
    Z = f_R(X, Y)
    plt.figure(1)
    ax = plt.axes(projection='3d')
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,linewidth=0, antialiased=False)

def Visualization_Sphere():

    X, Y = np.meshgrid(np.linspace(-1.3, 1.3, 31), np.linspace(-1.3, 1.3, 31))
    Z = f_S(X, Y)
    plt.figure(1)
    ax = plt.axes(projection='3d')
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,linewidth=0, antialiased=False)

def Visualization_Ackley():

    X,Y = np.meshgrid(np.linspace(-4, 4, 31), np.linspace(-4, 4, 31))
    Z = f_A(X, Y)
    plt.figure(1)
    ax = plt.axes(projection='3d')
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,linewidth=0, antialiased=False)

######## Contour Visualization

def contour_Michalewicz():

    plt.figure(2)
    X = np.linspace(0 , np.pi , 100)
    Y = np.linspace(0 , np.pi , 100)
    X,Y = np.meshgrid(X , Y)
    Z = f_M(X , Y)
    plt.contourf(X,Y,Z)

def contour_Rosenbrock():

    plt.figure(2)
    X, Y = np.meshgrid(np.linspace(-1.3, 1.3, 31), np.linspace(-0.9, 1.7, 31))
    Z = f_R(X, Y)
    plt.contourf(X,Y,Z)

def contour_Sphere():

    plt.figure(2)
    X, Y = np.meshgrid(np.linspace(-1.3, 1.3, 31), np.linspace(-1.3, 1.3, 31))
    Z = f_S(X, Y)
    plt.contourf(X,Y,Z)

def contour_Ackley():

    plt.figure(2)
    X, Y = np.meshgrid(np.linspace(-4, 4, 31), np.linspace(-4, 4, 31))
    Z = f_A(X, Y)
    plt.contour(X,Y,Z)


import numpy as np
from scipy import optimize

from matplotlib import pyplot as plt, cm, colors

def distance_from_center(c, x, y):
    '''
    Distance of each 2D points from the center (xc, yc)

    Parameters
    ----------
    c : array_like
        Coordinates of the center

    x,y : array_like
        Arrays with the x,y coordinates
    '''
    xc = c[0]
    yc = c[1]

    Ri = np.sqrt((x-xc)**2 + (y-yc)**2)

    return Ri - Ri.mean()

def least_square_circle(x, y):
    '''
    Least-square determination of the center of a circle

    Parameters
    ----------
    x,y : array_like
        Arrays with the x,y coordinates of the points on/inside the circle
    '''

    # coordinates of the barycenter
    x_m = np.mean(x)
    y_m = np.mean(y)
    center_estimate = x_m, y_m

    center, ier = optimize.leastsq(distance_from_center, center_estimate, args=(x, y))

    # results
    xc, yc = center
    Ri     = np.sqrt((x-xc)**2 + (y-yc)**2)
    R      = Ri.mean()
    residu = np.sum((Ri - R)**2)

    return xc, yc, R, residu

def plot_data_circle(x, y, xc, yc, R):
    f = plt.figure(0)
    plt.axis('equal')

    theta_fit = np.linspace(-np.pi, np.pi, 180)

    x_fit = xc + R*np.cos(theta_fit)
    y_fit = yc + R*np.sin(theta_fit)
    plt.plot(x_fit, y_fit, 'b-', label="fitted circle", lw=2)
    plt.plot([xc], [yc], 'bD', mec='y', mew=1)
    plt.xlabel('x')
    plt.ylabel('y')

    # plot data
    plt.plot(x, y, 'r-.', label='data', mew=1)

    plt.legend(loc='best', labelspacing=0.1)
    plt.grid()
    plt.title('Least Squares Circle')


import numpy as np
import math
def euclid_distance(X1, X2):
    #return np.linalg.norm(X1, X2)
    sqrsum = 0
    for i in range(len(X1)):
        sqrsum += (X1[i] - X2[i]) ** 2
    return math.sqrt(sqrsum)

class k_means():
    """K defines the number of clusters that the algorithm needs to find.
       X is the training X, and y is the training y,
       num_iters is the number of iterations that needs to perform,
       is_noisy is a boolean to control the stdout"""
    def __init__(self, k, X, y, num_iters, is_noisy, tolerance):
        self.is_noisy = is_noisy
        self.random_initialize(k, X)
        self.num_iters = num_iters
        self.clusters = [ []  for i in range(k)]
        self.X = X
        self.tolerance = tolerance
        if(is_noisy):
            print('Init completed.')

    """This function randomly choose k numbers of samples as the original center.
    """
    def random_initialize(self, k, X):
        #do the random_initialization to randomly select centroids
        rand_indexes = np.arange(k * 2)
        np.random.shuffle(rand_indexes)
        rand_indexes = rand_indexes[:k]
        self.centroids = [ X[i] for i in rand_indexes ]
        if(self.is_noisy):
            print('Randomly Selected Centroids: ')
            print(self.centroids)
    """
    The classify step, where it's updated by choosing the minimun distance to the
    center as it's cluster.
    """
    def classify(self):
        for i in range(self.num_iters):
            self.clusters = [[] for i in range(0, len(self.centroids))]
            for x in self.X:
                distances = [ euclid_distance(x, centroid) for centroid in self.centroids ]
                self.clusters[distances.index(min(distances))].append(x)
            old_centroids = self.centroids
            self.update_centroids()
            if(self.is_noisy):
                print("> epoch {0} completed, new centroids: {1}".format(i, self.centroids_toString()))
            if(self.tolerance!=0):
                if(self.is_noisy):
                    print("Checking tolerance ...")
                if(self.check_tolerance(old_centroids)):
                    break
    """
    Turn the numpy array into string for print.
    """
    def centroids_toString(self):
        string_centroids = []
        for centroid in self.centroids:
            string_centroids.append(np.array2string(centroid, precision=2, separator=',', suppress_small=True))
        return ','.join(string_centroids)

    def train(self):
        self.classify()
        resultX = []
        resultLabel = []
        for i in range(0,len(self.clusters)):
            for item in self.clusters[i]:
                resultX.append(item)
                resultLabel.append(i)
        return (resultX, resultLabel)

    def update_centroids(self):
        for i in range(len(self.clusters)):
            cur_cluster = self.clusters[i]
            self.centroids[i] = np.average(cur_cluster, axis = 0)
    """
    Determine when to stop if tolerance is set, it's determined by the updated distance
    between old centroid and the latest one.
    """
    def check_tolerance(self, old_centroids):
        isOptimal = False
        for i in range(len(self.centroids)):
            isOptimal = isOptimal and np.sum((old_centroids[i] - self.centroids[i]) / self.centroids[i] * 100) < tolerance
        return isOptimal


import numpy as np
import matplotlib.pyplot as plt

# Exercise 1

# Function definition
def myfunc( x ):
   out = np.cos(x) * np.exp(x)
   return out

# Exercise 2

# a) plot function

# create vector for x
x = np.linspace(-2*np.pi, 2*np.pi, 100, endpoint=True);
print x

# call the function
y = myfunc(x);

# plot the data
plt.plot(x, y)
plt.grid()
plt.ylabel('cos(x) * exp(x)')
plt.xlabel('x')

# b) store image
plt.savefig('myfunc.png')
plt.show()

# Exercise 3

# e) fix random seed
np.random.seed(123)

# a) normal distrubution
mu, sigma = 5.0, 2.0
normal_vector = np.random.normal(mu, sigma, 100000)

# b) uniform distribution
uniform_vector = np.random.uniform(0, 10, 100000)

# c) print mean and std. dev.
print np.mean(normal_vector), np.std(normal_vector)
print np.mean(uniform_vector), np.std(uniform_vector)

# d) plot
plt.figure()
count, bins, ignored = plt.hist(uniform_vector, 100, normed=True)
plt.plot(bins, np.ones_like(bins)*0.1, linewidth=2, color='r')

plt.figure()
count, bins, ignored = plt.hist(normal_vector, 100, normed=True)
plt.plot(bins, 1/(sigma * np.sqrt(2 * np.pi)) *
                np.exp( - (bins - mu)**2 / (2 * sigma**2) ),
         linewidth=2, color='r')

plt.show()


# python simulation of mvp transformation

import numpy as np

def get_model_matrix(angle, scale, x, y, z):
    R = np.array([[np.cos(angle), 0, np.sin(angle), 0], [0, 1, 0, 0], [-1*np.sin(angle), 0, np.cos(angle), 0], [0, 0, 0, 1]])
    S = np.array([[scale, 0, 0, 0], [0, scale, 0, 0], [0, 0, scale, 0], [0, 0, 0, 1]])
    T = np.array([[1, 0, 0, x], [0, 1, 0, y], [0, 0, 1, z], [0, 0, 0, 1]])
    TxR = np.dot(T, R)
    TxRxS = np.dot(TxR, S)
    return TxRxS

def get_view_matrix(x, y, z):
    view_matrix = np.array([[1, 0, 0, -1*x], [0, 1, 0, -1*y], [0, 0, 1, -1*z], [0, 0, 0, 1]])
    return view_matrix

def get_projection_matrix(eye_fov, aspect_ratio, z_near, z_far):
    b = 1 / np.tan(eye_fov / 2)
    a = b / aspect_ratio
    z_near = -1 * z_near
    z_far = -1 * z_far
    k = 1 / (z_near-z_far)
    c = (z_near+z_far)*k
    d = 2*z_near*z_far*k
    projection_matrix = np.array([[a, 0, 0, 0], [0, b, 0, 0], [0, 0, c, d], [0, 0, 1, 0]])
    return projection_matrix

if __name__ == "__main__":
    x1, y1, z1 = 2.203125, 4.0859375, 3.5859375
    view_matrix = get_view_matrix(x1, y1, z1)
    print("The view matrix is:\n")
    print(view_matrix)
    print("\n\n################\n\n")

    x2, y2, z2 = 3.315235, 6.59312, 1.23589
    angle = 0.78539815
    scale = 1.4609375
    model_matrix = get_model_matrix(angle, scale, x2, y2, z2)
    print("The model matrix is:\n")
    print(model_matrix)
    print("\n\n################\n\n")

    projection_matrix = get_projection_matrix(1.04719753, 1.6789, 2.203125, 4.0859375)
    print("The projection matrix is:\n")
    print(projection_matrix)
    print("\n\n################\n\n")

    print("The mvp matrix is:\n")
    print(np.dot(np.dot(projection_matrix, view_matrix), model_matrix))


from math import sqrt, pow
from distributions import norm
import scipy.stats as ss

# Cuando la desviacion poblacional es conocidad se recibe average (X barra) (s) que es la desviacion
# n que es tamano de la muestra y (z) que se define dependiendo del coeficiente de confianza deseado
# Seria 1.96 para un coeficiente de confianza del 95%
# 2.58 para un 99%
# 1.64 para 90%
def interval_poblational_average(average, s, n, z):
    standard = s / sqrt(n)
    minimun = average - z*standard
    maximun = average + z*standard
    return (minimun, maximun)

def interval_poblational_average_scipy(average, s, n, confidence_level):
  return ss.norm(average, s / (n**0.5)).interval(confidence_level)

def interval_poblational_average_t(average, deviation, sample_length, alpha):
  t = ss.t.interval(alpha, sample_length - 1)[1]
  standard = deviation / sqrt(sample_length)
  minimun = average - t*standard
  maximun = average + t*standard

  return (minimun, maximun)

def get_interval_p(n, n_special, z):
    p = n_special / n
    sp = sqrt((p * (1 - p)) / n)
    mini = p - z * sp
    maxi = p + z * sp
    return (mini, maxi)

def get_sample_length(z, s, error):
  return (pow(z, 2) * pow(s,2)) / pow(error, 2)

def get_sample_length_p_m(z, variance_p, average_m, average_p):
  return (pow(z, 2) * pow(variance_p, 2)) / (pow(average_m - average_p, 2))

def get_sample_length_p_p(z, proportion_p, proportion_m):
  pi = ( proportion_p ) * ( 1 - proportion_p )
  return (pow(z, 2) * pi) / pow( proportion_m - proportion_p, 2 )

def get_z(coefficient):
  return norm(1, 0, 0, coefficient / 2)


import numpy as np

def calculate(list):
  if len(list) != 9:
    raise ValueError("List must contain nine numbers.")

  else:
    list = np.array(list)

    #print(list)

    #initial declaration

    mean_col = [list[[0, 3, 6]].mean(), list[[1, 4, 7]].mean(), list[[2, 5, 8]].mean()]
    mean_rows = [list[[0, 1, 2]].mean(), list[[3, 4, 5]].mean(), list[[6, 7, 8]].mean()]

    var_col = [list[[0, 3, 6]].var(), list[[1, 4, 7]].var(), list[[2, 5, 8]].var()]
    var_rows = [list[[0, 1, 2]].var(), list[[3, 4, 5]].var(), list[[6, 7, 8]].var()]

    std_col = [list[[0, 3, 6]].std(), list[[1, 4, 7]].std(), list[[2, 5, 8]].std()]
    std_rows = [list[[0, 1, 2]].std(), list[[3, 4, 5]].std(), list[[6, 7, 8]].std()]

    min_col = [list[[0, 3, 6]].min(), list[[1, 4, 7]].min(), list[[2, 5, 8]].min()]
    min_rows = [list[[0, 1, 2]].min(), list[[3, 4, 5]].min(), list[[6, 7, 8]].min()]

    max_col = [list[[0, 3, 6]].max(), list[[1, 4, 7]].max(), list[[2, 5, 8]].max()]
    max_rows = [list[[0, 1, 2]].max(), list[[3, 4, 5]].max(), list[[6, 7, 8]].max()]

    sum_col = [list[[0, 3, 6]].sum(), list[[1, 4, 7]].sum(), list[[2, 5, 8]].sum()]
    sum_rows = [list[[0, 1, 2]].sum(), list[[3, 4, 5]].sum(), list[[6, 7, 8]].sum()]

    #return calculations
    return {
    'mean': [mean_col, mean_rows, list.mean()],
    'variance': [var_col, var_rows, list.var()],
    'standard deviation': [std_col, std_rows, list.std()],
    'max': [max_col, max_rows, list.max()],
    'min': [min_col, min_rows, list.min()],
    'sum': [sum_col, sum_rows, list.sum()]
  }