"""
Description: script to demonstrate estimation of a function using a
 			 Fourier series
Author: Tarkan Bilge
Date: 06/02/2021"""

# =============================================================================
# Import
# =============================================================================

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

# =============================================================================
# Functions
#==============================================================================

def fourier_series(f, interval, N):
	"""
	Calculates the Fourier series to approximate a function f.

	Parameters
	----------
	f : function
		Arbitrary function to be estimated by Fourier series.
	interval : list of float
		The start and end points of the interval of analysis.
	N : int
		Number of harmonics to estimate the function f with.

	Returns
	-------
	F : function
		The Fourier series approximation of f with N harmonics.
	"""

	P = interval[1] - interval[0]
	coefficient_list = []

	# The cooefficient sum should be zero if N = 0, but still a function of t
	coefficient_sum = lambda t: 0 * t

	# The coefficient for n = 0 is written separately to simplify the sum
	a0 = (2.0/P) * scipy.integrate.quad(f, interval[0], interval[1])[0]

	if N > 0:
		for n in range(1, N + 1):
			cos_term = lambda t, n=n: np.cos((2.0 * np.pi * n * t)/P)
			sin_term = lambda t, n=n: np.sin((2.0 * np.pi * n * t)/P)
			f_cos = lambda t, n=n : f(t) * cos_term(t)
			f_sin = lambda t, n=n : f(t) * sin_term(t)

			an = (2.0/P) * scipy.integrate.quad(f_cos, interval[0], interval[1])[0]
			bn = (2.0/P) * scipy.integrate.quad(f_sin, interval[0], interval[1])[0]
			coefficient = lambda t, n=n, an=an, bn=bn: (an * np.cos((2.0 * np.pi * n * t)/P)) + (bn * np.sin((2.0 * np.pi * n * t)/P))
			coefficient_list.append(coefficient)

		coefficient_sum = lambda t: sum([x(t) for x in coefficient_list])

	F = lambda t: a0/2.0 + coefficient_sum(t)
	return(F)

# =============================================================================
# Main
# =============================================================================

if __name__ == '__main__':

	# User input: input function
	f = lambda t: signal.sawtooth(2 * np.pi * t)

	# User input : Fourier series parameters
	N = 3
	interval = [0.0, 1.0]

	# Calculate fourier series estimate
	F = fourier_series(f, interval=interval, N=N)

	# Plotting
	t = np.linspace(0, 2, 1000)
	plt.plot(t, f(t))
	plt.plot(t, F(t))

	# Plot settings
	plt.ylim(-1.5, 1.5)
	plt.title(f"Fourier series estimation of a function; N = {N} over interval {interval}")
	plt.legend(['f(x)', 'F(x)'])
	plt.xlabel("x")
	plt.ylabel("y")

	plt.show()


import numpy as np
aArray = np.array([1,2,3])
print(aArray)
bArray = np.array([(1,2,3),(4,5,6)])
print(bArray)
# np.arange(start, stop, step)
c = np.arange(1,5,0.5)
print(c)
# return random floats between 0,1.0
d = np.random.random((2,2))
print(d)
# np.linspace(start, stop, nums, )
e = np.linspace(1,2,10,endpoint=False)
print(e)

# np.ones(shape, dtype=, order='') an ndarray with axis 0 = 2, axis 1 = 3 filled with one
f = np.ones([2,3])
print(f)

# np.zeros(shape, dtype=, order='') an ndarray with axis 0 = 2, axis 1 = 2, filled with zeros
g = np.zeros((2,2))
print(g)

# np.fromfunction(function, shape, dtype=, order='') an ndarray with function:(lambda i,j:(i+1)*(j+1)) and shape(9,9)
h = np.fromfunction(lambda i,j:(i+1)*(j+1),(9,9))
print(h)

# creating a 4x4 ndarray with filled with 1-16(1,17)
i = np.arange(1,17).reshape(4,4)
print(i)

j = np.array([1,3,7])
k = np.array([3,5,8])
print(np.vstack((j,k)))
print(np.hstack((j,k)))

l = np.array([(5,5,5),(5,5,5)])
m = np.array([(2,2,2),(2,2,2)])
print(l*m)
print(l+m)

n = np.array([1,2,3])
o = np.array([[1,2,3],[4,5,6]])
print(n+o)


import numpy as np
from scipy.linalg import hadamard

def gaussian_random_sketch(m, n, mean=0, variance=1):
    """
    m: Sketch size,
    n: Number of columns of the input matrix,
    mean: mean of gaussian distribution
    variance: variance of gaussian distribution

    returns: An m x n matrix sample from the Gaussian Distribution
    """
    return np.random.normal(loc=mean, scale=variance, size=(m, n))

def subsampled_randomized_hadamard_transforms(m, n):
    """
    m: Sketch size,
    n: Number of rows in the input matrix,

    returns: An m x n matrix subsampled randomized Hadamard transform
    """

    # if n is None:
    #     # Select n such that it is the smallest power of 2 that is larger than m
    #     p = int(round(np.log2(m), 0) + 1)
    #     n = 2 ** p
    #
    # Create the n x n Walsh-Hadamard matrix:
    H = hadamard(n)

    # Calculate diagonal - uniformly randomly 1 or -1
    d = np.random.uniform(0, 1, size=(n,))
    d = np.where(d > 0.5, 1, -1)

    # Use dot product to calculate HD
    HD = (H * d)

    # Calculate row sampling matrix
    # I_n = np.eye(n)
    # R = I_n[np.random.choice(n, m, replace=False), :]

    # Put everything together with 1 matrix multiplication
    # S = (1 / (m ** 0.5)) * np.matmul(R, HD)
    S = (1 / (m ** 0.5)) * HD[np.random.choice(n, m, replace=True), :]
    # H = hadamard(n)
    # b = np.random.binomial(1, m / n, size=(n,))
    # d = np.random.uniform(0, 1, size=(n,))
    # d = np.where(d > 0.5, 1, -1)
    # S = np.random.permutation(((b * H) * d).T)
    # S = S[np.where(S.any(axis=1))[0], :]

    return S

def sparse_johnson_lindenstrauss_transform(m, n, s):
    """
    m: Sketch size,
    n: Number of rows in the input matrix,
    s: Number of elements in each column to be non-zero.

    returns: An m x n matrix Sparse Johnson Lindenstrauss Transforms
    """

    # Calculate 1/sqrt{s} once
    a = 1 / (s ** 0.5)

    # Initialize s to be an m x n matrix filled with zeros
    S = np.zeros((m, n))

    # For each column, uniformly randomly select s rows that will be non-zero. Uniformly randomly assign it to be +/- 1/sqrt{s}
    sparse_array = np.random.uniform(0, 1, size=(s, n))
    sparse_array = np.where(sparse_array > 0.5, a, -1 * a)
    S[np.random.choice(m, size=(s, n)), np.arange(n)] = sparse_array

    return S


import random
import math
import numpy

def chisquarevariate(k):
	"""Generates a variate from chi square distrubuton with paramater k"""

	s = 0
	for i in range(k):
		s += math.pow(random.normalvariate(0, 1), 2)

	return s

def estimate(k, n):
	"""Estimate expected value and variance over n runs"""
	variates = []
	for i in range(n):
		variates.append(chisquarevariate(k))

	return (numpy.mean(variates), numpy.var(variates))

def conf(L):
	"""Compute a 95 percent confidence interval"""
	lower = numpy.mean(L) - 1.96 * numpy.std(L)/math.sqrt(len(L))
	upper = numpy.mean(L) + 1.96 * numpy.std(L)/math.sqrt(len(L))

	return (lower, upper)

if __name__ == "__main__":
	k = 9
	n = 10000
	m = 50

	random.seed(123)

	for i in range(1, k):

		Lvar = []
		Lmean = []
		for j in range(m):
			res = estimate(i, n)

			Lmean.append(res[0])
			Lvar.append(res[1])

		confMean = conf(Lmean)
		confVar = conf(Lvar)

		print "K = ", i
		print "  > Conf Mean: ", confMean
		print "  > Conf Var: ", confVar
		print "\n"


import numpy as np
import scipy.stats as sps
import matplotlib.pyplot as plt
import seaborn as sns
from marchenko_pastur import *
from embedding import *

def mutual_information(x, y, bins=30):
    c_xy = np.histogram2d(x, y, bins)[0]
    g, p, dof, expected = sps.chi2_contingency(c_xy, lambda_="log-likelihood")
    mi = 0.5 * g / c_xy.sum()
    return mi

def mutual_information_matrix(X,bins=30):
    p,n = X.shape
    mi_matrix = np.zeros((p,p))
    for i in range(p):
        for j in range(p):
            mi_matrix[i,j] = mutual_information(X[i,:],X[j,:],bins=bins)
    return mi_matrix

def plot_mi_matrix(X,ax,bins=30):
    mi_matrix = mutual_information_matrix(X,bins=bins)
    sns.heatmap(mi_matrix,ax=ax,cmap='inferno')
    ax.set_title('Mutual Information Heatmap')

def covariance_matrix(X,transform=True):
    if transform:
        X_ = transform_to_zero_mean_and_unit_std(X)
    else:
        X_ = X.copy()

    C = np.dot(X_,X_.T) / X.shape[1]
    return C

def plot_cov_matrix(X,axis,transform=True):
    C = covariance_matrix(X,transform=transform)
    sns.heatmap(C,ax=axis,cmap='inferno')
    axis.set_title('Covariance Heatmap')

def overview(X,skip=[]):
    fig,ax = plt.subplots(2,2)
    if 'marchenko-pastur' not in skip:
        marchenko_pastur_comparison(X,ax[0,0])
    if 'skree' not in skip:
        _,S = PCA(X)
        skree_plot(S,ax[0,1])
    if 'covariance' not in skip:
        plot_cov_matrix(X,ax[1,0])
    if 'mutual-information' not in skip:
        plot_mi_matrix(X,ax[1,1])
    plt.show()


import numpy as np

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

class Sigmoid:
    def __init__(self):
        self.y = None

    def forward(self, x):
        self.y = 1 / (1 + np.exp(-x))
        return self.y

    def backward(self, delta_output):
        return delta_output * self.y * (1 - self.y)

if __name__ == '__main__':
    sigmoiding = Sigmoid()
    sig_fw = sigmoiding.forward(0)
    print(sig_fw)
    sig_bw = sigmoiding.backward(1)
    print(sig_bw)


# -*- coding: utf-8 -*-
"""
Created on Tue Oct 26 16:46:16 2021

@author: Oliver
"""

# Define the core Trapezoid rule function defining the function, a,b
# and the number of strips N used. T is the integral in [a,b].
import numpy as np
import matplotlib.pyplot as plt

def trapz(f,a,b,N):
    x = np.linspace(a,b,N+1) # N+1 points make N subintervals
    y = f(x)
    y_right = y[1:] # right endpoints
    y_left = y[:1] # left endpoints
    dx = (b-a)/N
    T = (dx/2)* np.sum(y_right + y_left)
    return T

# Define the function to be integrated

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

a = 1
b = 10
n = 2000000
# N =50

print(trapz(f,a,b,n))

# graphing the trapezoidal rule
# defining x and y and plotting the curve
x = np.linspace(-1.5,1.5,100)
y = np.exp(x**2)
plt.plot(x,y)

# these commands fill a defined region of the graph to form a trapezoid area. then it calculates
#the area,A, shown within the trapezoid geometrically. this A is the approximation fo the integral oif
#the function
x0 = 0
x1 = 1
y0 = np.exp(x0**2)
y1 = np.exp(x1**2)
plt.fill_between([x0,x1],[y0,y1])
plt.show()
A = 0.5*(y1+y0)*(x1 - x0)
print("trapezoidal area", A)

Trapexoidal rule numerical integration.py


import math
from src.taxodist import td_calc
from src.taxodist import td_utils as utils
from treelib import Tree
import warnings
from scipy.optimize import linear_sum_assignment

def getJaccardSetSim(concepts_1: set, concepts_2: set):
    """ Returns Jaccard Set Similarity for the given concept sets """

    intersection = len(concepts_1.intersection(concepts_2))
    union = concepts_1.union(concepts_2)
    if union != 0:
        return float(intersection) / union
    else:
        warnings.warn("Union was zero")
        return 0

def getDiceSetSim(concepts_1: set, concepts_2: set):
    """ Returns Dice Set Similarity for the given concept sets """
    intersection = len(concepts_1.intersection(concepts_2))
    return (2*intersection)/(len(concepts_2)+len(concepts_1))

def getCosineSetSim(concepts_1: set, concepts_2: set):
    """ Returns Cosine Set Similarity for the given concept sets """
    intersection = len(concepts_1.intersection(concepts_2))
    return intersection/(math.sqrt(len(concepts_2)*len(concepts_1)))

def getOverlapSetSim(concepts_1: set, concepts_2: set):
    """ Returns Overlap Set Similarity for the given concept sets """
    intersection = len(concepts_1.intersection(concepts_2))
    return intersection/min(len(concepts_1),len(concepts_2))

def getMeanCSSetSim(concepts_1: set, concepts_2: set,tree: Tree, cs_mode:str,ic_mode: str = 'sanchez'):
    ''' Returns Set Similarity based on SS#7 from Jia et al. '''
    sum = 0
    depth = tree.depth()
    for concept_1 in concepts_1:
        for concept_2 in concepts_2:
            sum += utils.getCS(concept_1,concept_2,tree,depth,ic_mode,cs_mode)
    return sum/(len(concepts_1)*len(concepts_2))

def getHierachicalDistSetSim(concepts_1: set, concepts_2: set,tree: Tree, cs_mode:str,ic_mode: str = 'sanchez'):
    """ Returns hierarchical distance for the given concept sets based on https://doi.org/10.1016/j.jbi.2016.07.021"""

    if concepts_1 == concepts_2:
        return 0.0

    difference_1 = concepts_1.difference(concepts_2)
    difference_2 = concepts_2.difference(concepts_1)
    union = concepts_1.union(concepts_2)
    depth = tree.depth()

    first_summand = sum([1 - utils.getCS(concept_difference_1,concept_2,tree,depth,ic_mode,cs_mode) for concept_2 in concepts_2 for concept_difference_1 in difference_1])

    second_summand = sum([1 - utils.getCS(concept_difference_2,concept_1,tree,depth,ic_mode,cs_mode) for concept_1 in concepts_1 for concept_difference_2 in difference_2])

    return ( first_summand/len(difference_2) + second_summand/len(difference_1) )/len(union)

def getMaxWeightedBipartiteMatchingSim(concepts_1, concepts_2, tree, ic_mode, cs_mode):
    ''' Weighted undirected bipartite Graph with weight function CS(a,b).
        Matching = subset of edges with max weights aka highest similarity for the two given concept-sets. \n
        Returns max-sum of the CS-weighted edges. '''

    # get pairwise-similarity matrix for max bipartite matching
    cs_matrix = utils.getCSMatrix(concepts_1, concepts_2, tree, ic_mode, cs_mode)

    # calculate max similarity using hungarian algorithm
    row_ind, col_ind = linear_sum_assignment(cost_matrix=cs_matrix,maximize=True)

    return cs_matrix[row_ind, col_ind].sum()


#Milne's Corrector Predictor Method
import numpy as np

pynp1 = 0 #predictor
yn  = 1.504119
ynm1 =   1.2773913
ynm2 = 1.1168872
ynm3 =1

xnp1 = 0.4
xn  = 0.3
xnm1 =  0.2
xnm2 = 0.1
xnm3 =0

n = 2

h = 0.1
#order = 4 always

def dy(x,y):
    dyvalue = x*y + y**2
    return dyvalue

i = 0
while i<=n:
    #predictor:

    pynp1 = ynm3 + ((4*h)/3)*(2*dy(xnm2,ynm2)-dy(xnm1,ynm1)+2*dy(xn,yn))

    #corrector:

    cynp1 = ynm1 + (h/3)*(dy(xnm1,ynm1)+4*dy(xn,yn)+dy(xnp1,pynp1))

    #print:

    print("____________"+str(i)+"____________")
    print("xn = "+ str(xnp1))
    print("predictor pyn+1 = "+ str(pynp1))
    print("corrector cyn+1 = "+ str(cynp1))
    print("\n")

    #update:
    ynm3 = ynm2
    ynm2 = ynm1
    ynm1 = yn
    yn = cynp1 #not sure about this. for n >1 should we put the corrected value or the predicted for further iterations

    xnp1+=h
    xnm2+=h
    xnm1+=h
    xn+=h

    i+=1


def stiffness(n_elem, E, Iz, L, fixed_dofs):

    #Assemblage of the stiffness matrix for a 1D Euler-Bernoulli beam.
    #Is a uniformly distributed Finite Element discretization of a beam with
    #n_elem elements, length L, Young Modulus E, Flexural Inertia Iz and
    #boundary conditions fixed_dofs.

    import numpy as np

    L = L / n_elem #Unioform discretization, size of each element is total
                   # length divided by number of elements.

    k = np.array([[12 * E * Iz / L ** 3, 6 * E * Iz / L ** 2,\
                  -12 * E * Iz / L ** 3, 6 * E * Iz / L ** 2],
                 [  6 * E * Iz / L ** 2, 4 * E * Iz / L,\
                   -6 * E * Iz / L ** 2, 2 * E * Iz / L],
                 [-12 * E * Iz / L ** 3,-6 * E * Iz / L ** 2,\
                   12 * E * Iz / L ** 3,-6 * E * Iz / L ** 2],
                 [  6 * E * Iz / L ** 2, 2 * E * Iz / L,\
                   -6 * E * Iz / L ** 2 ,4 * E * Iz / L]])

    dof_node = 2 #Number of DOFs per node.

    tot_dofs = n_elem * dof_node + dof_node #Total number of DOFs.

    k_struct = np.zeros([tot_dofs,tot_dofs])

    for i in range(n_elem):
        k_struct[2*i:2*i+4, 2*i:2*i+4] += k #Assembly to structure size.

    for dof in fixed_dofs:
        for i in [0, 1]: #Removal of fixed DOFs.
            k_struct = np.delete(k_struct, dof, axis = i)

    return  k_struct

def random_load_generator(n_elem, fixed_dofs):
    #Generates a random load vector f for a linear FE beam element.

    import random
    import numpy as np

    n_nod = n_elem + 1 #Number of nodes.
    dof_nod = 2 #Number of DOF per node.
    n_dofs = n_nod * dof_nod #Total DOFs.
    free_dofs = n_dofs - np.size(fixed_dofs)
    f = np.zeros(free_dofs)

    for i in range(0, free_dofs, 2):
        if random.choice([True, False]):
            f[i] = random.random()

    return f

def moment_recovery(displ, n_elem, L):

    #Recovers the moment distribution for an Euler-Bernoulli beam of lenght L
    #with a displacement field displ and number of elements n_el.
    #Moments are calculated at elementary mid-points where the approximate
    #solution coincides with the exact one. This are known as super-convergent
    #points.

    import numpy as np

    L = L / n_elem #Length of each element

    B_x = lambda x: np.array([- 6 / L ** 2 + 12 * x / L ** 3, \
                              - 4 / L      +  6 * x / L ** 2, \
                                6 / L ** 2 - 12 * x / L ** 3, \
                              - 2 / L      +  6 * x / L ** 2])

    #B_x is the strain-displacement matrix. Provides the stress distribution
    #along a sigle beam element. Note that the moment fiel is linear.

    stress_elem = np.zeros([n_elem])

    displ = np.concatenate(([0, 0], displ, [0, 0])) #Addition of fixed DOFs.

    for elem in range(n_elem): #Stress calculation.
       stress_elem[elem] = - B_x(L / 2) @ displ[2*elem:2*elem+4]

    return stress_elem


#!/usr/bin/env python
# Adapted from https://github.com/Pyomo/PyomoGallery, see LICENSE.BSD

# Import
from pyomo.environ import *

# Creation of a Concrete Model
model = ConcreteModel()

## Define sets ##
#  Sets
#       i   canning plants   / seattle, san-diego /
#       j   markets          / new-york, chicago, topeka / ;
model.i = Set(initialize=['seattle','san-diego'], doc='Canning plans')
model.j = Set(initialize=['new-york','chicago', 'topeka'], doc='Markets')

## Define parameters ##
#   Parameters
#       a(i)  capacity of plant i in cases
#         /    seattle     350
#              san-diego   600  /
#       b(j)  demand at market j in cases
#         /    new-york    325
#              chicago     300
#              topeka      275  / ;
model.a = Param(model.i, initialize={'seattle':350,'san-diego':600}, doc='Capacity of plant i in cases')
model.b = Param(model.j, initialize={'new-york':325,'chicago':300,'topeka':275}, doc='Demand at market j in cases')
#  Table d(i,j)  distance in thousands of miles
#                    new-york       chicago      topeka
#      seattle          2.5           1.7          1.8
#      san-diego        2.5           1.8          1.4  ;
dtab = {
    ('seattle',  'new-york') : 2.5,
    ('seattle',  'chicago')  : 1.7,
    ('seattle',  'topeka')   : 1.8,
    ('san-diego','new-york') : 2.5,
    ('san-diego','chicago')  : 1.8,
    ('san-diego','topeka')   : 1.4,
}
model.d = Param(model.i, model.j, initialize=dtab, doc='Distance in thousands of miles')
#  Scalar f  freight in dollars per case per thousand miles  /90/ ;
model.f = Param(initialize=90, doc='Freight in dollars per case per thousand miles')
#  Parameter c(i,j)  transport cost in thousands of dollars per case ;
#            c(i,j) = f * d(i,j) / 1000 ;
def c_init(model, i, j):
    return model.f * model.d[i,j] / 1000
model.c = Param(model.i, model.j, initialize=c_init, doc='Transport cost in thousands of dollar per case')

## Define variables ##
#  Variables
#       x(i,j)  shipment quantities in cases
#       z       total transportation costs in thousands of dollars ;
#  Positive Variable x ;
model.x = Var(model.i, model.j, bounds=(0.0,None), doc='Shipment quantities in case')

## Define contrains ##
# supply(i)   observe supply limit at plant i
# supply(i) .. sum (j, x(i,j)) =l= a(i)
def supply_rule(model, i):
    return sum(model.x[i,j] for j in model.j) <= model.a[i]
model.supply = Constraint(model.i, rule=supply_rule, doc='Observe supply limit at plant i')
# demand(j)   satisfy demand at market j ;
# demand(j) .. sum(i, x(i,j)) =g= b(j);
def demand_rule(model, j):
    return sum(model.x[i,j] for i in model.i) >= model.b[j]
model.demand = Constraint(model.j, rule=demand_rule, doc='Satisfy demand at market j')

## Define Objective and solve ##
#  cost        define objective function
#  cost ..        z  =e=  sum((i,j), c(i,j)*x(i,j)) ;
#  Model transport /all/ ;
#  Solve transport using lp minimizing z ;
def objective_rule(model):
    return sum(model.c[i,j]*model.x[i,j] for i in model.i for j in model.j)
model.objective = Objective(rule=objective_rule, sense=minimize, doc='Define objective function')

## Display of the output ##
# Display x.l, x.m ;
def pyomo_postprocess(options=None, instance=None, results=None):
    model.x.display()

# This is an optional code path that allows the script to be run outside of
# pyomo command-line.  For example:  python transport.py
if __name__ == '__main__':
    # This emulates what the pyomo command-line tools does
    from pyomo.opt import SolverFactory
    import pyomo.environ
    opt = SolverFactory("glpk")
    results = opt.solve(model)
    #sends results to stdout
    results.write()
    print("\nDisplaying Solution\n" + '-'*60)
    pyomo_postprocess(None, None, results)


'''Meeus: Astronomical Algorithms (2nd ed.), chapter 15'''

import numpy as np

def rising(dec,lat):
    '''local hour angle for rising (alt=0 deg) - without refraction'''

    #type of output (same as input - number, list, numpy.array)
    out_type='lst'
    if (isinstance(dec,int) or isinstance(dec,float)) and (isinstance(lat,int) or isinstance(lat,float)):
        #all input args are numbers
        out_type='num'

    if isinstance(dec,np.ndarray) or isinstance(lat,np.ndarray):
        #numpy.array
        out_type='np'

    if isinstance(dec,list): dec=np.array(dec)
    if isinstance(lat,list): lat=np.array(lat)

    if out_type=='num': dec=np.array([dec])

    dec=np.deg2rad(dec)
    lat=np.deg2rad(lat)

    ha=np.arccos(-np.tan(lat)*np.tan(dec))

    ha=np.rad2deg(ha)

    if out_type=='num':
        ha=ha[0]
    elif out_type=='lst':
        ha=ha.tolist()
    return ha

def times(dec,ra,lat,lon,sid0):
    '''calculate time of rising, transit and setting; sid0 - sidereal time at Oh UT at Greenwich'''
    #type of output (same as input - number, list, numpy.array)
    out_type='lst'
    if (isinstance(dec,int) or isinstance(dec,float)) and (isinstance(ra,int) or isinstance(ra,float)) and (isinstance(lat,int) or isinstance(lat,float)) and (isinstance(lon,int) or isinstance(lon,float)) and (isinstance(sid0,int) or isinstance(sid0,float)):
        #all input args are numbers
        out_type='num'

    if isinstance(dec,np.ndarray) or isinstance(ra,np.ndarray) or isinstance(lat,np.ndarray) or isinstance(lon,np.ndarray) or isinstance(sid0,np.ndarray):
        #numpy.array
        out_type='np'

    if isinstance(dec,list): dec=np.array(dec)
    if isinstance(ra,list): ra=np.array(ra)
    if isinstance(lat,list): lat=np.array(lat)
    if isinstance(lon,list): lon=np.array(lon)
    if isinstance(sid0,list): sid0=np.array(sid0)

    if out_type=='num': sid0=np.array([sid0])

    dec=np.deg2rad(dec)
    lat=np.deg2rad(lat)

    ha=np.arccos(-np.tan(lat)*np.tan(dec))

    ha=np.rad2deg(ha)

    t=(ra-lon-sid0)/360.  #transit
    r=t-ha/360.           #rise
    s=t+ha/360.           #set

    r*=24
    t*=24
    s*=24

    r=r%24
    t=t%24
    s=s%24

    if out_type=='num':
        r=r[0]
        t=t[0]
        s=s[0]
    elif out_type=='lst':
        r=r.tolist()
        t=t.tolist()
        s=s.tolist()
    return r,t,s


from numpy import zeros
import time
import matplotlib.pyplot as plt

def GS(A):
    # function for determining the  solution using Gauss Siedel Iteration
    x_err=[]  # array to store the error in each iteration
    change=[]
    start=time.time()
    for i in range(n):
        for count in range(i+1,n):
            if abs(A[i][i]) < abs(A[count][i]):  #to make the matrix diagonally dominant
                t=A[i]
                A[i]=A[count]
                A[count]=t
    print(A)
    flag = 0
    while flag<n+1:
        for i in range(n):
            y=x[i]
            x[i]=A[i][n]
            for j in range(n):
                if j!=i:
                    x[i]=x[i]-A[i][j]*x[j]
            x[i]=x[i]/A[i][i]
            err=abs((x[i]-y)/x[i])
            x_err.append(err)
            if abs(err) <= 0.00001:
                flag=flag+1
    plt.figure(dpi=100)
    for q in range(n):
        change=x_err[q::n]
        plt.plot(range(len(change)),change)
    plt.title("error for each variable vs iteration")
    plt.xlabel("iteration number")
    plt.ylabel("error")
    plt.grid()
    plt.show()
    end=time.time()
    runtime=end - start
    print("Calculation time taken is : " + str(runtime))
    return x

tmp=input("Enter 1 for user input matrix, 2 for the Chapter 2 problem 1")
if tmp == '1':
    n = input("Enter the number of equations to solve ")
    n = int(n)
    x = zeros(n)
    A=[]
    for i in range(n):
        r=[]
        for j in range(n+1):
            prompt='Enter the coefficient ' + str(j+1) + ' of equation ' + str(i+1)
            r.append(float(input(prompt)))
        A.append(r)
    print(A)
else:
    n=6
    A=[[10.0, -1.0, 4.0, 0.0, 2.0, 9.0, 19.0], [0.0, 25.0, -2.0, 7.0, 8.0, 4.0, 2.0], [1.0, 0.0, 15.0, 7.0, 3.0, -2.0, 13.0], [6.0, -1.0, 2.0, 23.0, 0.0, 8.0, -7.0], [-4.0, 2.0, 0.0, 5.0, -25.0, 3.0, -9.0], [0.0, 7.0, -1.0, 5.0, 4.0, -22.0, 2.0]]
    x = zeros(n)
    x=GS(A)
    print(x)


import numpy as np

def sph2cart(theta: float, phi: float) -> np.ndarray:
    """
    Get the rotation matrix for transforming spherical coordinates
    to cartesian. Note that the matrix is orthogonal so the inverse transform
    is given by its transpose.
    """
    sin_th = np.sin(theta)
    cos_th = np.cos(theta)
    sin_ph = np.sin(phi)
    cos_ph = np.cos(phi)
    rot_matrix = np.array(
        [
            [sin_th * cos_ph, cos_th * cos_ph, -sin_ph],
            [sin_th * sin_ph, cos_th * sin_ph, cos_ph],
            [cos_th, -sin_th, 0],
        ]
    )
    return rot_matrix

def cart2sph(theta: float, phi: float) -> np.ndarray:
    """
    Get the rotation matrix for transforming cartesian coordinates to
    sphericals given sky angles. This is simply the transpose of the matrix that
    transforms sphericals to cartesian.
    """
    rot_matrix = sph2cart(theta, phi).T
    return rot_matrix


from math import log, sqrt, exp, pi
from scipy.stats import norm

class BlackScholes:
    r = 0.025

    def __init__(self, S0, K, vol, d, T, pcFlag=1, r=None):
        '''
        r is class attribute and set to be 2.5% by default
        '''
        self.S0 = S0
        self.K = K
        self.vol = vol
        self.d = d
        self.T = T
        self.pcFlag = pcFlag
        if r is not None:
            BlackScholes.r = r

    def bsValue(self, vol=None):
        if vol is None:
            self.d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * self.vol ** 2) * self.T) / (
                        self.vol * sqrt(self.T))
            self.d2 = self.d1 - self.vol * sqrt(self.T)
        else:
            self.d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * vol ** 2) * self.T) / (
                        vol * sqrt(self.T))
            self.d2 = self.d1 - vol * sqrt(self.T)

        return self.pcFlag * self.S0 * exp(-self.T * self.d) * norm.cdf(
            self.d1 * self.pcFlag) - self.pcFlag * self.K * exp(-BlackScholes.r * self.T) * norm.cdf(
            self.d2 * self.pcFlag)

    def delta(self, vol=None):
        if vol is not None:
            d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * vol ** 2) * self.T) / (vol * sqrt(self.T))
            return norm.cdf(d1)
        else:
            if not hasattr(self, 'd1'):
                self.d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * self.vol ** 2) * self.T) / (
                            self.vol * sqrt(self.T))
            return self.pcFlag * norm.cdf(self.pcFlag * self.d1) * exp(-self.T * self.d)

    def gamma(self, vol=None):
        if vol is not None:
            d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * vol ** 2) * self.T) / (vol * sqrt(self.T))
            return exp(-self.T * self.d) / (self.S0 * vol * sqrt(self.T)) * 1 / sqrt(2 * pi) * exp(-d1 ** 2 / 2)
        else:
            if not hasattr(self, 'd1'):
                self.d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * self.vol ** 2) * self.T) / (
                            self.vol * sqrt(self.T))
            return exp(-self.T * self.d) / (self.S0 * self.vol * sqrt(self.T)) * 1 / sqrt(2 * pi) * exp(
                -self.d1 ** 2 / 2)

    def vega(self, vol=None):
        if vol is not None:
            d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * vol ** 2) * self.T) / (vol * sqrt(self.T))
            return self.S0 * sqrt(self.T) * norm.pdf(d1) * exp(-self.T * self.d)
        else:
            if not hasattr(self, 'd1'):
                self.d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * self.vol ** 2) * self.T) / (
                            self.vol * sqrt(self.T))
            # return self.K * exp(-BlackSchole.r*self.T)*norm.pdf(self.d2)*sqrt(self.T)
            return self.S0 * sqrt(self.T) * norm.pdf(self.d1) * exp(-self.T * self.d)

    def theta(self, vol=None):
        '''
        Return theta per year
        '''
        if vol is not None:
            d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * vol ** 2) * self.T) / (vol * sqrt(self.T))
            d2 = d1 - vol * sqrt(self.T)
            return -exp(-self.d * self.T) * self.S0 * norm.pdf(d1) * vol / (2 * sqrt(self.T)) - \
                   self.pcFlag * BlackScholes.r * self.K * exp(-BlackScholes.r * self.T) * norm.cdf(self.pcFlag * d2) + \
                   self.pcFlag * self.d * self.S0 * exp(-self.d * self.T) * norm.cdf(self.pcFlag * d1)
        else:
            if not hasattr(self, 'd1'):
                self.d1 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * self.vol ** 2) * self.T) / (
                            self.vol * sqrt(self.T))
            if not hasattr(self, 'd2'):
                self.d2 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * self.vol ** 2) * self.T) / (
                            self.vol * sqrt(self.T)) - self.vol * sqrt(self.T)
            return -exp(-self.d * self.T) * self.S0 * norm.pdf(self.d1) * self.vol / (2 * sqrt(self.T)) - \
                   self.pcFlag * BlackScholes.r * self.K * exp(-BlackScholes.r * self.T) * norm.cdf(
                self.pcFlag * self.d2) + \
                   self.pcFlag * self.d * self.S0 * exp(-self.d * self.T) * norm.cdf(self.pcFlag * self.d1)

    def rho(self, vol=None):
        if vol is not None:
            d2 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * vol ** 2) * self.T) / (
                        vol * sqrt(self.T)) - vol * sqrt(self.T)
            return self.K * self.T * exp(-BlackScholes.r * self.T) * norm.cdf(d2)
        else:
            if not hasattr(self, 'd2'):
                self.d2 = (log(self.S0 / self.K) + (BlackScholes.r - self.d + 0.5 * self.vol ** 2) * self.T) / (
                            self.vol * sqrt(self.T)) - self.vol * sqrt(self.T)
            return self.pcFlag * self.K * self.T * exp(-BlackScholes.r * self.T) * norm.cdf(self.pcFlag * self.d2)

    def greeks(self, vol=None):
        result = {}
        result['delta'] = self.delta(vol)
        result['gamma'] = self.gamma(vol)
        result['vega'] = self.vega(vol)
        result['rho'] = self.rho(vol)
        result['theta'] = self.theta(vol)
        return result

S0 = 100
K = 85
B = 120
vol = 1
T = 1
r = 0.02
d = 0.01
# (S0, K, T, vol, r, d) = (10, 10, 1, 0.3, 0., 0.2)
option = BlackScholes(S0, K, vol, d, T, -1, r)
print('BSprice:', option.bsValue())

print('delta:', option.delta())
print('gamma:', option.gamma())
print('vega:', option.vega())
print('theta:', option.theta())
print('rho:', option.rho())
print(option.greeks())


import numpy as np
import pandas as pd
from pandas import DataFrame
from typing import Tuple
from plotnine import *
import math

def load_data(path: str) -> np.array:
    """
    Loads the data into a matrix (np array).
    :param path: The path to the csv of the data.
    :return: Data design matrix.
    """
    try:
        data = pd.read_csv(path)
    except FileNotFoundError:
        print("FAILED TO FIND THE DATA LOCATION!")
        return
    except Exception:
        print("AN ERROR OCCURRED WHILE LOADING THE DATA!")
        return
    return data

def fit_linear_regression(mat_x: np.array, res_vec: np.array) -> Tuple[np.array, np.array]:
    """
    Linear Regression solver
    Parameters:
    :param mat_x: The design matrix X (np array)
    :param res_vec: Response Vector y (np array)
    Returns: Tuple of the coefficient vector and the singular values of X.
    """
    ones_vec = np.ones(mat_x.shape[0])  # vectors of ones
    mat_x = np.vstack((ones_vec, mat_x))  # adding ones to the matrix
    mat_x_t = mat_x.transpose()  # transposing after adding one
    return np.linalg.pinv(mat_x_t) @ res_vec, np.linalg.svd(mat_x_t, compute_uv=False)

def predict(x: np.array, coef_v: np.array) -> np.array:
    """
    Prediction function
    :param x: Design matrix.
    :param coef_v: Coefficient vector.
    :return: The prediction of the result vector.
    """
    return np.dot(x.transpose(), coef_v)

def plot_log_detected(day_num, log_detected, prediction):
    """
    plot for the detection values Q21
    :param day_num: number of days
    :param log_detected: detected patients so far
    :param prediction: the prediction of the detected patients.
    :return: a plot.
    """
    df = DataFrame({'x': day_num,
                    'b': log_detected.to_numpy().reshape((1, len(log_detected)))[0],
                    'c': list(prediction.reshape((1, len(prediction)))[0])
                    })
    return ggplot(aes(x='x', y='b'), data=df) + geom_point(size=1) +\
           geom_line(aes(y='b'), color='black') + \
           geom_line(aes(y='c'), color='blue') +  \
           ggtitle("Log of covid19 sick people detected vs days") + \
           labs(y="Detected sick people", x="Day number")

def plot_detected(day_num, detected, prediction):
    """
    plot for the detection values Q21
    :param day_num: number of days
    :param detected: detected patients so far
    :param prediction: the prediction of the detected patients.
    :return: a plot.
    """
    df = DataFrame({'x': day_num,
                    'y': detected,
                    'c': list(map(lambda x: math.e**x, prediction.reshape((1, len(prediction)))[0]))
                    })
    return ggplot(df, aes(x='x', y='y')) + geom_point(size=1) + geom_line() + \
           geom_line(aes(y='c'), color='blue') + \
           ggtitle("covid19 sick people detected vs days") + \
           labs(y="Detected sick people", x="Day number") + scale_x_continuous()

if __name__ == "__main__":
    PATH_TO_CSV = "covid19_israel.csv"
    data = load_data(PATH_TO_CSV)
    detected = data['detected'].to_numpy()
    log_detected = DataFrame({'log_detected': [math.log(x, math.e) for x in data['detected']]})
    day_num = data['day_num'].to_numpy()
    w, singulars = fit_linear_regression(day_num.transpose(), log_detected)
    ones_vec = np.ones(day_num.shape[0])  # vectors of ones
    new_day_num = np.vstack((ones_vec, day_num))  # adding ones to the matrix
    prediction = predict(new_day_num, w)
    print(plot_log_detected(day_num, log_detected, prediction))
    print(plot_detected(day_num, detected, prediction))


import numpy as np
import matplotlib.pyplot as plt

#%matplotlib notebook

def circle_bound(x):
    y = np.sqrt(1 - x**2)
    #print(y)
    return y

def lets_make_pi(tot_points):
    circ_points = 0

    for i in range(tot_points):

        point_x = np.random.uniform(0,1)
        point_y = np.random.uniform(0,1)

        if circle_bound(point_x) >= point_y:
            circ_points = circ_points + 1
            plt.scatter(point_x, point_y,c="r")
        else:
            plt.scatter(point_x, point_y,c="b")

    pi = 4 * circ_points/tot_points
    #plt.axis("square")
    plt.title(f"Approximating Pi, Monte Carlo Approx. pi $\sim$ {pi}" )
    plt.xlabel('X coordinate')
    plt.ylabel('Y coordinate')
    plt.show()
    return pi


# -*- coding: utf-8 -*-
"""
Metodo dei Simpson
"""
import numpy as np

def simpson_composita(func, a, b, n):
    h = (b-a)/(2*n) # ! focus here
    nodi = np.arange(a, b+h, h)
    f = func(nodi)
    return (f[0] + 2*np.sum(f[2:2*n:2]) + 4*np.sum(f[1:2*n:2]) + f[n])*h/3 # ! focus here

def simp_toll(func, a, b, tol):
    N = 1
    err = 1
    IN = simpson_composita(func, a, b, N)
    nmax = 2048
    while N < nmax and err > tol:
        N = 2*N
        I2N = simpson_composita(func, a, b, N)
        err = abs(IN - I2N)/15 # ! focus here
        IN = I2N
    return IN, N


#interpolation -predicting missing points using a polynomial fit baised on points you are given.
# three types barycentric interpolate, least squares fit (polyFit) and cubic spline (interp1d).

-----------------------------------------------------------------------------------------------
#barycentric interpolate (example assesment 1 Q3 part a)
from scipy import interpolate
from scipy.interpolate import barycentric_interpolate as bi
#when you are given an array of x and corresponding y values you can use them to estimate a value y value at a value of x you have not been given (let the unknown x be called xu and its corresponding y value be called yu) using

yu=bi(X, Y, xu) #where X is an array of know x values and Y an array of known Y values

#Barycentric interpolate gives a polynomial of n-1 where n is the number of data points

-------------------------------------------------------------------------------------------------
#polyFit (least squares fit) (example assesment 1 Q3 part c)
#creates a least squares polynomial fit
from polyFit import * #where polyFit is a file on study direct

c = polyFit(xData,yData,m).
    Returns coefficients of the polynomial

P=polyFit(x,y,xu) #uses least squares fit to create a polynomial P
yu=P[0]+P[1]*(xu)+P[2]*(xu)**2  #can use coefficients of the polynomial to find yu using P[n]*xu**n

#gives a polynomial of degree n as you specify when using P[n]*xu**n

------------------------------------------------------------------------------------------------------------------
#cubic spline (interp1d) (example assesment 1 Q3 part b)

from scipy import interpolate

f=interpolate.interp1d(x,y, kind='cubic') #creates a cubic function that fits the graph can use kind= linear, quadratic ect or 1 2,3 for polynomial order

yu=f(xu) #uses interpolation function returned by interp1d to find yu at a point xu
print yu


import math as m
import numpy as np

from src.continuous.normal import NormalDist
from src.prob_distribution import ProbDist
from src.spaces.spaces1d_leafs import ContinuousSpace

class LogNormalDist(ProbDist):
    """Simple log-normal distribution."""

    def __init__(self, mean=0, var=1):
        """Create LogN(mean, var) distribution.

        :param mean Center of the gaussian
        :param var Variance around the center.
        """
        self.mean = mean
        self.var = var

        # create random generators
        self.NG = NormalDist(mean, var)
        super().__init__(ContinuousSpace(0, np.inf))

    def expectation(self):
        """Calculates the expectations for that distribution.

        :returns The expectation of the distribution"""

        return m.exp(self.mean + self.var / 2)

    def var(self):
        """Calculates the variance for that distribution.

        :returns The variance of the distribution"""

        return m.exp(2 * self.mean + self.var) * (m.exp(self.var) - 1)

    def sample(self, num_samples=1):
        """Generate random numbers from LogN(mean, var).

        :param num_samples How many random numbers should be generated.
        :returns Random numbers from LogN(mean, var).
        """

        # generate some samples
        Y = self.NG.sample(num_samples)
        return np.exp(Y)

    def c_pdf(self, x):
        """This method calculates the density LogN(x|mean, var).

        :param x What values should be evaluated.
        :returns The probability this element occurs.
        """

        var = self.var
        mean = self.mean
        return 1 / (np.multiply(x, np.sqrt(2 * var * np.pi))) \
               * np.exp(-0.5 * (np.subtract(np.log(x), mean) ** 2) / var)


import numpy as np

A=np.array([[4,6,10],[6,25,19],[10,19,62]]) # Matrix A

C=np.linalg.inv(A)  # Έτοιμη λύση της numpy

print('A^{-1} = ',C)

def Inverse(A) :   # Μέθοδος που ζητάει η Άσκηση

    n=len(A)
    B=np.zeros((n,n))

    for i in range(0,n) :
        e=np.zeros(n)
        e[i]=1
        x=np.linalg.solve(A,e)
        B[:,i] = x

    return B

B=Inverse(A)
print('B=',B)

print(abs(B-C)) # Διαφορά έτοιμης λύσης με την μέθοδο


import numpy as np

def shannon_entropy(p):
    """Calculates shannon entropy in bits.

    Parameters
    ----------
    p : np.array
        array of probabilities

    Returns
    -------
    shannon entropy in bits
    """
    return -np.sum(p * np.log2(p))

def max_shannon_entropy(n):
    """Returns max possible entropy given "n" mutations.

    The maximum possible entropy is the entropy of the
    uniform distribution. The uniform distribution has
    entropy equal to log(n) (I will use base 2).

    Parameters
    ----------
    n : int
        total mutation counts

    Returns
    -------
    max possible shannon entropy in bits
    """
    if n <= 0:
        return 0.
    return float(np.log2(n))

def kl_divergence(p, q):
    """Compute the Kullback-Leibler (KL) divergence for discrete distributions.

    Parameters
    ----------
    p : np.array
        "Ideal"/"true" Probability distribution
    q : np.array
        Approximation of probability distribution p

    Returns
    -------
    kl : float
        KL divergence of approximating p with the distribution q
    """
    # make sure numpy arrays are floats
    p = p.astype(float)
    q = q.astype(float)

    # compute kl divergence
    kl = np.sum(np.where(p!=0, p*np.log2(p/q), 0))
    return kl

def js_divergence(p, q):
    """Compute the Jensen-Shannon Divergence between two discrete distributions.

    Parameters
    ----------
    p : np.array
        probability mass array (sums to 1)
    q : np.array
        probability mass array (sums to 1)

    Returns
    -------
    js_div : float
        js divergence between the two distrubtions
    """
    m = .5 * (p+q)
    js_div = .5*kl_divergence(p, m) + .5*kl_divergence(q, m)
    return js_div

def js_distance(p, q):
    """Compute the Jensen-Shannon distance between two discrete distributions.

    NOTE: JS divergence is not a metric but the sqrt of JS divergence is a
    metric and is called the JS distance.

    Parameters
    ----------
    p : np.array
        probability mass array (sums to 1)
    q : np.array
        probability mass array (sums to 1)

    Returns
    -------
    js_dist : float
        Jensen-Shannon distance between two discrete distributions
    """
    js_dist = np.sqrt(js_divergence(p, q))
    return js_dist


import numpy as np
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')

from generate import generate_gaussian

np.random.seed(0)

# SAMPLING

# modifiable parameters
N1, N2 = 1000, 1000
sigma1, sigma2 = 1, np.sqrt(2)
mean1, mean2 = [1,2], [0,0]

cov1 = sigma1**2*np.identity(2)
cov2 = sigma2**2*np.identity(2)

# gaussian
A_train = generate_gaussian(mean1, cov1, N1)
B_train = generate_gaussian(mean2, cov2, N2)

'''
# uniform
A_train = []
while len(A_train) < N1:
	x, y = 2*np.random.rand(2) - 1
	if x**2 + y**2 < 1:
		point = 2*np.sqrt(2)*sigma1*np.array([x,y]) + mean1
		A_train.append(point)
B_train = []
while len(B_train) < N2:
	x, y = 2*np.random.rand(2) - 1
	if x**2 + y**2 < 1:
		point = 2*np.sqrt(2)*sigma2*np.array([x,y]) + mean2
		B_train.append(point)

A_train, B_train = np.array(A_train), np.array(B_train)
'''

train = np.concatenate((A_train, B_train))
train_label = np.append([1]*N1, [-1]*N2)

# gaussian
A_test = generate_gaussian(mean1, cov1, 2*N1)
B_test = generate_gaussian(mean2, cov2, 2*N2)

'''
# uniform
A_test = []
while len(A_test) < 3*N1:
	x, y = 2*np.random.rand(2) - 1
	if x**2 + y**2 < 1:
		point = np.sqrt(2)*sigma1*np.array([x,y]) + mean1
		A_test.append(point)
B_test = []
while len(B_test) < 3*N2:
	x, y = 2*np.random.rand(2) - 1
	if x**2 + y**2 < 1:
		point = np.sqrt(2)*sigma2*np.array([x,y]) + mean2
		B_test.append(point)

A_test, B_test = np.array(A_test), np.array(B_test)
'''

test = np.concatenate((A_test, B_test))
test_label = np.append([1]*3*N1, [-1]*3*N2)

##########

# LEARNING

# modifiable parameters
lr0 = .2 # initial learning rate
max_epoch = 15
w = 0.2*np.random.rand(3)

def accuracy(w, data, label):
	correct = sum([1 for x, y in zip(data, label) if y*w.dot(x) >= 0])
	return correct/len(data)

def unison_shuffles(a, b):
	p = np.random.permutation(len(a))
	return a[p], b[p]

data = np.array([np.append(x,1) for x in train])

accuracy_log = [[accuracy(w, data, train_label)]*2]
a = np.array(w)

print('learning, please wait...')

for epoch in range(max_epoch):

	lr = lr0/(epoch + 1)
	epoch_data, label = unison_shuffles(data, train_label)
	iteration = 0
	for x, y in zip(epoch_data, label):
		iteration += 1
		print(f'Epoch {epoch+1}, iteration {iteration}', end='\r')
		if y*w.dot(x) < 0:
			w += lr*y*x # learning rule
			a += w

	accuracy_log.append([accuracy(w, epoch_data, label),
		accuracy(a, epoch_data, label)])

accuracy_log = np.array(accuracy_log)

# PLOT

delta = 0.025
rangex = np.arange(-6, 7.5, delta)
rangey = np.arange(-4, 8, delta)
X, Y = np.meshgrid(rangex,rangey)

test_data = np.array([np.append(x,1) for x in test])

plt.figure(figsize = (14, 14))

plt.suptitle(f'(cd) Gaussian distributions with $\sigma_1$ = {sigma1}, $\sigma_2$ = sqrt(2), $N_1$ = {N1}, $N_2$ = {N2}',
	size = 'xx-large')

plt.subplot(221) # decision boundary of Bayes classifier

# F = 0 is implicit function
F = (X - 2)**2 + (Y - 4)**2 - 4*np.log(2) - 10

plt.title('Bayes classifier decision boundary')
plt.contour(X, Y, F, [0], colors = 'black')
plt.scatter(A_test[:,0], A_test[:,1], alpha=.5,
	s=15, label = 'Class A')
plt.scatter(B_test[:,0], B_test[:,1], alpha=.5,
	s=15, label = 'Class B')
plt.legend(loc = 'lower left')

plt.subplot(222) # decision boundary of perceptron

# F = 0 is implicit function
F = a[0]*X + a[1]*Y + a[2]

accu = accuracy(a, test_data, test_label)
plt.title('Perceptron decision boundary ({:.3f})'.format(accu))
plt.contour(X, Y, F, [0.], colors = 'black')
plt.scatter(A_test[:,0], A_test[:,1], alpha=.5,
	s=15, label = 'Class A')
plt.scatter(B_test[:,0], B_test[:,1], alpha=.5,
	s=15, label = 'Class B')
plt.legend(loc = 'lower left')

plt.subplot(224)

plt.title('Learning curve')
plt.xlabel('Epoch')
plt.ylabel('Train set accuracy')
plt.plot(range(max_epoch+1), accuracy_log[:,0],
	label = 'Learning perceptron')
plt.plot(range(max_epoch+1), accuracy_log[:,1],
	label = 'Average perceptron')
plt.legend(loc = 'lower left')

plt.savefig('gaussian.jpg')


import numpy as np
import matplotlib.pyplot as plt
from numpy.polynomial import Polynomial as Poly

def interpolate_polynomial(points, degree, min_x, max_x, title=None, add_func=None):
    """
    Interpolates a polynomial of the specified degree through the given points and plots it
    points - a list of points (x, y) to plot
    degree - the polynomial degree
    min_x, max_x - range of x values used to plot the interpolating polynomial
    """
    pts = np.array(points)
    x = pts[:, 0]
    y = pts[:, 1]
    p = Poly.fit(x, y, degree)
    p = p.convert(domain=[min_x, max_x])
    p_plot = p.linspace(1000)
    plt.plot(p_plot[0], p_plot[1], c="green")

    if add_func:
        v_y = np.vectorize(add_func)
        x2 = np.linspace(min_x, max_x, 1000)
        y2 = v_y(x2)
        plt.plot(x2, y2, c="blue")

    if title:
        plt.title(title)
    else:
        plt.title(f'Polynomial of degree {degree}')
    plt.xlabel("x")
    plt.ylabel("y")
    plt.scatter(x, y)
    plt.show()

points = np.array([(0, 0), (1, 0.8), (2, 0.9), (3, 0.1), (4, -0.8), (5, -1.0)])
interpolate_polynomial(points, len(points) - 1, -1, 6, add_func=lambda x: 1/(1+x**2))


import math as m
import numpy as np

from src.continuous.gamma import GammaDist
from src.prob_distribution import ProbDist
from src.spaces.spaces1d_leafs import ContinuousSpace

class BetaDist(ProbDist):
    """Simple beta distribution."""

    def __init__(self, a = 1, b = 1):
        """Create Beta(a,b) distribution.

        :param a First shape parameter of beta
        :param b Second shape parameter of beta
        """

        assert a > 0 and b > 0

        # save params
        self.a = a
        self.b = b

        # create two distributions when one wants to sample
        self.GaG = GammaDist(self.a, 1)
        self.GbG = GammaDist(self.b, 1)

        # define the space of the distribution
        super().__init__(ContinuousSpace(0, 1))

    def expectation(self):
        """Calculates the expectations for that distribution.

        :returns The expectation of the distribution"""

        return self.a / (self.a + self.b)

    def moment(self, k):
        """Calculates the k-th moment for that distribution.

        :param k which moment to calc
        :returns The k-th moment of the distribution"""

        a = self.a
        b = self.b
        t = m.gamma(a + b) * m.gamma(a + k) / (m.gamma(a + k + b) * m.gamma(a))
        return t

    def var(self):
        """Calculates the variance for that distribution.

        :returns The variance of the distribution"""

        a = self.a
        b = self.b
        return (a*b) / ((a + b) ** 2 * (a + b + 1))

    def c_pdf(self, x):
        """This method calculates the density Beta(x|a,b).

        :param x Which value should be evaluated.
        :returns The probability this element occurs.
        """

        assert np.all([np.logical_and(np.greater_equal(x, 0), np.greater_equal(1, x))])

        a = self.a
        b = self.b
        bab = m.gamma(a + b) / (m.gamma(a) * m.gamma(b))
        xa = np.power(x, (a - 1))
        xb = np.power(1 - x, (b - 1))
        return bab * xa * xb

    def sample(self, num_samples = 1):
        """Generate random numbers from Beta(a,b) by using acceptance rejection distributions.

        :param num_samples How many random numbers should be generated.
        :returns Random numbers x ~ Beta(a,b).
        """

        # create gamma distributed vars
        y1 = self.GaG.sample(num_samples)
        y2 = self.GaG.sample(num_samples)

        # transform
        return y1 / (y1 + y2)


import numpy as np
import cv2
from matplotlib import pyplot as plt

def euclidean_trans(theta, tx, ty):
    return np.array([
        [np.cos(theta), -np.sin(theta), tx],
        [np.sin(theta), np.cos(theta), ty],
        [0, 0, 1]
    ])

filename = '../Materials/fig1_6c.jpg'
img = cv2.imread(filename)

plt.imshow(img, cmap='gray')
pts = np.asarray(plt.ginput(4, timeout=-1))
plt.show()

print('chosen coord: ', pts)  # each row is a point

plt.plot(*zip(*pts), marker='o', color='r', ls='')
plt.imshow(img)
plt.show()

points = np.array([
    [1053.01298701,  460.10606061],
    [1364.7012987,   641.92424242],
    [1057.34199134,  867.03246753],
    [ 745.65367965,  641.92424242]
])

'''
Affine rectification
'''
print('\n-------- Task 1: Affine rectification --------')
pts_homo = np.concatenate((points, np.ones((4, 1))), axis=1)  # convert chosen pts to homogeneous coordinate
print('Task 1.1: Identify image of the line at inf on projective plane')
hor_0 = np.cross(pts_homo[0],pts_homo[1])
hor_1 = np.cross(pts_homo[2],pts_homo[3])
pt_ideal_0 = np.cross(hor_0, hor_1)
pt_ideal_0 /= pt_ideal_0[-1]  # normalize
print('@Task 1.1: first ideal point: ', pt_ideal_0)

ver_0 = np.cross(pts_homo[0],pts_homo[3])
ver_1 = np.cross(pts_homo[1],pts_homo[2])
pt_ideal_1 = np.cross(ver_0, ver_1)
pt_ideal_1 /= pt_ideal_1[-1]
print('@Task 1.1: second ideal point: ', pt_ideal_1)

l_inf = np.cross(pt_ideal_0,pt_ideal_1)
l_inf /= l_inf[-1]
print('@Task 1.1: line at infinity: ', l_inf)

print('Task 1.2: Construct the projectivity that affinely rectify image')
H = np.array([[1,0,0],[0,1,0],[l_inf[0],l_inf[1],l_inf[2]]])
print('@Task 1.2: image of line at inf on affinely rectified image: ', (np.linalg.inv(H).T @ l_inf.reshape(-1, 1)).squeeze())

H_E = euclidean_trans(np.deg2rad(0), 50, 250)

affine_img = cv2.warpPerspective(img, H_E @ H, (img.shape[1], img.shape[0]))

affine_pts = np.transpose((H_E @ H).dot(np.transpose(pts_homo)))
for i in range(affine_pts.shape[0]):
    affine_pts[i] /= affine_pts[i, -1]
    print('\t',affine_pts[i])

plt.plot(*zip(*affine_pts[:, :-1]), marker='o', color='r', ls='')
plt.imshow(affine_img)
plt.show()
print('-------- End of Task 1 --------\n')

'''
#Task 2: Metric rectification
'''

print('\n-------- Task 2: Metric rectification --------')
print('Task 2.1: transform 4 chosen points from projective image to affine image')
aff_hor_0 = np.cross(affine_pts[0],affine_pts[1])
aff_hor_1 = np.cross(affine_pts[2],affine_pts[3])

aff_ver_0 = np.cross(affine_pts[0],affine_pts[3])
aff_ver_1 = np.cross(affine_pts[1],affine_pts[2])

aff_hor_0 /= aff_hor_0[-1]
aff_hor_1 /= aff_hor_1[-1]
aff_ver_0 /= aff_ver_0[-1]
aff_ver_1 /= aff_ver_1[-1]
# Make new orthogonal constraint between the diagonals
aff_diag_0 = np.cross(affine_pts[0],affine_pts[2])
aff_diag_1 = np.cross(affine_pts[1],affine_pts[3])
print('@Task 2.1: first chosen point coordinate')
print('\t\t on projective image: ', pts_homo[0])
print('\t\t on affine image: ', affine_pts[0])

print('Task 2.2: construct constraint matrix C to find vector s')
C0 = np.array([aff_hor_0[0]*aff_ver_0[0],aff_hor_0[0]*aff_ver_0[1] + aff_hor_0[1]*aff_ver_0[0],aff_hor_0[1]*aff_ver_0[1]])

#C1 = np.array([aff_hor_1[0]*aff_ver_1[0],aff_hor_1[0]*aff_ver_1[1] + aff_hor_1[1]*aff_ver_1[0],aff_hor_1[1]*aff_ver_1[1]])
C1 = np.array([aff_diag_0[0]*aff_diag_1[0],aff_diag_0[0]*aff_diag_1[1] + aff_diag_0[1]*aff_diag_1[0],aff_diag_0[1]*aff_diag_1[1]])

C = np.vstack([C0, C1])
print('@Task 2.2: constraint matrix C:\n', C)

print('Task 2.3: Find s by looking for the kernel of C (hint: SVD)')
[usvd, ssvd, svdvh]= np.linalg.svd(C)
s = np.transpose(svdvh)[:, -1]
print('@Task 2.3: s = ', s)
print('@Task 2.3: C @ s = \n', C @ s.reshape(-1, 1))
mat_S = np.array([
    [s[0], s[1]],
    [s[1], s[2]],
])
print('@Task 2.3: matrix S:\n', mat_S)

print('Task 2.4: Find the projectivity that do metric rectificaiton')
E, Q = np.linalg.eig(mat_S)
K = Q.dot(np.sqrt(np.diag(E)))
K_inv = np.linalg.inv(K)
H = np.array([[K_inv[0][0],K_inv[0][1],0],[K_inv[1][0],K_inv[1][1],0],[0,0,1]])

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

print('@Task 2.3: image of dual conic on metric rectified image: ', H @ aff_dual_conic @ H.T)

H_E = euclidean_trans(np.deg2rad(0), -250, -900) @ euclidean_trans(np.deg2rad(-20),0,0)
H_fin = H_E @ H
eucl_img = cv2.warpPerspective(affine_img, H_fin, (img.shape[1], img.shape[0]))

eucl_pts = (H_fin @ affine_pts.T).T
for i in range(eucl_pts.shape[0]):
    eucl_pts[i] /= eucl_pts[i, -1]

plt.plot(*zip(*eucl_pts[:, :-1]), marker='o', color='r', ls='')
plt.imshow(eucl_img)
plt.show()


from scipy.special import comb

def calculate_probability(k: int, m: int, n: int) -> float:
    """
    Calculates the probability that two randomly selected mating organisms will produce an individual
    possessing a dominant allele (and thus displaying the dominant phenotype). Assume that any two
    organisms can mate.

    :param k: number of homozygous dominant organisms
    :param m: number of homozygous recessive organisms
    :param n: number of heterozygous organisms
    :return: The probability that two randomly selected mating organisms will produce an individual
    possessing a dominant allele (and thus displaying the dominant phenotype). Assume that any two
    organisms can mate.
    """
    # Calculate total number of organisms in the population:
    total_population = k + m + n

    # Calculate the number of combos that could be made (valid or not):
    total_combinations = comb(total_population, 2)

    # Calculate the number of combinations that have a dominant allele therefore are valid.
    valid_combinations = (comb(k, 2)) + (k * m) + (k * n) + (.5 * m * n) + (.75 * comb(m, 2))

    # An event is simply a collection of outcomes. Because outcomes are distinct, the probability of
    # an event can be written as the sum of the probabilities of its constituent outcomes.
    probability = valid_combinations / total_combinations

    return probability


## 2. Drawing lines ##

import matplotlib.pyplot as plt
import numpy as np

x = [0, 1, 2, 3, 4, 5]
# Going by our formula, every y value at a position is the same as the x-value in the same position.
# We could write y = x, but let's write them all out to make this more clear.
y = [0, 1, 2, 3, 4, 5]

# As you can see, this is a straight line that passes through the points (0,0), (1,1), (2,2), and so on.
plt.plot(x, y)
plt.show()

# Let's try a slightly more ambitious line.
# What if we did y = x + 1?
# We'll make x an array now, so we can add 1 to every element more easily.
x = np.asarray([0, 1, 2, 3, 4, 5])
y = x + 1

# y is the same as x, but every element has 1 added to it.
print(y)

# This plot passes through (0,1), (1,2), and so on.
# It's the same line as before, but shifted up 1 on the y-axis.
plt.plot(x, y)
plt.show()

# By adding 1 to the line, we moved what's called the y-intercept -- where the line intersects with the y-axis.
# Moving the intercept can shift the whole line up (or down when we subtract).
plt.plot(x,x-1)
plt.show()
plt.plot(x,x+10)
plt.show()

## 3. Working with slope ##

import matplotlib.pyplot as plt
import numpy as np

x = np.asarray([0, 1, 2, 3, 4, 5])
# Let's set the slope of the line to 2.
y = 2 * x

# See how this line is "steeper" than before?  The larger the slope is, the steeper the line becomes.
# On the flipside, fractional slopes will create a "shallower" line.
# Negative slopes will create a line where y values decrease as x values increase.
plt.plot(x, y)
plt.show()
plt.plot(x,4*x)
plt.show()
plt.plot(x,0.5*x)
plt.show()
plt.plot(x, (-2*x))
plt.show()

## 4. Starting out with linear regression ##

# The wine quality data is loaded into wine_quality
from numpy import cov
slope_density = cov(wine_quality['density'],wine_quality['quality'])

## 5. Finishing linear regression ##

from numpy import cov

# This function will take in two columns of data, and return the slope of the linear regression line.
def calc_slope(x, y):
  return cov(x, y)[0, 1] / x.var()

intercept_density = wine_quality["quality"].mean() - (calc_slope(wine_quality["density"], wine_quality["quality"]) * wine_quality["density"].mean())

## 6. Making predictions ##

from numpy import cov

def calc_slope(x, y):
  return cov(x, y)[0, 1] / x.var()

# Calculate the intercept given the x column, y column, and the slope
def calc_intercept(x, y, slope):
  return y.mean() - (slope * x.mean())

def predicted(x):
    return x * slope + intercept

slope = calc_slope(wine_quality["density"], wine_quality["quality"])
intercept = calc_intercept(wine_quality["density"], wine_quality["quality"], slope)

predicted_quality = wine_quality["density"].apply(predicted)

## 7. Finding error ##

from scipy.stats import linregress

# We've seen the r_value before -- we'll get to what p_value and stderr_slope are soon -- for now, don't worry about them.
slope, intercept, r_value, p_value, stderr_slope = linregress(wine_quality["density"], wine_quality["quality"])

# As you can see, these are the same values we calculated (except for slight rounding differences)
print(slope)
print(intercept)

def pred(x):
    return x*slope + intercept

pred_d = wine_quality['density'].apply(pred)
rss = 0
for i in range(len(pred_d)):
    rss += (wine_quality['quality'][i] - pred_d[i])**2

## 8. Standard error ##

from scipy.stats import linregress
import numpy as np

# We can do our linear regression
# Sadly, the stderr_slope isn't the standard error, but it is the standard error of the slope fitting only
# We'll need to calculate the standard error of the equation ourselves
slope, intercept, r_value, p_value, stderr_slope = linregress(wine_quality["density"], wine_quality["quality"])

predicted_y = np.asarray([slope * x + intercept for x in wine_quality["density"]])
residuals = (wine_quality["quality"] - predicted_y) ** 2
rss = sum(residuals)
stderr = (rss / (len(wine_quality["quality"]) - 2)) ** .5

def within_percentage(y, predicted_y, stderr, error_count):
  within = stderr * error_count

  differences = abs(predicted_y - y)
  lower_differences = [d for d in differences if d <= within]

  within_count = len(lower_differences)
  return within_count / len(y)

within_one = within_percentage(wine_quality["quality"], predicted_y, stderr, 1)
within_two = within_percentage(wine_quality["quality"], predicted_y, stderr, 2)
within_three = within_percentage(wine_quality["quality"], predicted_y, stderr, 3)

Probability Statistics Beginner/Linear regression-15.py


# -*- coding: utf-8 -*-
"""
Created on Wed Sep 18 10:09:32 2019

@author: hamil
"""

import numpy as np
import matplotlib.pyplot as plt
import scipy
from scipy import integrate

#Create function to take the integral of / area under the curve
x_values = np.arange(0,10,0.01)
y_values = x_values**2

#Define function that will use definition of the sum of the rectangle areas underneath curve
def integral_funct(h, initial, final):
    #determine the rectangle and area using left side y-value of rectangle
    area_array = []
    y_values = []
    x_values = np.arange(initial,final,0.01)
    for numm in x_values:
        new_value = numm**2
        y_values.append(new_value)
    y_values = y_values[:-1]
    total_sum = np.sum(area_array)
    for each_num in y_values:
        area = h*each_num
        area_array.append(area)
    total_sum = np.sum(area_array)
    return area_array, total_sum

#Test the integral function for x**2 from x=1 to x=10

test1 = integral_funct(0.01,0,10)
test1_area = test1[0]
#print("This is the individual area array:",test1_area)
test1_sum = test1[1]
print("Total area calculated by my function:",test1_sum)

#This is not as close in value as I thought it would be. Analytically, the value
#for the example test is about 333.33.

#Now compare to the trapz function
test_trapz = np.trapz(y_values,x_values, dx=0.01)
print("Total integral calculated by the Numpy's Trapz funct:",test_trapz)

#This is a better comparison to my function versus the analytical value. The value
#provided by the trapz is in between the two other values.

#Now use different functions from scipy to compute the integral
attempt1 = scipy.integrate.trapz(y_values,x_values, dx=0.01)
attempt2 = scipy.integrate.simps(y_values,x_values, dx=0.01)
def x_squared(x):
    y = x**2
    return y
attempt3 = scipy.integrate.romberg(x_squared, a=0, b=10)
#sum_attempt3 = np.sum(attempt3)

print("The integral calculated by the Scipy trapz funct:", attempt1)
print("The integral calculated by the Scipy simps funct:", attempt2)
print("The integral calculated by the Scipy romberg function:", attempt3)

#Here we can see the the two scipy functions trapz and simps have similiar values
#as the numpy trapz which is not too far off from my function. But the Scipy
#romberg function actually provides the calculated answer for the analytical value


# -*- coding: utf-8 -*-
"""
Created on Tue Feb 02 15:48:57 2016

@author: well8613
"""

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

def main():
    k=0.1
    dt=5

    t=np.arange(0,math.log(10)/k,0.05)
    T=np.exp(-k*t)
    plt.plot(t,T)

    t=np.arange(0,math.log(10)/k,dt)
    plt.plot(t,cooling_euler(k,t,dt))
    plt.title('Temperature')
    plt.xlabel('Time'); plt.ylabel('Temperature (as proportion of T0 - Ta)')

    plt.plot(t,cooling_rk2(cooling_diffeq,t,dt,1))
    plt.legend(['Exact','Euler','RK2'])
    '''
    dt=np.arange(.2,4.2,.2)
    error=np.exp(-k*dt) + k*dt -1
    plt.figure()
    plt.plot(dt,error)
    plt.title('Error with step size')
    plt.xlabel('step size'); plt.ylabel('Error')
    return
    '''

def cooling_rk2(G,t,dt,T0):
    '''rk2 for cooling function

     Parameters
    ----------
    G:function
        cooling_diffeq gives the derivative at T

    t:array,float
        time/independent variable

    dt:float
        time step

    T0:float
        initial temperature

    Returns
    -------
    T:array,float
        rk2 values for T
    '''
    T= 0*t
    T[0]=1
    for i in range(1,len(T)):
        k1 = G(T[i-1],t)
        k2 = G(T[i-1]+k1*dt*0.5,t)
        T[i] = T[i-1] + k2*dt
    return np.array(T)

def cooling_diffeq(T,t):
    '''Provides the slope of the cooling function

    Parameters
    ---------
    T: float
        initial temperature

    t: array, float
        time/independent variable

    Returns
    -------
    slope: float
        derivative at a certain T
    '''
    k=0.1
    slope = -k*T
    return slope

def cooling_euler(k,t,dt):
    ''' Approximates the cooling function exp(-kt), using Euler's method

    Parameters
    ----------
    k:float
        the cooling constant

    t:array,float
        time/independent variable

    dt:float
        time step

    Returns
    -------
    T:array,float
    '''
    T=0*t
    T[0]=1
    for i in range(1,len(T)):
        T[i]=T[i-1]-k*T[i-1]*dt
    return T

def cooling_taylor(k,t,t_0,n):
    ''' Gives the nth order Talor polynomial for the cooling function exp(-kt)

    Parameters
    ----------
    k:float
        the cooling constant

    t:array,float
        time/independent variable

    t_0:float
        center of Taylor expansion

    n:int
        order of taylor polynomial

    Returns
    -------
    T:array,float
    '''
    T=1
    for i in range(1,n+1):
        T=T+ ((-k*(t-t_0))**i)/math.factorial(i)
    T=T*np.exp(-k*t_0)
    return T

if __name__=="__main__":main()


def sparseness(W, dim=0):
    '''vector sparseness along specified dimension'''

    import numpy as np
    n = W.shape[dim]
    l2 = np.sqrt(np.sum(np.square(W), dim))           # l2-norm
    l1 =         np.sum(np.abs(   W), dim)            # l1-norm
    return (np.sqrt(n) - l1 / l2) / (np.sqrt(n) - 1)  # sparseness


from scipy import *
import sympy as sym
from approx1D import *
import matplotlib.pyplot as plt

Ns = [2, 4, 8, 16]
Taylor     = [0.0983, 0.00263,  7.83e-07, 3.57e-10]
Sinusoidal = [0.0027, 0.00061,  0.00012,  2.17e-05]
Bernstein  = [0.0021, 4.45e-05, 8.73e-09, 4.49e-15]
Lagrange   = [0.0021, 4.45e-05, 8.73e-09, 2.45e-12]

x = sym.Symbol('x')
psi = [1, x]

u, c = regression_with_noise(log2(Sinusoidal), psi, log2(Ns))
print(("estimated model for sine: %3.2e*N**(%3.2e)" % \
      (2**(c[0]), c[1])))

# check the numbers estimated by the model by manual inspection
for N in Ns:
  print((2**c[0] * N **c[1]))

X = log2(Ns)
U = sym.lambdify([x], u)
UU = U(X)

plt.plot(X, log2(Sinusoidal))
plt.plot(X, UU)
plt.legend(["data", "model"])
plt.show()

u, c = regression_with_noise(log(Bernstein), psi, Ns)
print(("estimated model for Bernstein: %3.2e*exp(%3.2e*N)" % (exp(c[0]), c[1])))

# check the numbers estimated by the model by manual inspection
for N in Ns:
  print((exp(c[0]) * exp(N * c[1])))

X = Ns
U = sym.lambdify([x], u)
UU = U(array(X))

plt.plot(X, log(Bernstein))
plt.plot(X, UU)
plt.legend(["data", "model"])
plt.show()

CPU_Taylor    = [0.0123, 0.0325, 0.108,  0.441]
CPU_sine      = [0.0113, 0.0383, 0.229,  1.107]
CPU_Bernstein = [0.0384, 0.1100, 0.3368, 1.187]
CPU_Lagrange  = [0.0807, 0.3820, 2.5233, 26.52]

plt.plot(log2(Ns), log2(CPU_Taylor))
plt.plot(log2(Ns), log2(CPU_sine))
plt.plot(log2(Ns), log2(CPU_Bernstein))
plt.plot(log2(Ns), log2(CPU_Lagrange))
plt.legend(["Taylor", "sine", "Bernstein", "Lagrange"])
plt.show()


import numpy as np

def compute_distances(X, k, n_data, centroids):
    distances = np.zeros((n_data, k))
    for idx_centroids in range(k):
        dist = np.sqrt(np.sum((X - centroids[idx_centroids]) ** 2, axis=1))
        distances[:, idx_centroids] = dist
    return distances

def init_centroid(X, k, n_data):
    # 1つ目のセントロイドをランダムに選択
    idx = np.random.choice(n_data, 1)
    centroids = X[idx]
    for i in range(k - 1):
        # 各データ点とセントロイドとの距離を計算
        distances = compute_distances(X, len(centroids), n_data, centroids)

        # 各データ点と最も近いセントロイドとの距離の二乗を計算
        closest_dist_sq = np.min(distances**2, axis=1)

        # 距離の二乗の和を計算
        weights = closest_dist_sq.sum()

        # [0, 1)の乱数と距離の二乗和を掛ける
        rand_vals = np.random.random_sample() * weights

        # 距離の二乗の累積和を計算し，rand_valと最も値が近いデータ点のindexを取得
        candidate_ids = np.searchsorted(np.cumsum(closest_dist_sq), rand_vals)

        # 選ばれた点を新たなセントロイドとして追加
        centroids = np.vstack([centroids, X[candidate_ids]])
    return centroids

def k_means(X, k, max_iter=300):
    """
    X.shape = (データ数, 次元数)
    k = クラスタ数
    """
    n_data, n_features = X.shape

    # 重心の初期値
    centroids = init_centroid(X, k, n_data)

    # 新しいクラスタを格納するための配列
    new_cluster = np.zeros(n_data)

    # 各データの所属クラスタを保存する配列
    cluster = np.zeros(n_data)

    for epoch in range(max_iter):
        # 各データ点と重心との距離を計算
        distances = compute_distances(X, k, n_data, centroids)

        # 新たな所属クラスタを計算
        new_cluster = np.argmin(distances, axis=1)

        # すべてのクラスタに対して重心を再計算
        for idx_centroids in range(k):
            centroids[idx_centroids] =   X[new_cluster == idx_centroids].mean(axis=0)

        # クラスタによるグループ分けに変化がなかったら終了
        if (new_cluster == cluster).all():
            break

        cluster = new_cluster

    return cluster

if __name__=="__main__":
    X = np.arange(10*5).reshape(10, 5)
    print("X\n", X)
    k = 3
    print("k=",k)

    cluster = k_means(X, k, max_iter=300)
    print("cluster", cluster)


import numpy as np

from src.datas.data_x import Data
from src.model import BaseModel

class Model(BaseModel):
    """
    Fit plane z = ax + by + c by minimising orthogonal distances.
    """

    def __init__(self):
        self.parameters = None

    def fit(self, data: Data):
        n_points = len(data)
        if n_points < 3:
            raise Exception("Not enough point to solve plane")
        elif n_points == 3:
            self.parameters = self._solve_plane_analytically(data.x)
        else:
            self.parameters = self._fit_plane(data.x)

    def calculate_errors(self, data: Data):
        """
        Errors are orthogonal distances to plane.
        """
        xyz1 = np.hstack((data.x, np.ones((len(data), 1))))
        abcd = np.insert(self.parameters, 2, -1).T
        return abs(xyz1 @ abcd) / np.linalg.norm(abcd[:-1])

    @staticmethod
    def _solve_plane_analytically(xyz):
        # These two vectors are in the plane
        v1 = xyz[2, :] - xyz[0, :]
        v2 = xyz[1, :] - xyz[0, :]

        # The cross product is a vector normal to the plane
        n = np.cross(v1, v2)

        # d = a * x + b * y + c * z
        a, b, c = n
        d = - np.dot(n, xyz[2, :])

        # z = c1 * x + c2 * y + c3
        c1 = -a / c
        c2 = -b / c
        c3 = -d / c
        return np.array([c1, c2, c3]).T

    @staticmethod
    def _fit_plane(xyz):
        """
        Singular value decomposition method.
        Minimizes orthogonal distances.
        Returns fitted coefficients of equation z = c1*x + c2*y + c3 as [c1, c2, c3]
        """

        # Find the average of points (centroid) along the columns
        xyz_mean = np.average(xyz, axis=0)

        # Create CX vector (centroid to point) matrix
        cx = xyz - xyz_mean

        # Singular value decomposition
        u, s, v = np.linalg.svd(cx)

        # The last row of V matrix is the eigenvector with smallest eigenvalue
        # This is normal of fitted plane
        n = v[-1]

        # Extract a, b, c, d coefficients
        # ax + by + cz + d = 0
        x0, y0, z0 = xyz_mean
        a, b, c = n
        d = -(a * x0 + b * y0 + c * z0)

        # z = c1 * x + c2 * y + c3
        c1 = -a / c
        c2 = -b / c
        c3 = -d / c
        return np.array([c1, c2, c3]).T


import numpy as np

# sigmoid function
def nonlin(x,deriv=False):
    if(deriv==True):
        return x*(1-x)
    return 1/(1+np.exp(-x))

# input dataset
X = np.array([  [0,0,1],
                [0,1,1],
                [1,0,1],
                [1,1,1] ])

print("X : ",X)
# output dataset
y = np.array([[0,0,1,1]]).T

print("y : ",y)
# seed random numbers to make calculation
# deterministic (just a good practice)
np.random.seed(1)

print("X : ",X)
# initialize weights randomly with mean 0
syn0 = 2*np.random.random((3,1)) - 1

print("syn0 : ",syn0)
for iter in range(1000000):
    # forward propagation
    l0 = X
    l1 = nonlin(np.dot(l0,syn0))
    # how much did we miss?
    l1_error = y - l1
    # multiply how much we missed by the
    # slope of the sigmoid at the values in l1
    l1_delta = l1_error * nonlin(l1,True)
    # update weights
    syn0 += np.dot(l0.T,l1_delta)
    if iter%100000 == 0:
        print("***************************** iteration :",iter," ********************************")
        print("np.dot(l0,syn0) : ",np.dot(l0,syn0))
        print("l0 : ",l0)
        print("l1 : ",l1)
        print("l1_error : ",l1_error,"\n")
        print("l1_delta : ",l1_delta,"\n")
        print("syn0 : ", syn0)

print ("Output After Training:")
print (l1)


import numpy as np
import scipy
import sympy
from numpy import linalg as lg
from numpy.linalg import solve
from numpy.linalg import eig
from scipy.integrate import quad

# Question 1
'''
	  [1]
T(u) =[2]
	 [-3]

	 [k/4]
T(v)=[c/4]
	 [a/4]
'''

# Question 2
a1 = np.matrix([[1, -4, 3], [0, 1, -2], [2, -9, 6]])
b1 = np.matrix([[-6, -5, -5]]).T
c1 = np.column_stack([a1, b1])
print(c1)

d1 = sympy.Matrix(c1).rref()
print(d1) # Correct

# Is the vector x found in the previous step unique?
# Yes, because there are no free variables in the system of equations.

# Question 3
'''
	[-8]
v1 =[-9]

	[-1]
v2 = [4]

	[-8 -1]
A = [-9  4]

'''

# Question 4
'''
a. A linear transformation is a special type of function.
True. A linear transformation is a function from set of real numbers R Superscript n to set of real numbers R Superscript m that assigns to each vector x in set of real numbers R Superscript n a vector T(x) in set of real numbers R Superscript m.

b. If A is a 3 times 5 matrix and T is a transformation defined by T(x)equalsAx, then the domain of T is set of real numbers R cubed.

False. The domain is actually set of real numbers R Superscript 5, because in the product Ax, if A is an m times n matrix then x must be a vector in set of real numbers R Superscript n.

c. If A is an m times n matrix, then the range of the transformation x maps to  Ax is set of real numbers R Superscript m.
False. The range of the transformation is the set of all linear combinations of the columns of A, because each image of the transformation is of the form Ax.

d. Every linear transformation is a matrix transformation.

False. A matrix transformation is a special linear transformation of the form x maps to Ax where A is a matrix.

e. e. A transformation T is linear if and only if Tleft parenthesis c 1 Bold v 1 plus c 2 Bold v 2 right parenthesisequalsc 1 Upper T left parenthesis Bold v 1 right parenthesis plus c 2 Upper T left parenthesis Bold v 2 right parenthesis for all Bold v 1 and Bold v 2 in the domain of T and for all scalars c 1 and c 2.

True. This equation correctly summarizes the properties necessary for a transformation to be linear.

'''

# Question 5
'''
Assume that T is a linear transformation. Find the standard matrix of T.
T: set of real numbers R squaredright arrowset of real numbers R Superscript 4, Upper T left parenthesis Bold e 1 right parenthesisequals(6, 1, 6, 1), and Upper T left parenthesis Bold e 2 right parenthesisequals(negative 7, 4, 0, 0), where Bold e 1equals(1,0) and Bold e 2equals(0,1)

	[6, -7]
	[1,  4]
A = [6,  0]
	[1,  0]

'''

# Question 6
# Trig question

# Question 7
'''
Assume that T is a linear transformation. Find the standard matrix of T.
T: set of real numbers R squaredright arrowset of real numbers R squared, first performs a horizontal shear that transforms Bold e 2 into Bold e 2 plus 17 Bold e 1 (leaving Bold e 1 unchanged) and then reflects points through the line x 2 equals negative x 1.

	 [0 -1]
A =[-1 -17]

'''

# Question 8
# Fill in the missing entries for the matrix

# Question 9
# Fill in the missing entries for the matrix

# Question 10
a2 = np.matrix([[1, 1, 2],[2, 6, -16]])
print(a2)
b2 = sympy.Matrix(a2).rref()
print(b2) # Correct

# Question 11
'''
a. If A is a 4 times 3 matrix, then the transformation x maps to Ax maps set of real numbers R cubed onto set of real numbers R Superscript 4. Choose the correct answer below.
False. The columns of A do not span set of real numbers R Superscript 4.

b. Every linear transformation from set of real numbers R Superscript n to set of real numbers R Superscript m is a matrix transformation. Choose the correct answer below.
True. There exists a unique matrix A such that Upper T left parenthesis Bold x right parenthesis equals Upper A Bold x for all x in set of real numbers R Superscript n.

c. The columns of the standard matrix for a linear transformation from set of real numbers R Superscript n to set of real numbers R Superscript m are the images of the columns of the n times n identity matrix under T. Choose the correct answer below.
True. The standard matrix is the m times n matrix whose jth column is the vector Upper T left parenthesis Bold e Subscript j right parenthesis, where Bold e Subscript j is the jth column of the identity matrix in set of real numbers R Superscript n.

d. A mapping T: set of real numbers R Superscript nmaps toset of real numbers R Superscript m is one-to-one if each vector in set of real numbers R Superscript n maps onto a unique vector in set of real numbers R Superscript m. Choose the correct answer below.
False. A mapping T is said to be one-to-one if each b in set of real numbers R Superscript m is the image of at most one x in set of real numbers R Superscript n.

e. The standard matrix of a horizontal shear transformation from set of real numbers R squared to set of real numbers R squared has the form left bracket Start 2 By 2 Matrix 1st Row 1st Column a 2nd Column 0 2nd Row 1st Column 0 2nd Column d EndMatrix right bracket . Choose the correct answer below.
False. The standard matrix has the form left bracket Start 2 By 2 Matrix 1st Row 1st Column 1 2nd Column k 2nd Row 1st Column 0 2nd Column 1 EndMatrix right bracket .

'''

# Question 12
'''
Determine if the specified linear transformation is (a) one-to-one and (b) onto. Justify each answer.

a.
T is not one-to-one because the columns of the standard matrix A are linearly dependent.

b.
T is onto because the columns of the standard matrix A span set of real numbers R squared.
'''

# Question 13
# The transformation T is not one-to-one because the equation Upper T left #parenthesis Bold x right parenthesis equals Bold 0 has a nontrivial solution.

# Question 14
a3 = np.matrix([[110, 120, 350], [4, 2, 8], [20, 18, 56], [2, 5, 12]])
print(a3)
b3 = sympy.Matrix(a3).rref()
print(b3) # Correct

import numpy,from numpy,import scipy,from scipy,import sympy


# -*- coding: utf-8 -*-
"""
Created on Sat Jul 13 00:25:40 2019

@author: MAHDI
"""
import sys
import numpy as np

def PrintSqMatrix(a, n):
    for i in range(n):
        for j in range(n-1):
            print("%.4f" % (a[i][j]), end=' ')
        print("%.4f" % (a[i][n-1]))
    return

def PrintColumnMatrix(mat, n):
    for i in range(n):
        print("%.4f" % (mat[i]))
    return

def DecomposeLU(a, n):
    n=int(n)
    l = np.eye(n)
    u = np.array(a)
#    print('l += ' ,l,a )
#    print(a[0][0])
    for k in range(n):
        for i in range(k+1, n):
# =============================================================================
#             if np.abs(u[k][k])<=1e-10:
#                 return 0
# =============================================================================
            factor = u[i][k]/u[k][k]
            l[i][k] = factor
            for j in range(n):
                u[i][j] = u[i][j]-factor*u[k][j]
# =============================================================================
#     print(l)
#     print(u)
#     print(a)
#
# =============================================================================
    return (l, u)

def Forwardsubstitution(l, b, n):
    y = np.zeros(n)
# =============================================================================
#     print(y)
#     print(b)
# =============================================================================
    for i in range(n):
        sum = 0.0
        for j in range(0, i):
            sum += l[i][j]*y[j]
        y[i] = (b[i]-sum)/l[i][i]
    return y

def Backwardsubstitution(u, y, n):
    x = np.zeros(n)
# =============================================================================
#     print(y)
#     print(b)
# =============================================================================
    for i in range(n-1, -1, -1):
        sum = 0.0
        for j in range(i+1, n):
            sum += u[i][j]*x[j]
        x[i] = (y[i]-sum)/u[i][i]
    return x

def Nosolution():
    print("No unique solution")
    return

def CheckSolution(u, n):
    for i in range(n):
        non_zero=False
        for j in range(n):
            if abs(u[i][j]) >= 1e-12:
                non_zero=True
                break
        if non_zero == False :
            return False
    for i in range(n):
        if abs(u[i][i])<=1e-12:
            return False
    return True

def Main():
    inp = open('in1.txt')
    sys.stdout = open('out1.txt', 'w')
    N = int(inp.readline())
#    print(n)
    A = [list(map(float, inp.readline().strip().split(' '))) for i in range(N)]
    A = np.array(A)
    B = [float(inp.readline()) for i in range(N)]
    B = np.array(B)

# =============================================================================
#     print(A)
#     print(b)
# =============================================================================

    # input taken

    L, U = DecomposeLU(A, N)
    PrintSqMatrix(L, N)
    print()
    PrintSqMatrix(U, N)
    print()

    if CheckSolution(U, N) is False:
        Nosolution()
        return

#    print('shape of b',b.shape)
    Y = Forwardsubstitution(L, B, N)
    PrintColumnMatrix(Y, N)
    print()
    X = Backwardsubstitution(U, Y, N)
    PrintColumnMatrix(X, N)
    return

if '__main__' == __name__:
    Main()

Numerical/Offline 2 on LU Decomposition And Simplex Method/1.py


# AUTOGENERATED! DO NOT EDIT! File to edit: Fourier.ipynb (unless otherwise specified).

__all__ = ['FourierModel', 'Seasonal']

# Cell
import matplotlib.pyplot as plt

import torch
import torch.nn as nn
import torch.nn.functional as F

import numpy as np

torch.Tensor.ndim = property(lambda x: x.dim())

# Cell
_TWOPI = 2*np.pi

class FourierModel(nn.Module):
    """
    Block that outputs sin's and cos' as basis functions.
    parameters:
    - p: period
    - scale: time axis scaling factor
    - n: number of fourier components
    """
    def __init__(self, p:float=365.25, scale:float=1, n:int=7):
        super().__init__()
        self.np = [(i+1, p/scale) for i in range(n)]
        self.n, self.p = n, p
        if n > 0:
            self.linear = nn.Linear(n * 2, 1, bias=False)

    def forward(self, t:torch.Tensor):
        if len(self.np) > 0:
            cos = [torch.cos(_TWOPI * n * t / p) for n,p in self.np]
            sin = [torch.sin(_TWOPI * n * t / p) for n,p in self.np]

            return self.linear(torch.cat(cos + sin, dim=1))

        else:
            return 0

    def plot(self, ax=None, title=None):
        if self.n > 0:
            t = torch.linspace(0, self.p, steps=100)
            y = self.forward(t[:,None])
            if ax is None:
                fig, ax = plt.subplots(figsize=(12,5))
            ax.plot(t, y)
            ax.set_xlabel('Days')

class Seasonal(nn.Module):
    """
    Combination of Fourier Blocks that gives weekly, monthly and
    yearly seasonality.
    parameters:
    - y_n: Number of yearly components
    - m_n: Number of monthly components
    - w_n: Number of weekly components
    - scale: time axis scaling factor
    """
    def __init__(self, y_n=10, m_n=5, w_n=3, scale=1):
        super().__init__()
        self.y_n, self.m_n, self.w_n = y_n, m_n, w_n
        y_p=365.25; m_p=30.5; w_p=7
        self.yearly = FourierModel(y_p, scale, y_n) # , w[:,:idxs[0]]
        self.monthly = FourierModel(m_p, scale, m_n) # w[:,idxs[0]:idxs[1]]
        self.weekly = FourierModel(w_p, scale, w_n) # w[:,idxs[1]:idxs[2]]

    def forward(self, t):
        return self.yearly(t) + self.monthly(t) + self.weekly(t)

    def plot_components(self):
        plot = [True if c>0 else False for c in
                [self.y_n, self.m_n, self.w_n]]
        period = [self.yearly, self.monthly, self.weekly]
        period = [p for (p, pl) in zip(period, plot) if pl]
        fig, axs = plt.subplots(sum(plot), 1, figsize=(12, 12))

        for p, ax in zip(period, axs):
            p.plot(ax)


import math
import numpy as np
import matplotlib.pyplot as plt
time = np.arange(0,math.pi,0.1)
amp = np.sin(time)
plt.title("Half Sine Wave")
plt.xlabel("Time")
plt.ylabel("Amplitude")
plt.plot(time,amp)
plt.show()
print(amp)
l = str(len(amp))
print("There are "+l+" bits")
plt.scatter(time,amp)
plt.vlines(time,[0]*32,amp)
plt.title("Sampled Wave")

quant = 4
ampl = (amp * (2**quant)).astype(int)
print(ampl)

plt.plot(time,ampl)
plt.scatter(time,ampl)
plt.vlines(time,[0]*32,ampl)

for i in range (32):
    b = ampl[i]
    n = bin(b)
    n = n[2:]
    length = len(n)
    if (length<5):
        s = str(n)
        e = 5 - length
        print('0'+'.'+(e-1)*'0'+s)
    else:
        print(n)


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

"""A generator of graphs written in Python and LaTeX.
   https://github.com/jariazavalverde/graphs
"""

import numpy as np

# ADJACENCY MATRICES

def complete(n):
	"""Returns the adjacency matrix of a complete graph K(n).
	   For: n > 0."""
	if n < 1:
		return None
	size = n
	adjacency = np.ones((size,size))
	for i in xrange(size):
		adjacency[i][i] = 0
	return adjacency

def friendship(n):
	"""Returns the adjacency matrix of a friendship graph F(n).
	   For: n > 0."""
	if n < 1:
		return None
	size = 2*n+1
	adjacency = np.zeros((size, size))
	for i in xrange(1,n+1):
		adjacency[0][i] = 1
		adjacency[i][0] = 1
		adjacency[0][n+i] = 1
		adjacency[n+i][0] = 1
		adjacency[i][n+i] = 1
		adjacency[n+i][i] = 1
	return adjacency

def johnson(n, k):
	"""Returns the adjacency matrix of a johnson graph J(n,k).
	   For: n > 0, k > 0, k < n."""
	if n < 1 or k < 1 or k > n:
		return None
	subsets = filter(lambda x: len(x) == k, _powerset(range(n)))
	size = len(subsets)
	adjacency = np.zeros((size, size))
	for i in xrange(size):
		for j in xrange(i+1, size):
			if len(subsets[i].intersection(subsets[j])) == k-1:
				adjacency[i][j] = 1
				adjacency[j][i] = 1
	return adjacency

def petersen(n, k):
	"""Returns the adjacency matrix of a generalized petersen graph GP(n,k).
	   For: n > 0, k > 0, k < n/2."""
	if n < 1 or k < 1 or float(k) >= float(n)/2.0:
		return None
	# u_0, ..., u_{n-1}, v_0, ..., v_{n-1}
	size = n*2
	adjacency = np.zeros((size, size))
	for i in xrange(n):
		# u_i <-> u_{i+1}
		adjacency[i][(i+1) % n] = 1
		adjacency[(i+1) % n][i] = 1
		# u_i <-> v_i
		adjacency[i][i+n] = 1
		adjacency[i+n][i] = 1
		# v_i <-> v_{i+k}
		adjacency[n+i][n + (i+k) % n] = 1
		adjacency[n + (i+k) % n][n+i] = 1
	return adjacency

def windmill(k, n):
	"""Returns the adjacency matrix of a windmill graph Wd(k, n).
	   For: k > 1, n > 1."""
	if k < 2 or n < 2:
		return None
	size = (k-1)*n+1
	adjacency = np.zeros((size, size))
	for i in xrange(n):
		for j in xrange(k-1):
			z = i*(k-1)+j+1
			adjacency[0][z] = 1
			adjacency[z][0] = 1
			for l in xrange(k-1):
				x = i*(k-1)+j+1
				y = i*(k-1)+l+1
				if x != y:
					adjacency[x][y] = 1
					adjacency[y][x] = 1
	return adjacency

# HANDLING AND TYPE CHECKING

adjacency_functions = {
	"complete": (complete, [("n", int)], "n > 0"),
	"friendship": (friendship, [("n", int)], "n > 0"),
	"johnson": (johnson, [("n", int), ("k", int)], "n > 0, k > 0, k < n"),
	"petersen": (petersen, [("n", int), ("k", int)], "n > 0, k > 0, k < n/2"),
	"windmill": (windmill, [("k", int), ("n", int)], "k > 1, n > 1")
}

# AUXILIAR OPERATIONS

def _powerset(A):
	"""Returns the powerset of a given set."""
	P = [set([])]
	for i in xrange(len(A)):
		for j in xrange(len(P)):
			subset = P[j].copy()
			subset.add(i)
			P.append(set(subset))
	return P

# AUTHORSHIP INFORMATION

__author__ = "José Antonio Riaza Valverde"
__copyright__ = "Copyright 2019, José Antonio Riaza Valverde"
__credits__ = ["José Antonio Riaza Valverde"]
__license__ = "BSD 3-Clause"
__version__ = "1.0.0"
__maintainer__ = "José Antonio Riaza Valverde"
__email__ = "riaza.valverde@gmail.com"
__status__ = "Development"


import numpy as np

def angle_between(vec1, vec2, deg=True):
    """
    This function computes the angle between vectors along the last dimension of the input arrays.
    This version is a numerically stable one based on arctan2 as described in this post:
     - https://scicomp.stackexchange.com/a/27769/39858

    Parameters
    ----------
    vec1 : array
        An arbitrarily batched arry of vectors
    vec2 : array
        An arbitrarily batched arry of vectors
    deg : bool (optional)
        Whether angles are returned in degrees or radians. The default is degrees (deg=True).

    Returns
    -------
    angles : array
        A vector of angles with the same leading dimensions of vec1 and vec2.
    """
    v1 = vec1 / np.linalg.norm(vec1, axis=-1)[..., None]
    v2 = vec2 / np.linalg.norm(vec2, axis=-1)[..., None]
    x1 = np.linalg.norm(v1 - v2, axis=-1)
    x2 = np.linalg.norm(v1 + v2, axis=-1)
    alpha = 2.0 * np.arctan2(x1, x2)
    if deg:
        return np.rad2deg(alpha)
    return alpha


# -*- coding: utf-8 -*-
"""A set of functions that make it easy to play with soft inforamtion"""

import numpy as np
from numpy import pi, exp, sqrt, log

def normal(x, mean, std):
    """
    Normal distribution

    Args:
        x: input value
        mean: the mean of the distribution
        std: standard deviation
    """
    return 1/(std*sqrt(2*pi))*exp(-(x-mean)**2/(2*std**2))

def dist(xa, ya, xb, yb):
    """Return the distance between a and b"""
    a = np.array((xa, ya))
    b = np.array((xb, yb))
    return np.linalg.norm(a-b)

def log_normal(x, mean, std):
    """
    Natural logarithm of a normal distribution

    Args:
        x: input value
        mean: the mean of the distribution
        std: standard deviation
    """
    return -log(std) - (log(2) + log(pi))/2 - (x-mean)**2/(2*std**2)

def logprob_distance(xa, ya, xb, yb, measured_dist, std):
    """
    Logprob that a and b are in (xa, ya), (xb, yb) under the measured distance.

    Args:
        xa: abscissa of point a
        ya: ordinate of point a
        xb: abscissa of point b
        yb: ordinate of point b
        measured_dist: measured distance between a and b
        std: standard deviation of the measurement
    """
    points_dist = dist(xa, ya, xb, yb)
    return log_normal(points_dist, measured_dist, std)

def make_logprob_distance(idx_a, idx_b, measured_dist, std):
    """
    Make the function that return the logprob of positions under the measured distance

    Args:
        idx_a: index of point a
        idx_b: index of point b
        measured_dist: measured distance between a and b
        std: standard deviation of the measurement
    """
    def func(points):
        """
        Return the logprob of positions under the measured distance

        Args:
            points: estimated positions ([[x0, y0, h0], [x1, y1, h1], ...])
        """
        xa, ya = points[idx_a]
        xb, yb = points[idx_b]
        return logprob_distance(xa, ya, xb, yb, measured_dist, std)

    return func

def make_logprob_position(idx, measured_x, measured_y, std):
    """
    Returns the soft position information function that can be applied to the estimated positions

    Args:
        idx: index of point
        measured_x: measured abscissa
        measured_y: measured ordinate
        std: standard deviation of the measurement

    Returns:
        (function): the logSI function that takes the estimated positions of the points as input.
    """
    def func(points):
        """
        Returns log-prob of the estimated positions under the measured position.

        Args:
            points: estimated positions ([[x0, y0, h0], [x1, y1, h1], ...])
        """
        estimated_x, estimated_y = points[idx]
        return logprob_distance(estimated_x, estimated_y, measured_x, measured_y, 0, std)

    return func


from scipy.special import jv
import numpy as np
import matplotlib.pyplot as plt

plt.style.use('../styles/tnakamot_engineering.mplstyle')

x      = np.linspace(0, 15, 100)
orders = np.arange(0, 8)

J      = np.zeros( ( np.size(x), np.size(orders) ) )
labels = []
for order in orders:
    J[:,order] = jv(order, x)
    labels.append(r'$J_%d$' % order)

fig = plt.figure()
ax  = fig.add_subplot(1, 1, 1)
lines = ax.plot( x, J )

ax.set_title('Bessel function of the first kind')
ax.set_xlabel( r'$x$' )
ax.set_ylabel( 'Functions' )
ax.set_xlim( (np.min(x), np.max(x)) )
ax.set_ylim( (-0.6, 1.0) )
ax.legend( lines, tuple(labels), ncol = 2 )

fig.savefig('example3.pdf')
fig.savefig('example3.png')
fig.savefig('example3.svg')

plt.show()