import numpy as np
import scipy.stats as si

    #S: spot price
    #K: strike price
    #T: time to maturity % year; choose 252 trading days or 365 calendar days i.e 30/252 or 30/365, it should be how much time left not total option duration
    #r: interest rate
    #sigma: volatility of underlying asset
    #q: continuous dividend rate

p = print
    # annual dividend yield; use this only if you are unsure
def div_yield(freq, S, div):
    div_yield = np.log((div * freq)/S)
    return div_yield

def err_msg(option_type):
    p('{0} is not valid option type\nchoose c for call and p for put').format(option_type)

def checks(sigma, S, K, r, T, q):
    arr = [sigma, S, K, r, T, q]
    for i in arr:
        if np.isnan(i):
            p('input not number')
        if not i:
            p('input missing\n ')

def d1(sigma, S, K, r, T, q):
    #checks(sigma, S, K, r, T, q)
    d1 = (np.log(S / K) + (r - q + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    return d1

def d2(sigma, S, K, r, T, q):
    #checks(sigma, S, K, r, T, q)
    d2 = d1(sigma, S, K, r, T, q) - sigma * np.sqrt(T)
    return d2

    #div paying asset using BSM
def bsm_price(option_type, sigma, S, K, r, T, q):

    option_type = option_type.lower()

    #bsm formula for pricing
    _d1 = d1(sigma, S, K, r, T, q)
    _d2 = d2(sigma, S, K, r, T, q)

    if option_type == 'c':
        price = S * si.norm.cdf(_d1, 0.0, 1.0) - K * np.exp(-r * T) * si.norm.cdf(_d2, 0.0, 1.0)
        return price
    elif option_type == 'p':
        price = K * np.exp(-r * T) * si.norm.cdf(-_d2, 0.0, 1.0) - S * np.exp((r - q) * T) * si.norm.cdf(-_d1, 0.0, 1.0)
        return price
    else:
        err_msg(option_type)

    #bsm formula for delta
def delta(option_type, sigma, S, K, r, T, q):
    option_type = option_type.lower()

    _d1 = d1(sigma, S, K, r, T, q)

    if option_type == 'c':
        delta = np.exp(-q*T) * si.norm.cdf(_d1)
        return delta
    elif option_type == 'p':
        delta = np.exp(-q*T) * (si.norm.cdf(_d1) - 1)
        return delta
    else:
        err_msg(option_type)

    #bsm formula for gamma
def gamma(sigma, S, K, r, T, q):

    _d1 = d1(sigma, S, K, r, T, q)

    gamma = np.exp(-q * T - 0.5 * _d1 ** 2)/ (S * sigma * np.sqrt(2 * np.pi * T))
    return gamma

    #bsm formula for vega
def vega(sigma, S, K, r, T, q):

    _d1 = d1(sigma, S, K, r, T, q)

    vega = 0.01 * S * np.exp(-q * T) * np.sqrt(T) * np.exp(- 0.5 * _d1 ** 2)/ np.sqrt(2 * np.pi)
    return vega

# Enhanced IV based on research BS estimator; P and C should have the same unless arbitrage
def IV(option_type, sigma, S, K, r, T, q):
    option_type = option_type.lower()
    option = bsm_price(option_type, sigma, S, K, r, T, q)
    cm1 = np.sqrt( 2 * np.pi )/ ( 2 * ( S + K ))
    br1 = ( 2 * option ) + K - S
    br2 = ( 1.85 * (S + K) * (K - S) ** 2) / ( np.pi * np.sqrt( S * K ))
    IV = cm1 * ( br1 + np.sqrt( br1 ** 2 - br2 ))
    return IV


#@ Model: Transportation Assignment
#@ Description: Model to find minimum cost assignment between warehouses and retailers, given supply and demand constraints $$\min \sum_{i=1}^{3}\sum_{j=1}^{4}c_{ij}x_{ij}$$$$\sum_{j=1}^4 x_{ij}=s_i,\quad\forall i=1,2,3$$$$\sum_{i=1}^3 x_{ij}=d_j,\quad\forall j=1,2,3,4$$$$x_{ij}\geq 0 \quad\forall i,j$$

import cvxpy as cp
import json

#@ Input Object: s
#@ Description: Supply from each warehouse
s = [500,700,800]

#@ Input Object: d
#@ Description: Demand from each retailer
d = [400,900,200,500]

#@ Input Object: c
#@ Description: Matrix of costs
c = [[12,13,4,6],[6,4,10,11],[10,9,12,14]]

#@ Variable: x
#@ Description: Assignment from warehouse i to retailer j (non-negative)
#@ Labels: x_labels
x = cp.Variable((3,4), nonneg=True)

warehouse = ['A', 'B', 'C']
retailer = ['W', 'X', 'Y', 'Z']
x_labels = {}
for i in range(3):
    for j in range(4):
        x_labels[(i,j)] = '{} to {}'.format(warehouse[i], retailer[j])

#@ Function: objectivefn
#@ Description: Costs (minimize) $$\sum_{i=1}^3\sum_{j=1}^4 c_{ij}x_{ij}$$
objectivefn = cp.sum(cp.multiply(c,x.T))

#@ Constraint: supply
#@ Description: $$\sum_{j=1}^3 x_{ij} = s_i,\quad\forall i=1,2,3$$
#@ Labels: supply_labels
supply = cp.sum(x, axis=1) == s

supply_labels = {}
for i in range(3):
    supply_labels[i] = 'supply warehouse {}'.format(warehouse[i])

#@ Constraint: demand
#@ Description: $$\sum_{i=1}^4 x_{ij} = d_j,\quad\forall j=1,2,3,4$$
#@ Labels: demand_labels
demand = cp.sum(x, axis=0) == d

demand_labels = {}
for j in range(4):
    demand_labels[j] = 'demand retailer {}'.format(retailer[j])

#@ Problem: assignment
constraints = []
constraints.append(supply)
constraints.append(demand)

assignment = cp.Problem(cp.Minimize(objectivefn), constraints)

#@ Solver: solver
solver = "ECOS"

assignment.solve(solver=solver, verbose=True)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan  6 10:12:44 2021

@author: vganapati
"""

import numpy as np
import matplotlib.pyplot as plt

def F(mat2D): # Fourier transform assuming center pixel as center
    return np.fft.fftshift(np.fft.fft2(np.fft.fftshift(mat2D)))

def Ft(mat2D): # Inverse Fourier transform assuming center pixel as center
    return np.fft.ifftshift(np.fft.ifft2(np.fft.ifftshift(mat2D)))

def make_meshgrid(dx = 0.01,
                  dy = 0.01,
                  Lx_max = 1,
                  Ly_max = 1):

    Lx_min = -Lx_max
    Ly_min = -Ly_max
    x = np.arange(Lx_min,Lx_max,dx)
    y = np.arange(Ly_min,Ly_max,dy)
    xm, ym = np.meshgrid(x,y, indexing='ij')
    extent = [Lx_min, Lx_max-dx, Ly_min, Ly_max-dy]

    # Fourier transform dimensions
    F_extent = [len(x)/(4*Lx_min), len(x)/(4*Lx_max) - 1/(Lx_max*2),
                len(y)/(4*Ly_min), len(y)/(4*Ly_max) - 1/(Ly_max*2)]

    return(x,y,xm,ym,extent,F_extent)

def make_circle(dx = 0.01,
                dy = 0.01,
                Lx_max = 1,
                Ly_max = 1,
                a = 1, # stretch in x
                b=1, # stretch in y
                ):

    x,y,xm,ym,extent,F_extent = make_meshgrid(dx,
                                              dy,
                                              Lx_max,
                                              Ly_max)

    circle = np.zeros_like(xm)
    circle[((a*xm)**2+(b*ym)**2) < 1] = 1
    circle[((a*xm)**2+(b*ym)**2) == 1] = 0.5

    F_circle = F(circle)

    return(circle, extent, F_circle, F_extent)

def plot(img, extent, log=False, figsize_x = 10, figsize_y = 10):

    if log:
        img_abs = np.log(np.abs(img))
    else:
        img_abs = np.abs(img)

    plt.figure(figsize = [figsize_x,figsize_y])
    plt.title('Magnitude')
    plt.imshow(img_abs, interpolation='none', extent = extent, cmap='gray')
    plt.colorbar()

    plt.figure(figsize = [figsize_x,figsize_y])
    plt.title('Phase')
    plt.imshow(np.angle(img), interpolation='none', extent = extent, cmap='hsv',
               vmin = -np.pi, vmax = np.pi)
    plt.colorbar()

def rect(mesh):
    output = np.zeros_like(mesh)
    output[np.abs(mesh)<0.5] = 1
    output[np.abs(mesh)==0.5] = 0.5
    return(output)

def triangle(mesh):
    output = np.zeros_like(mesh)
    output[np.abs(mesh)<=1] = 1 - np.abs(mesh[np.abs(mesh)<=1])
    return(output)

def sgn(mesh):
    output = np.zeros_like(mesh)
    output[mesh>0] = 1
    output[mesh<0] = -1
    return(output)

def comb(mesh):
    output = np.zeros_like(mesh)
    output[np.abs(mesh % 1) <= 1e-10] = 1
    return(output)

exp_func_0 = lambda mesh: np.exp(-np.pi*mesh**2)
exp_func_1 = lambda mesh: np.exp(1j*np.pi*mesh)
exp_func_2 = lambda mesh: np.exp(1j*np.pi*mesh**2)
exp_func_3 = lambda mesh: np.exp(-(np.abs(mesh)))

def make_2D(dx = 0.01,
            dy = 0.01,
            Lx_max = 1,
            Ly_max = 1,
            a = 1,
            b=1,
            func=rect # options are rect, triangle, sgn, comb, or exp_func_n
            ):

    x,y,xm,ym,extent,F_extent = make_meshgrid(dx,
                                              dy,
                                              Lx_max,
                                              Ly_max)

    mat2D = func(a*xm)*func(b*ym)

    return(mat2D, extent, F(mat2D), F_extent)

def make_2D_delta(dx = 0.01,
                  dy = 0.01,
                  Lx_max = 1,
                  Ly_max = 1,
                  a = 1,
                  b=1,
                  ):

    x,y,xm,ym,extent,F_extent = make_meshgrid(dx,
                                              dy,
                                              Lx_max,
                                              Ly_max)
    delta_x = np.zeros_like(xm)
    delta_y = np.zeros_like(xm)
    delta_x[np.abs(xm)<1e-10]=1/np.abs(a)
    delta_y[np.abs(ym)<1e-10]=1/np.abs(b)

    mat2D = delta_x*delta_y

    return(mat2D, extent, F(mat2D), F_extent)

if __name__ == "__main__":
    func = rect
    mat2D, extent, F_mat2D, F_extent = make_2D(func=func)
    plot(mat2D, extent)
    plot(F_mat2D, F_extent)

    mat2D, extent, F_mat2D, F_extent = make_2D_delta()
    plot(mat2D, extent)


# -*- encoding: utf-8 -*-

import warnings
import numpy as np
from math import radians

from ..config import R
from ..api import OSOptions
from ..exceptions import TypeWarning

if OSOptions.is_sklearn_available:
	from sklearn.metrics.pairwise import haversine_distances # Using SKLearn for Calculating Haversine

def EuclideanDistance(startPoint : np.ndarray, targetPoint : np.ndarray) -> float:
	'''Calculates Eculidean Distance b/w Two Points in n-Dimensional Space

	: param startPoint  : Starting Point (P)
	: param targetPoint : Target Point, or Point-Q
	'''
	if (type(startPoint) != np.ndarray) or (type(targetPoint) != np.ndarray):
		warnings.warn(f'Expects np.ndarray got {type(startPoint)} and {type(targetPoint)}, Attempting a Fix.', TypeWarning)
		startPoint  = np.array(startPoint)
		targetPoint = np.array(targetPoint)

	return np.sqrt(np.sum((startPoint - targetPoint) ** 2))

def ManhattanDistance(startPoint : np.ndarray, targetPoint : np.ndarray) -> float:
	'''Calculates Manhattan Distance b/w Two Points in n-Dimensional Space

	: param startPoint  : Starting Point (P)
	: param targetPoint : Target Point, or Point-Q
	'''
	if (type(startPoint) != np.ndarray) or (type(targetPoint) != np.ndarray):
		warnings.warn(f'Expects np.ndarray got {type(startPoint)} and {type(targetPoint)}, Attempting a Fix.', TypeWarning)
		startPoint  = np.array(startPoint)
		targetPoint = np.array(targetPoint)

	return sum([abs(i) for i in (startPoint - targetPoint)])

def HaversineDistance(startPoint : list, targetPoint : list, **kwargs) -> float:
	'''Calculate Haversine Distance

	: param startPoint  : Starting Point (P). Format [longitude, latitude]
	: param targetPoint : Target Point, or Point-Q. Format [longitude, latitude]

	Keyword Arguments
	-----------------
		: param input_unit  : (str) Unit of the Latitude and Longitude (in deg or rad). Default 'deg'
		: param output_unit : (str) Output unit (in rad, m, km). Default 'km'
	'''
	input_unit  = kwargs.get('input_unit', 'deg')
	output_unit = kwargs.get('output_unit', 'km')

	# Check argument(s)
	if input_unit not in ['deg', 'rad']:
		raise ValueError(f'{input_unit} is invalid.')

	if output_unit not in ['m', 'km', 'rad']:
		raise ValueError(f'{output_unit} is invalid.')

	if input_unit == 'deg':
		startPoint_rad  = [radians(i) for i in startPoint]
		targetPoint_rad = [radians(i) for i in targetPoint]

	if OSOptions.is_sklearn_available:
		dist = haversine_distances([startPoint_rad, targetPoint_rad])
		dist = dist[0][1] # since this returns a np.ndarray or 2x2
	else:
		dist = _haversine_wo_sklearn_(*startPoint, *targetPoint)

	if output_unit == 'rad':
		return dist
	elif output_unit == 'm':
		return dist * R

	return dist * R / 1000

def _haversine_wo_sklearn_(lon1 : int or float, lat1 : int or float, lon2 : int or float, lat2 : int or float):
	'''Calculate Haversine, if scikit-learn Package is unavailable'''
	dlat = lat2 - lat1 # delta Latitude
	dlon = lon2 - lon1 # delta Longitude

	a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2
	c = 2 * np.arcsin(np.sqrt(a)) # this is in Radian, no need to Change

	return c


import numpy as np
from matplotlib import pyplot as plt

def random_point(x_pos=100, y_pos=100, radius=40, inner_r=10):
    """
    Create a random point in a circle of radius 'radius' centered in (x_pos, y_pos)
    :param x_pos: position x of the center of the circle
    :param y_pos: position y of the center of the circle
    :param radius: radius of the circle
    :param inner_r: inner radius in which no points have to be made
    :return: position of a random point
    """
    # random angle
    alpha = 2 * np.pi * np.random.rand()
    # random radius
    r = radius * np.sqrt(np.abs(np.random.rand())) + inner_r
    # calculating coordinates
    x = r * np.cos(alpha) + x_pos
    y = r * np.sin(alpha) + y_pos
    return x, y
    # print("Random point", (x, y))

def create_base_image(n_points=0, x_pos=100, y_pos=100, radius=40, inner_r=10):
    """
    Create an image with a random distribution of n points
    :param n_points: number of points in image
    :param x_pos:
    :param y_pos:
    :param radius:
    :param inner_r:
    :return: dict with x and y arrays
    """
    x = np.zeros(n_points)
    y = np.zeros(n_points)
    for idx, point in enumerate(range(n_points)):
        x[idx], y[idx] = random_point(x_pos, y_pos, radius, inner_r)
    return np.concatenate((np.reshape(x, (1, n_points)), np.reshape(y, (1, n_points))))

def scatter_image_v(image_array, scatter=5):
    """
    Create a vertically 'moved' image scattering original points and merging them on the original
    :param image_array: 2-dim array with original image
    :param scatter: length of scatter
    :return: original image with scatter. The total amount of points has doubled
    """
    n_points = len(image_array[0])*2
    x = image_array[0]
    y = image_array[1]
    x = np.concatenate((x, x))
    y_moved = y + scatter
    y = np.concatenate((y, y_moved))
    return np.array((np.reshape(x, (1, n_points)), np.reshape(y, (1, n_points))))

def randomize_image(image_array):
    """
    Create a randomize version of the same image with doubled points
    :param image_array: 2-dim array
    :return: randomized version of the same image with doubled points
    """
    n_points = len(image_array[0])
    another_image = create_base_image(n_points)
    x = np.concatenate((image_array[0], another_image[0]))
    y = np.concatenate((image_array[1], another_image[1]))
    return np.concatenate((np.reshape(x, (1, n_points*2)), np.reshape(y, (1, n_points*2))))

def plot_points(image_array):
    plt.plot(image_array[0], image_array[1])

if __name__ == '__main__':
    image_array = create_base_image(1000)
    random_img = randomize_image(image_array)
    scattered_img = scatter_image_v(image_array, scatter=3)
    plt.plot(scattered_img[0], scattered_img[1], '.', c='black')
    # plt.plot(random_img[0], random_img[1], '.', c='red')
    plt.show()


import numpy as np
import matplotlib.pyplot as plt

def normal_pdf(x, mu, sigma):
    pdf = 1/(sigma * np.sqrt(2*np.pi)) * np.exp(-(x-mu)**2 / (2*sigma**2))
    return pdf

def unifrom_pdf(x, a, b):
    pdf = np.piecewise(x, [(x>=a) & (x<=b), (x<a) & (x>b)], [1/(b-a), 0])
    return pdf

# Random sampling of a normal distribution
my_mu, my_sigma = 0, 0.1 # mean and standard deviation
sn = np.random.default_rng().normal(loc=my_mu, scale=my_sigma, size=10000)
fig = plt.figure()
ax1 = fig.add_subplot(2, 1, 1)
ax1.hist(sn, density=True, bins='auto', edgecolor='k', color='#c7ddf4', label='Random Sampling of the Normal Distribution')
my_xn = np.linspace(my_mu - 4 * my_sigma, my_mu + 4 * my_sigma, 1000)
my_yn = normal_pdf(x=my_xn, mu=my_mu, sigma=my_sigma)
ax1.plot(my_xn, my_yn,linewidth=2, linestyle='--', color='#ff464a', label='Target Normal Probability Density Function')
ax1.set_ylim(0.0, 7.0)
ax1.set_xlabel('x')
ax1.set_ylabel('Prob. Density')
ax1.legend()

# Random sampling of a uniform distribution
my_a, my_b = -1, 1 # lower and upper bound of the uniform distribution
su = np.random.default_rng().uniform(low=my_a, high=my_b, size=10000)
ax2 = fig.add_subplot(2, 1, 2)
ax2.hist(su, density=True, bins='auto', edgecolor='k', color='#c7ddf4', label='Random Sampling of the Uniform Distribution')
my_xu = np.linspace(-2, 2, 1000)
my_yu = unifrom_pdf(x=my_xu, a=my_a, b=my_b)
ax2.plot(my_xu, my_yu, linewidth=2, linestyle='--', color='#ff464a', label='Target Uniform Probability Density Function')
ax2.set_ylim(0, 1)
ax2.set_xlabel('x')
ax2.set_ylabel('Prob. Density')
ax2.legend()

fig.tight_layout()


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

one = np.ones(15)
noise = np.random.normal(size=20)
x = np.linspace(-3, 3, 20)
x = np.random.permutation(x)

# training error and testing error

testX = x[15:]
X = np.vstack([x[:15],one])

#print("{}".format( noise ))
#print("{}".format( x ))
#print("{}".format( one ))
#print("{}".format( X ))
#print("{}".format( X.shape ))
#print("{}".format( testX ))

y = np.add(x[:15] * 2, noise[:15])
#print("{}".format( y ))

testY = np.add(x[15:] * 2, noise[15:])
#print("{}".format( testY ))

Wlin = np.linalg.inv(X.dot(X.T)).dot(X).dot(y.T)
#print("{}".format( Wlin ))

c = x[:15] * Wlin[0] + Wlin[1]
d = x[15:] * Wlin[0] + Wlin[1]
trainError = math.pow( np.square(np.subtract( c, y )).mean(), 1/2 )
print("training error : {}".format( trainError ))
testError = math.pow( np.square(np.subtract( d, testY )).mean(), 1/2 )
print("testing errors : {}".format( testError ))

a = np.linspace(-3, 3, 100)
b = a * Wlin[0] + Wlin[1]

plt.scatter(x[:15], y, color = 'blue')
plt.scatter(x[15:], testY, color = 'yellow')
plt.plot(a, b, color = 'red')
plt.ylim(-8, 8)
plt.title('Fitting plots for training error and testing error')
plt.xlabel("trainingPoint : blue , testingPoint : yellow")
plt.show()

# cross-validation errors ( leave-one-out )

sum = 0

for i in range(15):

	tmpX = np.delete(x[:15], i)
	validX = x[i]
	X = np.vstack([tmpX, one[:14]])

	#print("{}".format( tmpX ))
	#print("{}".format( validX ))
	#print("{}".format( X ))

	tmpY = np.add(tmpX * 2, np.delete(noise[:15], i) )
	#print("{}".format( tmpY ))

	validY = np.add(validX * 2, noise[i])
	#print("{}".format( validY ))

	Wlin = np.linalg.inv(X.dot(X.T)).dot(X).dot(tmpY.T)
	#print("{}".format( Wlin ))

	d = validX * Wlin[0] + Wlin[1]
	crossError = np.abs(np.subtract( d, validY ))
	#print("{}".format( crossError ))
	sum += crossError

	a = np.linspace(-3, 3, 100)
	b = a * Wlin[0] + Wlin[1]
	plt.plot(a, b, color = 'red')

print("cross-validation errors for leave-one-out : {}".format( sum/15 ))

plt.scatter(x[:15], y, color = 'blue')
plt.ylim(-8, 8)
plt.title('Fitting plots for cross-validation errors ( leave-one-out )')
plt.xlabel("trainingPoint + validationPoint : blue")
plt.show()

# cross-validation errors ( five-fold )

sum = 0

for i in range(0, 15, 3):

	tmpX = np.delete(x[:15], [i, i+1, i+2])
	validX = x[i:i+3]
	X = np.vstack([tmpX, one[:12]])

	#print("{}".format( tmpX ))
	#print("{}".format( validX ))
	#print("{}".format( X ))

	tmpY = np.add(tmpX * 2, np.delete(noise[:15], [i, i+1, i+2]) )
	#print("{}".format( tmpY ))

	validY = np.add(validX * 2, noise[i:i+3])
	#print("{}".format( validY ))

	Wlin = np.linalg.inv(X.dot(X.T)).dot(X).dot(tmpY.T)
	#print("{}".format( Wlin ))

	d = validX * Wlin[0] + Wlin[1]
	crossError = math.pow( np.square(np.subtract( d, validY )).mean(), 1/2 )
	#print("{}".format( crossError ))
	sum += crossError

	a = np.linspace(-3, 3, 100)
	b = a * Wlin[0] + Wlin[1]
	plt.plot(a, b, color = 'red')

print("cross-validation errors for five-fold : {}".format( sum/5 ))

plt.scatter(x[:15], y, color = 'blue')
plt.ylim(-8, 8)
plt.title('Fitting plots for cross-validation errors ( five-fold )')
plt.xlabel("trainingPoint + validationPoint : blue")
plt.show()


import scipy

# ==================================
# === Error function definitions ===
# ==================================

def gradient(x, x_min, x_max):
    """
    Gradient scaling function. The gradient is computed
    to result in +/-1 scales at x_max and x_min correspondingly.

    Parameters
    ----------
    x: ndarray
        An input array, for which to compute the scalings.
    x_min: float
        A point, that corresponds to -1 output value.
    x_max: float
        A point, that corresponds to +1 output value.

    Returns
    -------
    ndarray:
        An array of scales, ranging [-1;1] in [x_min; x_max] range.
    """

    res = (2*x - (x_min + x_max)) / (x_max - x_min)

    return res

def step(x, break_points):
    """
    Step-like scaling function.

    Parameters
    ----------
    x: ndarray
        An input array, for which to compute the scalings.
    break_points: tuple
        A list of the break points. Each entry should be a tuple of
        (break_position, break_width).

    Returns
    -------
    ndarray
        Array of computed scales in the [-1; 1] range.
    """

    # Applying the first break point
    break_point = break_points[0]
    break_x = break_point[0]
    break_width = break_point[1]

    res = scipy.tanh((x - break_x) / break_width)
    sign = 1

    # If there are more break points given, applying them as well
    for break_point in break_points[1:]:
        # First recalling the previous break point position
        break_x_old = break_x

        # New break point data
        break_x = break_point[0]
        break_width = break_point[1]

        # Will fill only points above the transition position
        trans_x = (break_x + break_x_old) / 2.0
        above_trans_x = scipy.where(x >= trans_x)

        # Flip the sign - above the transition position function behaviour is reversed
        sign *= -1
        res[above_trans_x] = sign * scipy.tanh((x[above_trans_x] - break_x) / break_width)

    return res


'''
Angular radius of query circle = r
Radius of Earth = R (kilometers)
Circle that is formed by all points which have distance d (kilometers) from M the query circle
Then, r = d/R
#Computing the Minimum and Maximum Latitude
   Let, M=(lat, lon)
  lat_min = lat - r rad
  lat_max = lat + r rad

# Computing the Minimum and Maximum Longitude
	latT = arcsin(sin(lat)/cos(r))
	lon_min = lonT1 = lon - delta(lon)
	lon_max = lonT2 = lon + delta(lon)
	delta(lon) = arccos( ( cos(r) - sin(latT) * sin(lat) ) / ( cos(latT) * cos(lat) ) ) = arcsin(sin(r)/cos(lat))
# Poles and the 180th Meridian
	#TODO
# Optimized SQL Query
	SELECT * FROM Places WHERE
    (Lat => lat_min AND Lat <= lat_max) AND (Lon >= lon_min AND Lon <= lon_max)
	AND
    acos(sin(lat) * sin(Lat) + cos(lat) * cos(Lat) * cos(Lon - (lon))) <= r;
***********************************************************************************************
Source : http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#SQLQueries
**********************************************************************************************
'''

import math
import numpy as np
RADIUS_EARTH = 6371.0

class Geolocation:

	def __init__(self,lat,lon,distance):

		self.lat = lat  # in radians
		self.lon = lon # in radians
		self.distance = float(distance) # in kilometers

	def angular_radius(self):

		return float(self.distance/RADIUS_EARTH)

	def min_max_latitudes(self):

		lat_min = self.lat - self.angular_radius()
		lat_max = self.lat + self.angular_radius()

		return (lat_min,lat_max)

	def min_max_longitudes(self):

		r = self.angular_radius()

		latT = np.arcsin(math.sin(self.lat)/math.cos(r))

		delta_lon = np.arccos( ( math.cos(r) - math.sin(latT) * math.sin(self.lat) ) / ( math.cos(latT) * math.cos(self.lat) ) )

		lon_min =  self.lon - delta_lon
		lon_max =  self.lon + delta_lon

		return (lon_min,lon_max)


import numpy as np

def l2_distance(a, b):
    """Computes the Euclidean distance matrix between a and b.
    """

    if a.shape[0] != b.shape[0]:
        raise ValueError("A and B should be of same dimensionality")

    aa = np.sum(a**2, axis=0)
    bb = np.sum(b**2, axis=0)
    ab = np.dot(a.T, b)

    return np.sqrt(aa[:, np.newaxis] + bb[np.newaxis, :] - 2*ab)


import numpy as np
import matplotlib.pyplot as plt

# %matplotlib inline

a_np_list = np.array([0,1,2,3,4])

a_np_list.size:5
a_np_list.ndim:1
a_np_list.shape: (5,)

b = np.array([3.1,11.02,6.2,213.2,5.2])
print(type(b)) # :numpy.ndarray
b.dtype:np.dtype("float64")

c = np.array([20,1,2,3,4])
c:np.array([20,1,2,3,4])
c[0]=100
c:np.array([100,1,2,3,4])
c[4]=0
c:np.array([100,1,2,3,4])
d=c[1:4]
d:np.array([1,2,3])
c[3:5]=300,400
c:np.array([0,1,2,300,400])

u=[1,0]
v=[0,1]
z=[]
for n, m in zip(u,v):
    z.append(n+m)

u=np.array([1,0])
v=np.array([0,1])
z=u+v
z:np.array([1,1])

u=[1,0]
v=[0,1]
z=[]
for n, m in zip(u,v):
    z.append(n-m)

u=np.array([1,0])
v=np.array([0,1])
z=u-v
z:np.array([1,1])

y=np.array([1,2])
z=2*y
z:np.array([2,4])

y=[1,2]
z=2*y
for n in y:
    z.append(2*n)

u=np.array([1,2])
v=np.array([3,2])
z=u*v
z:np.array([3,4])

u=[1,2]
v=[3,2]
z=[]
for n, m in zip(u,v):
    z.append(n*m)

u=np.array([1,2])
v=np.array([3,1])
result=np.dot(u,v)
result:5

u=np.array([1,2,3,-1])
z=u+1
z:np.array([2,3,4,0])

a=np.array([1,-1,1,-1])
mean_a=a.mean
mean_a=0.0

a=np.array([1,4])
z=a*(1-1+1-1)
z=0

b=np.array([1,-2,3,4,5])
max_b=b.max()
max_b:5

np.pi
x=np.array([0,np.pi/2,np.pi])
y=np.sin(x)
y:np.array([0,1,1.2e-16])

np.linspace(-2,2,num=5)
np.linspace(-2,2,num=9)

x=np.linspace(0,2*np.pi,100)
y=np.sin(x)
plt.plot(x,y)
plt.show()


import math
from decimal import *
from scipy import poly1d
import scipy.special
import numpy as np
from fractions import Fraction as F
import time
"""
CardinalityFC(n,k)

inputs:
n: number of variables
k: the value of the threshold

CNF clauses are special cases of cardinality constraints

return:
the n*1 vector of Fourier coefficients of Card(x1,x2,...,xn)>=k, in other words, x1+x2+...+xk<=n-2k. Ordered by degree, thus ret[0] is the constant.
"""
def binom(n,k):
    if k==0: return 1
    ans = F(1)
    for i in range(n):
        ans = ans * (i+1)
        if i < k:
            ans = ans/(i+1)
        else:
            ans = ans/(n-i)
    return ans

def verify_paserval(x):
    ans = 0
    for i in range(len(x)):
        ans += x[i]*x[i]*binom(len(x)-1,i)
    return ans

def CardinalityFC(n,k):
#    print('n='+repr(n)+' k='+repr(k))
    startall = time.time()
    if n==1 and k==1:
        return [0,1]
    d = np.zeros(n + 1)
    if k==0:
        d[0]=-1
        return d
    templist = ([-1 for i in range(n-k)] + [1 for i in range(k-1)])
    templist = np.array(templist,dtype=object)
#    print('before poly1d takes '+repr(time.time()-startall))

    start = time.time()
    temppoly = poly1d(templist,True) * (1-2*((k-1)%2))   # complexity: O(n(logn)^2)
#    print('poly1d takes '+repr(time.time()-start))
    temparray = temppoly.c[::-1]
    start = time.time()
    temparray = [F(temparray[i],(2**(n-1))) for i in range(len(temparray))]
#    print('temparray/2^n-1 takes '+repr(time.time()-start))
    start = time.time()
    binom_nk = binom(n-1,k-1)
    binom_ni_inv = [1 for i in range(n)]  # iteratively computing binom(n-1,i)
    for i in range(0,n-1):
        binom_ni_inv[i+1] = binom_ni_inv[i] * (i+1) / (n-i-1)
    binocoef = [binom_nk * binom_ni_inv[i] for i in range(n)]  #complexity: O(nk)
    #binocoef = [binom_nk / binom(n-1,i) for i in range(n)]  #complexity: O(nk)
 #   print('binom takes '+repr(time.time()-start))
    temparray = [temparray[i] * binocoef[i] for i in range(len(temparray))]
    for j in range(n):
        d[j+1] = F(temparray[j])
    start = time.time()
    templist3 = []
    templist3.append(binom(n,k))
    for i in range(k,n):
        templist3.append(templist3[i-k] * (n-i) / (i+1) )
  #  print('m1 uses '+repr(time.time()- start))
    #templist3 = [F(binom(n,i)) for i in range(k,n+1)]
    start = time.time()
    d[0] = F(1 - F(int(sum(templist3)),(2 ** (n - 1))))
  #  print('m2 uses '+repr(time.time()- start))
  #  print('CardFC takes '+repr(time.time()-startall))
    return d

# the Fourier Coefficients of Not-all-equal constraints
def NAEFC(n):
    d = np.zeros(n + 1)
    d[0] = (F(1,2))**(n-2)-1
    for i in range(2,n+1,2):
        d[i] = (F(1/2))**(n-2)
    return d

#total = 0
#for i in range(0,101):
#    total = abs(coef[i])*binom(100,i)
#    print(repr(total)+','),


import numpy as np

def _assert_even_mesh(x_nodes):
    x_nodes_forward = np.roll(x_nodes, -1)
    dxs = x_nodes_forward - x_nodes
    if not np.isclose(0, np.max(np.abs(1 - dxs[:-1] / dxs[0]))):
        raise Exception('Central differences can only be used on even meshes')

def fd_point(x_nodes, f_nodes, i):
    dx = x_nodes[i + 1] - x_nodes[i]
    dy = f_nodes[i + 1] - f_nodes[i]
    return dy / dx

def bd_point(x_nodes, f_nodes, i):
    dx = x_nodes[i] - x_nodes[i - 1]
    df = f_nodes[i] - f_nodes[i - 1]
    return df / dx

def three_points_midpoint(x_nodes, f_nodes, i):
    _assert_even_mesh(x_nodes[i-1:i+2])
    dx = x_nodes[i] - x_nodes[i - 1]
    return (f_nodes[i+1] - f_nodes[i-1]) / (2*dx)

def three_points_left_endpoint(x_nodes, f_nodes, i):
    _assert_even_mesh(x_nodes[i:i+2])
    dx = x_nodes[i + 1] - x_nodes[i]
    return (-3*f_nodes[i] + 4*f_nodes[i + 1] - f_nodes[i + 2]) / (2*dx)

def three_points_right_endpoint(x_nodes, f_nodes, i):
    _assert_even_mesh(x_nodes[i-2:i+1])
    dx = x_nodes[i] - x_nodes[i - 1]
    return (f_nodes[i - 2] - 4*f_nodes[i - 1] + 3*f_nodes[i]) / (2*dx)

def cd(x_nodes, f_nodes):
    df = np.zeros_like(f_nodes)
    df[0] = three_points_left_endpoint(x_nodes, f_nodes, 0)
    df[1:-1] = np.array([three_points_midpoint(x_nodes, f_nodes, i) for i in range(1, len(f_nodes) - 1)])
    df[-1] = three_points_right_endpoint(x_nodes, f_nodes, len(f_nodes) - 1)
    return df

def fd(x_nodes, f_nodes):
    df = np.zeros_like(f_nodes)
    df[0:-1] = np.array([fd_point(x_nodes, f_nodes, i) for i in range(0, len(f_nodes) - 1)])
    df[-1] = df[-2]
    return df


from typing import List

import numpy as np

from sklearn.metrics import f1_score as f1_score_sk

def mean_squared_error(y_true: List[float], y_pred: List[float]) -> float:
    assert len(y_true) == len(y_pred)
    # sum (( actual - predicted ) ^2) /n
    totalError = 0.0
    for i in range(0, len(y_pred)):
        totalError += np.power((y_true[i] - y_pred[i]), 2)
    return totalError / len(y_pred)

def f1_score(real_labels: List[int], predicted_labels: List[int]) -> float:
    """
    f1 score: https://en.wikipedia.org/wiki/F1_score
    """
    # precsion = true positives / positives pred
    # recall = true positives classified / total positives
    # 2 * [ (precision * recall) / (precision + recall) ]

    assert len(real_labels) == len(predicted_labels)
    truePositPred = sum(1 if (p == 1 and r == p) else 0 for r,p in zip(real_labels, predicted_labels))
    positPred = sum(1 if p ==1 else 0 for p in predicted_labels)
    precision = truePositPred / positPred

    totalPosit = sum(1 if r == 1 else 0 for r in real_labels)
    recall = truePositPred / totalPosit
    if (precision + recall) == 0:
        return 0
    return 2 * ((precision * recall) / (precision+recall))

def phi(f, k):
    # yeah this is dirty
    # for each dimension of feature, raise to power of 1..k
    return [i**x for x in range(1,k+1) for i in f]

def polynomial_features(
        features: List[List[float]], k: int
) -> List[List[float]]:
    return [phi(f,k) for f in features]

def euclidean_distance(point1: List[float], point2: List[float]) -> float:
    assert(len(point1) == len(point2))
    # d(x,y) = √⟨x−y)*(x−y⟩
    x = np.array(point1)
    y = np.array(point2)

    return np.power(np.subtract(x,y).dot(np.subtract(x,y)),.5)

def inner_product_distance(point1: List[float], point2: List[float]) -> float:
    assert len(point1) == len(point2)
    # d(x,y) = ⟨x,y⟩
    x = np.array(point1)
    y = np.array(point2)
    return x.dot(y)

def gaussian_kernel_distance(
        point1: List[float], point2: List[float]
) -> float:
    # d(x,y) = exp(−1/2√⟨x−y,x−y⟩)
    assert len(point1) == len(point2)
    x = np.array(point1)
    y = np.array(point2)
    return -np.exp(-.5 * (np.power(np.subtract(x,y).dot(np.subtract(x,y)),.5)))

class NormalizationScaler:
    def __init__(self):
        pass

    def __call__(self, features: List[List[float]]) -> List[List[float]]:
        """
        normalize the feature vector for each sample . For example,
        if the input features = [[3, 4], [1, -1], [0, 0]],
        the output should be [[0.6, 0.8], [0.707107, -0.707107], [0, 0]]
        """
        return [self.normalize(f) for f in features]

    def normalize(self, f):
        eu_dist = euclidean_distance([0]*len(f), f)
        # iterate over all dimensions dividing by eu dist while checking for divide by 0
        return [i / eu_dist if eu_dist != 0 else 0.0 for i in f]

class MinMaxScaler:
    """
    I am assuming the parameters are valid when __call__
            is being called the first time (you can find min and max).

    Example:
        train_features = [[0, 10], [2, 0]]
        test_features = [[20, 1]]

        scaler = MinMaxScale()
        train_features_scaled = scaler(train_features)
        # now train_features_scaled should be [[0, 1], [1, 0]]

        test_features_sacled = scaler(test_features)
        # now test_features_scaled should be [[10, 0.1]]

        new_scaler = MinMaxScale() # creating a new scaler
        _ = new_scaler([[1, 1], [0, 0]]) # new trainfeatures
        test_features_scaled = new_scaler(test_features)
        # now test_features_scaled should be [[20, 1]]

    """

    def __init__(self):
        self.min = []
        self.max = []

    def __call__(self, features: List[List[float]]) -> List[List[float]]:
        """
        normalize the feature vector for each sample . For example,
        if the input features = [[2, -1], [-1, 5], [0, 0]],
        the output should be [[1, 0], [0, 1], [0.333333, 0.16667]]
        """
        features = np.array(features)
        # find min and max if not inited
        if len(self.min) == 0:
            self.min = features.min(axis=0)
        if len(self.max) == 0:
            self.max = features.max(axis=0)

        return [self.normalize(f) for f in features]

    def normalize(self, f):
        return [(x - mi) / (ma - mi) for x,mi,ma in zip(f,self.min,self.max)]


# -*- coding: utf-8 -*-
"""
Created on Tue Aug 31 22:04:01 2021

@author: Julien

https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle
"""

#  _____                            _
# |_   _|                          | |
#   | |  _ __ ___  _ __   ___  _ __| |_ ___
#   | | | '_ ` _ \| '_ \ / _ \| '__| __/ __|
#  _| |_| | | | | | |_) | (_) | |  | |_\__ \
# |_____|_| |_| |_| .__/ \___/|_|   \__|___/
#                 | |
#                 |_|

import cmath
import numpy as np

#   _____                _              _
#  / ____|              | |            | |
# | |     ___  _ __  ___| |_ __ _ _ __ | |_ ___
# | |    / _ \| '_ \/ __| __/ _` | '_ \| __/ __|
# | |___| (_) | | | \__ \ || (_| | | | | |_\__ \
#  \_____\___/|_| |_|___/\__\__,_|_| |_|\__|___/

X_LIMITS = (0, 1)
Y_LIMITS = (-0.1, np.sin(np.pi/3)+0.1)

#  ______                _   _
# |  ____|              | | (_)
# | |__ _   _ _ __   ___| |_ _  ___  _ __  ___
# |  __| | | | '_ \ / __| __| |/ _ \| '_ \/ __|
# | |  | |_| | | | | (__| |_| | (_) | | | \__ \
# |_|   \__,_|_| |_|\___|\__|_|\___/|_| |_|___/

def compute_new(z1, z2, up):
    '''
    uses complex numbers to compute the next points to add for each edge.

    Parameters
    ----------
    z1 : complex
        first vertice.
    z2 : complex
        second vertice.
    up : boolean
        wether or not add the point in a clockwise or counterclockwise fashion.

    Returns
    -------
    a, b : complex, complex
        the new point(s) generated from the given edge.
    up : boolean
        returning "up" value for computing purposes
    '''
    v = (z2-z1)/2 #v is the 'vector' from z1 to the middle of the segment [z1, z2]

    #rotating the vectors by 60 degrees clokwise or counterclockwise depending on the up value
    #and on the starting point
    if up :
        a = z1 + v*1j**(2/3)
        b = z2 + v*1j**(4/3)
    else :
        a = z1 - v*1j**(4/3)
        b = z2 - v*1j**(2/3)

    up = not(up) #flipping the up value

    return a, b, up

def partial_sierpinski_triangle(T):
    '''
    Generates the next generation of the fractal curve algorithm. For each pair of consecutive points of T
    that make a vertice, we add between those two points the new point(s) generated by the "compute_new"
    method.

    Parameters
    ----------
    T : list[complex]
        the current state of the algorithm.

    Returns
    -------
    res : list[complex]
        The next step of the algorithm.
    '''

    up = len(T)%10<3
    res = []
    for i in range(len(T)-1):
        res.append(T[i])
        a, b, up = compute_new(T[i], T[i+1], up)
        res.append(a)
        res.append(b)
    res.append(T[-1])
    return res

def sierpinski_triangle(n):
    '''
    Recursive method to build the final fractal curve of degree n.

    Parameters
    ----------
    n : int
        The degree of the fractal curve to build.

    Returns
    -------
    list[complex]
        The list of complex numbers that represent the n-th degree fractal curve.
    '''

    if n==0 :
        return [complex(0,0), complex(1,0)]
    else :
        return partial_sierpinski_triangle(sierpinski_triangle(n-1))

def pts_num(n):
    '''
    Optional function that returns the amount of points in the n-th generation of the algorithm.

    Parameters
    ----------
    n : int
        The degree of the fractal curve.

    Returns
    -------
    int
        The number of vertices needed to build the n-th degree fractal curve.
    '''

    n0 = 2
    return (3**n)*(n0-1)+1

#  _            _
# | |          | |
# | |_ ___  ___| |_ ___
# | __/ _ \/ __| __/ __|
# | ||  __/\__ \ |_\__ \
#  \__\___||___/\__|___/

if __name__ == '__main__' :
    import matplotlib.pyplot as plt

    N = 12
    T = sierpinski_triangle(N)
    Tr = [el.real for el in T]
    Ti = [el.imag for el in T]
    plt.plot(Tr, Ti, lw=np.exp(-N/10))
    plt.axis('equal')
    plt.show()


from numpy import dot
from pytest import mark

from girard import linear_algebra as la

@mark.parametrize('v1, v2, expected', [
    ([10], [5], 100000),
    ([3, 4], [3, 5], 27648),
    ([1, 2, 3], [6, 5, 2], 288)
])
def test_vector_vector_exp(v1, v2, expected):
    assert la.vector_vetor_exp(v1, v2) == expected

@mark.parametrize('vector, normalized', [
    ([3, 4], [0.6, 0.8]),
    ([12, 5], [0.9230769230769231, 0.38461538461538464])
])
def test_normalize(vector, normalized):
    assert la.normalize(vector) == normalized

@mark.parametrize('vector, base_dimension, i, j, value', [
    ([1], 2, 0 ,1, 1),
    ([1], 2, 1 ,0, 1),
    ([1, 4, 9], 3, 0, 1, 1),
    ([1, 4, 9], 3, 1, 0, 1),
    ([1, 4, 9], 3, 0, 2, 4),
    ([1, 4, 9], 3, 2, 0, 4),
    ([1, 4, 9], 3, 1, 2, 9),
    ([1, 4, 9], 3, 2, 1, 9),
    ([2, 4, 8, 16, 32, 64], 4, 0, 1, 2),
    ([2, 4, 8, 16, 32, 64], 4, 0, 2, 4),
    ([2, 4, 8, 16, 32, 64], 4, 0, 3, 8),
    ([2, 4, 8, 16, 32, 64], 4, 1, 2, 16),
    ([2, 4, 8, 16, 32, 64], 4, 1, 3, 32),
    ([2, 4, 8, 16, 32, 64], 4, 2, 3, 64)
])
def test_access_vector_dim_n_choose_two(vector, base_dimension, i, j, value):
    assert la.access_vector_dim_n_choose_two(vector, base_dimension, i, j) == value

@mark.parametrize('cone_vectors, pairwise_dots', [
    ([[1,2,3], [4,5,6], [7,8,9]], [32, 50, 122]),
    ([[1,2,3, 11], [4,5,6, 13], [7,8,9, 19], [23, 31, 57, 93]], [175, 259, 1279, 369, 1798, 2689]),
    ([[1,2,3, 10, 11], [4,5,6, 12, 13], [7,8,9, 19, 14], [23, 31, 57, 93, 16], [41, 42, 43, 32,42]],
     [295, 394, 1362, 1036, 532, 1913, 1562, 2913, 2206, 8344])
])
def test_pairwise_dor_products(cone_vectors, pairwise_dots):
    assert la.pairwise_dot_products(cone_vectors) == pairwise_dots

@mark.parametrize('cone_vectors', [
    [[1,2,3], [4,5,6], [7,8,9]],
    [[1,2,3, 11], [4,5,6, 13], [7,8,9, 19], [23, 31, 57, 93]],
    [[1,2,3, 10, 11], [4,5,6, 12, 13], [7,8,9, 19, 14], [23, 31, 57, 93, 16], [41, 42, 43, 32,42]]
])
def test_access_on_vector_of_pairwise_dots(cone_vectors):
    pairwise_dot = la.pairwise_dot_products(cone_vectors)

    for i in range(len(cone_vectors)):
        for j in range(len(cone_vectors)):
            if i == j:
                continue

            expected_value = dot(cone_vectors[i], cone_vectors[j])

            assert la.access_vector_dim_n_choose_two(pairwise_dot, len(cone_vectors), i, j) == expected_value


import numpy as np
from sklearn.linear_model import LinearRegression

n = 120
beta = np.array([0.5, 2.5, -1.44])
p = np.shape(beta)[0]

mu = 0
sigma = 0.098765
seed = 4321
rng = np.random.default_rng(seed)
epsilon = rng.normal(mu, sigma, n)

x1 = np.ones((n,1))
x2 = rng.random((n,1))
x3 = np.repeat([1,2,3,4,5], n/5)[:,np.newaxis]
x = np.concatenate((x1,x2,x3), axis=1)
y = x @ beta + epsilon

reg = LinearRegression().fit(x, y)
true_beta_hat = np.append(reg.intercept_, reg.coef_[1:p])

def compute_gamma_val(regressor, regressand):
    return (regressor.T @ regressand) / (regressor.T @ regressor)

def compute_gamma_and_residuals(x):
    n,p = np.shape(x)
    gamma = np.diag(np.ones(p))
    Z = np.empty((n,p))
    Z[:,0] = np.ones(n)
    for j_idx in range(1,p):
        for k_idx in range(p):
            if k_idx < j_idx:
                gamma[k_idx, j_idx] = compute_gamma_val(Z[:, k_idx], x[:, j_idx])
            else:
                pass
    Z[:,j_idx] = x[:,j_idx] - sum([gamma[i_idx,j_idx] * Z[:,i_idx] for i_idx in range(j_idx)])
    return (gamma, Z)

def compute_D(residuals):
    _,p = np.shape(residuals)
    norms = np.array([np.linalg.norm(residuals[:,col_idx]) for col_idx in range(p)])
    D = np.diag(norms)
    return D

def gram_schmidt(x,y):
    gamma, Z = compute_gamma_and_residuals(x)
    D = compute_D(Z)
    Q = Z @ np.linalg.inv(D)
    R = D @ gamma
    beta_hat = np.linalg.solve(R, Q.T @ y)
    return beta_hat

print("Beta hat from sklearn: ", true_beta_hat)
print("Beta hat from our G-S procedure:", gram_schmidt(x,y))


import numpy as np

class Loss(object):
    def __call__(self, X, *args, **kwargs):
        return self.forward(X, *args, **kwargs)

    def forward(self, Y_true, Y_pred, *args, **kwargs):
        pass

    def backward(self, Y_true, Y_pred, *args, **kwargs):
        """
        Computes the gradient of the loss with respect to Y_pred
        """
        pass

class MSE(Loss):
    def forward(self, Y_true, Y_pred):
        J = np.mean(np.square(Y_pred - Y_true))
        return J

    def backward(self, Y_true, Y_pred):
        size = Y_true.size

        dJ_dY_pred = 2 * (Y_pred - Y_true) / size
        return dJ_dY_pred

class BinaryCrossentropy(Loss):
    def forward(self, Y_true, Y_pred, epsilon=1e-8):
        Y_pred = np.clip(Y_pred, epsilon, 1 - epsilon)

        J = -np.mean(Y_true * np.log(Y_pred) + (1 - Y_true) * np.log(1 - Y_pred))
        return J

    def backward(self, Y_true, Y_pred, epsilon=1e-8):
        Y_pred = np.clip(Y_pred, epsilon, 1 - epsilon)
        size = Y_true.size

        dJ_dY_pred = ((1 - Y_true) / (1 - Y_pred) - Y_true / Y_pred) / size
        return dJ_dY_pred

class CategoricalCrossentropy(Loss):
    """
    Expects Y_true to be one-hot encoded and Y_pred to be normalized probabilities (e.g.
    the output of a Softmax layer)
    """
    def forward(self, Y_true, Y_pred, epsilon=1e-8):
        Y_pred = np.clip(Y_pred, epsilon, 1 - epsilon)
        m = Y_true.shape[0]

        J =  -np.sum(Y_true * np.log(Y_pred)) / m
        return J

    def backward(self, Y_true, Y_pred, epsilon=1e-8):
        Y_pred = np.clip(Y_pred, epsilon, 1 - epsilon)
        m = Y_true.shape[0]

        dJ_dY_pred = -(Y_true / Y_pred) / m
        return dJ_dY_pred


from Plot_Tools import Basic_Plot as BP
import numpy as np
import sys

class Gradient_Descent_Solver_with_Numpy:
    def __init__(self, X, Y, LR,
                 ci=1000, tol=1e-12,
                 max_cnt=1e9, rnd=6):

        if type(X) is not np.ndarray:
            X = np.asarray(X)
        if type(Y) is not np.ndarray:
            Y = np.asarray(Y)

        self.X = X
        self.Y = Y
        self.LR = LR
        self.ci = ci
        self.tol = tol
        self.max_cnt = max_cnt
        self.rnd = rnd

        self.num_records = len(X)
        self.num_dims = len(X[0])

        self.Yp = np.zeros((self.num_records, 1))
        self.delta = np.zeros((self.num_records, 1))
        self.randomize_weights()

        self.cnt_list = []
        self.cost_list = []

    def set_weights(self, ws):
        if type(ws) is not np.ndarray:
            ws = np.asarray(ws)

        self.ws = ws

    def set_labels(self, Y):
        if Y is not np.ndarray:
            Y = np.asarray(Y)

        self.Y = Y

    def randomize_weights(self):
        self.ws = np.random.rand(self.num_dims, 1)

    def model(self, X):
        if X is not np.ndarray:
            X = np.asarray(X)
        self.Yp = np.matmul(X, self.ws)
        return self.Yp

    def train(self):
        cost_delta = 1.0
        cost_last = 1.0

        self.count = 0
        self.cost_list = []
        self.cnt_list = []

        while cost_delta > self.tol and self.__iterations_below_max__():
            self.model(self.X)
            self.__update_weights__()

            self.cost_now = self.__cost__()
            cost_delta = abs(cost_last - self.cost_now)
            cost_last = self.cost_now

            self.__record_values__()

    def __update_weights__(self):
        self.delta = self.Yp - self.Y
        dcdw = np.sum(self.X * self.delta, axis=0).reshape((self.num_dims, 1))
        self.ws = self.ws - self.LR * dcdw

    def __cost__(self):
        return np.sum(np.square(self.delta)) ** 0.5

    def __record_values__(self):
        self.count += 1

        if self.count % self.ci == 0:
            self.cost_list.append(self.cost_now)
            self.cnt_list.append(self.count)

    def __iterations_below_max__(self):
        if self.count < self.max_cnt:
            return True
        else:
            print("Exceeded Max Iterations")
            return False

    def report_results(self):
        ws = np.around(self.ws, decimals=6)
        print(f'Solved Weights: {ws}')
        print(f'Iteration Steps to Solution: {self.count}')

    def plot_solution_convergence(self):
        BP(self.cnt_list, self.cost_list,
           t='Cost vs. Solution Steps',
           x_t='Solution Steps', y_t='Cost')

    def plot_predictions(self, X, Y, col_of_X=1):
        if type(X) is not np.ndarray:
            X = np.asarray(X)
        Xsp = self.X[:, col_of_X].tolist()
        Xtp = X[:, col_of_X].tolist()

        BP(Xtp, self.Yp, xp=Xsp, yp=self.Y,
           t='Model Predictions vs. Inputs',
           x_t='Inputs',
           y_t='Predictions and Original Output')


# modelling a linear relationship between "chirps of a cricket" and ground temperature.

# Let's import tensorFlow and python dependencies
import numpy as np
import tensorflow as tf
import pandas as pd
import matplotlib.pyplot as plt

# Download and Explore the Data
df = pd.read_csv("PierceCricketData.csv")
print(df.head())

# Plot the Data Points
x_data, y_data = (df["Chirps"].values,df["Temp"].values)

# plots the data points
plt.plot(x_data, y_data, 'ro')
# label the axis
plt.xlabel("# Chirps per 15 sec")
plt.ylabel("Temp in Farenhiet")

# Create a Data Flow Graph using TensorFlow
X = tf.placeholder(tf.float32, shape=(x_data.size))
Y = tf.placeholder(tf.float32, shape=(y_data.size))

m = tf.Variable(3.0)
c = tf.Variable(2.0)

# Construindo o Modelo
Ypred = tf.add(tf.multiply(X, m), c)

# Create and Run a Session to Visualize the Predicted Line
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

pred = sess.run(Ypred, feed_dict={X:x_data})

#plot initial prediction against datapoints
plt.plot(x_data, pred)
plt.plot(x_data, y_data, 'ro')
# label the axis
plt.xlabel("# Chirps per 15 sec")
plt.ylabel("Temp in Farenhiet")

# normalization factor
nf = 1e-1

# seting up the loss function
loss = tf.reduce_mean(tf.squared_difference(Ypred*nf,Y*nf))

# Define an Optimization Graph to Minimize the Loss and Training the Model

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
#optimizer = tf.train.AdagradOptimizer(0.01 )

# pass the loss function that optimizer should optimize on.
train = optimizer.minimize(loss)

# Initialize all the vairiables again
sess.run(tf.global_variables_initializer())

# Run session to train and predict the values of 'm' and 'c'
convergenceTolerance = 0.0001
previous_m = np.inf
previous_c = np.inf

steps = {}
steps['m'] = []
steps['c'] = []

losses=[]

for k in range(100000):
    # run a session to train , get m and c values with loss function
    _, _m, _c, _l = sess.run([train, m, c, loss], feed_dict={X: x_data, Y: y_data})

    steps['m'].append(_m)
    steps['c'].append(_c)
    losses.append(_l)
    if (np.abs(previous_m - _m) <= convergenceTolerance) or (np.abs(previous_c - _c) <= convergenceTolerance):
        print("Finished by Convergence Criterion")
        print("k = {}".format(k))
        print("Loss = {}".format(_l))
        print("m = {}".format(_m))
        print("c = {}".format(_c))
        break
    previous_m = _m,
    previous_c = _c,

sess.close()

plt.plot(losses[:])
plt.show()


## 3. Statistical significance ##

import numpy as np
import matplotlib.pyplot as plt
mean_group_a = np.mean(weight_lost_a)
mean_group_b = np.mean(weight_lost_b)
print(mean_group_a)
print(mean_group_b)
plt.hist(weight_lost_a)
plt.show()
plt.hist(weight_lost_b)
plt.show()

## 4. Test statistic ##

mean_difference = mean_group_b - mean_group_a
print(mean_difference)

## 5. Permutation test ##

import numpy as np
mean_difference = 2.52
print(all_values)
mean_differences = []
for i in range(1000):
    group_a, group_b = [],[]
    for loop in all_values:
        tmp = np.random.rand()
        if tmp >= 0.5: group_a.append(loop)
        else: group_b.append(loop)
    iteration_mean_difference = numpy.mean(group_b) - numpy.mean(group_a)
    mean_differences.append(iteration_mean_difference)
plt.hist(mean_differences)
plt.show()

## 7. Dictionary representation of a distribution ##

sampling_distribution = {}
for loop in mean_differences:
    if sampling_distribution.get(loop,False):
        val =sampling_distribution.get(loop)
        sampling_distribution[loop] = val+1
    else:
        sampling_distribution[loop] = 1

## 8. P value ##

frequencies = []
for lopp in sampling_distribution:
    if lopp >= 2.52: frequencies.append(lopp)
p_value = sum(frequencies) / 1000

Probability Statistics Intermediate/Significance Testing-174.py


# -*- coding: utf-8 -*-
"""
Created on Sat Nov 27 20:58:50 2021

@author: Panayiota Damianou
"""
import numpy as np
import sympy
import matplotlib.pyplot as plt
from scipy import integrate

# Legendre polynomial
def leg(n, x):
    if(n == 0):
        return 1 # P0 = 1
    elif(n == 1):
        return x # P1 = x
    else:
        return (((2 * n)-1)*x * leg(n-1, x)-(n-1)*leg(n-2, x))/float(n)

def hbasis(i,x):
#  Evaluates the function Ni(y) at x
#  In function L(y) i-2 is the degree of the legendre polynomial

    if i==1:
        Ni=0.5 *(1-x)
    elif i==2:
        Ni=0.5 *(1+x);
    else:
        Ni=(np.sqrt(1/(4*i-6)))*(leg(i-1,x)-leg(i-3,x))
    return Ni

def dhbasis(i,x):
#   Evaluates the derrivative of the function Ni(x) at x
#   In function L(y) i-2 is the degree of the legendre polynomial

    if i==1:
        dNi=-0.5
    elif i==2:
        dNi=0.5
    else:
        dNi=leg(i-2,x)*np.sqrt((2*i-3)/2)
    return dNi

def stifness_matrix(p):
#evaluates the elemental stifness matrix of size (p+1)x(p+1)
    K=np.zeros((p+1,p+1))
    K[0,0]=K[1,1]=0.5
    K[0,1]=K[1,0]=-0.5
    if p>=1:
        for i in range(2,p+1):
            K[i,i]=1
    return K

def mass_matrix(p):
# Evaluates the elemental mass matrix of size (p+1)x(p+1)
    G=np.zeros((p+1,p+1))
    G[0,0]=G[1,1]=2/3
    G[0,1]=G[1,0]=1/3
    if p>=1:
        G[0,2]=G[1,2]=G[2,0]=G[2,1]=-1/np.sqrt(6)
    for i in range(2,p+1):
        G[i,i]=2/(((2*i)-1)*((2*i)-5))
    if p>=3:
        G[0,3]=G[3,0]=1/3*np.sqrt(10)
        G[1,3]=G[3,1]=-1/3*np.sqrt(10)
        for i in range(2,p+1):
            if i+2<=p+1:
               G[i,i+2]=G[i+2,i]=(-1)/(((2*i)-1)*np.sqrt(((2*i)-3)*((2*i)+1)))
    return G

def load_vector(p,f,l,c):
#Evaluates the element load vector
    b=np.zeros((1,p+1))
    for i in range(p+2):
        g = lambda x : f(x,l,c) * hbasis(i,x)
        b[i]= integrate.quad(g,-1,1)
    return b

def fem_solution(p,f,x,l,c):
# Evaluates the finite element method solution and the coifficients that generate the solution
    A=stifness_matrix(p)+mass_matrix(p)
    b=load_vector(p,f,l,c)
    a=A.solve(b)
    ufe_list=[a[i]*[hbasis(i,point) for point in x] for i in range(1,p+2)]
    ufe=sum([sum(l) for l in ufe_list])
    return a, ufe

def energy_norm(p,f,x,l,c):
# Evaluates the energy norm of the finite element method solution and it finds
# the percentage of the error
    a=fem_solution(p,f,x,l,c)
    enorm= np.dot(a, load_vector(p,f,l,c))
    err=1
    return enorm,err

# IMPORTANT NOTE (IF ERROR): [f(x) for x in x_list]

def main():
    f = lambda x,l,c : (((1+x)**(l-2))*2*l*(1+x))-((1-x)*l*(l-1))+(c*(1-x)*(1+x)**2)
    l=[8.7,4.4,2.9,1.2]
    for k in l:
        c=1
        p=[2,3,4,5,6,7,8]
        error=[]
        x = np.linspace(-1,1,1001)
        for j in p:
            error.append(energy_norm(j,f,x,k,c)[1])
        fig, axes = plt.subplots(1,3, figsize=(12,3))

        axes[k].loglog(x,error)

        axes[k].xlabel("error")
        axes[k].ylabel("N")

    l=[1.1]
    c=2
    p=4
    x = np.linspace(-1,1,1001)
    u_Ex = lambda x : (1-x)*((1+x)**l)
    u_Fe = fem_solution(p,f,x)[1]
    fig , axes =plt.subplots()
    axes[0].plot(x,u_Fe, color="red")
    axes[0].plot(x,u_Ex, color="blue")
    axes[0].set_xlabel("x")
    axes[0].set_ylabel("y")
    axes[0].legend("Γραφική Παραστάση των u_(FE) και u_(EX)")

    axes[1].plot(x,abs(u_Ex-u_Fe),color='black')
    axes[1].set_xlabel("x")
    axes[1].set_ylabel("y")
    axes[1].legend("Γραφική Παραστάση του σφάλματος |u_(FE)-u_(EX)|")

if __name__ == "__main__":
    main()


from numpy import array, zeros

'''
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Taking user input ~~~~~~~~~~~~~~~~~~~~~~~~~~~
while True:
    try:
        N = int(input("Enter the Number of Equations: "))
        if N > 0: break
        else: print("Number of Equations must be greater than 0")
    except ValueError:
        print("Enter a Natural Number")

col, colB = [], []
for i in range(N):
    row = []
    for j in range(N):
        while True:
            try:
                coeff = float(input("Enter Coefficient "+str(j+1)+\
                                    " of Equation "+str(i+1)+": "))
            except ValueError:
                print("Enter a Real Number")
                continue
            else: break
        row.append(coeff)
    col.append(row)

    while True:
        try:
            const = float(input("Enter the Constant of Equation "+str(i+1)+": "))
        except ValueError:
                print("Enter a Real Number")
                continue
        else: break
    colB.append(const)

A = array(col, float)
B = array(colB, float)
print()
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'''
# System of Equations
'''
A = array([[ 3, -.1, -.2],
           [.1,   7, -.3],
           [.3, -.2,  10]], float)
B = array([7.85, -19.3, 71.4], float)
'''
A = array([[2, 7, -1,  3, 1],
           [2, 3,  4,  1, 7],
           [6, 2, -3, 2, -1],
           [2, 1,  2, -1, 2],
           [3, 4,  1, -2, 1]], float)
B = array([5, 7, 2, 3, 4], float)
'''
A = array([[0, 7, -1,  3, 1],
           [2, 3,  4,  1, 7],
           [6, 2,  0, 2, -1],
           [2, 1,  2,  0, 2],
           [3, 4,  1, -2, 1]], float)
B = array([5, 7, 2, 3, 4], float)
'''

N = len(B)

# Coincident or Parallel Equations  # a1 x + b1 y = c1       a2 x + b2 y = c2
for i in range(N-1):
    ratioA = A[i,:] / A[i+1,:]      # A[0,col]/A[1,col]        [a1/a2, b1/b2]
    ratioB = B[i] / B[i+1]          # B[0] / B[1]               c1/c2

    if all(ratioA == ratioA[0]):    # a1/a2 = b1/b2             Conditions of
        if ratioB == ratioA[0]:     # a1/a2 = b1/b2  = c1/c2    coincident
            print("Two or More Equations are Coincident")
        else:                       # a1/a2 = b1/b2 != c1/c2    parallel
            print("Two or More Equations are Parallel")
        raise SystemExit            # else: a1/a2 != b1/b2      intersect

# Elimination:                      # k = 1 to n-1
for k in range(N-1):                # k = 0 to N-2  # Index starts from 0

    # Partial Pivoting
    if abs(A[k,k]) < 1e-12:         # 0 in the main diagonal
        for i in range(k+1, N):
            if abs(A[i,k]) > abs(A[k,k]):
                A[[k,i]] = A[[i,k]] # A[k,:], A[k+1,:] = A[k+1,:], A[k,:]
                B[[k,i]] = K[[i,k]] # B[k],   B[k+1]   = B[k+1],   B[k]
                break

    for i in range(k+1, N):         # i = k+1 to N-1
        if A[i,k] == 0: continue    # fctr = A[k,k] / 0 will be inf

        fctr = A[k,k] / A[i,k]

        for j in range(k, N):       # j = k to N-1
            A[i,j] = A[k,j] - fctr * A[i,j]

        B[i] = B[k] - fctr * B[i]

# Back Substitution:
X = zeros(N, float)
X[N-1] = B[N-1] / A[N-1][N-1]

for i in range(N-2, -1, -1):        # i = N-2 to 0

    sumAX = 0
    for j in range(i+1, N):         # j = i+1 to N-1
        sumAX += A[i,j] * X[j]

    X[i] = (B[i] - sumAX) / A[i,i]  # X[i]=(B[i]-sum(A[i,i+1:]*X[i+1:]))/A[i,i]

print("The Solution of the System:")
for i in range(N):
    print('X[', i+1, '] = ', round(X[i], 6), sep='')

'''
  1  2 3 4  b
1│3 -2 5 0│ 2
2│4  5 8 1│ 4
3│1  1 2 1│ 5
4│2  7 6 5│ 7               Elimination:

  1  2   3 4    b
1│3 -2   5 0  │ 2           Fixing row 1, multiply from row 2 to 4, col 1 to b
2│3 3.75 6 .75│ 3                      k              i = k+1 to n, j = k to n
3│3  3   2 3  │15    a[1,1]/a[row,1] a[1,1]/a[2,1] a[1,1]/a[3,1] a[1,1]/a[4,1]
4│3 10.5 6 7.5│10.5           fctr = a[k,k]/a[i,k]

  1  2     3  4     b
1│3 -2     5  0  │  2       From fixed row 1, substract row 2 to 4, col 1 to b
2│0 -5.75 -1 -.75│ -1                      k          i = k+1 to n, j = k to n
3│0 -5    -1 -3  │-13       a[i,j] = a[k,j] - fctr * a[i,j]
4│0 -12.5 -4 -7.5│-8.5      b[i]   = b[k]   - fctr * b[i]

│3 -2     5      0  │ 2     Fixing row 2, multiply from row 3 to 4, col 2 to b
│0 -5.75 -1     -.75│-1                k              i = k+1 to n, j = k to n
│0 -5.75 -1.15 -3.45│-14.95 a[2,2]/a[row,2] a[2,2]/a[3,2] a[2,2]/a[4,2]
│0 -5.75 -1.84 -3.45│-3.91  a[k,k]/a[i,k]

│3 -2     5   0  │ 2        From fixed row 2, substract row 3 to 4, col 2 to b
│0 -5.75 -1  -.75│-1                       k          i = k+1 to n, j = k to n
│0  0    .15  2.7│-14.9     a[i,j] = a[k,j] - fctr * a[i,j]
│0  0    .84  2.7│-3.91     b[i]   = b[k]   - fctr * b[i]

│3 -2     5   0  │ 2        Fixing row 3, multiply from row 4 to 4, col 3 to b
│0 -5.75 -1  -.75│-1                   k              i = k+1 to n, j = k to n
│0  0    .15  2.7│-13.95    a[3,3]/a[row,2] a[3,3]/a[4,3]
│0  0    .15 .482│.51964    a[k,k]/a[i,k]

│3 -2     5   0  │ 2        From fixed row 3, substract row 4 to 4, col 3 to b
│0 -5.75 -1  -.75│-1                       k          i = k+1 to n, j = k to n
│0  0    .15  2.7│13.95     a[i,j] = a[k,j] - fctr * a[i,j]
│0  0     0  2.22│13.43     b[i]   = b[k]   - fctr * b[i]

fctr = a[k,k] / a[i,k]
a[i,j] = a[k,j] - fctr * a[i,j]
b[i]   = b[k]   - fctr * b[i]
where fixed row k = 1 to n-1, row below fixed row i = k+1 to n, j = k to n

Back Substitution :                            AX = B
a[1,1]x[1] + a[1,2]x[2] + a[1,3]x[3] + a[1,4]x[4] = b[1]
             a[2,2]x[2] + a[2,3]x[3] + a[2,4]x[4] = b[2]
                          a[3,3]x[3] + a[3,4]x[4] = b[3]
                                       a[4,4]x[4] = b[4]
x[4] =  b[4] / a[4,4] = 6.056
x[n] =  b[n] / a[n,n]

x[3] = (b[3]                             - a[3,4]*x[4]) / a[3,3] = -16
x[2] = (b[2]               - a[2,3]*x[3] - a[2,4]*x[4]) / a[2,2] = 2.167
x[1] = (b[1] - a[1,2]*x[2] - a[1,3]*x[3] - a[1,4]*x[4]) / a[1,1] = 28.78
x[i] = (b[i] - a[i,j]*x[j] - a[i,j]*x[j] - a[i,j]*x[j]) / a[i,i]

x[i] = (b[i] - ∑(a[i,j]*x[j])) / a[i,i]
where i = n-1 to 1, j = i+1 to n

'''

5. Systems of Linear Equations/2. Gauss Elimination Method.py


import numpy as np, os, sys

import matplotlib as mpl #patch-wise similarities, droi images

import matplotlib.pyplot as plt

def datagen1d(eps,num):

  x=np.random.uniform(low=0,high=1,size=(num,1))
  y=np.cos(3*2*np.pi*x)+eps*np.random.normal(size=(num,1))

  print(x.shape,',y.shape',y.shape)

  #this creates features with an appended 1 for use as a term modeling the bias
  x=np.concatenate((x, np.ones_like(x)),axis=1)

  #x.shape=(numdata,dims) dims=2 here
  #y.shape=(numdata)
  #print(x.shape,y.shape)

  return x,y

def rndsplit(x,y,numtr):

  inds=np.arange(y.size)
  np.random.shuffle(inds)

  xtr=x[inds[0:numtr],:]
  ytr=y[inds[0:numtr]]

  xv=x[inds[numtr:],:]
  yv=y[inds[numtr:]]

  return xtr,ytr,xv,yv

def gendata(numtrain,numtest):

  xtr,ytr = datagen1d(eps=0.3,num= int( numtrain) ) #numtotal
  xv,yv = datagen1d(eps=0.3,num= numtest ) #fix 3k test samples
  #xtr,ytr,xv,yv = rndsplit(x,y,numtr=int( 0.7*numtotal))
  return xtr,ytr,xv,yv

def linreg_train(xtr,ytr,C):

  print(ytr.shape)

  #your code here

  return w

def linreg_apply(xv,w):
  return np.dot(xv,w)

def mse(ypred,ytrue):
  e=np.mean( (ypred-ytrue)**2 )
  return e

def run1(xtr,ytr,xv,yv,C):

  w=linreg_train(xtr,ytr,C=C) # 0.1

  ypred=linreg_apply(xv,w)

  print('xtr',xtr.shape,'w',w.shape,xv.shape,yv.shape,ypred.shape)

  e=mse(ypred,yv)

  plt.figure(1)
  plt.plot(xv[:,0],ypred,'b-')
  plt.plot(xv[:,0],yv,'g.')
  #plt.show()

  #print('mse',e)

  return e

def rbffeats(x,protos,gamma):

  #implement your code here

  #what should be here:
  #x.shape = (numsamples,1)  bcs dims=1 for this example
  # protos.shape=(numprotos,1)
  pass

def run2(xtr,ytr,xv,yv,C):

  randinds=np.random.choice(np.arange(xtr.shape[0]),size=50,replace=False)
  protos=xtr[randinds,:]

  gamma=0.05

  traindata_nobiasdim=xtr[:,0].reshape((xtr.shape[0],1))
  protos_nobiasdim=protos[:,0].reshape((protos.shape[0],1))

  fttr=rbffeats(traindata_nobiasdim,protos_nobiasdim,gamma)

  w=linreg_train(fttr,ytr,C=C) # 0.1

  print(w.shape)

  valdata_nobiasdim=xv[:,0].reshape((xv.shape[0],1))

  ftv=rbffeats(valdata_nobiasdim,protos_nobiasdim,gamma)

  ypred=linreg_apply(ftv,w)

  print('xtr',xtr.shape,'w',w.shape,xv.shape,yv.shape,ypred.shape)

  e=mse(ypred,yv)

  plt.figure(2)
  plt.plot(xv[:,0],yv,'go')
  plt.plot(xv[:,0],ypred,'bx')

  #print('mse',e)

  return e

if __name__=='__main__':

  xtr,ytr,xv,yv=gendata(1600,5000)

  plt.figure(3)
  plt.plot(xv[:,0],yv,'go')
  plt.show()

  e=run1(xtr,ytr,xv,yv,1e-3)
  print('mse',e)

  e=run2(xtr,ytr,xv,yv,1e-3)
  print('mse',e)

  plt.show()


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

"""
1. f : The function whose roots we want to find
2. a : lower bound on the root
3. b : upper bound on the root
4. e : permissible error in the value of root obtained
5. N_max : maximum number of iterations after which function stops.
"""

"""Function 1"""

# for range 1 : {-3,0}, error = 0.0001
root = 0
f1_N_R1 = []
f1_Roots_R1 = []

for i in range(1,11):
    #print()
    #print("N_Max = {}".format(i))
    root = bisection(func_num = 1,a = -3,b = 0,e = 0.001,N_Max = i)
    f1_N_R1.append(i)
    f1_Roots_R1.append(root)

# for range 2 : {-5,5}, error = 0.0001
root = 0
f1_N_R2 = []
f1_Roots_R2 = []

for i in range(1,11):
    #print()
    #print("N_Max = {}".format(i))
    root = bisection(func_num = 1, a = -5,b = 5,e = 0.001,N_Max = i)
    f1_N_R2.append(i)
    f1_Roots_R2.append(root)

#print(f1_N_R2)
#print(f1_Roots_R2)
#print()

"""Function 2"""

# for range 1 : {-3,0}, error = 0.0001
root = 0
f2_N_R1 = []
f2_Roots_R1 = []

for i in range(1,11):
    #print()
    #print("N_Max = {}".format(i))
    root = bisection(func_num = 2, a = -3,b = 0,e = 0.001,N_Max = i)
    f2_N_R1.append(i)
    f2_Roots_R1.append(root)

# for range 2 : {-5,5}, error = 0.0001
root = 0
f2_N_R2 = []
f2_Roots_R2 = []

for i in range(1,11):
    #print()
    #print("N_Max = {}".format(i))
    root = bisection(func_num = 2, a = -5,b = 5,e = 0.001,N_Max = i)
    f2_N_R2.append(i)
    f2_Roots_R2.append(root)

func = np.vectorize(f)
f1_value_at_roots_R1 = func(1,f1_Roots_R1)
f1_value_at_roots_R2 = func(1,f1_Roots_R2)
f2_value_at_roots_R1 = func(2,f2_Roots_R1)
f2_value_at_roots_R2 = func(2,f2_Roots_R2)

"""
# change the data and use the following code
# to plot and save for both the Functions
plt.plot(f2_N_R1,f2_value_at_roots_R1,'.-',label = 'initial Limit : {-3,0}')
plt.plot(f2_N_R2,f2_value_at_roots_R2,'.-',label = 'initial Limit : {-5,5}')
plt.xlabel('N',fontsize = 10)
plt.ylabel('Function Value at Root',fontsize = 10)
plt.xticks(fontsize = 8)
plt.yticks(fontsize = 8)
plt.title('Bisection Method - Function2 - permissible error : 0.0001')
plt.grid(linestyle = '--')
plt.legend()
plt.savefig('bsm-f2.png')
plt.show()
"""

# Plotting Absolute Values
f1_value_at_roots_R1_ABS =  [abs(ele) for ele in f1_value_at_roots_R1]
f1_value_at_roots_R2_ABS =  [abs(ele) for ele in f1_value_at_roots_R2]
f2_value_at_roots_R1_ABS =  [abs(ele) for ele in f2_value_at_roots_R1]
f2_value_at_roots_R2_ABS =  [abs(ele) for ele in f2_value_at_roots_R2]

# change the data and use the following code
# to plot and save for both the Functions ABSOLUTE VALUES
plt.plot(f2_N_R1,f2_value_at_roots_R1_ABS,'.-',label = 'initial Limit : {-3,0}')
plt.plot(f2_N_R2,f2_value_at_roots_R2_ABS,'.-',label = 'initial Limit : {-5,5}')
plt.xlabel('N',fontsize = 10)
plt.ylabel('Function Value at Root',fontsize = 10)
plt.xticks(fontsize = 8)
plt.yticks(fontsize = 8)
plt.title('Bisection Method - Function2 Absolute Value - permissible error : 0.001')
plt.grid(linestyle = '--')
plt.legend()
plt.savefig('bsm-f2-abs.png')
plt.show()

AS2101_Labwork/3.Trials-References/Task 3/Submission Codes/Bisection Method/bsm_plot/bsm_plot.py


# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题

# plt.figure(figsize=(10, 6), dpi=90)

def sincos():
    '''
    三角函数
    '''

    x = np.linspace(0, 10, 1000)
    y = np.sin(x)
    z = np.cos(x**2)

    fig, ax = plt.subplots()
    ax.plot(x, y, label="$sin(x)$", color="red", linewidth=0.2)
    ax.plot(x, z, "b--", label="cos(x^2)")

    legend = ax.legend(loc='upper center', shadow=True, fontsize='x-large')

    plt.xlabel("Time(s)")
    plt.ylabel("Volt")
    plt.title("PyPlot 曲线 Demo")

    plt.show()

def linearplo():
    '''
    线性
    '''

    n = 256
    x = np.linspace(-np.pi, np.pi, n, endpoint=True)
    y = np.sin(2 * x)

    x1=np.linspace(-50,100,500,endpoint=True)
    y1=(x1**2)/9
    plt.plot(x1,y1)

    plt.show()

    X1=np.linspace(-4, 4, 100, endpoint = True)
    plt.plot(X1, (X1**2) / 9)

def scatterplot():
    '''
    散点图
    '''
    N=256
    x=np.random.rand(N)
    y=np.random.rand(N)

    # 普通颜色
    # plt.scatter(x,y)

    # 多种颜色
    # plt.scatter(x, y, c=['b','r','g'])

    area=np.pi * (20 * np.random.rand(N))**2  # 0 to 15 point radiuses
    # 随机颜色
    color=2 * np.pi * np.random.rand(N)
    plt.scatter(x, y, s = area, c = color, alpha = 0.5, cmap = plt.cm.hsv)
    plt.show()

def Ax3D():
    # 3D图标必须的模块，project='3d'的定义
    np.random.seed(42)

    # 采样个数500
    n_samples = 500
    dim = 3

    # 先生成一组3维正态分布数据，数据方向完全随机
    samples = np.random.multivariate_normal(
        np.zeros(dim),
        np.eye(dim),
        n_samples
    )

    # 通过把每个样本到原点距离和均匀分布吻合得到球体内均匀分布的样本
    for i in range(samples.shape[0]):
        r = np.power(np.random.random(), 1.0/3.0)
        samples[i] *= r / np.linalg.norm(samples[i])

    upper_samples = []
    lower_samples = []

    for x, y, z in samples:
        # 3x+2y-z=1作为判别平面
        if z > 3*x + 2*y - 1:
            upper_samples.append((x, y, z))
        else:
            lower_samples.append((x, y, z))

    fig = plt.figure('3D scatter plot')
    ax = fig.add_subplot(111, projection='3d')

    uppers = np.array(upper_samples)
    lowers = np.array(lower_samples)

    # 用不同颜色不同形状的图标表示平面上下的样本
    # 判别平面上半部分为红色圆点，下半部分为绿色三角
    ax.scatter(uppers[:, 0], uppers[:, 1], uppers[:, 2], c='r', marker='o')
    ax.scatter(lowers[:, 0], lowers[:, 1], lowers[:, 2], c='g', marker='^')

    plt.show()

def fun(x,y):
    return np.power(x,2)+np.power(y,2)

def Ax3DSq():
    fig1=plt.figure("3D 曲面图",figsize=(10,6))#创建一个绘图对象
    ax=Axes3D(fig1)#用这个绘图对象创建一个Axes对象(有3D坐标)
    X=np.arange(-2,2,0.1)
    Y=np.arange(-2,2,0.1)#创建了从-2到2，步长为0.1的arange对象
    #至此X,Y分别表示了取样点的横纵坐标的可能取值
    #用这两个arange对象中的可能取值一一映射去扩充为所有可能的取样点
    X,Y=np.meshgrid(X,Y)
    Z=fun(X,Y)#用取样点横纵坐标去求取样点Z坐标

    ax.plot_surface(X, Y, Z, rstride=2, cstride=2, cmap=plt.cm.rainbow)    #用取样点(x,y,z)去构建曲面
    ax.set_xlabel('x label', color='r')
    ax.set_ylabel('y label', color='g')
    ax.set_zlabel('z label', color='b')#给三个坐标轴注明
    plt.show()#显示模块中的所有绘图对象

def brokenline():

    a = b = np.arange(0, 3, .02)
    c = np.exp(a)
    d = c[::-1]
    fig, ax = plt.subplots()
    ax.plot(a, c, 'k--', label='A',color='r')
    ax.plot(a, d, 'k:', label='B',color='b')
    ax.plot(a, c + d, 'k', label='C',color='y')
    legend = ax.legend(loc='upper center', shadow=True, fontsize='x-large')

    plt.show()

if __name__ == '__main__':

    # sincos()
    # linearplo()
    # scatterplot()
    # Ax3D()
    # Ax3DSq()
    # brokenline()


import numpy.linalg
from Point import *
#from bresenham import bresenham

def random_partition(n,n_data):
	"""return n random rows of data (and also the other len(data)-n rows)"""
	all_idxs = numpy.arange( n_data )
	numpy.random.shuffle(all_idxs)
	idxs1 = all_idxs[:n]
	idxs2 = all_idxs[n:]
	return idxs1.tolist(), idxs2.tolist()

def leastSquares(points,  weighted=False):
	x_d = []
	y_d = []
	for point in points:
		(x, y) = point.toTuple()
		if weighted:
			w = point.w
			x_d += [x]*w
			y_d += [y]*w
		else:
			x_d.append(x)
			y_d.append(y)

	n=len(x_d)

	B=numpy.array(y_d)
	A=numpy.array(([[x_d[j], 1] for j in range(n)]))
	X=numpy.linalg.lstsq(A,B)[0]
	a=X[0]; b=X[1]
	#print("Line is: y=",a,"x+",b)

	Xplot = []
	Yplot = []

	x = min(x_d)
	y = a*x + b
	Xplot.append(x)
	Yplot.append(y)

	x = max(x_d)
	y = a*x + b
	Xplot.append(x)
	Yplot.append(y)
	return (Xplot, Yplot, a, b)

def calcResidue(a, b, xi, yi):
	yi_ = a*xi + b
	return (yi - yi_)

def calcTotalError(points, a, b):
	totalError = 0

	n = len(points)
	for point in points:
		(xi, yi) = point.toTuple()
		ei = calcResidue(a, b, xi, yi)
		totalError += ei*ei

	return totalError

class LinearLeastSquaresModel:
	"""linear system solved using linear least squares

	This class serves as an example that fulfills the model interface
	needed by the ransac() function.

	"""
	#def __init__(self):
	def fit(self, data, weighted=False):
		return leastSquares(data, weighted=weighted)
	def get_error( self, data, model):
		(_, _, a, b) = model
		totalError = calcTotalError(data, a, b)
		n = len(data)
		err_per_point = totalError/n
		return err_per_point

def getDataByIndex(data, idxs):
	returnData = []

	if type(idxs) != list:
		print("idxs = ", idxs)
		print("type(idxs) = ", type(idxs))
		returnData = [data[idxs]]
	else:
		for i in idxs:
			returnData.append(data[i])
		#if type(returnData) != type(list):
		#   returnData = [returnData]
	return returnData

def ransac(data,model,n,k,t,d,debug=False,return_all=False, weighted=False, random=True):
	"""fit model parameters to data using the RANSAC algorithm

This implementation written from pseudocode found at
http://en.wikipedia.org/w/index.php?title=RANSAC&oldid=116358182

{{{
Given:
	data - a set of observed data points
	model - a model that can be fitted to data points
	n - the minimum number of data values required to fit the model
	k - the maximum number of iterations allowed in the algorithm
	t - a threshold value for determining when a data point fits a model
	d - the number of close data values required to assert that a model fits well to data
Return:
	bestfit - model parameters which best fit the data (or nil if no good model is found)
iterations = 0
bestfit = nil
besterr = something really large
while iterations < k {
	maybeinliers = n randomly selected values from data
	maybemodel = model parameters fitted to maybeinliers
	alsoinliers = empty set
	for every point in data not in maybeinliers {
		if point fits maybemodel with an error smaller than t
			 add point to alsoinliers
	}
	if the number of elements in alsoinliers is > d {
		% this implies that we may have found a good model
		% now test how good it is
		bettermodel = model parameters fitted to all points in maybeinliers and alsoinliers
		thiserr = a measure of how well model fits these points
		if thiserr < besterr {
			bestfit = bettermodel
			besterr = thiserr
		}
	}
	increment iterations
}
return bestfit
}}}
"""
	alsoinliers = []
	iterations = 0
	bestfit = None
	besterr = numpy.inf
	best_inlier_idxs = None
	while iterations < k:
		maybeinliers = data
		test_points = data
		maybe_idxs, test_idxs = random_partition(n,len(data))
		if random:
			# print("maybe_idxs = ", maybe_idxs)
			# print("test_idxs = ", test_idxs)
			maybeinliers = getDataByIndex(data, maybe_idxs)
			test_points = getDataByIndex(data, test_idxs)
		#print("maybeinliers = ", maybeinliers)

		maybemodel = model.fit(maybeinliers, weighted=weighted)
		test_err = model.get_error( test_points, maybemodel)
		#print("test_err = ", test_err)
		#print("len test_idxs = ", len(test_idxs))
		also_idxs = test_idxs[test_err < t] # select indices of rows with accepted points
		#print("also_idxs = ", also_idxs)

		#print("also_idxs = ", also_idxs)
		#alsoinliers = getDataByIndex(data, also_idxs)
		alsoinliers = []
		test_err = 0
		for point in test_points:
			(_, _, a, b) = maybemodel
			(xi, yi) = point.toTuple()
			ei = abs(calcResidue(a, b, xi, yi))
			#ei = ei*ei
			test_err += ei
			if ei < t:
				alsoinliers.append(point)

		#if alsoinliers != list:
		#	alsoinliers = [alsoinliers]

		if debug:
			print ('test_err.min()',test_err.min())
			print ('test_err.max()',test_err.max())
			print ('numpy.mean(test_err)',numpy.mean(test_err))
			#print("alsoinliers = ", alsoinliers)
			print ('iteration %d:len(alsoinliers) = %d'%(iterations,len(alsoinliers)))
		if len(alsoinliers) > d:
			betterdata = maybeinliers + alsoinliers  #numpy.concatenate( (maybeinliers, alsoinliers) )
			bettermodel = model.fit(betterdata)
			better_errs = model.get_error( betterdata, bettermodel)

			thiserr = 0
			for point in betterdata:
				(_, _, a, b) = bettermodel
				(xi, yi) = point.toTuple()
				ei = abs(calcResidue(a, b, xi, yi))
				#ei = ei*ei
				thiserr += ei
				#if ei < t:
				#	alsoinliers.append(point)

			thiserr = numpy.mean(thiserr)#( better_errs )
			if thiserr < besterr:
				bestfit = bettermodel
				besterr = thiserr
				#best_inlier_idxs = numpy.concatenate( (maybe_idxs, also_idxs) )
				#print("best_inlier_idxs = ", best_inlier_idxs)
		iterations+=1
	if bestfit is None:
		print("did not meet fit acceptance criteria")
		return None
		#raise ValueError("did not meet fit acceptance criteria")

	alsoinliers = sorted(alsoinliers, key=lambda p: p.x)
	# print("alsoinliers: ", alsoinliers)

	return alsoinliers

	if return_all:
		return bestfit#, {'inliers':best_inlier_idxs}
	else:
		return bestfit


#
# undamped pendulum motion, in small-angle approximation
#
# ODE system:   1) dtheta/dt = omega
#               2) domega/dt = -Omega0^2 * theta
#
#     where Omega0^2 = g / L
#
# solved numerically via Euler's method
#
#
# by Denes Molnar for PHYS 580, Fall 2020

import math
import numpy as np

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

# compute evolution of theta and omega from given initconds
def computeTrajectory(initconds, Omega0, dt, nsteps):
   (th0, om0) = initconds

   # allocate storage - store both theta and omega
   theta = np.zeros(nsteps + 1)
   omega = np.zeros(nsteps + 1)
   theta[0] = th0
   omega[0] = om0

   # solve using Euler method
   for i in range(nsteps):
      theta[i + 1] = theta[i] + omega[i] * dt
      omega[i + 1] = omega[i] - Omega0**2 * theta[i] * dt

   # return results
   return theta, omega

# get parameters
#

# physical parameters and initial conditions (units are in [] brackets)
L    = float( input('length of pendulum [m]: ') )
th0  = float( input('initial angle wrt to vertical [rad]: ') )
om0  = float( input('initial angular velocity [rad/s]: ') )
#
g    = 9.8      # gravitational acceleration [m/s^2] (hardcoded)

Omega0 = math.sqrt(g / L)

# computational parameters: dt[s], nsteps
dt = float( input('dt [s]: ') )
nsteps = int( input('number of time steps to calculate: ') )

# compute evolution
#

theta, omega = computeTrajectory( (th0, om0), Omega0, dt, nsteps)
# time values, for plotting
timevals = np.array( [ dt * i  for i in range(nsteps + 1) ] )
# calculate energy at each timestep
#energy = [ omega[i]**2 + Omega0*Omega0 * theta[i]**2   for i in range(nsteps + 1) ]
energy = omega**2 + Omega0**2 * theta**2  # use numpy by-element array operations

# plots
#

fontsize = 30   # fontsize, need to be tuned to screen resolution
linewidth = 3

# create 3 plots under each other
fig, axArray = plt.subplots(3, sharex = True)

(ax0, ax1, ax2) = axArray

# theta
ax0.plot(timevals, theta, linewidth = linewidth, label = "theta")

titleString  = "dt=" + str(dt) + ", L=" + str(L)
titleString += ", omega0=" + str(om0) + ", theta0=" + str(th0)

ax0.set_title(titleString, fontsize = fontsize)
ax0.tick_params(labelsize = fontsize)
ax0.legend(fontsize = fontsize)

# omega
ax1.plot(timevals, omega, linewidth = linewidth, label = "omega")

ax1.tick_params(labelsize = fontsize)
ax1.legend(fontsize = fontsize)

# energy
ax2.plot(timevals, energy, linewidth = linewidth, label = "energy")

ax2.tick_params(labelsize = fontsize)
ax2.legend(fontsize = fontsize)
ax2.set_xlabel("t[s]", fontsize = fontsize)

# show plot
plt.show()

#EOF


import numpy as np

def get_epipole(F):
    '''
    Epipole is the eigenvector associated with smallest eigenvalue of F
    '''
    evalue, evector = np.linalg.eig(F)  # normalized evector
    index = np.argmin(evalue)
    epipole = evector[:, index]
    return epipole

def get_rotation_axis(d):
    # d_i to make image plane parallel
    # intersection line
    axis = np.array([-d[1], d[0], 0])
    return axis

def get_angle(epipole, axis):
    return np.arctan(epipole[2] / (axis[1] * epipole[0] - axis[0] * epipole[1]))

def get_plane_rotation_matrix(axis, angle):
    cos_angle = np.cos(angle)
    sin_angle = np.sin(angle)
    dx = axis[0]
    dx2 = dx ** 2
    dy = axis[1]
    dy2 = dy ** 2
    return np.array([[dx2 + (1 - dx2) * cos_angle, dx * dy * (1 - cos_angle), dy * sin_angle],
                     [dx * dy * (1 - cos_angle), dy2 + (1 - dy2) * cos_angle, -dx * sin_angle],
                     [-dy * sin_angle, dx * sin_angle, cos_angle]])

def get_scanline_rotation_matrix(angle):
    cos = np.cos(angle)
    sin = np.sin(angle)
    return np.array([[cos, -sin, 0],
                     [sin, cos, 0],
                     [0, 0, 1]])

def compute_prewarp(F, all=False):
    # apply a 3D rotation to make the image planes parall
    epipole1 = get_epipole(F)
    epipole2 = get_epipole(F.T)
    # step 1: rotate image plane
    axis1 = get_rotation_axis(epipole1)
    theta1 = get_angle(epipole1, axis1)
    R1_plane = get_plane_rotation_matrix(axis1, theta1)

    conjugate = F @ axis1
    axis2 = get_rotation_axis(conjugate)
    theta2 = get_angle(epipole2, axis2)
    R2_plane = get_plane_rotation_matrix(axis2, theta2)

    # step2: align scanline
    new_epipole1 = R1_plane @ epipole1
    new_epipole2 = R2_plane @ epipole2

    phi1 = -np.arctan(new_epipole1[1] / new_epipole1[0])
    phi2 = -np.arctan(new_epipole2[1] / new_epipole2[0])
    R1_scanline = get_scanline_rotation_matrix(phi1)
    R2_scanline = get_scanline_rotation_matrix(phi2)

    # step 3: get homography
    H1 = R1_scanline @ R1_plane
    H2 = R2_scanline @ R2_plane
    H1 /= H1[-1,-1]
    H2 /= H2[-1,-1]
    if all:
        return H1, H2, R1_plane, R2_plane, R1_scanline, R2_scanline
    return H1, H2


import numpy as np
from scipy.stats import norm

def calculate_likelihood(mu, var, x):
    return norm.pdf(x, loc=mu, scale=np.sqrt(var))

def calculate_log_likelihood(mu, var, x):
    res = norm.logpdf(x, loc=mu, scale=np.sqrt(var))
    # es[res > 0] = 0  # catch numerical issues
    return res


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

import numpy as np

base_data = (np.random.random((5, 5)) - 0.5) * 100
print("base_data = \n{}\n".format(base_data))

print("np.amin(base_data) = {}".format(np.amin(base_data)))
print("np.amax(base_data) = {}".format(np.amax(base_data)))
print("np.average(base_data) = {}".format(np.average(base_data)))
print("np.sum(base_data) = {}".format(np.sum(base_data)))
print("np.sin(base_data) = \n{}".format(np.sin(base_data)))

# a = np.array([[1, 2, 3], [4, 5, 6]])
a = np.arange(1, 7).reshape(2, 3)

b = np.array([[2, 1, 0], [1, 1, 1]])

c = a.transpose()

print('\na = %s type=%s\n' % (a, type(a)))
print('b = %s\n' % b)

print('a + 1 = %s' % (a + 1))
print('a * 2 = %s' % (a * 2))
print('a * b = %s' % (a * b))
print('a + b = %s' % (a + b))
print('np.multiply(a, b) = %s' % (np.multiply(a, b)))
print('np.multiply(np.mat(a), np.mat(b)) = %s' % (np.multiply(np.mat(a), np.mat(b))))
print('np.mat(a) * np.mat(b) = %s' % (np.mat(a) * np.mat(c)))

print('c = %s' % c)
print('a.T = %s' % a.T)
print('dot(a, c) = %s\n' % np.dot(a, c))
print('a @ c = %s' % (a @ c))

print('sum=%s min=%s max=%s mean=%s var=%s std=%s\n' % (a.sum(), a.min(), a.max(), a.mean(), a.var(), a.std()))

print('np.hstack = %s\n' % np.hstack((a, b)))
print('np.vstack = %s\n' % np.vstack((a, b)))
print('np.hsplit(a,3) = %s\n' % np.hsplit(a, 3))
print('np.vsplit(a,2) = %s\n' % np.vsplit(a, 2))

print('np.diag(a) = %s' % np.diag(a))
print('diag(diag(a)) = %s' % np.diag(np.diag(a)))

x = np.arange(10)

print('x = %s\n' % x)
print('x[2] = %s\n' % x[2])
print('x[-2] = %s\n' % x[-2])
print('x[2:5] = %s\n' % x[2: 5])
print('x[::-1] = %s\n' % x[::-1])
print('x[::-2] = %s\n' % x[::-2])

indexs = [2, 3, 4]
print('x[indexs]=%s' % (x * 2)[indexs])
x[::2] = [-1, -2, -3, -4, -5]
print('x after::2 = %s\n' % x)
print('x[::1] = %s\n' % x[::2])

print('a[1] = %s\n' % a[1])
print('a[1, :] = %s\n' % a[1, :])
print('a[:, 1] = %s\n' % a[:, 1])
print('a[1:3, 1:3] = %s\n' % a[1:3, 1:3])

x = np.arange(12).reshape(3, 4)
x = x > 4
print('x = %s\n' % x)
print('bools.any = %s\n' % x.any())
print('bools.all = %s\n' % x.all())

print('type(a) = %s' % type(a))
print('type((np.mat(a)) = %s' % type(np.mat(a)))

print('\na = %s\n' % a)
print("a's ndim {}".format(a.ndim))
print("a's shape {}".format(a.shape))
print("a's size {}".format(a.size))
print("a's dtype {}".format(a.dtype))
print("a's itemsize {}".format(a.itemsize))

# 生成均值为loc，标准差为scale的正态分布矩阵，numpy中很多方法如果size不写则返回一个值
y = np.random.normal(10, 1, (2, 5))
print('\ny = %s\n' % y)
print('y.mean=%s y.std=%s' % (y.mean(), y.std()))

D = np.mat("1 2 3; 2 3 1; 3 1 2")
print('D.det = %s' % np.linalg.det(D))
# print('A.det = %s' % np.linalg.det(np.mat(a))) #LinAlgError: Last 2 dimensions of the array must be square
print('\nD = %s type = %s' % (D, type(D)))
D_I = D.I
print('D.I = %s type = %s' % (D_I, type(D_I)))
print('D * D.I = %s' % np.dot(D, D_I))
print('D.I * D = %s' % np.dot(D_I, D))

print('\neye(3) = %s' % (np.eye(3)))

M = np.array([1, 2, 3])
N = np.array([1, 0, 2])
print('\nM = %s    N = %s type(M)=%s' % (M, N, type(M)))

DOT_MN = np.dot(M, N)
print('dot(M,N)=%s  type=%s' % (DOT_MN, type(DOT_MN)))

DOT_MAT_MN = np.dot(np.mat(M), np.mat(N).T)
print('dot(mat(M), mat(N).T)=%s  type=%s' % (DOT_MAT_MN, type(DOT_MAT_MN)))

np_array = np.array([np.inf, -np.inf, np.nan, -128, 128])
print('np.nan_to_num=%s' % np.nan_to_num(np_array))


# -*- coding: utf-8 -*-
"""
Interpolaciones para explicar el fenomeno de Runge

"""
from __future__ import division, print_function
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import lagrange
import sympy as sym

plt.rcParams["axes.spines.right"] = False
plt.rcParams["axes.spines.top"] = False
plt.rcParams["mathtext.fontset"] = "cm"

def base_lagrange(x_datos, var, cont):
    """Crea un polinomio base de Lagrange para los datos x"""
    prod = sym.prod((var - x_datos[i])/(x_datos[cont] - x_datos[i])
                    for i in range(len(x_datos)) if i != cont)

    return sym.lambdify(var, sym.simplify(prod), "numpy")

runge = lambda x: 1/(1 + 25*x**2)
x = np.linspace(-1, 1, 201)
y = runge(x)
x_inter = np.linspace(-1, 1, 11)
y_inter = runge(x_inter)
x_cheb = -np.cos(np.linspace(0, np.pi, 11))
y_cheb = runge(x_cheb)
gris = "#969696"

plt.close("all")

#%% Funcion de Runge
plt.figure(figsize=(4, 3))
plt.plot(x, y)
plt.plot(x_inter, y_inter, "ok")
plt.xlabel("$y$", fontsize=14)
plt.ylabel("$y$", fontsize=14)
plt.savefig("runge_fun.pdf", bbox_inches="tight", transparent=True)

#%% Interpolacion equidistante
plt.figure(figsize=(5, 2.5))
plt.subplot(122)
plt.title("Funciones base")
for cont_base in range(11):
    if cont_base == 5:
        color = None
        zorder = 4
        linewidth = 2
    else:
        color = gris
        zorder = 3
        linewidth = 1
    base = base_lagrange(x_inter, sym.symbols("x"), cont_base)
    y_base = base(x)
    plt.plot(x, y_base, color=color, zorder=zorder, linewidth=linewidth)
    plt.xlabel("$x$", fontsize=14)
    plt.ylabel("$y$", fontsize=14)

plt.subplot(121)
plt.title("Interpolación")
plt.plot(x, y)
inter = lagrange(x_inter, y_inter)
plt.plot(x, inter(x), linestyle="dashed")
plt.plot(x_inter, y_inter, "ok")
plt.xlabel("$x$", fontsize=14)
plt.ylabel("$y$", fontsize=14)
plt.tight_layout()
plt.savefig("runge_equi.pdf", bbox_inches="tight", transparent=True)

#%% Interpolacion con nodes de Chebyshev
plt.figure(figsize=(5, 2.5))
plt.subplot(122)
plt.title("Funciones base")
for cont_base in range(11):
    if cont_base == 5:
        color = None
        zorder = 4
        linewidth = 2
    else:
        color = gris
        zorder = 3
        linewidth = 1
    base = base_lagrange(x_cheb, sym.symbols("x"), cont_base)
    y_base = base(x)
    plt.plot(x, y_base, color=color, zorder=zorder, linewidth=linewidth)
    plt.xlabel("$x$", fontsize=14)
    plt.ylabel("$y$", fontsize=14)

plt.subplot(121)
plt.title("Interpolación")
plt.plot(x, y)
inter = lagrange(x_cheb, y_cheb)
plt.plot(x, inter(x), linestyle="dashed")
plt.plot(x_cheb, y_cheb, "ok")
plt.xlabel("$x$", fontsize=14)
plt.ylabel("$y$", fontsize=14)
plt.tight_layout()
plt.savefig("runge_cheb.pdf", bbox_inches="tight", transparent=True)

#%% Interpolacion con nodes de Chebyshev
plt.figure(figsize=(5, 2.5))
titles = ["Puntos equidistantes", "Puntos no equidistantes"]
x_sample = [x_inter, x_cheb]
for cont in range(2):
    ax = plt.subplot(1, 2, cont + 1)
    plt.title(titles[cont])
    for cont_base in [0, 5]:
        if cont_base == 0:
            linestyle = None
        else:
            linestyle = "dashed"
        base = base_lagrange(x_sample[cont], sym.symbols("x"), cont_base)
        y_base = base(x)
        plt.plot(x, y_base, linestyle=linestyle)

    plt.xlabel("$x$", fontsize=14)
    plt.ylim(-1.5, 7)
    if cont == 0:
        plt.ylabel("$y$", fontsize=14)

plt.legend(["Punto izquierda", "Punto central"])
ax.yaxis.set_ticks([])
ax.spines["left"].set_color("none")
plt.tight_layout()
plt.savefig("runge_comparacion.pdf", bbox_inches="tight", transparent=True)

#plt.show()


import numpy.random as rnd
import matplotlib.pyplot as plt
import numpy as np
import time as tm

# the function walk1D consists of N steps in the positive/negative direction based on a randomly generated value
def walk1D(steps):
    path = np.zeros(steps, dtype=int)

    for i in range(steps-1):
        if rnd.randint(2):
            path[i+1] = path[i] + 1
        else:
            path[i+1] = path[i] - 1

    return path[-1]

def walk1Dgooder(steps):
    direction = np.array([-1,1])

    path =  np.cumsum(direction[rnd.randint(2, size=steps)], axis=0)
    return path[-1]

def walk1Dstats(steps, numWalkers):
    xf = np.zeros(numWalkers)

    for i in range(numWalkers):
        xf[i] = walk1D(steps)

    displacement = np.mean(xf)
    stddev = np.std(xf)
    distance = np.mean(np.abs(xf))

    print("Average displacement: %f metres"  %(displacement))
    print("Standard deviation:   %f metres"  %(stddev))
    print("Average distance:     %f metres"  %(distance))

    return xf

# look at an individual random walk
numSteps = 100000

walk = walk1D(numSteps)
walk = walk1Dgooder(numSteps)

plotTheWalk = 0

# plot the walk:  plot position vs. step number (represented by index, below)
if plotTheWalk:
    index = np.arange(numSteps)
    plt.plot(index, walk)
    plt.plot(index, walk1Dgooder(numSteps), 'g')
    plt.plot(index, walk1Dgooder(numSteps), 'r')
    plt.plot(index, walk1Dgooder(numSteps), 'b')

# look at the statistics for many random walks
# vall the random walk function for each walker, and save into the final_pos array
numWalkers = 1000
numSteps = 1000

# the stats that we are interested in relates to final positions of the walks assuming that all walks start at the same initial position (x=0)
x_final = walk1Dstats(numSteps,numWalkers)

# for walk1Dstats, with function returning x_final:
plotStats = 1
if plotStats:
    r=100
    plt.hist(x_final, range=(-r,r), bins=r)

    plt.title('2-D Random Walk')
    plt.xlabel('Displacement')
    plt.ylabel('Number of Walkers')

# look at the relationship between final_x number of steps
plotRelationship = 0
if plotRelationship:
    num = np.array([10,50,100,500,1000,5000,10**4])
    Dist = np.zeros(num.size)

    for i in range(num.size):
        Dist[i]=walk1Dstats(num[i],numWalkers)

    plt.plot(num,Dist,'ok')

plt.savefig('distribution1D.png')


# Demo of perceptron algorithm in 2d
# Code is modified from various sources, including
#https://medium.com/@thomascountz/19-line-line-by-line-python-perceptron-b6f113b161f3
#http://stamfordresearch.com/scikit-learn-perceptron/
#https://glowingpython.blogspot.com/2011/10/perceptron.html
#https://stackoverflow.com/questions/31292393/how-do-you-draw-a-line-using-the-weight-vector-in-a-linear-perceptron?rq=1
#https://medium.com/@thomascountz/calculate-the-decision-boundary-of-a-single-perceptron-visualizing-linear-separability-c4d77099ef38

import numpy as np
import matplotlib.pyplot as plt

figdir = "../figures"
def save_fig(fname):
    if figdir: plt.savefig(os.path.join(figdir, fname))

np.random.seed(0)

class Perceptron(object):

    def __init__(self, no_of_inputs, max_iter=10, learning_rate=1):
        self.max_iter = max_iter
        self.learning_rate = learning_rate
        self.weights = np.zeros(no_of_inputs + 1)
        self.weights_hist = []

    def predict_single(self, inputs):
        summation = np.dot(inputs, self.weights[1:]) + self.weights[0]
        if summation > 0:
          output = 1
        else:
          output = 0
        return output

    def predict(self, X):
        n = X.shape[0]
        yhat = np.zeros(n)
        for i in range(n):
            yhat[i] = self.predict_single(X[i,:])
        return yhat

    def fit(self, training_inputs, labels):
        for epoch in range(self.max_iter):
            for inputs, label in zip(training_inputs, labels):
                prediction = self.predict_single(inputs)
                self.weights[1:] += self.learning_rate * (label - prediction) * inputs
                self.weights[0] += self.learning_rate * (label - prediction)
                self.weights_hist.append(np.copy(self.weights))

def generateData(n):
     # Generates a 2D linearly separable dataset with 2n samples.
     # Red and blue clusters in top left and bottom right quadrant
     xb = (np.random.rand(n)*2-1)/2-0.5
     yb = (np.random.rand(n)*2-1)/2+0.5
     xr = (np.random.rand(n)*2-1)/2+0.5
     yr = (np.random.rand(n)*2-1)/2-0.5
     XB = np.stack([xb,yb], axis=1)
     XR = np.stack([xr,yr], axis=1)
     X = np.concatenate([XB, XR])
     y = np.concatenate([np.zeros(n, dtype=np.int), np.ones(n, dtype=np.int)])
     return X, y

X, y = generateData(10)

def plot_dboundary_contourf(net):
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    h = 0.02
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))

    fig, ax = plt.subplots()
    Z = net.predict(np.c_[xx.ravel(), yy.ravel()])

    Z = Z.reshape(xx.shape)
    ax.contourf(xx, yy, Z) #, cmap=plt.cm.Paired)
    ax.axis('off')
    colormap = np.array(['r', 'k'])
    ax.scatter(X[:, 0], X[:, 1], c=colormap[y])
    #ax.axis('square')

def plot_dboundary(weights, offset):
    w1 = weights[0]
    w2 = weights[1]
    b = offset
    slope = -w1/w2
    intercept = -b/w2
    xx = np.linspace(-1, 1, 10)
    yy = xx*slope + intercept
    plt.figure()
    colormap = np.array(['r', 'k'])
    plt.scatter(X[:,0], X[:,1], c=colormap[y], s=40)
    plt.plot(xx, yy, 'k-')

ninputs = 2
net = Perceptron(ninputs)
net.fit(X, y)

w = net.weights[1:]
b = net.weights[0]
plot_dboundary(w, b)
plot_dboundary_contourf(net)

'''
H = net.weights_hist
niter = len(H)
snapshots = [int(t) for t in np.linspace(0, 20, 5)]
#snapshots = [15,  20, 25]
for t in snapshots:
    w = H[t][1:]
    b = H[t][0]
    plot_dboundary(w, b)
    plt.title('iter {}'.format(t))
'''

# sklearn version
from sklearn.linear_model import perceptron
net_sklearn = perceptron.Perceptron()
net_sklearn.fit(X, y)
w = net_sklearn.coef_[0]
offset = net_sklearn.intercept_[0]

plot_dboundary(w, b)
plot_dboundary_contourf(net)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 23 20:58:05 2020

@author: tyrion
"""
import numpy as np

def sphere(n_grid = 30, equalize_areas = True):
    '''
    Create vectors to conveniently plot a sphere

    Arguments
    ----------
    n_grid  : int, optional, default 30
        Number of grid points for the sphere for both
        longitude and lattitude
    equalize_areas : bool, optional, default True
        If True, enforces that surface patches are of same area

    Returns
    ----------
    x : ndarray
    y : ndarray
    z : ndarray
    '''

    if equalize_areas == True:
        u = np.arccos(np.linspace(-1, 1, n_grid))

    else:
        u = np.linspace(0, np.pi, n_grid)

    v = np.linspace(0, 2 * np.pi, n_grid)

    x = np.outer(np.sin(u), np.sin(v))
    y = np.outer(np.sin(u), np.cos(v))
    z = np.outer(np.cos(u), np.ones_like(v))

    return x, y, z

def evaluate_on_sphere(func, n_grid = 30, equalize_areas = True):
    '''
    Evaluate a function over a sphere

    Arguments
    ----------
    func : callable
        Must be of the form ndarray (n, 3)-> (n, )
    n_grid  : int, optional, default 30
        Number of grid points for the sphere for both
        longitude and lattitude
    equalize_areas : bool, optional, default True
        If True, enforces that surface patches are of same area

    Returns
    ----------
    f : ndarray (n, )
    '''
    if equalize_areas == True:
        u = np.arccos(np.linspace(-1, 1, n_grid))

    else:
        u = np.linspace(0, np.pi, n_grid)
    v = np.linspace(0, 2 * np.pi, n_grid)

    u_grid, v_grid = np.meshgrid(u, v)

    vertex_vecs = np.array([np.sin(v_grid)*np.sin(u_grid), \
                        np.cos(v_grid)*np.sin(u_grid),np.cos(u_grid)])

    vertex_vecs = vertex_vecs.reshape(3,n_grid*n_grid).T

    #calculate function values for the sphere faces

    f_faces = func(vertex_vecs).reshape(n_grid,n_grid).T

    return f_faces

def spherical_hist(vectors, n_grid = 100):
    '''
    Basic spherical histogram

    Arguments
    ----------
    vectors : ndarray (n, 3)
        Vectors to calculate histogram of
    n_grid  : int, optional, default 100
        number of grid points for the sphere for both
        longitude and lattitude

    Returns
    ----------
    hist : ndarray
    x : ndarray
    y : ndarray
    z : ndarray
    '''

    #u = np.linspace(0, np.pi , n_grid, endpoint = True)
    u = np.flip(np.arccos(np.linspace(-1,1,n_grid, endpoint = True)))
    v = np.linspace(-np.pi, np.pi, n_grid, endpoint = True)

    phis = np.arctan2(vectors[:,1], vectors[:,0])
    #print(np.rad2deg(phis))
    thetas = np.arccos(vectors[:,2])

    hist,thetabins, phibins = np.histogram2d(thetas, phis, bins = [u,v])

    #u_surface = np.linspace(0, np.pi , n_grid -1, endpoint = True)
    u_surface = np.flip(np.arccos(np.linspace(-1,1,n_grid -1, endpoint = True)))
    v_surface = np.linspace(-np.pi, np.pi, n_grid -1, endpoint = True)
    #print(u_centers)
    x = np.outer(np.sin(u_surface), np.cos(v_surface))
    y = np.outer(np.sin(u_surface), np.sin(v_surface))
    z = np.outer(np.cos(u_surface), np.ones_like(v_surface))

    return hist, x, y, z


import functools
import math
import numpy as np
from typing import Union

from scipy import special

numberTypes = (float, np.float64, np.float32, int, np.int32, np.int64)
onesDict = {}

def ones(value: np.ndarray):
    if value.shape not in onesDict.keys():
        newOnes = np.ones(value.shape)
        onesDict[value.shape] = newOnes
        return newOnes
    return onesDict[value.shape]

def Sigmoid(value: Union[np.ndarray, float]) -> Union[np.ndarray, float]:
    if isinstance(value, numberTypes):
        if value > 230:
            return 1
        elif value < -230:
            return 0
        return 1 / (1 + math.exp(-value))
    elif isinstance(value, (np.ndarray,)):
        return ones(value) / (ones(value) + np.exp(-value))
    else:
        assert value is None

def SigmoidDerivative(value: Union[np.ndarray, float]):
    if isinstance(value, numberTypes):
        return value * (1 - value)
    elif isinstance(value, np.ndarray):
        return value * (ones(value) - value)
    else:
        assert value is None

def Softplus(value: Union[np.ndarray, float]):
    if isinstance(value, numberTypes):
        return math.log(1 + math.exp(value))
    elif isinstance(value, np.ndarray):
        return np.log(ones(value) + np.exp(value))
    else:
        assert value is None

def SoftplusDerivative(value: Union[np.ndarray, float]):
    if isinstance(value, numberTypes):
        return value / (1 + value)
    elif isinstance(value, np.ndarray):
        return value / (ones(value) + value)
    else:
        assert value is None

def Softmax(value: np.ndarray):
    if isinstance(value, np.ndarray):
        exp = np.exp(value - (ones(value) * np.max(value)))
        return exp / np.sum(exp)
    else:
        assert value is None

def SoftmaxDerivative(value: np.ndarray):
    if isinstance(value, np.ndarray):
        return value * (ones(value) - value)
        # if need derivative of same value, because every element changes the other elements value by definition
    else:
        assert value is None

def Relu(value: Union[np.ndarray, float]):
    if isinstance(value, numberTypes):
        return max(0, value)
    elif isinstance(value, np.ndarray):
        return np.maximum(ones(value)*0, value)
    else:
        assert value is None

def ReluDerivative(value: Union[np.ndarray, float]):
    if isinstance(value, numberTypes):
        if value > 0:
            return 1
        else:
            return 0
    elif isinstance(value, np.ndarray):
        return np.where(value > 0, 1, 0)
    else:
        assert value is None

# Todo maybe add leaky-relu = max(value,0) + x*min(value,0)