# Import the necessary modules
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# In this script, we will consider a receptor which can bind two ligands.
# Using the statistical mechanics in we learned in lecture, we can enumerate
# these states, figure out the multiplicity, and compute their statistical
# weights.  How does the probability of each state change with a concentration
# of ligand? Let's find out!

# We'll start by declaring some variables.
d_eb = -5  # Energetic difference between bound and unbound states (in kT)
d_ei = -2  # Energetic difference of interaction
L = np.logspace(-4, -1, 1000)  # Range of ligand concentration.

# To save our fingers some work, we'll define the partition function.
Z = 1 + 2 * L * np.exp(-d_eb) + L**2 * np.exp(-(2 * d_eb + d_ei))

# Now we'll compute the probability of each state
p_empty = 1 / Z  # Nothing bound -- empty receptor.
p_single = L * np.exp(-d_eb) / Z  # Probability of one ligand being bound.
p_double = L**2 * np.exp(-(2 * d_eb + d_ei)) / Z  # Probability of both bound.

# Now we'll plot the probabilites as a function of ligand concentration.
plt.figure()
plt.semilogx(L, p_empty, '-', label='empty')
plt.semilogx(L, p_single, '-', label='singly bound')
plt.semilogx(L, p_double, '-', label='doubly bound')

# Add labels as one always should.
plt.xlabel('ligand concentration (M)')
plt.ylabel('probability of state')
plt.legend()
plt.show()

# We can see that with a high concentration of ligand, the most common state
# is having both bound at once. In the middle of the range, empty and doubly
# bound are equal with a singly bound state less probable. Let's now compute
# the average number of bound ligands as a function of concentration.

# Since we have already enumerated our probabilities, the calculation is
# trivial.
n_bound = 2 * p_single + 2 * p_double

# Plot it!
plt.figure()
plt.plot(L, n_bound, 'k-')
plt.xlabel('ligand concentration (M)')
plt.ylabel('average number of bound ligands')
plt.show()

# Now go back and try changing the energy of interaction and see how the
# curves change!


# -*- coding: utf-8 -*-
"""
Created on Sun May  9 08:34:01 2021

@author: Raza_Jutt
"""

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

x = []
for i in range(0,201):
    x.append(i/100)

y=[]
for i in x:
    y.append(math.sqrt(math.cos(i)*math.cos(i) +1 ))

rand_x = []
rand_y = []
for i in range(0,10000):
    rand_x.append(random.uniform(0.00,2.00))
    rand_y.append(random.uniform(1.00,1.41))

xpoints = np.array(x)
ypoints = np.array(y)

x_coordinates = rand_x
y_coordinates = rand_y

plt.plot(xpoints, ypoints,'r')
plt.scatter(x_coordinates, y_coordinates,s=0.1, marker="x")
plt.show()

count = 0
for i in range(0,10000):
    x=rand_x[i]
    if math.sqrt(math.cos(x)*math.cos(x) +1 ) > rand_y[i] :
        count += 1

print(count/10000)


# Gradient Descent Implementation (fromt theory notebook)
# Demonstrated multi-collinearity problem from artificially generated dataset

# Code Flow:
    # 1. Import all relevant libraries.
    # 2. Generate sample data.
    # 3. Calculate weights using gradient descent.
    # 4. Plot the costs.
    # 5. Plot prediction vs actual.

# 1. Imports:
import numpy as np
import matplotlib.pyplot as plt

# 2. Generate sample data:
N = 10
D = 3
X = np.zeros((N, D))
X[:,0] = 1 # bias term
X[:5,1] = 1
X[5:,2] = 1
Y = np.array([0]*5 + [1]*5)

# 3. Calculate weights using gradient descent:
# w = np.linalg.solve(X.T.dot(X), X.T.dot(Y))
# won't work because of multicollinearity
# Hence gradient descent
costs = [] # keep track of squared error cost
w = np.random.randn(D) / np.sqrt(D) # randomly initialize w
learning_rate = 0.001

for t in range(1000): # 1000 iterations chosen
  # update w
  Yhat = X.dot(w)
  delta = Yhat - Y
  w = w - learning_rate*X.T.dot(delta)

  # find and store the cost
  mse = delta.dot(delta) / N # mean-sq error
  costs.append(mse) # append cost

# 4.Plot the costs:
plt.figure(1)
plt.plot(costs)
plt.xlabel('Iteration no.')
plt.ylabel('Cost')
plt.title('Change in cost')

# 5.Plot prediction vs actual
plt.figure(2)
plt.plot(Yhat, label='Prediction')
plt.plot(Y, label='Actual')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Actual vs Prediction - Gradient Descent')
plt.legend()
plt.show()

1.Linear Regression/1.Code - Using Theory/5.Gradient Descent.py


import get_root as gr
import numpy as np
from scipy.integrate import quad

#Part A
#integral of B_nu
def B_x_integrand(ln_x):
  x = np.exp(ln_x)
  tol = 1.0e-15
  B_denom = np.exp(x)-1  #denominator of the planck function
  exp_minus_1 = x + 0.5*(x**2) + (x**3)/6. #taylor expansion of denominator

  if( (np.fabs(B_denom - exp_minus_1) < tol) & (x<1)):
    Bx = (x**3)/exp_minus_1;
  else:
    Bx = (x**3)/B_denom

  return x * Bx  # x * dB / dlnx  * dlnx = dB/dx * dx

#Part B
#equation for finding max of dBdnu
def root_dBdnu(x):
  return x-3*(1-np.exp(-1*x))

#equation for finding max of dBdlambda
def root_dBdlambda(y):
  return y-5*(1-np.exp(-1*y));

#Part C
#equation for finding max of d2BdnudT
def root_d2BdnudT(z):
  return np.exp(z)*(z-4)+z+4;

def main():

    print("***** Question 2, Part A *****")

    #find the integral of B_nu dnu
    Bi, _ = quad(B_x_integrand,-32, 32)
    ans = np.pi**4 / 15.
    print('Normalized integral of B_nu dnu = %e.' % Bi)
    print('Fractional error in integral = %e.' % float((Bi-ans)/ans))

    print("***** Question 2, Part B *****")

    #find the maximum of dBdnu
    x_dBdnu = gr.get_root(root_dBdnu,3.)
    print('Maximum of dBdnu occurs at x = %e.' % x_dBdnu)

    #find the maximum of dBdlambda
    y_dBdlambda = gr.get_root(root_dBdlambda,3.)
    print('Maximum of dBdlambda occurs at y = %e.' % y_dBdlambda)

    print("***** Question 2, Part C *****")

    #find the maximum of d^2B/dnudT
    x_d2BdnudT = gr.get_root(root_d2BdnudT,4.)
    print('Maximum of d2BdnudT occurs at x = %e.' % x_d2BdnudT)

#execute the program
if __name__=='__main__':
    main()


import numpy as np

class Quaternion:
    """ Classe pour les rotations 3D via les quaternions """

    @classmethod
    def from_v_theta(cls, v, theta):
        """ Fonction pour passer de v et thêta au quaternion normalisé """
        v = np.asarray(v)                                                # Convertis l'entrée (int) en (array)
        v = v * np.sin(theta / 2) / np.sqrt(np.sum(v * v))               # v = v*sin(x/2) / ||v||
        x = np.ones(4)                                                   # x = [1, 1, 1, 1]
        x[0], x[1], x[2], x[3] = np.cos(theta / 2), v[0], v[1], v[2]     # x = [x[0], v[0], v[1], v[2]]
        return cls(x)

    def __init__(self, x):
        self.x = np.asarray(x)                    # Convertis l'entrée (int) en (array)

    ''' Fonction pour permettre la multipliaction de deux quaternions.
        Permet la rotation du cube en utilisant la souris '''
    def __mul__(self, other):
        sxr = self.x.reshape(4, 1)                # sxr est x définit en colonne
        oxr = other.x.reshape(1, 4)               # oxr est x définit en ligne
        prod = sxr * oxr                          # Matrice [4,4] produit de sxr et oxr

        # Produit final
        ret = np.array([(prod[0, 0] - prod[1, 1] - prod[2, 2] - prod[3, 3]),
                        (prod[0, 1] + prod[1, 0] + prod[2, 3] - prod[3, 2]),
                        (prod[0, 2] - prod[1, 3] + prod[2, 0] + prod[3, 1]),
                        (prod[0, 3] + prod[1, 2] - prod[2, 1] + prod[3, 0])]).T
        return self.__class__(ret)

    ''' Fonction pour passer du quaternion normalisé à v et thêta '''
    def as_v_theta(self):
        x = self.x.reshape(4, -1)                 # Décompose x en chacun de ses éléments puis le transpose

        # Calcul de theta
        norm = np.sqrt((x ** 2).sum(0))           # calcul de la norme de x
        theta = 2 * np.arccos(x[0] / norm)        # Calcul de thêta

        # Calcul de v
        v = np.array(x[1:])                       # Création de v. Sélectionne les 3 derniers éléments de x
        v /= np.sqrt(np.sum(v ** 2))              # Normalise v (v est une matrice ligne)
        v = v.T                                   # Transpose v (v est à présent une colonne)
        return v, theta

    """ Renvoie la matrice de rotation du quaternion normalisé """
    def as_rotation_matrix(self):
        v, theta = self.as_v_theta()              # Convertis x en v et thêta
        v = v.T                                   # Transpose v

        c = np.cos(theta)                         # cos(theta)
        c1 = 1. - c                               # 1 - cos(theta)
        s = np.sin(theta)                         # sin(theta)

        # Matrice de rotation
        mat = np.array([[v[0] ** 2 * c1 + c, v[0] * v[1] * c1 - v[2] * s, v[0] * v[2] * c1 + v[1] * s],
                        [v[1] * v[0] * c1 + v[2] * s, v[1] ** 2 * c1 + c, v[1] * v[2] * c1 - v[0] * s],
                        [v[2] * v[0] * c1 - v[1] * s, v[2] * v[1] * c1 + v[0] * s, v[2] ** 2 * c1 + c]]).T
        return mat.reshape(3, 3)

    def rotate(self, points):
        M = self.as_rotation_matrix()             # M reçoit la rotation de la matrice
        return np.dot(points, M.T)                # Produit scalaire entre les points et la matrice de rotation

def project_points(points, q, view, vertical=None):
    if vertical is None:
        vertical = [0, 1, 0]                      # Définis l'axe vertical par défaut
    view = np.asarray(view)                       # Convertis l'entrée (int) en array

    xdir = np.cross(vertical, view).astype(float) # Création du nouveau vecteur unitaire correspondant à l'horizontale
    xdir /= np.sqrt(np.dot(xdir, xdir))           # Normalisation

    ydir = np.cross(view, xdir)                   # Création du nouveau vecteur unitaire correspondant à la verticale
    ydir /= np.sqrt(np.dot(ydir, ydir))           # Normalisation

    zdir = view / np.sqrt(np.dot(view, view))     # Création du nouveau vecteur unitaire correspondant à la côte

    R = q.as_rotation_matrix()                    # Rotation des points

    # Projeté des points sur la vue
    dpoint = np.dot(points, R.T) - view
    dpoint_view = np.dot(dpoint, view).reshape(dpoint.shape[:-1] + (1,))
    dproj = -dpoint * np.dot(view, view) / dpoint_view

    trans = list(range(1, dproj.ndim)) + [0]
    return np.array([np.dot(dproj, xdir), np.dot(dproj, ydir), -np.dot(dpoint, zdir)]).transpose(trans)


#coding: utf-8
import numpy as np

def LIFsimulation(V_rest=-65, V_thre=-40, V_reset=-70, V_fire=20, C=2e-4, R=7.5e4, I=5e-4, dt=0.1, T=100):
    """Leaky Integrate-and-Fire(LIF) model.
    I-(V-Vrest)/Rm = Cm*(dV/dt)
    """
    Vm = V_rest
    Time = np.arange(0,T+dt,dt)
    V = np.zeros_like(Time)
    for i in range(len(V)):
        V[i] = Vm
        # dV/dt=(IR-(Vm-Vrest))/RC
        dVdt = (I*R-(Vm-V_rest))/(R*C)
        V_plus_dV = Vm+dt*dVdt
        Vm = V_reset if Vm>V_thre else V_fire if V_plus_dV > V_thre else V_plus_dV
    return Time,V

def LITSpikeFrequency(Is, **params):
    freqs=[]
    for I in Is:
        params["I"]=I
        Time,V = LIFsimulation(**params)
        first, second = np.where(V==params.get("V_fire", 20))[0][:2]
        span = (second-first)*params.get("dt", 0.1)*1e-3
        freqs.append(1/span)
    return np.asarray(freqs)

def HHsimulation(V_rest=-65, V_thre=-55, V_reset=-70, V_fire=20,
                 gl=3.0e1, gK=3.6e3, gNa=1.2e4,
                 Vl=-54.402, VK=-77.0, VNa=50.0,
                 Cm=1e2, I=0, dt=0.1, T=100):
    """Hodgkin-Huxley model. (`hh_psc_alpha`)
    I=Cm*(dVm/dt) + gl*(Vm-Vl) + gK*n^4*()
    """
    alpha_n = lambda Vm: (1e-2*(Vm+55)) / (1-np.exp(-(Vm+55)/10))
    beta_n  = lambda Vm: 0.125*np.exp(-(Vm+65)/80)
    alpha_m = lambda Vm: (0.1*(Vm+40)) / (1-np.exp(-(Vm+40)/10))
    beta_m  = lambda Vm: 4*np.exp(-(Vm+65)/18)
    alpha_h = lambda Vm: 7e-2*np.exp(-(Vm+65)/20)
    beta_h  = lambda Vm: 1 / (1+np.exp(-(Vm+35)/10))

    # Initialization
    Vm = V_rest
    Time = np.arange(0,T+dt,dt)
    V = np.zeros_like(Time)

    n = alpha_n(Vm) / (alpha_n(Vm)+beta_n(Vm))
    m = alpha_m(Vm) / (alpha_m(Vm)+beta_m(Vm))
    h = alpha_h(Vm) / (alpha_h(Vm)+beta_h(Vm))
    for i,t in enumerate(Time):
        V[i] = Vm
        dVdt = (I-gl*(Vm-Vl)-gK*(n**4)*(Vm-VK)-gNa*(m**3)*h*(Vm-VNa))/Cm
        V_plus_dV = Vm+dt*dVdt
        n += (alpha_n(Vm)*(1-n) - beta_n(Vm)*n)*dt
        m += (alpha_m(Vm)*(1-m) - beta_m(Vm)*m)*dt
        h += (alpha_h(Vm)*(1-h) - beta_h(Vm)*h)*dt
        Vm = V_reset if Vm>V_thre else V_fire if V_plus_dV > V_thre else V_plus_dV
    return Time,V

def STDPsimulation(pre, post, dt=0.1, T=100):
    Time = np.arange(0,T+dt,dt)
    X  = np.zeros_like(Time); Y  = np.zeros_like(Time)
    Pre_Neuron  = np.zeros_like(Time); Post_Neuron = np.zeros_like(Time)
    Pre_Neuron[Time == pre] = 1; Post_Neuron[Time == post] = 1
    for i in range(len(Time)-1):
        X[i+1] = X[i]*np.exp(-0.1/20)+Pre_Neuron[i]
        Y[i+1] = Y[i]*np.exp(-0.1/20)+Post_Neuron[i]
    dW = -Pre_Neuron*Y + Post_Neuron*X
    res = [
        Time,
        (Pre_Neuron,Post_Neuron,X,Y,dW),
        {
            "label": ("Pre_Neuron", "Post_Neuron", "X", "Y", "dW"),
            "color": ("red", "blue", "red", "blue", "green")
        }
    ]
    return res


import logging

import numpy as np
import scipy.stats as ss
from sklearn.metrics import mutual_info_score

def histogram2d(x, y, bins=None):
    if bins is None:
        bins = num_bins(x.shape[0], corr=np.corrcoef(x, y)[0, 1])
    histogram, *_ = np.histogram2d(x, y, bins=bins)
    return histogram

def marginal(x, bins=None):
    """
    Marginal entropy H[X] = -sum(Ni/N * log(Ni/N))
    :param x: input data
    :type x: array_like
    :param bins: the number of equal-width bins in the given range (10,
    by default)
    :type bins: int, optional
    :return: entropy is calculated as ``S = -sum(pk * log(pk), axis=axis)``.
    :rtype: float
    """
    if bins is None:
        bins = num_bins(x.shape[0])
    histogram, *_ = np.histogram(x, bins=bins)
    return ss.entropy(histogram)

def joint(x, y, bins=None):
    """
    Joint entropy H[X,Y] = H[X] + H[Y] - I[X,Y]
    :param x: X observations
    :type x: array_like
    :param y: Y observations
    :type y: array_like
    :param bins: the number of equal-width bins in the given range (10,
    by default)
    :type bins: int, optional
    :return: Joint entropy
    :rtype: float
    """
    # TODO : Use a better JE without using the mutual info function

    return marginal(x, bins=bins) + marginal(y, bins=bins) \
        - mutual_info(x, y, bins=bins)

def mutual_info(x, y, bins=None, norm=False):
    """
    Mutual Information : The informational gain in X that results from
    knowing the value of Y
    :param x: X observations
    :type x: array_like
    :param y: Y observations
    :type y: array_like
    :param bins: the number of equal-width bins in the given range (10,
    by default)
    :type bins: int, optional
    :param norm: Parameter to get the normalized version of the measure or
    not (False, by default)
    :type norm: bool, optional
    :return: Mutual Information I[X,Y] = H[X] - H[X|Y]
    :rtype:
    """

    if bins is None:
        bins = num_bins(x.shape[0], corr=np.corrcoef(x, y)[0, 1])

    mi = mutual_info_score(
        None, None, contingency=histogram2d(x, y, bins=bins)
    )

    if norm:
        return mi / min(marginal(x, bins=bins),
                        marginal(y, bins=bins))
    return mi

def conditional(x, y, bins=None):
    """
    Conditional entrop H(X|Y) = H(X,Y) - H(Y)
    :param x: X observations
    :type x: array_like
    :param y: Y observations
    :type y: array_like
    :param bins: the number of equal-width bins in the given range (None,
    by default)
    :type bins: int, optional
    :return: conditional entropy
    :rtype: float
    """
    return joint(x, y, bins=bins) - marginal(y, bins=bins)

def variation_info(x, y, bins=None, norm=False):
    """
    Variation info VI(X,Y) = H(X|Y) + H(Y|X) = H(X) + H(Y) - 2 I(X,Y)
    :param x: X observations
    :type x: array_like
    :param y: Y observations
    :type y: array_like
    :param bins: the number of equal-width bins in the given range (10,
    by default)
    :type bins: int, optional
    :param norm: Parameter to get the normalized version of the measure or
    not (False, by default)
    :type norm: bool, optional
    :return: variation info
    :rtype: float
    """
    if bins is None:
        bins = num_bins(x.shape[0], corr=np.corrcoef(x, y)[0, 1])

    i_xy = mutual_info(x, y, bins=bins)
    h_x = marginal(x, bins=bins)
    h_y = marginal(y, bins=bins)

    v_xy = h_x + h_y - 2 * i_xy
    if norm:
        h_xy = h_x + h_y - i_xy
        return v_xy / h_xy
    return v_xy

def num_bins(n_obs, corr=None):
    """
    Optimal number of bins for discretization as described in :
    Abdenour Hacine-Gharbi, Philippe Ravier, Rachid Harba, Tayeb Mohamadi,
    Low bias histogram-based estimation of mutual information for feature
    selection,
    Pattern Recognition Letters,
    Volume 33, Issue 10,
    2012,
    Pages 1302-1308,
    ISSN 0167-8655,
    https://doi.org/10.1016/j.patrec.2012.02.022.
    (http://www.sciencedirect.com/science/article/pii/S0167865512000761)
    :param n_obs: number of observations
    :type n_obs: int
    :param corr: Correlation between X, Y
    :type corr: float
    :return: Optimal number of bins
    :rtype: int
    """
    if corr is None:
        z = (8 + 324 * n_obs + 12 * (
                36 * n_obs + 729 * n_obs ** 2) ** 0.5) ** (1 / 3.)

        b = round(z / 6. + 2. / (3 * z) + 1. / 3)
    else:
        try:
            b = round(
                2 ** (-.5) * (1 + (
                        1 + 24 * n_obs / (1 - corr ** 2)) ** .5)
                ** .5)

        except (ZeroDivisionError, OverflowError):
            logging.error(
                f"To use the optimal bining for joint entropy, "
                f"the correlation should not be equal to 1 or -1. "
                f"The correlation given is equal to {corr}"
            )
            return num_bins(n_obs)

    return int(b)


import numpy as np

def leastsq(x: np.ndarray, y: np.ndarray, sigma:float)-> list:
    """ Computes the least squares of the 1D vectors x and y.

    Raises:
        ValueError: If the lengths of the arrays are not equal.
        ValueError: If the array x is empty. It is checked after the lengths so y would also be empty.

    Returns:
        tuple(2,2): Returns a tuple containing two tuples.
            The first one contains at position 0 the slope (m in literature) and at position 1 its error.
            The second one contains at position 0 the y-intercept (b in literature) and at position 1 its error.
    """
    n = len(x)

    if n != len(y):
        raise ValueError(f'Length of the data array must be equal, length of x is {n} and y is {len(y)}. Please check. ')

    if n == 0:
        raise ValueError(f'Arrays cannot be empty. Please check.')

    sum_x, sum_y = sum(x), sum(y)
    sum_x2 = sum(x*x)
    sum_xy = sum(x*y)

    div = 1 / (sum_x**2 - n*sum_x2)
    m = (sum_x*sum_y - n*sum_xy) * div
    b = (sum_x*sum_xy - sum_xy*sum_x2) * div

    m_e = np.sqrt( n*sigma**2 * (-1) * div )
    b_e = np.sqrt( sum_x2*sigma**2 * (-1) * div )

    return (m,m_e), (b, b_e)

if __name__ == '__main__':

    x = eval('['+ input("Introduce x data separated by ,:") + ']')
    y = eval('['+ input("Introduce y data separated by ,:") + ']')

    sigma = float(input("Introduce Sigma: "))

    leastsq = leastsq(np.array(x), np.array(y), sigma)

    print(f'm={leastsq[0][0]}  m_error={leastsq[0][1]} \n b={leastsq[1][0]}  b_error={leastsq[1][1]}')


from scipy.spatial import Delaunay
import numpy as np
import matplotlib.pyplot as plt

def find_points(first_point, second_point, third_point, fourth_point, count):
  """
  First point: left bottom
  Second point: left up
  Third point: right up
  fourth_point: right bottom
  suppose the points creates a rectangular
  """
  x_difference = third_point[0] - second_point[0]
  y_difference = third_point[1] - fourth_point[1]
  points_array = []

  i = first_point[1]
  j = first_point[0]
  x_count = x_difference/count
  y_count = y_difference/count

  while i <= y_difference:
    while j <= x_difference:
      points_array.append([j, i])

      if j < third_point[0]:
        if i < third_point[1]:
          points_array.append([j+(x_count/2), i+(y_count/2)])

      j += x_count

    i += y_count
    j = first_point[0]
  return points_array

a = find_points([0,0], [0,1], [1,1], [1,0], 3)
points = np.array(a)
print(points)

tri = Delaunay(points)
plt.triplot(points[:,0], points[:,1], tri.simplices)
plt.plot(points[:,0], points[:,1], 'o')

# plt.xlim(-0.5, 1.5); plt.ylim(-0.5, 1.5)
plt.show()


import numpy as np
from copy import deepcopy
import random
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.patches as mpatches

from envs.gridworld.grid import Grid, PlayableGrid, get_new_state

STATE_SPACE = [(x, y) for x in range(10) for y in range(10)]
# Update state space by removing wall positions and finish position
for wall_position in Grid.WALL_POSITIONS:
    STATE_SPACE.remove(wall_position)
STATE_SPACE.remove((0, 9))

def value_iteration() -> np.ndarray:
    grid = Grid()

    # Initialise variables
    theta = 0.5
    value_fn = np.array([np.zeros(10)] * 10)

    while True:
        delta = 0
        for state in STATE_SPACE:
            prev_value = value_fn[state]
            possible_actions = grid.find_possible_actions(state)
            outcome_states = [
                get_new_state(state, action) for action in possible_actions
            ]
            rewards = [
                grid.get_reward(state) + value_fn[outcome_state]
                for outcome_state in outcome_states
            ]
            value_fn[state] = max(rewards)
            delta = max(delta, prev_value - value_fn[state])
        if delta < theta:
            break

    print("value function: \n", value_fn)
    return value_fn

def policy_iteration() -> np.ndarray:
    grid = Grid()

    # Initialise variables
    theta = 1
    value_fn = np.array([np.zeros(10)] * 10)
    policy = np.array(
        [[grid.find_possible_actions((y, x)) for x in range(10)] for y in range(10)]
    )

    policy_unchanged = False
    while not policy_unchanged:
        # Policy evaluation
        while True:
            delta = 0
            for state in STATE_SPACE:
                prev_value = value_fn[state]
                outcome_states = [
                    get_new_state(state, action) for action in policy[state]
                ]
                outcome_values = [value_fn[state] for state in outcome_states]
                value_fn[state] = grid.get_reward(state) + (
                    1 / len(outcome_values)
                ) * sum(outcome_values)
                delta = max(delta, abs(prev_value - value_fn[state]))
            if delta < theta:
                print("\n Policy evaluated succesfully!")
                break
        visualise_value_fn(value_fn)

        # Policy improvement
        policy_unchanged = True
        for state in STATE_SPACE:
            prev_action = policy[state]
            possible_actions = grid.find_possible_actions(state)
            outcome_states = [
                get_new_state(state, action) for action in possible_actions
            ]
            outcome_values = np.array(
                [
                    grid.get_reward(state) + value_fn[outcome_state]
                    for outcome_state in outcome_states
                ]
            )
            action_ref = np.where(outcome_values == max(outcome_values))[0]
            policy[state] = possible_actions[action_ref]
            policy_unchanged = (
                np.all(prev_action == policy[state]) if policy_unchanged else False
            )
        print("\n Policy improved succesfully!")

    print("value function: \n", value_fn)
    return value_fn

def visualise_value_fn(value_fn: np.ndarray):
    value_fn = deepcopy(value_fn)
    nrows, ncols = value_fn.shape
    values = np.linspace(np.min(value_fn), np.max(value_fn), num=9)
    value_fn[np.where(value_fn == 0)] = None
    value_fn[0, 9] = 0

    im = plt.imshow(
        value_fn,
        extent=(0, nrows, 0, ncols),
        interpolation="nearest",
        cmap=cm.gist_rainbow,
    )
    # get the colors of the values, according to the
    # colormap used by imshow
    colors = [im.cmap(im.norm(value)) for value in reversed(values)]
    # create a patch (proxy artist) for every color
    patches = [
        mpatches.Patch(color=colors[i], label=f"{np.round(values[-(i + 1)], 1)}")
        for i in range(len(values))
    ]
    # put those patched as legend-handles into the legend
    plt.legend(handles=patches, bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.0)
    plt.xlabel("x Position")
    plt.ylabel("y Position")
    plt.show()

def main():
    value_function = policy_iteration()
    playable_grid = PlayableGrid()
    path_taken = np.array([["0"] * 10] * 10)
    path_taken[0, 9] = "F"
    path_taken[9, 0] = "S"

    while True:
        possible_actions = playable_grid.find_possible_actions(
            playable_grid.agent_state
        )
        outcome_states = [
            get_new_state(playable_grid.agent_state, action)
            for action in possible_actions
        ]
        rewards = [
            playable_grid.get_reward(playable_grid.agent_state)
            + value_function[outcome_state]
            for outcome_state in outcome_states
        ]
        best_actions = [
            action
            for action, reward in zip(possible_actions, rewards)
            if reward == max(rewards)
        ]
        action_chosen = random.choice(best_actions)
        playable_grid.take_action(action_chosen)
        if playable_grid.done:
            break
        symbol = "-" if action_chosen in [(0, 1), (0, -1)] else "|"
        path_taken[playable_grid.agent_state] = symbol

    print("final reward = ", playable_grid.agent_reward)
    print("final state = ", playable_grid.agent_state)
    print("Path: \n", path_taken)

if __name__ == "__main__":
    main()


#!/usr/bin/env python3
import matplotlib.pyplot as plt
import numpy as N

def main(dt=1e-1, R=4, T=1):
    """Example linear stochastic differential equation:
    λX(t) dt + μX(t)dW(t)
    """
    # The number of points in weiner process we need
    wN = int(N.ceil(T/dt))
    # First get the random numbers needed to make the weiner process.
    dWt = N.sqrt(dt) * N.random.randn(wN-1)
    W = N.cumsum(dWt)
    W = N.insert(W, 0, 0)

    ld = 2
    mu = 1

    # Euler-Maruyama solution
    # Xⱼ = Xⱼ₋₁ + Δt ⋆ (λ ⋆ Xⱼ₋₁) + μ ⋆ Xⱼ₋₁ ⋆ (Wⱼ - Wⱼ₋₁)
    # Wⱼ = W[Δt⋆j⋆R]
    # Δt = R⋆dt, this is done to make life easy for ourselves.

    Dt = R * dt
    X = 1                       # Initial value X(0)
    Xm = 1
    vso = [X]
    vsm = [Xm]
    vdt = [X]
    tso = [0]
    Xd = 1
    vs = [Xd]

    for j in range(0, int(wN/R)):
        part_sum = sum(dWt[(j*R):((j+1)*R)])
        # EM
        X = X + (Dt * (ld * X)) + (mu * X * part_sum)
        vso.append(X)
        tso.append(dt*R*j)

        # This is with a large step already, using W(ⱼ - Wⱼ₋₁) = sqrt(Δ
        # t) N(0,1)
        vdt.append(vdt[-1] + (Dt * ld * X) +
                   (mu * X * N.sqrt(Dt) * N.random.rand()))

        # Milstein's method, with partial derivative.
        Xm = (Xm + (Dt * (ld * X)) + (mu * Xm * part_sum)
              + 0.5*mu**2*Xm*((part_sum**2) - Dt))
        vsm.append(Xm)

        # Deterministic
        Xd = Xd + Dt * Xd * ld
        vs.append(Xd)

    plot_dict = dict()
    plot_dict['t'] = tso
    plot_dict['vsm'] = vsm
    plot_dict['vdt'] = vdt

    # This is the real closed form solution
    Xtruet = N.arange(0, T, dt)
    Xtrue = N.exp((ld-0.5*mu**2)*(Xtruet+mu*W))
    plt.plot(Xtruet, Xtrue)
    plt.plot(tso, vso, marker='1')
    plt.plot(plot_dict['t'], plot_dict['vsm'], marker='2')
    plt.plot(plot_dict['t'], plot_dict['vdt'], marker='*')
    plt.plot(tso, vs, marker='3')
    plt.show()

if __name__ == '__main__':
    # N.random.seed(100)            # Remove this later on
    for i in range(10):
        main(dt=(1/2**8), R=4, T=2)


try:
    from scipy.special import erf as _erf
    from numpy import euler_gamma as _euler_gamma
    import numpy as _np
    from typing import Union, Dict, List
    from math import sqrt as _sqrt, log as _log, pi as _pi, exp as _exp
    from univariate._base import SemiInfinite
except Exception as e:
    print(f"some modules are missing {e}")

class MaxwellBoltzmann(SemiInfinite):
    """
    This class contains methods concerning Maxwell-Boltzmann Distirbution [#]_.

    .. math::
        \\text{MaxwellBoltzmann}(x;a) = \\sqrt{\\frac{2}{\\pi}} \\frac{x^2 \\exp{-x^2/(2a^2)}}{a^3}

    Args:

        a(int): parameter where a > 0
        x(float): random variable where x >= 0

    Reference:
        .. [#] Wikipedia contributors. (2021, January 12). Maxwell–Boltzmann distribution. https://en.wikipedia.org/w/index.php?title=Maxwell%E2%80%93Boltzmann_distribution&oldid=999883013
    """

    def __init__(self, a: int):
        if a < 0:
            raise ValueError(
                'parameter a should be a positive number. Entered value:{}'.format(a))
        if type(a) is not int:
            raise TypeError('parameter should be in type int')

        self.a = a

    def pdf(self, x: Union[List[float], _np.ndarray, float]) -> Union[float, _np.ndarray]:
        """
        Args:
            x (Union[List[float], _np.ndarray, float]): random variable(s)

        Raises:
            ValueError: when there exist a value of x less than 0

        Returns:
            Union[float, _np.ndarray]: evaluation of pdf at x
        """
        a = self.a

        if isinstance(x, (_np.ndarray, List)):
            if not type(x) is _np.ndarray:
                x = _np.array(x)
            if _np.any(x < 0):
                raise ValueError('random values must not be lesser than 0')
            return _sqrt(2/_pi)*(x**2*_np.exp(-x**2/(2*a**2)))/a**3

        if x < 0:
            raise ValueError('random values must not be lesser than 0')
        return _sqrt(2/_pi)*(x**2*_exp(-x**2/(2*a**2)))/a**3

    def cdf(self, x: Union[List[float], _np.ndarray, float]) -> Union[float, _np.ndarray]:
        """
        Args:
            x (Union[List[float], _np.ndarray, float]): data point(s) or interest

        Returns:
            Union[float, _np.ndarray]: evaluation of cdf at x
        """
        a = self.a

        if isinstance(x, (_np.ndarray, List)):
            if not type(x) is _np.ndarray:
                x = _np.array(x)
            x0 = _np.power(x, 2)
            return _erf(x/(_sqrt(2)*a))-_sqrt(2/_pi)*(x0*_np.exp(-x0/(2*a**2)))/(a)

        return _erf(x/(_sqrt(2)*a)) - _sqrt(2/_pi)*(x**2*_exp(-x**2/(2*a**2)))/(a)

    def mean(self) -> float:
        """
        Returns: Mean of the Maxwell-Boltzmann distribution.
        """
        return 2*self.a*_sqrt(2/_pi)

    def median(self) -> Union[float, str]:
        """
        Returns: Median of the Maxwell-Boltzmann distribution.
        """
        return "currently unsupported"

    def mode(self) -> float:
        """
        Returns: Mode of the Maxwell-Boltzmann distribution.
        """
        return _sqrt(2)*self.a

    def var(self) -> float:
        """
        Returns: Variance of the Maxwell-Boltzmann distribution.
        """
        return (self.a**2*(3*_pi-8))/_pi

    def std(self) -> float:
        """
        Returns: Standard deviation of the Maxwell-Boltzmann distribution
        """
        return _sqrt((self.a**2*(3*_pi-8))/_pi)

    def skewness(self) -> float:
        """
        Returns: Skewness of the Maxwell-Boltzmann distribution.
        """
        return (2*_sqrt(2)*(16-5*_pi))/_np.power((3*_pi-8), 3/2)

    def kurtosis(self) -> float:
        """
        Returns: Kurtosis of the Maxwell-Boltzmann distribution.
        """
        return 4*((-96+40*_pi-3*_pi**2)/(3*_pi-8)**2)

    def entropy(self) -> float:
        """
        Returns: differential entropy of the Maxwell-Boltzmann distribution.

        Reference: Park, S.Y. & Bera, A.K.(2009). Maximum entropy autoregressive conditional heteroskedasticity model. Elsivier.
        link: http://wise.xmu.edu.cn/uploadfiles/paper-masterdownload/2009519932327055475115776.pdf
        """
        a = self.a
        return _log(a*_sqrt(2*_pi)+_euler_gamma-0.5)

    def summary(self) -> Dict[str, Union[float, str]]:
        """
        Returns:
            Dictionary of Maxwell-Boltzmann distirbution moments. This includes standard deviation.
        """
        return {
            'mean': self.mean(), 'median': self.median(), 'mode': self.mode(),
            'var': self.var(), 'std': self.std(), 'skewness': self.skewness(), 'kurtosis': self.kurtosis()
        }


"""
Author: Towaha
Email: soft@hotmail.co.uk
"""
import numpy as np
import sys
sys.path.append("..")
from libs.utils import load_dataset_mnist, preprocess_data, Trainer
from libs.mnist_lib import MNIST
from optimizations_algorithms.optimizers import SGD
from nn_components.activations import softmax
from nn_components.losses import CrossEntropy

class SoftmaxRegression:

    def __init__(self, feature_dim:int, num_classes:int, optimizer:object, loss_func:object=CrossEntropy()):
        """
        Constructor for softmax regression. It can be seen as the simplest neural network with input layer and output layer.
        Parameter
        ---------
        feature_dim: (int) dimension of input feature.
        num_classes: (int) number of output classes.
        optimizer: (object) optimizer used to optimize loss w.r.t W.
        loss_func: (object) the type of loss function to optimize.
        """
        self.loss_func = loss_func
        self.optimizer = optimizer
        self.W = np.random.normal(size=(feature_dim, num_classes))

    def _forward(self, X:np.ndarray):
        """
        Compute softmax transformation.
            LINEAR: Z = X.dot(W)
            SOFTMAX: A = softmax(Z)
        Returns
        -------
        Softmax: e^z / sum(e^z).
            Shape = (N, num_class)
        """
        Z = X.dot(self.W)
        A = softmax(Z)
        return A

    def backward(self, Y:np.ndarray, Y_hat:np.ndarray, X:np.ndarray):
        """
        Compute gradient matrix.
        Parameters
        ----------
        X: training set.
            Shape = (N, D).
        y: training one-hot label vectors.
            Shape = (N, num_class).
        y_hat: predicted probabilities.
            Shape = (N, num_class).
        Returns
        -------
        Gradient of cross entropy loss respect to W: 1/N*(X.T.dot(Y_hat - Y))
            Shape = (D, num_class).
        """
        dZ = self.loss_func.backward(Y_hat, Y)
        dW = X.T.dot(dZ)
        dW = self.optimizer.minimize(dW)
        self.W = self.W - dW

    def __call__(self, X:np.ndarray):
        return self._forward(X)

    def predict(self, X_test:np.ndarray):
        return np.argmax(X_test.dot(self.W), axis=-1)

if __name__ == '__main__':
    load_dataset_mnist("../libs")
    mndata = MNIST('../libs/data_mnist')

    images, labels = mndata.load_training()
    images, labels = preprocess_data(images, labels)
    optimizer = SGD(0.01)
    batch_size = 64
    epochs = 20
    loss_func = CrossEntropy()

    softmax_regression = SoftmaxRegression(feature_dim=images.shape[1], num_classes=labels.shape[1], optimizer=optimizer, loss_func=loss_func)

    trainer = Trainer(softmax_regression, batch_size, epochs)
    trainer.train(images, labels)

    images_test, labels_test = mndata.load_testing()
    images_test, labels_test = preprocess_data(images_test, labels_test, test=True)

    pred = softmax_regression.predict(images_test)

    print("Accuracy:", len(pred[labels_test == pred]) / len(pred))
    from sklearn.metrics.classification import confusion_matrix

    print("Confusion matrix: ")
    print(confusion_matrix(labels_test, pred))


# -*- coding: utf-8 -*-
# @Author: Juan Quintana
# @Date:   2018-09-12 16:41:39
# @Last Modified by:   Juan Quintana
# @Last Modified time: 2018-09-25 17:39:34

import numpy as np
from pandas import read_csv
from scipy.stats import multivariate_normal
from sklearn.preprocessing import MinMaxScaler

def estimateGaussian(dataset):
    mu = np.mean(dataset, axis=0)
    sigma = np.cov(dataset.T)
    return mu, sigma

def multivariateGaussian(dataset, mu, sigma):
    p = multivariate_normal(mean=mu, cov=sigma)
    return p.pdf(dataset)

# outliers detection using a Multi-Gaussian method for dataframe data
def launch_df(data: 'df', threshold: float, snamex: str, snamey: str, isdeep: bool=False)->tuple:
    """
    Outliers detection using a Multi-Gaussian method.
    data -- dataframe with the columns to be checked.
    threshold -- threshold to be used to select the anomalous data.
    snamex -- column name of the first column data.
    snamey -- column name of the second column data.
    isdeep -- display or not information and draw a plot (default False)
    return -- tuple(dataframe with a new column 'isoutlier' where is labeled outliers / non outliers., basic info into a dict)
    """

    # validate column name arguments
    if not snamex in data.columns.tolist():
        print('[error] "%s" column do not exists into the dataframe.' % snamex)
        return None
    if not snamey in data.columns.tolist():
        print('[error] "%s" column do not exists into the dataframe.' % snamey)
        return None

    #  min max scaler
    scaler = MinMaxScaler()
    tr_data = scaler.fit_transform(data[[snamex, snamey]].as_matrix())

    # dimessions
    n_samples = tr_data.shape[0]
    n_dim = tr_data.shape[1]
    if isdeep:
        print('[info] Number of datapoints: %d' % n_samples)
        print('[info] Number of dimensions/features: %d' % n_dim)
        print('[info] Outliers will be identify according to "%s" and "%s"' % (snamex, snamey))

    # calculate multivariable gaussian distribution
    mu, sigma = estimateGaussian(tr_data)
    p = multivariateGaussian(tr_data, mu, sigma)

    # selecting outlier datapoints
    outliers = np.asarray(np.where(p < threshold))

    # display
    if isdeep:
        print('[info] Threshold = %s' % threshold)
        print('[info] Number of Outliers = %s (%.3f%s)' % (len(outliers[0]), len(outliers[0])*100./n_samples, '%'))
    # store information
    dinfo = {'threshold': threshold, 'num_outliers': len(outliers[0]), 'percent_outliers': len(outliers[0])*100./n_samples}

    # set label of is outlier or not
    data['isoutlier'] = np.ones(n_samples) * False
    data['isoutlier'].iloc[outliers[0]] = np.ones(len(outliers[0])) * True
    data['isoutlier'] = data['isoutlier'].astype(int)

    # store final chart
    if isdeep:
        import matplotlib.pyplot as plt
        fig, ax = plt.subplots(figsize=(5, 5))
        plt.xlabel('%s' % snamex)
        plt.ylabel('%s' % snamey)
        plt.plot(tr_data[:, 0], tr_data[:, 1], 'bx')
        plt.plot(tr_data[outliers, 0], tr_data[outliers, 1], 'ro')
        plt.title('Number of Outliers = %s (%.3f%s)\nThreshold = %s' %
                  (len(outliers[0]), len(outliers[0])*100./n_samples, '%', threshold), fontsize=14)
        ax.set_xlim([0., 1.])
        ax.set_ylim([0., 1.])
        plt.plot()
    # return
    return (data, dinfo)

# outliers detection using a Multi-Gaussian method for array data
def launch_array(data: 'array', threshold: float, isdeep: bool=False)->tuple:
    """
    Outliers detection using a Multi-Gaussian method.
    data -- array with the columns to be checked.
    threshold -- threshold to be used to select the anomalous data.
    isdeep -- display or not information and draw a plot (default False)
    return -- tuple(array with a new column 'isoutlier' where is labeled outliers / non outliers., basic info into a dict)
    """

    #  min max scaler
    scaler = MinMaxScaler()
    tr_data = scaler.fit_transform(data)

    # dimessions
    n_samples = tr_data.shape[0]
    n_dim = tr_data.shape[1]
    if isdeep:
        print('[info] Number of datapoints: %d' % n_samples)
        print('[info] Number of dimensions/features: %d' % n_dim)

    # calculate multivariable gaussian distribution
    mu, sigma = estimateGaussian(tr_data)
    p = multivariateGaussian(tr_data, mu, sigma)

    # selecting outlier datapoints
    outliers = np.asarray(np.where(p < threshold))

    # display
    if isdeep:
        print('[info] Threshold = %s' % threshold)
        print('[info] Number of Outliers = %s (%.3f%s)' % (len(outliers[0]), len(outliers[0])*100./n_samples, '%'))
    # store information
    dinfo = {'threshold': threshold, 'num_outliers': len(outliers[0]), 'percent_outliers': len(outliers[0])*100./n_samples}

    # set label of is outlier or not
    isoutlier = np.ones(n_samples) * False
    isoutlier[outliers[0]] = np.ones(len(outliers[0])) * True

    # store final chart
    if isdeep:
        import matplotlib.pyplot as plt
        fig, ax = plt.subplots(figsize=(5, 5))
        plt.xlabel('v1')
        plt.ylabel('v2')
        plt.plot(tr_data[:, 0], tr_data[:, 1], 'bx')
        plt.plot(tr_data[outliers, 0], tr_data[outliers, 1], 'ro')
        plt.title('Number of Outliers = %s (%.3f%s)\nThreshold = %s' %
                  (len(outliers[0]), len(outliers[0])*100./n_samples, '%', threshold), fontsize=14)
        ax.set_xlim([0., 1.])
        ax.set_ylim([0., 1.])
        plt.plot()
    # return
    return (np.c_[data, isoutlier], dinfo)


import numpy as np
from scipy.interpolate import interp1d

# convenience function: return interpolator that extends boundary values
def myinterp(x, y):
    return interp1d(x, y, bounds_error=False, fill_value=(y[0], y[-1]))

# calculate coefficients of a polynomial that fits x, y points
# the polynomial order is len(x)-1 (e.g., 3 points yields quadratic)
def calc_piecewise_poly(u, order=3, W=None, strategy='overlap'):
    # solve the linear system of equations
    if W is None:
        W = calc_interp_w(npts=len(u), order=order, strategy=strategy)

    # generate coefficients
    U = (W*u).sum(axis=2)

    # return coefficients
    return U

# calculate the tensor, "W", that maps input points
# to coefficients of polynomial segments.  w[j, k, i] maps
# the i-th spline point to the k-th coefficient of the
# j-th polynomial segment.
def calc_interp_w(npts, order=3, strategy='overlap'):
    # set up equations
    if strategy == 'overlap':
        A, B = ovl_pwp_mats(npts=npts, order=order)
    else:
        raise Exception(f'Unknown strategy: {strategy}')

    # solve the equations
    C = np.linalg.solve(A, B)

    # fill in the W tensor
    W = np.zeros((npts, order+1, npts), dtype=float)
    W[:-1, :, :] = C.reshape((npts-1, order+1, npts))

    # a final PWC segment is included for make the math easier
    W[-1, 0, -1] = 1

    # return W tensor
    return W

# return matrices for piecewise-polynomial fit
def ovl_pwp_mats(npts, order):
    # create empty equation matrices
    A = np.zeros(((npts-1)*(order+1), (npts-1)*(order+1)), dtype=float)
    B = np.zeros(((npts-1)*(order+1), npts), dtype=float)

    # for the middle of the curve, how many points should
    # match below the starting point (tgt_lo) and above (tgt_hi)
    tgt_lo = order//2
    tgt_hi = order-tgt_lo

    # build up the equations
    idx = 0
    for i in range(npts-1):
        # figure out the starting and stopping matching points
        if (i-tgt_lo) < 0:
            lo = 0
            hi = lo + order
        elif (i+tgt_hi) > (npts-1):
            hi = npts-1
            lo = hi-order
        else:
            lo = i-tgt_lo
            hi = i+tgt_hi

        # add equations for each point
        offset = i*(order+1)
        for j in range(lo, hi+1):
            A[idx, offset:(offset+order+1)] = eval_poly(j-i, order=order)
            B[idx, j] = 1
            idx += 1

    return A, B

# evaluate a polynomial; return a such that
# a[k] = x^k
# sum(ak*x^k, 0, order) == sum(bk*x^k, 0, order)
def eval_poly(x, order):
    return x**np.arange(order+1)

# evaluate a piecewise polynomial waveform
# U[i, j] is the ith segment, jth coefficient (i.e., jth power)
def eval_piecewise_poly(t, th, U):
    # convert t to a numpy array if needed
    t = np.array(t)

    # calculate coefficient indices and remainders
    ivec = np.floor(t/th).astype(int)
    rvec = (t-(ivec*th))/th

    # sum contributions from each polynomial order
    pows = rvec[..., np.newaxis]**np.arange(U.shape[1])
    retval = (U[ivec, :]*pows).sum(axis=len(pows.shape)-1)

    # return result
    return retval


#Imports
from scipy.integrate import dblquad

#Constants
LowerLimit_x = 0.0
UpperLimit_x = 10.0

LowerLimit_y = 0.0
UpperLimit_y = 10.0

#Defining Function
def function(x,y):
	return (x**2)+(y**2)

# Turning the constants into a function. (Makes the code work).
def Lfy(x):
	return LowerLimit_y
def Ufy(x):
	return UpperLimit_y

#Using Scipy.Integrate.dblQuad inputs of the function, the lower integration limit and the upper integration limit
Answer = dblquad(function,LowerLimit_x,UpperLimit_x,Lfy,Ufy)

#Returns the Definite intergral and an estimate of the absolute error in an array
#Answer[0] (first term) = The numerical value for the integration
#Answer[1] (second term) = The Error on your integration
print Answer


import numpy as np
import matplotlib.pyplot as plt
import csv
import math
import random
from scipy import stats

def csv_dict_writer(path):
    csv_dict = []
    with open(path, encoding='utf-8') as r_file:
        file_reader = csv.reader(r_file, delimiter=",")
        for row in file_reader:
            csv_dict = list(map(float, row))
    return csv_dict

def get_mu(data):
    s = 0
    for val in data:
        s += val
    s /= len(data)
    return s

def get_disp(mu, data):
    disp = 0
    for item in data:
        disp += ((item - mu)**2)
    disp /= (len(data)-1)
    return disp

def plotting_histogram(data):
    domain = np.arange(min(data), max(data))
    n, autobins, patches = plt.hist(data, density=1, bins=len(domain),
                                    color='green')  # density=False would make counts
    plt.ylabel('Probability')
    plt.xlabel('Data')
    n = n*(autobins[1]-autobins[0])
    return n

def binom(n, k):
    return math.factorial(n) // math.factorial(k) // math.factorial(n - k)

def normal_distribution(data):
    mu = get_mu(data)
    disp = get_disp(mu, data)
    sigma = np.sqrt(disp)
    #domain = np.linspace(min(data), max(data), 1000)
    domain = np.arange(min(data), max(data))
    y_deduced = ((1 / (np.sqrt(2 * np.pi) * sigma)) *
                 np.exp(-0.5 * (1 / sigma * (domain - mu))**2))
    plt.plot(domain, y_deduced, '-', color='red', label='normal')
    return y_deduced

def exp_distribution(data):
    lambda_mu = 1 / get_mu(data)
    lambda_disp = 1 / np.sqrt(get_disp(get_mu(data), data))
    #domain = np.linspace(0, max(data), 1000)
    domain = np.arange(0, max(data))
    y_deduced = lambda_disp * np.exp(-lambda_disp * domain)
    plt.plot(domain+1, y_deduced, '--', color='cyan', label='exponential')
    return y_deduced

def geometric_distribution(data):
    p = 1 / get_mu(data)
    if min(data) < 0:
        x = np.arange(0, int(max(data)))
    else:
        x = np.arange(int(min(data)), int(max(data)))
    y_deduced = []
    for item in x:
        y_deduced.append(((1-p)**item)*p)
    plt.plot(x, y_deduced, color='magenta', label='geometric')
    return y_deduced

def poisson_distribution(data):
    mu = get_mu(data)
    if min(data) < 0:
        x = np.arange(0, int(max(data)))
    else:
        x = np.arange(int(min(data)), int(max(data)))
    y_deduced = []
    for item in x:
        y_deduced.append(np.exp(-mu) * mu**item / math.factorial(item))
    plt.plot(x, y_deduced, '-', color='pink', label='poisson')
    return y_deduced

def binomial_distribution(data):
    mu = get_mu(data)
    value = int(max(data))
    p = mu / value
    domain = np.linspace(min(data), max(data), value)
    y_deduced = []
    for i in range(value):
        y_deduced.append(binom(value, i) * p**i * (1-p)**(value - i))

    plt.plot(domain, y_deduced, '-', color='orange', label='binomial')
    return y_deduced

def unifrom_distribution(data):
    a = min(data)
    b = max(data)
    points_num = 100
    y = 1 / (b-a)
    domain = np.linspace(a, b, points_num)
    plt.plot(domain, [y]*points_num, '--', color='black', label='uniform')
    return [y]*points_num

def t_test(data, left, right):
    mo = get_mu(data)
    sigma = np.sqrt(get_disp(mo, data))
    t = (mo - left) / sigma
    result = stats.t.cdf(t, len(data)-1)
    print(f"p-value:{result}\n")

def chi_square(emperal, teoretic, text):
    result = 0
    for item in range(len(emperal)):
        result += (emperal[item]-teoretic[item])**2/teoretic[item]
    print(f"Кси квадрат для {text} распределения: {result}")
    #print(stats.chisquare(res), "\n")

'''
def chi2_contingency(data1, data2):
    chi2, prob, df, expected = stats.chi2_contingency([[data1], [data2]])
    output = "test Statistics: {}\ndegrees of freedom: {}\np-value: {}\n"
    print(output.format(chi2, df, prob))

'''

"""def test(data1, data2):
    stat, p, dof, expected = stats.chi2_contingency([data1,data2])
    print('dof=%d' % dof)
    #print(expected)
    # interpret test-statistic'''
    prob = 0.95
    critical = stats.chi2.ppf(prob, dof)
    print('probability=%.3f, critical=%.3f, stat=%.3f' %
          (prob, critical, stat))
    if abs(stat) >= critical:
        print('Dependent (reject H0)')
    else:
        print('Independent (fail to reject H0)')
    # interpret p-value'''
    prob = 0.95
    alpha = 1.0 - prob
    print('significance=%.3f, p=%.3f' % (alpha, p))
    if p <= alpha:
        print('Dependent (reject H0)')
    else:
        print('Independent (fail to reject H0)')"""

def anaylize_data(data, name):
    mo = get_mu(data)
    disp = np.sqrt(get_disp(mo, data))
    interval_estimation_left = mo - np.sqrt(get_disp(mo, data))
    interval_estimation_right = mo + np.sqrt(get_disp(mo, data))
    plt.vlines(mo, ymin=0, ymax=0.3, linestyles='-',
               color='blue', label='point estimate')
    plt.vlines(interval_estimation_left, ymin=0, ymax=0.3,
               linestyles='dotted', color='blue', label='interval estimate')
    plt.vlines(interval_estimation_right, ymin=0,
               ymax=0.3, linestyles='dotted', color='blue')
    print(
        f"Точечная оценка:{get_mu(data)}\nИнтервальная оценка [{interval_estimation_left}|{interval_estimation_right}]")
    t_test(data, interval_estimation_left, interval_estimation_right)

    '''1)normal 2)exponential 3)geometric'''
    n = plotting_histogram(data)
    val = []
    names = ['normal', 'exponential', 'binomial',
             'uniform', 'poisson', 'geomtric']
    val.append(normal_distribution(data))  # 0
    val.append(exp_distribution(data))  # 1
    val.append(binomial_distribution(data))  # 2
    val.append(unifrom_distribution(data))  # 3
    val.append(poisson_distribution(data))  # 4
    val.append(geometric_distribution(data))  # 5
    #for item in range(len(val)):
    #    chi_square(n, val[item], text=names[item])
    #chi_square(n, val[0])
    # test(n,val[0])
    plt.legend()
    plt.savefig(f'{name}.png')
    plt.show()
    plt.cla()

if __name__ == '__main__':
    data1 = csv_dict_writer('set_1.csv')
    data2 = csv_dict_writer('set_2.csv')
    data3 = csv_dict_writer('set_3.csv')
    anaylize_data(data1, '1')
    anaylize_data(data2, '2')
    anaylize_data(data3, '3')


import sys
import numpy as np
import matplotlib.pyplot as plt
sys.path.append("..")
from utils import *
from linear_regression import *
from svm import *
from softmax import *
from features import *
from kernel import *

##Given the following parameters
X = np.array([
        [1, 2, 3],
        [2, 4, 6],
        [3, 6, 9],
        [4, 8, 12],
    ])
n_components = 2
##Understanding Principal Components Analysis. These two functions were given.
def center_data(X):
    feature_means = X.mean(axis=0)
    return (X - feature_means), feature_means

def principal_components(centered_data):
    scatter_matrix = np.dot(centered_data.transpose(), centered_data)
    eigen_values, eigen_vectors = np.linalg.eig(scatter_matrix)
    # Re-order eigenvectors by eigenvalue magnitude:
    idx = eigen_values.argsort()[::-1]
    eigen_values = eigen_values[idx]
    eigen_vectors = eigen_vectors[:, idx]
    return eigen_vectors

def project_onto_PC(X, pcs, n_components, feature_means):
    x_centered, feature_means = center_data(X)
    n,m = X.shape
    X_pca = np.dot(x_centered, pcs)
    return X_pca[0:n, 0:n_components]

##Trying the MINST regression using the given components
train_x, train_y, test_x, test_y = get_MNIST_data()

def center_data(X):
    feature_means = X.mean(axis=0)
    return (X - feature_means)

def principal_components(centered_data):
    scatter_matrix = np.dot(centered_data.transpose(), centered_data)
    eigen_values, eigen_vectors = np.linalg.eig(scatter_matrix)
    # Re-order eigenvectors by eigenvalue magnitude:
    idx = eigen_values.argsort()[::-1]
    eigen_values = eigen_values[idx]
    eigen_vectors = eigen_vectors[:, idx]
    return eigen_vectors

#principal_components(center_data(train_x))
def project_onto_PC(X, n_components):
    data_centered = center_data(X)
    pcs= principal_components(data_centered)
    x_centered = center_data(X)
    n,m = X.shape
    X_pca = np.dot(x_centered, pcs)
    return X_pca[0:n, 0:n_components]

test_x_pca = project_onto_PC(test_x, n_components)
train_x_pca= project_onto_PC(train_x, n_components)

def run_softmax_on_MNIST_using_PCA(temp_parameter=1):
    n_components = 18
    train_x, train_y, test_x, test_y = get_MNIST_data()
    train_x_pca = project_onto_PC(train_x, n_components)
    test_x_pca = project_onto_PC(test_x, n_components)
    theta, cost_function_history = softmax_regression(train_x_pca, train_y,
                                                      temp_parameter, alpha=0.3,
                                                      lambda_factor=1.0e-4, k=10,
                                                      num_iterations=150)
    plot_cost_function_over_time(cost_function_history)
    test_error = compute_test_error(test_x_pca,
                                    test_y, theta,
                                    temp_parameter)
    return test_error

print('softmax PCA using test_error=', run_softmax_on_MNIST_using_PCA(temp_parameter=1))

##Dimensionality Reduction using Principal Component Analysis-- Other Approach
train_x_centered, feature_means = center_data(X)
pcs = principal_components(train_x_centered)

##Mean of each feature
feature_means= np.mean(X, axis=0)

##Center of the data
data_center= X - feature_means

##Covariance of the matrix in order to check the covariance score for each column with respect to the actual column
cov_matrix= np.cov(data_center)
eigenval, eigenvec = np.linalg.eig(cov_matrix)
significance = [np.abs(i)/np.sum(eigenval) for i in eigenval]

#Plotting the Cumulative Summation of the Explained Variance
plt.figure()
plt.plot(np.cumsum(significance))
plt.xlabel('Number of Components')
plt.ylabel('Variance (%)') #for each component
plt.title('Pulsar Dataset Explained Variance')
plt.show()

Machine-Learning-with-Python- From-LM-to-DL/Unit 2. Non Linear Classification, Linear Regression, Colaborative Filtering/mnist/part1/test_environment6.py


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

class LearningRateDecay:
    def __init__(self, iteration, iteration_max=10000, lr=0.1, lr_min=1e-6):
        ''' learning rate decays with iteration. '''

        self.lr = lr
        self.lr_min = lr_min
        self.iteration = iteration
        self.iteration_max = iteration_max

    def exp(self, gamma=0.999, auto_params=True):
        '''
        exponential decay, return: lr * gamma^iteration

        :param auto_params: if True, gamma is set automatically
        '''

        if auto_params:
            gamma = (self.lr_min/self.lr)**(1./self.iteration_max)
        lr_new = self.lr * gamma**self.iteration
        return lr_new

    def step(self, stepsize=1000, gamma=0.3, auto_params=True):
        '''
        learning rate decays step by step, similar to 'exp'

        :param auto_params: if True, gamma is set automatically
        '''

        if auto_params:
            gamma = (self.lr_min/self.lr)**(1./(self.iteration_max*1.0/stepsize))
        lr_new = self.lr * gamma**(math.floor(self.iteration*1.0/stepsize))
        return lr_new

    def poly(self, decay_step=500, power=0.999, cycle=True):
        ''' polynomial decay, return: (lr-lr_min) * (1 - iteration/decay_steps)^power +lr_min '''

        if cycle:
            decay_steps = decay_step * math.ceil(self.iteration*1.0/decay_step)
        else:
            decay_steps = self.iteration_max
        lr_new = (self.lr-self.lr_min) * (1 - self.iteration*1.0/decay_steps)**power + self.lr_min
        return lr_new

#%% test
if __name__=='__main__':
    iteration = 10000
    lr_all_1 = []
    lr_all_2 = []
    lr_all_3 = []
    for ite in range(1, iteration+1):
        lr_all_1.append(LearningRateDecay(ite, iteration_max=iteration,lr=7.4e-5).exp(gamma=0.999, auto_params=True))
#        lr_all_2.append(LearningRateDecay(ite, iteration_max=iteration).step(stepsize=1000, gamma=0.3, auto_params=True))
#        lr_all_3.append(LearningRateDecay(ite, iteration_max=iteration,lr=0.01).poly(decay_step=500, power=1,cycle=True))

    lr_all_1 = np.array(lr_all_1)
#    lr_all_2 = np.array(lr_all_2)
#    lr_all_3 = np.array(lr_all_3)
    plt.figure(figsize=(8,6))
    plt.plot(lr_all_1, label='lr decay 1')
#    plt.plot(lr_all_2, label='lr decay 2')
#    plt.plot(lr_all_3, label='lr decay 3')
    plt.legend(fontsize=14)


import numpy as np

def batchnorm_forward(x, gamma, beta, bn_param):
    """
    Forward pass for batch normalization.
    During training the sample mean and (uncorrected) sample variance are
    computed from mini-batch statistics and used to normalize the incoming data.
    During training we also keep an exponentially decaying running mean of the mean
    and variance of each feature, and these averages are used to normalize data
    at test-time.
    At each time step we update the running averages for mean and variance using
    an exponential decay based on the momentum parameter:
    running_mean = momentum * running_mean + (1 - momentum) * sample_mean
    running_var = momentum * running_var + (1 - momentum) * sample_var
    Note that the batch normalization paper suggests a different test-time
    behavior: they compute sample mean and variance for each feature using a
    large number of training images rather than using a running average. For
    this implementation we have chosen to use running averages instead since
    they do not require an additional estimation step; the torch7 implementation
    of batch normalization also uses running averages.
    Input:
    - x: Data of shape (N, D)
    - gamma: Scale parameter of shape (D,)
    - beta: Shift parameter of shape (D,)
    - bn_param: Dictionary with the following keys:
      - mode: 'train' or 'test'; required
      - eps: Constant for numeric stability
      - momentum: Constant for running mean / variance.
      - running_mean: Array of shape (D,) giving running mean of features
      - running_var Array of shape (D,) giving running variance of features
    Returns a tuple of:
    - out: of shape (N, D)
    - cache: A tuple of values needed in the backward pass
    """
    mode = bn_param["mode"]
    eps = bn_param.get("eps", 1e-5)
    momentum = bn_param.get("momentum", 0.9)

    N, D = x.shape
    running_mean = bn_param.get("running_mean", np.zeros(D, dtype=x.dtype))
    running_var = bn_param.get("running_var", np.zeros(D, dtype=x.dtype))
    out, cache = None, None
    if mode == "train":
        sample_mean = np.mean(x, axis=0)
        x_minus_mean = x - sample_mean
        sq = x_minus_mean ** 2
        var = 1.0 / N * np.sum(sq, axis=0)
        std = np.sqrt(var + eps)
        ivar = 1.0 / std
        x_norm = x_minus_mean * ivar
        gamma_x = gamma * x_norm
        out = gamma_x + beta
        running_var = momentum * running_var + (1 - momentum) * var
        running_mean = momentum * running_mean + (1 - momentum) * sample_mean

        cache = (out, x_norm, beta, gamma, x_minus_mean, ivar, std, var, eps)

    elif mode == "test":
        x = (x - running_mean) / np.sqrt(running_var)
        out = x * gamma + beta
    else:
        raise ValueError('Invalid forward batchnorm mode "%s"' % mode)

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

    return out, cache

def batchnorm_backward(d_out, cache):
    """
    Backward pass for batch normalization.
    For this implementation, you should write out a computation graph for
    batch normalization on paper and propagate gradients backward through
    intermediate nodes.
    Inputs:
    - d_out: Upstream derivatives, of shape (N, D)
    - cache: Variable of intermediates from batchnorm_forward.
    Returns a tuple of:
    - dx: Gradient with respect to inputs x, of shape (N, D)
    - d_gamma: Gradient with respect to scale parameter gamma, of shape (D,)
    - d_beta: Gradient with respect to shift parameter beta, of shape (D,)
    """
    N, D = d_out.shape
    out, x_norm, beta, gamma, xmu, ivar, std, var, eps = cache

    dx_norm = d_out * gamma
    d_ivar = np.sum(dx_norm * xmu, axis=0)
    dx_mu1 = dx_norm * ivar
    d_std = -1.0 / (std ** 2) * d_ivar
    d_var = 0.5 * 1. / np.sqrt(var + eps) * d_std
    dsq = 1.0 / N * np.ones((N, D)) * d_var
    dx_mu2 = 2 * xmu * dsq
    dx1 = dx_mu1 + dx_mu2
    d_mean = -1.0 * np.sum(dx1, axis=0)
    dx2 = 1. / N * np.ones((N, D)) * d_mean
    dx = dx1 + dx2
    d_beta = np.sum(d_out, axis=0)
    d_gamma = np.sum(d_out * x_norm, axis=0)

    return dx, d_gamma, d_beta

def batchnorm_backward_alt(d_out, cache):
    """
    Alternative backward pass for batch normalization.
    For this implementation you should work out the derivatives for the batch
    normalization backward pass on paper and simplify as much as possible. You
    should be able to derive a simple expression for the backward pass.
    Note: This implementation should expect to receive the same cache variable
    as batchnorm_backward, but might not use all of the values in the cache.
    Inputs / outputs: Same as batchnorm_backward
    """
    out, x_norm, beta, gamma, xmu, ivar, std, var, eps = cache
    N, D = d_out.shape

    d_gamma = np.diat(np.dot(d_out.T, x_norm))
    d_beta = np.sum(d_out, axis=0)

    d_out_dx = gamma * (1 - 1 / N) / ivar * (1 + 1 / N * ((out - beta) / gamma) ** 2)

    dx = d_out * d_out_dx

    return dx, d_gamma, d_beta

def spatial_batchnorm_forward(x, gamma, beta, bn_param):
    """
    Computes the forward pass for spatial batch normalization.
    Inputs:
    - x: Input data of shape (N, C, H, W)
    - gamma: Scale parameter, of shape (C,)
    - beta: Shift parameter, of shape (C,)
    - bn_param: Dictionary with the following keys:
        - mode: 'train' or 'test'; required
        - eps: Constant for numeric stability
        - momentum: Constant for running mean / variance. momentum=0 means that
        old information is discarded completely at every time step, while
        momentum=1 means that new information is never incorporated. The
        default of momentum=0.9 should work well in most situations.
        - running_mean: Array of shape (D,) giving running mean of features
        - running_var Array of shape (D,) giving running variance of features
    Returns a tuple of:
    - out: Output data, of shape (N, C, H, W)
    - cache: Values needed for the backward pass
    """
    ########################################################################
    # TODO: Implement the forward pass for spatial batch normalization.    #
    #                                                                      #
    # HINT: You can implement spatial batch normalization using the        #
    # vanilla version of batch normalization defined above. Your           #
    # implementation should be very short; ours is less than six lines.   #
    ########################################################################

    x_swapped = np.transpose(x, (0, 2, 3, 1))
    x_swapped_reshaped = np.reshape(x_swapped, (-1, x_swapped.shape[-1]))

    out_temp, cache = batchnorm_forward(x_swapped_reshaped, gamma, beta, bn_param)
    out = np.transpose(np.reshape(out_temp, x_swapped.shape), (0, 3, 1, 2))

    ########################################################################
    #                           END OF YOUR CODE                           #
    ########################################################################

    return out, cache

def spatial_batchnorm_backward(d_out, cache):
    """
    Computes the backward pass for spatial batch normalization.
    Inputs:
    - d_out: Upstream derivatives, of shape (N, C, H, W)
    - cache: Values from the forward pass
    Returns a tuple of:
    - dx: Gradient with respect to inputs, of shape (N, C, H, W)
    - d_gamma: Gradient with respect to scale parameter, of shape (C,)
    - d_beta: Gradient with respect to shift parameter, of shape (C,)
    """
    ########################################################################
    # TODO: Implement the backward pass for spatial batch normalization.   #
    #                                                                      #
    # HINT: You can implement spatial batch normalization using the        #
    # vanilla version of batch normalization defined above. Your           #
    # implementation should be very short; ours is less than six lines.   #
    ########################################################################

    d_out_swapped = np.transpose(d_out, (0, 2, 3, 1))
    d_out_swapped_reshaped = np.reshape(d_out_swapped, (-1, d_out_swapped.shape[-1]))

    dx_sr, d_gamma, d_beta = batchnorm_backward(d_out_swapped_reshaped, cache)
    dx = np.transpose(np.reshape(dx_sr, d_out_swapped.shape), (0, 3, 1, 2))

    ########################################################################
    #                           END OF YOUR CODE                           #
    ########################################################################

    return dx, d_gamma, d_beta


#     Copyright 2016-present CERN – European Organization for Nuclear Research
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.

import numpy as np

from qf_lib.containers.series.qf_series import QFSeries

def cvar(qf_series: QFSeries, percentage: float) -> float:
    """
    Calculates Conditional Value at Risk for a given percentage. Percentage equal to 0.05 means 5% CVaR.

    Parameters
    ----------
    qf_series: QFSeries
        Series of returns/prices
    percentage: float
        Percentage defining CVaR (what percentage of worst-case scenarios should be considered"

    Returns
    -------
    float
        Conditional value at risk as a number from range (-1,1). Simplifying: means how much money can be lost
        in the worst "percentage" % of all cases.
    """
    returns_tms = qf_series.to_simple_returns()
    number_of_returns = len(returns_tms.values)
    tail_length = round(number_of_returns * percentage)

    assert tail_length > 0, 'Too few values in the series'

    sorted_returns = sorted(returns_tms.values)

    tail_returns = sorted_returns[:tail_length]
    return np.mean(tail_returns, dtype=np.float64)


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import math
import numpy as np

from measurement_stats import value

def unweighted(*values):
    """

    :param values:
    :return:
    """

    if not values:
        return value.ValueUncertainty()

    if isinstance(values[0], (list, tuple)):
        values = values[0]
        if not values:
            return value.ValueUncertainty()

    values = [v.value for v in values]
    return value.ValueUncertainty(
            value=float(np.mean(values)),
            uncertainty=float(np.std(values))
    )

def weighted(*values):
    """
    Calculates the uncertainty weighted average of the provided values,
    where each value is a ValueUncertainty instance. For mathematical
    formulation of the weighted average see "An Introduction to Error
    Analysis, 2nd Edition" by John R. Taylor, Chapter 7.2.

    :param values:
    :return:
    """

    if not values:
        return value.ValueUncertainty()

    if isinstance(values[0], (list, tuple)):
        values = values[0]
        if not values:
            return value.ValueUncertainty()

    wxs = 0.0
    ws = 0.0
    for v in values:
        w = 1.0/(v.uncertainty*v.uncertainty)
        wxs += w*v.value
        ws += w

    ave = wxs / ws
    unc = 1.0 / math.sqrt(ws)

    return value.ValueUncertainty(value=ave, uncertainty=unc)

def weighted_mean_and_deviation(*values):
    """
    Returns the mean and standard deviation of a weighted set of values.
    For further info see:
        http://stats.stackexchange.com/questions/6534/
            how-do-i-calculate-a-weighted-standard-deviation-in-excel

    :param values:
    :return:
    """

    if not values:
        return value.ValueUncertainty()

    if isinstance(values[0], (list, tuple)):
        values = values[0]
        if not values:
            return value.ValueUncertainty()

    if len(values) == 1:
        return values[0].clone()

    wxs = 0.0
    ws  = 0.0
    weights = []

    for v in values:
        w = 1.0/(v.uncertainty*v.uncertainty)
        weights.append(w)
        wxs += w*v.value
        ws += w

    ave = wxs/ws
    dev = 0.0
    N = len(values)
    for i in range(N):
        dev += weights[i]*(values[i].value - ave)**2

    denom = ws*(N - 1.0)/N
    dev = math.sqrt(dev/denom)

    return value.ValueUncertainty(value=ave, uncertainty=dev)


"""
Warp/Bend a line to a circle
============================
"""

import numpy as np
import matplotlib.pyplot as plt

"""
Interpret a 1D array of points as the circumference of a circle
centered at (0,0) and return the corresponding (x,y) coordinates.
"""

def warp(a):
    a0 = a - a[0]
    L = a0[-1]
    R = L / 2 / np.pi

    x = R * np.cos(a0 / R)
    y = R * np.sin(a0 / R)

    return x, y

if __name__ == "__main__":
    a = np.linspace(17.0, 42.0, 100)
    x, y = warp(a)
    def almost_equal(a, b):
        return abs(a-b) < 1.e-10

    # start point == end point
    assert almost_equal(x[0], x[-1]) and almost_equal(y[0], y[-1])

    # center (ignoring the duplicated end point) around (0,0)
    assert almost_equal(np.mean(x[:-1]), 0.)
    assert almost_equal(np.mean(y[:-1]), 0.)

    plt.plot(*warp(a))
    plt.show()


from matplotlib import cm
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
import numpy as np
import regression

def loadDataSet(filename):
    numFeat = len(open(filename).readline().split('\t')) - 1
    X = []
    y = []
    file = open(filename)
    for line in file.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        X.append(lineArr)
        y.append(float(curLine[-1]))
    return np.mat(X), np.mat(y).T

if __name__ == "__main__":
    # load data
    X, y = loadDataSet('data/house_price.txt');

    m,n = X.shape
    # add x0 as 1 for each feature
    X = np.concatenate((np.ones((m,1)), X), axis=1)

    # learing rate
    rate = 0.02
    # maximum number of iterations
    maxLoop = 1500
    # precision
    epsilon = 0.01

    result, timeConsumed = regression.gradientDescentOptimizer(rate, maxLoop, epsilon, regression.standarize(X), regression.standarize(y))
    theta, errors, thetas = result

    # plot predicted line
    fittingFig = plt.figure()
    title = 'gradient descent: rate=%.2f, maxLoop=%d, epsilon=%.3f \n time: %ds'%(rate,maxLoop,epsilon,timeConsumed)
    ax = fittingFig.add_subplot(111, title=title)
    trainingSet = ax.scatter(X[:, 1].flatten().A[0], y[:,0].flatten().A[0])

    xCopy = X.copy()
    xCopy.sort(0)
    yHat = xCopy*theta
    fittingLine, = ax.plot(xCopy[:,1], yHat, color='g')

    ax.set_xlabel('Lot Size/x1000sq.ft')
    ax.set_ylabel('Sale Price/x10,000$')

    plt.legend([trainingSet, fittingLine], ['Training Set', 'Linear Regression'])
    plt.show()

    # cost function
    errorsFig = plt.figure()
    ax = errorsFig.add_subplot(111)
    ax.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.4f'))

    ax.plot(range(len(errors)), errors)
    ax.set_xlabel('Number of iterations')
    ax.set_ylabel('Cost J')

    plt.show()

    # 3D cost function
    size = 100
    theta0Vals = np.linspace(-10,10, size)
    theta1Vals = np.linspace(-2, 4, size)
    JVals = np.zeros((size, size))
    for i in range(size):
        for j in range(size):
            col = np.matrix([[theta0Vals[i]], [theta1Vals[j]]])
            JVals[i,j] = regression.J(col, X, y)

    theta0Vals, theta1Vals = np.meshgrid(theta0Vals, theta1Vals)
    JVals = JVals.T
    contourSurf = plt.figure()
    ax = contourSurf.gca(projection='3d')

    ax.plot_surface(theta0Vals, theta1Vals, JVals,  rstride=2, cstride=2, alpha=0.3,
                cmap=cm.rainbow, linewidth=0, antialiased=False)
    ax.plot(thetas[0], thetas[1], 'rx')
    ax.set_xlabel(r'$\theta_0$')
    ax.set_ylabel(r'$\theta_1$')
    ax.set_zlabel(r'$J(\theta)$')

    plt.show()

    contourFig = plt.figure()
    ax = contourFig.add_subplot(111)
    ax.set_xlabel(r'$\theta_0$')
    ax.set_ylabel(r'$\theta_1$')

    CS = ax.contour(theta0Vals, theta1Vals, JVals, np.logspace(-2,3,20))
    plt.clabel(CS, inline=1, fontsize=10)

    ax.plot(theta[0,0], theta[1,0], 'rx', markersize=10, linewidth=2)

    ax.plot(thetas[0], thetas[1], 'rx', markersize=3, linewidth=1)
    ax.plot(thetas[0], thetas[1], 'r-')

    plt.show()


"""Exponential distribution
"""
import numpy as np
from scipy.stats import expon

from xgboost_distribution.distributions.base import BaseDistribution
from xgboost_distribution.distributions.utils import check_is_ge_zero

class Exponential(BaseDistribution):
    """Exponential distribution with log score

    Definition:

        f(x) = 1 / scale * e^(-x / scale)

    We reparameterize scale -> log(scale) = a to ensure scale >= 0. Gradient:

        d/da -log[f(x)] = d/da -log[1/e^a e^(-x / e^a)]
                        = 1 - x e^-a
                        = 1 - x / scale

    The Fisher information = 1 / scale^2, when reparameterized:

        1 / scale^2 = I ( d/d(scale) log(scale) )^2 = I ( 1/ scale )^2

    Hence we find: I = 1

    """

    @property
    def params(self):
        return ("scale",)

    def check_target(self, y):
        check_is_ge_zero(y)

    def gradient_and_hessian(self, y, params, natural_gradient=True):
        """Gradient and diagonal hessian"""

        (scale,) = self.predict(params)

        grad = np.zeros(shape=(len(y), 1))
        grad[:, 0] = 1 - y / scale

        if natural_gradient:
            fisher_matrix = np.ones(shape=(len(y), 1, 1))

            grad = np.linalg.solve(fisher_matrix, grad)
            hess = np.ones(shape=(len(y), 1))  # we set the hessian constant
        else:
            hess = -(grad - 1)

        return grad, hess

    def loss(self, y, params):
        scale = self.predict(params)
        return "ExponentialError", -expon.logpdf(y, scale=scale).mean()

    def predict(self, params):
        log_scale = params
        scale = np.exp(log_scale)
        return self.Predictions(scale=scale)

    def starting_params(self, y):
        return (np.log(np.mean(y)),)


from scipy.stats import norm
from scipy.stats import fisher_exact
from scipy.stats import chi2_contingency

SAMPLE_SIZE_THRESHOLD = 50

def samples_to_contingency_table(samples):
    """
    Turns the samples array into a contingency table

    Assumes samples come in the pattern: (sample_total1, subsample1, sample_total2, subsample2, ...)

    Reverses contingency_table_to_samples()
    """
    return [[samples[i] - samples[i+1], samples[i+1]] for i in xrange(0, len(samples), 2)]

def contingency_table_to_samples(table):
    """
    Turns an M x 2 contingency_table into a samples array

    Reverses samples_to_contingency_table()
    """
    return [r[0] + r[1] if i == 0 else r[1] for r in table for i in xrange(len(r))]

def two_proportion_z_score(control_size, control_conversion, attribute_size, attribute_conversion, pooled_sample=True):
    """
    Calculate the z-score between two proportions (often used for A/B testing)

    Answers the question: Is the difference in conversion rate between two sample groups due to chance? Or is it a significant difference?

    Parameters
    -----------
    attribute vs. control : The labels are arbitrary and you will get the same result with opposite sign if the values are swapped

    attribute/control_size : total number of people in this sample
    attribute/control_conversion : subgroup of people in the sample (should always be <= attribute/control_size)

    pooled_sample : Choose between pooling the sample for calculating the Standard Error, or not
        This assumes the null hypothesis (attribute_pct == control_pct) and can be derived from the non-pooled-sample Standard Error
        Most resources I found had the pooled sample as standard (so I defaulted to it)

    Example
    -----------
    66,471 people were part of a study. Of those 5,201 were shown an ad.
    And of the 5,201 67 bought the product.
    Of the unexposed people (66,471 - 5,201 = 61,270) 200 bought the product.
    Are the exposed and unexposed conversion rates significantly different?

    control_size = 61,270
    control_conversion = 200
    attribute_size = 5,201
    attribute_conversion = 67

    zscore = 10.52848...

    Assumptions
    -----------
    - The test statistic follows a Normal Distribution (this is generally true the larger the sample per the Central Limit Theorem)
        - This is an approximate measure (unlike "exact" tests) approximations are used for mean and variance measures
        - For small sample sizes use Fisher's Exact Test
    - Each sample is independent
    - The sample is obtained by simple random sampling (every member of the total population has an equal chance of being selected)

    For more information, see:
    - https://onlinecourses.science.psu.edu/stat414/node/268
    - http://stattrek.com/hypothesis-test/difference-in-proportions.aspx?Tutorial=AP
    """
    attribute_pct = float(attribute_conversion) / attribute_size
    control_pct = float(control_conversion) / control_size

    if pooled_sample:
        total_pct = float(attribute_conversion + control_conversion) / (attribute_size + control_size)
        standard_error = ( total_pct * (1. - total_pct) * (1. / attribute_size + 1. / control_size) ) ** .5
    else:
        standard_error = ( (attribute_pct * (1. - attribute_pct) / attribute_size) + (control_pct * (1. - control_pct) / control_size) ) ** .5

    zscore = (attribute_pct - control_pct) / standard_error
    return zscore

def fishers_exact_test(control_size, control_conversion, attribute_size, attribute_conversion, alternative='two-sided'):
    """
    Fisher's Exact Test

    Mostly used as an alternative to the chi-squared test with low sample sizes

    Since this test is based on a hypergeometric distribution (not symmetrical) two-tailed p-values != 2 * one-tailed
        the p-value for each table with a lower probablity must be summed
        this is a pain, so I've just wrapped scipy's implementation

    Parameters
    ----------
    alternative : ['two-sided', 'less', 'greater']
        represents the alternative hypothesis (opposite to the null hypothesis)

    For more information, see:
    - https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.fisher_exact.html
    - https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.hypergeom.html
    - https://en.wikipedia.org/wiki/Fisher%27s_exact_test
    """
    samples = [control_size, control_conversion, attribute_size, attribute_conversion]
    contingency_table = samples_to_contingency_table(samples)
    oddsratio, pvalue = fisher_exact(contingency_table, alternative)
    return pvalue

def p_value_from_z_score(zscore, two_tailed=True):
    pvalue = norm.sf( abs(zscore) )
    if two_tailed:
        pvalue *= 2.
    return pvalue

def two_proportion_p_value(control_size, control_conversion, attribute_size, attribute_conversion, pooled_sample=True, two_tailed=True):
    samples = [control_size, control_conversion, attribute_size, attribute_conversion]

    if any(map(lambda x: x < SAMPLE_SIZE_THRESHOLD, samples)):
        pvalue = fishers_exact_test(*samples)
    else:
        zscore = two_proportion_z_score(*samples, pooled_sample=pooled_sample)
        pvalue = p_value_from_z_score(zscore, two_tailed)

    return pvalue

def chi_squared_independence_test(arr, convert_to_table=False, yates_correction=False):
    """
    Chi Squared Test of Independence

    Answers the question: Did these data come from different distributions? Or are the differences due to chance?

    You'll notice on a 2x2 contingency table, the p-value is the same as the two_proportion_p_value()
    For consistency I'd recommend using the same SAMPLE_SIZE_THRESHOLD variable to determine if you have a "small" sample

    Parameters
    ----------------
    arr : Either pass the contingency table as an array of arrays, or pass a samples array
        i.e., samples = [control_size, control_conversion, attribute_size, attribute_conversion]
        e.g., samples = [374, 26, 210, 8] == contingency_table = [[348, 26], [202, 8]]

    convert_to_table : If you passed a samples array, you'll need this to be True, otherwise
        if you passed a contingency table directly, leave it as False

    Assumptions
    ----------------
    - The test statistic follows a Chi-Squared Distribution (this is generally true the larger the sample per the Central Limit Theorem)
        - This is an approximate measure (unlike "exact" tests) approximations are used for mean and variance measures
        - For small sample sizes use the use Fisher's Exact Test, or the Yates correction (see the "Yates Correction" section for more info)
    - Each sample is independent
    - The sample is obtained by simple random sampling (every member of the total population has an equal chance of being selected)

    Yates Correction
    ----------------
    This is a correction for small sample sizes in a 2x2 contingency table
    I would not recommend using this correction. It tends to be overly conservative (higher p-value than should be)
    Instead, for small samples I'd recommend using Fisher's Exact Test
    To read more about this see: http://www.statisticshowto.com/what-is-the-yates-correction/
        and see the sources near the end

    For more information, see:
    - https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chi2_contingency.html
    """
    if convert_to_table:
        table = samples_to_contingency_table(arr)
    else:
        table = arr

    chi2, pvalue, dof, expected = chi2_contingency(table, correction=yates_correction)
    return pvalue


# -*- coding: utf-8 -*-
"""
Created on Tue Feb 23 18:56:28 2021

@author: m1390
"""

import numpy as np
import matplotlib.pyplot as plt
#%%
class Cubic_Spline:

    def __init__(self, x, y, f=None):
        """

        Parameters
        ----------
        x : data points
            N-D vector.
        y : data evaluations
            N-1 vector.
        f: explicit function
            Function

        Returns
        -------
        None.

        """
        self.x = x
        self.y = y
        self.f = f

        # number of subintervals
        self.n = self.x.shape[0] - 1

        # piece-wise coefficients of the cubic splines
        self.coefficients = None

        # I: interval for evaluation
        # S: evaluation for interval
        self.I = None
        self.S = None

    def reset(self,x,y,f=None):
        self.__init__(x,y,f)

    def tridiag(self,u,h,v):
        """
        This function solves a tridiagonal system specifically for
        natural cubic splines. (reduced)

        It can be generalized for other cubic splines.

        Parameters
        ----------
        n : int
            n+1 points
        u : n-1 dim vector 1,...,n-1
            diagonal elements.
        h : n-1 dim vector
            tridiagonal elements.
        v : n-1 dim vector
            objective for system.

        Returns
        -------
        z : n-1 dim vector
            system coefficients.

        """
        n = self.n
        # Gaussian elimination step
        for k in range(1,n-1):
            u[k] = u[k] - h[k-1]**2/u[k-1]
            v[k] = v[k] - h[k-1] * v[k-1]/u[k-1]

        # back substitution step
        z = np.zeros((n-1))
        z[-1] = v[-1]/u[-1]
        for k in range(2,n):
            z[-k] = (v[-k] - h[-k] * z[-(k-1)]) / u[-k]

        return u,v,z

    def train(self):

        # data points x
        x = self.x

        # y : vector [y0,y1,y2,...,yn] function evaluations on x.
        y = self.y

        # obtain tridiagonal system
        # subinterval lengths h: n dim vector (from 0 to n-1)
        h = x[1:] - x[:-1]
        v = 6 * (1/h[1:] * (y[2:]-y[1:-1]) - 1/h[:-1]*(y[1:-1] - y[:-2]))
        u = 2 * (h[:-1]+h[1:])

        _,_,z = self.tridiag(u, h[1:], v)

        z = np.concatenate(([0], z, [0]))

        # compute coefficients for natural splines
        self.coefficients = [np.array([zi1/(6*hi),
                                       zi/(6*hi),
                                       (yi1/hi-hi/6*zi1),
                                       yi/hi-hi/6*zi])
                             for (zi,zi1,hi,yi,yi1) in
                             zip(z[:-1],z[1:],h,y[:-1],y[1:])]

    def evaluate(self,N):
        # evaluate natural cubic spline
        # N is number of points to sample for each subinterval

        n = self.n

        x = self.x

        for j in range(n):

            # loop over sub-intervals
            coeff = self.coefficients[j]

            # 2 boundary points for interval j
            bdry = x[j:j+2]

            # equally sample 51 points from interval j
            Ij = np.linspace(bdry[0],bdry[1],N).reshape(-1,1)

            # obtain data matrix
            X = np.concatenate([
                    (Ij - bdry[0])**3,
                    (bdry[1] - Ij)**3,
                    (Ij - bdry[0]),
                    (bdry[1] - Ij)
                ],1)

            # reduce back to original shape
            Ij = Ij.flatten()

            # evaluate on piecewise cubic spline
            Sj = X @ coeff

            if j == 0:
                S = Sj.copy()
                I = Ij.copy().flatten()
            else:
                S = np.concatenate([S,Sj])
                I = np.concatenate([I,Ij.flatten()])

        self.S = S
        self.I = I

    def plot(self):
        plt.figure()
        ax = plt.subplot(111)
        ax.spines["top"].set_visible(False)
        ax.spines["right"].set_visible(False)

        # Ensure that the axis ticks only show up on the bottom and left of the plot.
        # Ticks on the right and top of the plot are generally unnecessary chartjunk.
        ax.get_xaxis().tick_bottom()
        ax.get_yaxis().tick_left()

        ax.scatter(self.x,self.y,color='chocolate',label='nodes')
        ax.plot(self.I,self.S,label='NS')

        if self.f is not None:
            function = self.f(self.I)
            ax.plot(self.I,function,color='grey',label='f')

        plt.legend()
        plt.xlabel('x')
        plt.ylabel('y')


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CS231n Convolutional Neural Networks for Visual Recognition
http://cs231n.github.io/

Python Numpy Tutorial
http://cs231n.github.io/python-numpy-tutorial/

Numpy Reference
https://docs.scipy.org/doc/numpy/reference/
￣
python_numpy_tutorial-numpy_array_math.py
2019-07-02 (Tue)
"""
# Python Numpy Tutorial > Numpy > Array Math
#   Basic math functions operate elementwise on arrays.
#   In the numpy module, they're available both as
#     operator overloads and as functions.
#
# This examples cover:
#   Basic Math Functions
#     Elementwise sum         x+y or np.add(x,y)
#     Elementwise subtraction x-y or np.subtract(x,y)
#     Elementwise product     x*y or np.multiply(x,y)
#     Elementwise division    x/y or np.divide(x,y)
#     Elementwise square root        np.sqrt(x)
#   Inner Product 'dot
#     Inner product of vectors
#     Matrix-vector product
#     Matrix-matrix product
#     sum (as an example of math functions in numpy)
#
# Read more about:
#   numpy's full list of math functions
#     Mathematical functions
#     https://docs.scipy.org/doc/numpy/reference/routines.math.html
#   array manipulation routines
#     Array manipulation routines
#     https://docs.scipy.org/doc/numpy/reference/routines.array-manipulation.html

import numpy as np

##########################
#  Basic Math Functions  #
##########################

x = np.array( [[1,2],[3,4]], dtype=np.float64 )
y = np.array( [[5,6],[7,8]], dtype=np.float64 )
print( x )
#[[1. 2.]
# [3. 4.]]

print( y )
#[[5. 6.]
# [7. 8.]]

# Elementwise sum
print( x+y )
#[[ 6.  8.]
# [10. 12.]]

print( np.add(x,y) )
#[[ 6.  8.]
# [10. 12.]]

# Elementwise subtraction
print( x-y )
#[[-4. -4.]
# [-4. -4.]]

print( np.subtract(x,y) )
#[[-4. -4.]
# [-4. -4.]]

# Elementwise product
print( x*y )
#[[ 5. 12.]
# [21. 32.]]

print( np.multiply(x,y) )
#[[ 5. 12.]
# [21. 32.]]

# Elementwise division
print( x/y )
#[[0.2        0.33333333]
# [0.42857143 0.5       ]]

print( np.divide(x,y) )
#[[0.2        0.33333333]
# [0.42857143 0.5       ]]

# Elementwise square root
print( np.sqrt(x) )
#[[1.         1.41421356]
# [1.73205081 2.        ]]

#########################
#  Inner Product 'dot'  #
#########################
# Unlike MATLAB, * is elementwise multiplication,
#   not matrix multiplication.
# Instead, the dot function is used to compute
#   inner products of vectors,
#   to multiply a vector by a matrix, and
#   to multiply matrices.
# Dot is available both
#   as a function in the numpy module and
#   as an instance method of array objects.

x = np.array( [[1,2],[3,4]]  )
print(x, x.shape)
#[[1 2]
# [3 4]] (2, 2)

y = np.array( [[5,6],[7,8]] )
print(y, y.shape)
#[[5 6]
# [7 8]] (2, 2)

v = np.array( [9,10] )
print(v, v.shape)
#[ 9 10] (2,)

w = np.array( [11,12] )
print(w, w.shape)
#[11 12] (2,)

# Inner product of vectors
print( v.dot(w) )
# 219
# [9 10] [11 12] = 9*11+10*12 = 99 + 120 = 219

print( np.dot(v,w) )
# 219

# Matrix-vector product
#   x v = (2x2) x (2x1) = (2x1)
#   rank 1 array is procuded.
print( x.dot(v) )
# [29 67]

print( np.dot(x,v) )
# [29 67]

# Matrix-matrix product
#   produce rank 2 array.
print( x.dot(y) )
#[[19 22]
# [43 50]]

print( np.dot(x,y) )
#[[19 22]
# [43 50]]

#####################################
# NOTE: numpy math functions 'sum'  #
#####################################

x = np.array( [[1,2],[3,4]] )  # NOTE
print(x)                       # NOTE
#[[1 2]                        # NOTE
# [3 4]]                       # NOTE

print( np.sum(x) )             # All elements
#10

print( np.sum(x,axis=0) )      # Each column # NOTE
#[4 6]                         # NOTE

print( np.sum(x,axis=1) )      # Each row # NOTE
# [3 7]                        # NOTE

##########################
#  Transposing a matrix  #
##########################

x = np.array( [[1,2],[3,4]]  )
print(x)
#[[1 2]
# [3 4]]

print(x.T)
#[[1 3]
# [2 4]]

# NOTE: Taking the transpose of a rank 1 array DOES NOTHING!
v = np.array([1,2,3])  # NOTE
print(v, v.shape)      # NOTE
#[1 2 3] (3,)          # NOTE

print(v.T, v.T.shape)  # NOTE
#[1 2 3] (3,)          # NOTE


import numpy as nmp
from CodeEntropy.FunctionCollection import CustomFunctions as CF

def transform_coordinates(arg_origVector, arg_oldBase, arg_newBase):
	"""Given a 3D vector (origVector; V) with components in the old_base (3,3 matrix),
	transform it to a new 3D vector (return value) with components in the new_base (3x3 matrix).
	A 3X3 transformation matrix TM is created which gives new vector components V' = TM @ V.
	TM[i,j] = dot(axis{j_new}, axis{i_old}).

	NOTE: Axes in both coordinate system have to be orthogonal"""

	#transformation matrix
	TM = [[nmp.dot(j,i) for i in arg_newBase] for j in arg_oldBase]

	return TM @ arg_origVector

#END

def get_cartesian_midpoint3D(arg_point1, arg_point2):
	""" Get the cartesian midpoint of the line joining two 3D points """
	return nmp.multiply(0.5, nmp.add(arg_point1, arg_point2))

#END

def generate_orthonormal_axes_system(arg_coord1, arg_coord2, arg_coord3):
	"""Generate a 3 x 3 matrix with columns as axes of the returning coordinate system.
	They must be orthonormal (assert).
	Axis 1: Along the C-N line, from altitude bisector to C
	Axis 2: from altitde bisecting point of C-N to Ca
	Axis 3: Cross of Axis1 and Axis 2

	Return the basis and the origin"""

	basis = nmp.ndarray((3,3))

	r1 = arg_coord1
	r2 = arg_coord2
	r3 = arg_coord3

	r31 = r3 - r1
	r21 = r2 - r1

	#derived formula
	rAltitude = nmp.dot(r31, r21) * r21
	rAltitude /= nmp.linalg.norm(r21)**2
	rAltitude += r1

	# Axis 0
	axis0 = r2 - rAltitude
	axis0 /= nmp.linalg.norm(axis0)
	basis[0,:] = axis0

	# Axis 1
	axis1 = r3 - rAltitude
	axis1 /= nmp.linalg.norm(axis1)
	basis[1,:] = axis1

	# Axis 2
	# axis2 = nmp.cross(axis0, axis1)
	axis2 = CF.cross_product(axis0, axis1)
	axis2 /= nmp.linalg.norm(axis2)
	basis[2,:] = axis2

	# due to FP limitations, the check will verly likely fail
	# assert(nmp.dot(axis1, axis2) == 0)

	return basis, rAltitude

#END

def get_altitude(arg_lineEndPoint1, arg_lineEndPoint2, arg_sourcePoint):
	"""
	For the three points in the input,
	2 form a line segement and
	the thrid one is the point from
	where the altitude on the line segement is computed.

	Returns te altitude vector"""

	r1 = arg_lineEndPoint1
	r2 = arg_lineEndPoint2
	r3 = arg_sourcePoint

	r31 = r3 - r1
	r21 = r2 - r1

	#derived formula
	rAltitude = nmp.dot(r31, r21) * r21
	rAltitude /= nmp.linalg.norm(r21)**2
	rAltitude = r31 - rAltitude

	return rAltitude

# END

def get_sphCoord_axes(arg_r):
	""" For a given vector in space, treat it is a radial vector rooted at 0,0,0 and
	derive a curvilinear coordinate system according to the rules of polar spherical
	coordinates"""

	x2y2 = arg_r[0]**2 + arg_r[1]**2
	r2 = x2y2 + arg_r[2]**2

	if x2y2 != 0.:
		sinTheta = nmp.sqrt(x2y2/r2)
		cosTheta = arg_r[2]/nmp.sqrt(r2)

		sinPhi = arg_r[1]/nmp.sqrt(x2y2)
		cosPhi = arg_r[0]/nmp.sqrt(x2y2)

	else:
		sinTheta = 0.
		cosTheta = 1

		sinPhi = 0.
		cosPhi = 1

	# if abs(sinTheta) > 1 or abs(sinPhi) > 1:
	#	 print('Bad sine : T {} , P {}'.format(sinTheta, sinPhi))

	# cosTheta = nmp.sqrt(1 - sinTheta*sinTheta)
	# cosPhi = nmp.sqrt(1 - sinPhi*sinPhi)

	# print('{} {} {}'.format(*arg_r))
	# print('Sin T : {}, cos T : {}'.format(sinTheta, cosTheta))
	# print('Sin P : {}, cos P : {}'.format(sinPhi, cosPhi))

	sphericalBasis = nmp.zeros((3,3))

	# r^
	sphericalBasis[0,:] = nmp.asarray([sinTheta*cosPhi, sinTheta*sinPhi, cosTheta])

	# Theta^
	sphericalBasis[1,:] = nmp.asarray([cosTheta*cosPhi, cosTheta*sinPhi, -sinTheta])

	# Phi^
	sphericalBasis[2,:] = nmp.asarray([-sinPhi, cosPhi, 0.])

	return sphericalBasis

# END

def compute_dihedral(arg_ri, arg_rj, arg_rk, arg_rl):
	"""
	Return the dihedral angle in degrees formed by the atoms with the input coordinates.
	The formula to compute was obtained from:
	https://www.math.fsu.edu/~quine/MB_10/6_torsion.pdf

	"""

	# define the directed line segments (vectors)
	a = nmp.subtract(arg_rj, arg_ri) # i->j
	b = nmp.subtract(arg_rk, arg_rj) # j->k
	c = nmp.subtract(arg_rl, arg_rk) # k->l

	# Complex number formalism for finding the angle
	# Z = X + jY
	X = -nmp.dot(a,c) * nmp.dot(b,b)
	X += ( nmp.dot(a,b) * nmp.dot(b,c) )

	Y = nmp.dot(a, nmp.cross(b,c))
	Y *= nmp.linalg.norm(b)

	# dihedral angle (in degrees)
	dih = nmp.angle(complex(X,Y), deg=True)

	return dih
# END