import numpy as np
import math
import scipy as sp
from scipy import stats
import math
import fileinput

#####Calculate the Threshold Boundary of the 95% Confidence Interval for the mean
def mean_confidence_interval(data, confidence=0.95):
    num_data = len(data)
    std = np.std(data)
    boundary_threshold = 1.96*std/(math.sqrt(num_data))
    return boundary_threshold

######Extract the data
i=-1
for line in fileinput.input():
    if i==-1:
        count=0
        i=i+1
    if i==0:
        data=[int(x) for x in line.split(" ")]

######Convert data to numpy array
data_list = np.array(data)

######Find the frequency of each value in the data
counts = np.bincount(data_list)

######Find 95% Confidence Interval for the mean
boundary_threshold=mean_confidence_interval(data)

######Find the Lower and Upper Boundary of the 95% Confidence Interval for the mean
lower_boundary=np.mean(data)-boundary_threshold
upper_boundary=np.mean(data)+boundary_threshold

print np.mean(data) ####  Mean of the data
print np.median(data) ####  Median of the data
print np.argmax(counts) ####  Mode of the data
print np.std(data) #### Standard deviation of the data
print lower_boundary, upper_boundary


from Test import Test, Test as test

'''
In this simple exercise, you will create a program that will take two lists of integers, a and b. Each list will consist of 3 positive integers above 0, representing the dimensions of cuboids a and b. You must find the difference of the cuboids' volumes regardless of which is bigger.

For example, if the parameters passed are ([2, 2, 3], [5, 4, 1]), the volume of a is 12 and the volume of b is 20. Therefore, the function should return 8.

Your function will be tested with pre-made examples as well as random ones.

If you can, try writing it in one line of code.
'''

def prod_list(list):
    prod = 1
    for num in list:
        prod *= num
    return prod

def find_difference(a, b):
    return abs(prod_list(a) - prod_list(b))

# Top solution
from numpy import prod

def find_difference(a, b):
    return abs(prod(a) - prod(b))

test.assert_equals(find_difference([3, 2, 5], [1, 4, 4]), 14, "{0} should equal 14".format(find_difference([3, 2, 5], [1, 4, 4])))
test.assert_equals(find_difference([9, 7, 2], [5, 2, 2]), 106, "{0} should equal 106".format(find_difference([9, 7, 2], [5, 2, 2])))


import numpy as np
from .base_signal import BaseSignal

__all__ = ['Sinusoidal']

class Sinusoidal(BaseSignal):
    """Signal generator for harmonic (sinusoidal) waves.

    Parameters
    ----------
    amplitude : number (default 1.0)
        Amplitude of the harmonic series
    frequency : number (default 1.0)
        Frequency of the harmonic series
    ftype : function (default np.sin)
        Harmonic function

    """

    def __init__(self, amplitude=1.0, frequency=1.0, ftype=np.sin):
        self.vectorizable = True
        self.amplitude = amplitude
        self.ftype = ftype
        self.frequency = frequency

    def sample_next(self, time, samples, errors):
        """Sample a single time point

        Parameters
        ----------
        time : number
            Time at which a sample was required

        Returns
        -------
        float
            sampled signal for time t

        """
        return self.amplitude * self.ftype(2*np.pi*self.frequency*time)

    def sample_vectorized(self, time_vector):
        """Sample entire series based off of time vector

        Parameters
        ----------
        time_vector : array-like
            Timestamps for signal generation

        Returns
        -------
        array-like
            sampled signal for time vector

        """
        if self.vectorizable is True:
            signal = self.amplitude * self.ftype(2*np.pi*self.frequency *
                                                 time_vector)
            return signal
        else:
            raise ValueError("Signal type not vectorizable")


import numpy as np
from scipy.special import binom

def deriv(n, dx, order):
    """ Matrix derivative. Equi-spaced derivative via forward finite differences, mapping R^n into R^(n-order).

    Args:
        n (int): Number of data points
        dx (float): Width of x[k+1] - x[k]
        order (int): Order of finite difference method to use.

    Return:
        (:obj:`ndarray` of float): An n-by-(n-order) matrix derivative.

    Raises:
        ValueError: Requires n >= 2 and n - order >= 1.
    """
    if n < 2 or n - order < 1:
        raise ValueError('Bad size n={} for derivative of order {}'.format(n, order))

    # Implement finite difference at 1st order accuracy
    method = [(-1)**(order+i)*binom(order,i) for i in range(order+1)]
    # Construct matrix
    M = [method + [0] * (n - len(method))]
    for row in range(n - len(method)):
        M.append([0] * (row + 1) + method + [0] * (n - len(method) - row - 1))
    return np.array(M) / dx ** order

def integ(n, dx=1):
    """ Equi-spaced anti-derivative via the trapezoid rule mapping R^n to R^n.

    Args:
        n (int): Number of data points
        dx (float): Width of x[k+1] - x[k]

    Return:
        (:obj:`ndarray` of float): An n-by-n matrix integral.

    Raises:
        ValueError: Requires n in positive integers.
    """
    if n == 1:
        return np.array([])
    elif n == 2:
        return np.array([[0, 0],
                         [1, 1]]) * dx / 2
    elif n > 2:
        M = [[0] * n]
        for row in range(0, n - 1):
            M.append([1] + [2] * row + [1] + [0] * (n - row - 2))
        return np.array(M) * dx / 2
    else:
        raise ValueError('Bad size of {}'.format(n))


# coding: utf-8
import numpy as np

def print_array(data):
    print(" ".join(list(["%d" % i for i in data])))

def print_matrix(data):
  print('[')
  for d2 in range(np.shape(data)[0]):
      print("  ",list(data[d2]))
  print(']')

x = np.array([2,3,4])
print_array(x)

z = np.array([[2,3,6],[3,4,5]])
print_matrix(z)

"""
max
"""
print("max()")
y = x.max()
print(y)
y = np.max([2, 3, 4])
print(y)

"""
amax
"""
print("amax()")
y = np.amax([2, 3, 4])
print(y)

"""
max axis=0
"""
print("max(axis=0)")
y = z.max(axis=0)
print_array(y)

"""
max axis=1
"""
print("max(axis=1)")
y = np.max([[2,3,6],[3,4,5]], axis=1)
print_array(y)

"""
min
"""
print("min()")
y = x.min()
print(y)
y = np.min([2, 3, 4])
print(y)

"""
amin
"""
print("amin()")
y = np.amin([2, 3, 4])
print(y)

"""
min axis=0
"""
y = z.min(axis=0)
print_array(y)

"""
min axis=1
"""
y = np.min([[2,3,6],[3,4,5]], axis=1)
print_array(y)

"""
max axis=0 keepdims
"""
y = np.max([[2,3,6],[3,4,5]], axis=0, keepdims=True)
print_matrix(y)

"""
min keepdims
"""
y = np.min([[2,3,6],[3,4,5]], keepdims=True)
print_matrix(y)


# Create by Packetsss
# Personal use is allowed
# Commercial use is prohibited

import numpy as np

a = np.array([1, 2, 3])
# numpy list

b = np.array([[9.0, 8.0, 7.0], [6.0, 5.0, 4.0]])
'''print(b)'''
# 2d array

'''print(b.ndim)'''
# get dimension

'''print(a.shape)'''
# get # of elements in 1st, 2nd... dimension

'''print(a.dtype)'''
# int32 by default
# a = np.array([1, 2, 3], dtype="int16") to change type

'''print(a.itemsize)'''
# int 32 have size of 4

'''print(a.size * a.itemsize)
or
print(a.nbytes)'''
# total size

c = np.array([[1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]])

'''print(c[0, 2] == 3)'''
# get specific element

'''print(c[0, :])'''
# get whole 1st row

'''print(c[0, 1:-1:2])'''
# step the array

c[1, 5] = 20
'''print(c)'''
# change element

c[:, 2] = [1, 2]
# change all 2nd cln to 5

d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
'''print(d)'''
# 3d array

'''print(d[0, 1, 1])'''
# index for 4

d[:, 1, :] = [[9, 9], [8, 8]]
# replace value

e = np.zeros((5, 3, 4))
'''print(e)'''
# get multidimensional zeros matrix

f = np.ones(3)
'''print(f)'''
# get all ones

'''print(np.full((2, 2), 99))'''
# get all 99's

'''print(np.full_like(c, 4))'''
# get all 4's using c's dimension

'''print(np.random.rand(4, 2))
print(np.random.random_sample(c.shape))'''
# random from 0 to 1 using given size

'''print(np.random.randint(1, 5, size=(3, 3)))'''
# get a randi matrix from 2 to 4

'''print(np.identity(5))'''
# identity matrix

arr = np.array([[1, 2, 3]])
r1 = np.repeat(arr, 3, axis=0)
'''print(r1)'''
# repeat arr 3 times

quiz = np.zeros((9, 9))
quiz[0, :] = 1
quiz[:, 0] = 1
quiz[-1, :] = 1
quiz[:, -1] = 1
dim = int(np.floor(quiz.shape[0] / 2))

quiz[dim, dim] = 9
'''print(quiz)'''

g = np.array([1, 2, 3, 4])
'''print(g+2)'''
# add every element by 2

g * 2
g - 2
g ** 3
np.sin(g)
# all calculation

h = np.array([1, 0, 1, 0])
'''print(g + h)'''
# array add array

a1 = np.ones((2, 3))
b1 = np.full((3, 2), 2)
'''print(np.matmul(a1, b1))'''
# matrix multiplication

c1 = np.identity(3)
'''print(np.linalg.det(c1))'''
# identity matrix has a det of 1

stats = np.array([[1, 2, 3], [4, 5, 6]])
'''print(np.min(stats), np.max(stats, axis=1), np.sum(stats, axis=0))'''
# axis 1 is the most row, axis 0 is the most column

'''print(stats.reshape((3, 2)))'''
# change rows to clns, clns to rows

stack = np.vstack([a, stats, stats])
'''print(stack)'''
# join multiple matrix together, vertical stack

'''print(np.hstack([stats, stats]))'''
# horizontal stack

tx = np.genfromtxt("numpy_data.txt", delimiter=",")
# get all data from txt separated by a comma

tx1 = tx.astype("int32")
# change float type to int32

s = (tx1 > 50)
ss = (~((tx1 > 50) & (tx1 < 100)))
# get a boolean array of trues and falses
# ~ is not

gtfy = tx1[tx1 > 50]
# all values greater than 50

'''print(g[[1, 3]])'''
# index multiple elements

any1 = np.any(tx1 > 50, axis=0)
'''print(any1)'''
# return a row vector of any elements in all clns > 50, can use all as well

ee = np.array([1, 2, 3, 4, 5])
exam = np.array([ee, ee+5, ee+10, ee+15, ee+20, ee+25])
'''print(exam)'''

# qt1
'''print(exam[2:4, 0:2])'''

# qt2
'''print(exam[[0, 1, 2, 3], [1, 2, 3, 4]])'''

# qt3
'''print(exam[[0, 4, 5], 3:])'''

# Numpy dot product: np.dot(arr1, arr2)


#! /usr/bin/env python
"""
File: integrate_exp.py

Copyright (c) 2016 Michael Seaman

License: MIT

Description: a module for evaluating the improper integral
of f from -inf to +inf given below. The integrator class and
the midpoint integrator from HW 9 will be used as it already
has running tests.
f(x) = e^(-x^2)
"""

import numpy as np
from Integrator import Midpoint
import pandas as pd

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

def T(n, L):
    """
    Calculates the integral of f above from 0 to L
    with n trapazoids.
    """
    a = 0
    b = L
    mid_int = Midpoint(a, b, n)
    return mid_int.integrate(f)

def T_dataframe(n, L):
    """
    Calculates the integral of f above from 0 to every value in
    the array_like L every value in n for the number of approximations.
    Outputs a pandas DataFrame.
    """
    data = np.zeros((len(L),len(n)))
    for i in xrange(len(L)):
        for j in xrange(len(n)):
            data[i][j] = T(n[j], L[i])
    df = pd.DataFrame(data)
    df.index = ["L = " + str(i) for i in L]
    df.columns = ["n = " + str(i) for i in n]
    return df

def T_dataframe_error(n, L):
    """
    Calculates the difference in sqrt(pi) and the integral of f above from 0 to every value in
    the array_like L every value in n for the number of approximations.
    Outputs a pandas DataFrame.
    """
    data = np.zeros((len(L),len(n)))
    for i in xrange(len(L)):
        for j in xrange(len(n)):
            data[i][j] = .5 * np.pi**.5 - T(n[j], L[i])
    df = pd.DataFrame(data)
    df.index = ["L = " + str(i) for i in L]
    df.columns = ["n = " + str(i) for i in n]
    return df


#!/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_broadcasting.py
2019-07-02 (Tue)
"""
# Python Numpy Tutorial > Numpy > Broadcasting
#   When performing arithmetic operations,
#     broadcasting is a powerful mechanism that allows numpy
#     to work with arrays of different shapes.
#   Frequently we have a smaller array and a larger array, and
#     we want to use the smaller array multiple times
#     to perform some operation on the larger array.
#   Broadcasting typically makes your code more concise and faster,
#     so you should strive to use it where possible.
#
# This examples cover:
#
#
# Read more about:
#   (full list of) universal functions that support broadcasting
#     Available ufuncs
#     https://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs
#   Explanation of this topic from different documents
#     Broadcasting
#     https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html
#

import numpy as np

# Add a constant vector to each row of a matrix.
x = np.array( [[1,2,3],[4,5,6],[7,8,9],[10,11,12]] )
print(x)
#[[ 1  2  3]
# [ 4  5  6]
# [ 7  8  9]
# [10 11 12]]

v = np.array( [1,0,1] )
print(v)
#[1 0 1]

# Create an empty matrix with the same shape as x.
y = np.empty_like( x )
print('np.empty_like(x)=')
print(y)
#np.empty_like(x)=
#[[ 1  2  3]
# [ 4  5  6]
# [ 7  8  9]
# [10 11 12]]

# Add the vector v to each row of the matrix x
# This works; however when the matrix x is very large,
#   computing an explicit loop in Python could be slow.
for i in range(4):
    y[i,:] = x[i,:] + v
print(y)
#[[ 2  2  4]
# [ 5  5  7]
# [ 8  8 10]
# [11 11 13]]

# Stack 4 copies of v on top of each other
vv = np.tile(v, (4,1) )
print( vv )
#[[1 0 1]
# [1 0 1]
# [1 0 1]
# [1 0 1]]

# Add x and vv elementwise
y = x + vv
print( y )
#[[ 2  2  4]
# [ 5  5  7]
# [ 8  8 10]
# [11 11 13]]

# Add v to each row of x using broadcasting
y = x + v
print( y )
#[[ 2  2  4]
# [ 5  5  7]
# [ 8  8 10]
# [11 11 13]]

# TODO: Read the following explanation cuz I'm gonna skip reading it.
#The line y = x + v works even though x has shape (4, 3) and v has shape (3,) due to broadcasting; this line works as if v actually had shape (4, 3), where each row was a copy of v, and the sum was performed elementwise.
#
#Broadcasting two arrays together follows these rules:
#
#If the arrays do not have the same rank, prepend the shape of the lower rank array with 1s until both shapes have the same length.
#The two arrays are said to be compatible in a dimension if they have the same size in the dimension, or if one of the arrays has size 1 in that dimension.
#The arrays can be broadcast together if they are compatible in all dimensions.
#After broadcasting, each array behaves as if it had shape equal to the elementwise maximum of shapes of the two input arrays.
#In any dimension where one array had size 1 and the other array had size greater than 1, the first array behaves as if it were copied along that dimension
#If this explanation does not make sense, try reading the explanation from the documentation or this explanation.

######################################
# Some applications of broadcasting  #
######################################

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

print(w, w.shape)
#[4 5] (2,)

print( np.reshape( v,(3,1) )*w )
#[[ 4  5]
# [ 8 10]
# [12 15]]

#1*[4 5] = [4 5]
#2*[4 5] = [8 10]
#3*[4 5] = [12 15]

# Add a vector to each row of a matrix
x = np.array( [[1,2,3],[4,5,6]] )
print( x )
#[[1 2 3]
# [4 5 6]]

print( x+v )
#[[2 4 6]
# [5 7 9]]
# [1 2 3] is added to both rows. In other words,
# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3).

print( (x.T + w ).T )
#[[ 5  6  7]
# [ 9 10 11]]

# Let's see how it worked.
print( x.T )
#[[1 4]
# [2 5]
# [3 6]]

print( x.T + w )
#[[ 5  9]
# [ 6 10]
# [ 7 11]]

# Another solution is to reshape w to a column vector shape shape (2,1).
print( x + np.reshape(w,(2,1)) )
#[[ 5  6  7]
# [ 9 10 11]]

print( np.reshape(w,(2,1)) )
#[[4]
# [5]]

# Multiply a matrix by a constant
print( x*2 )
#[[ 2  4  6]
# [ 8 10 12]]


import numpy as np
import warnings

def pielou_evenness(array, alpha = 0.5):
    """
    Compute Pielou's Evenness Index

    0 : maximal skew of population towards clonal frequency of a single sequence
    1 : extreme evenness across clonal frequencies i

    Parameters
    ----------
    array: np.array
        array of values
    alpha : float
        represents the smoothing parameter added to all values to avoid zero

    Returns
    -------
    p_evenness : float

    between 0 and 1

    Examples
    -------
    >>> pielou_evenness(np.array([1,1,1,1,1,1]))
    1.0
    >>> pielou_evenness(np.array([10,10,10,10,10,10]))
    1.0
    >>> pielou_evenness(np.array([10,1,1,1,1,1]))
    0.6546601218437399
    >>> pielou_evenness(np.array([10,1]))
    0.4394969869215134
    >>> pielou_evenness(np.array([1000,1,1,1,1,1]))
    0.02196415527496694
    >>> pielou_evenness(np.array([1]))
    1

    Notes
    -----
    Chiffelle et al. 2020: "Pielou's index, which is itself derived from the ratio between the Shannon entropy and
    the maximization of the diversity distribution fo species with a sample...where '

    The compliment of clonal evenness (1-Pielou's index) is often used to get a Clonality score"
        0 represents a maximally diverse population with even frequencies, and
        1 represents a a set with a high degree of clonal dominance.

              N
             ___
             ╲      p   log  ⎛p ⎞
       =   - ╱       i     b ⎝ i⎠
             ‾‾‾
             i=1
                    ──────────────
                       log  (N)
                           b
    For N clones or species, indexed i, let p_i be the frequency of the ith clone

    Is sensitive to number of total clones. For more information see:

    Chiffelle, J., Genolet, R., Perez, M. A., Coukos, G., Zoete, V., & Harari, A. (2020).
    T-cell repertoire analysis and metrics of diversity and clonality.
    Current Opinion in Biotechnology, 65, 284-295.
    """
    if array.size == 1:
        warnings.warn("pielou_evenness() received input array of length 1, returning 1 by default")
        return 1

    array = array.astype('float64').flatten()

    if np.any(array == 0):
        array += np.min(a[np.nonzero(a)])/2

    array = array / np.sum(array)

    numerator = np.dot(array, np.log2(array))
    denominator = np.log2(array.size)

    p_evenness =  -1 * (numerator/denominator)

    assert 0 <= p_evenness, "Pielou's index cannot be less than zero, check input values"
    assert 1 >= p_evenness, "Pielou's index cannot be greater than 1, check input values"

    return p_evenness


"""
File: Lagrange_poly1.py
Exercise 5.23
Copyright (c) 2016 Andrew Malfavon
License: MIT
Implement Lagrange's interpolation formula
for a coninuous function.
"""

import numpy as np

#multiples each result of the array
def L_k(x, k, xp, yp):
    xk = xp[k]
    xp = np.delete(xp, k)
    arr = []
    for i in range(len(xp)):
        arr.append((x - xp[i]) / (xk - xp[i]))
    return np.prod(arr)

#sums each result of the array
def p_L(x, xp, yp):
    arr = []
    for k in range(len(xp)):
        arr.append(yp[k] * L_k(x, k, xp, yp))
    return np.sum(arr)

#tests the polynomial p_L goes through each point
def test_p_L(xp = np.linspace(0, np.pi, 5), yp = np.sin(np.linspace(0, np.pi, 5))):
    values = 0
    for k in range(len(xp)):
        values += abs(p_L(xp[k], xp, yp) - yp[k])
    return values
    assert values == 0.0


import numpy as np

# activation func
def step_funciton(x):
  y = x > 0
  return y.astype(np.int)

def sigmoid(x):
  sigmoid_range = 34.538776394910684
  x2 = np.maximum(np.minimum(x, sigmoid_range), -sigmoid_range)

  return 1 / (1 + np.exp(-x2))

def relu(x):
  return np.maximum(0, x)

# output
def softmax(a):
  c = np.max(a) # get max num
  exp_a = np.exp(a - c) # sub largest value from each element

  sum_exp_a = np.sum(exp_a)
  y = exp_a / sum_exp_a

  return y

def identity_function(x):
  return x

# loss func
def mean_squared_err(y, t):
  return 0.5 * np.sum((y-t)**2)

def cross_entropy_err(y, t):
  delta = 1e-7
  return -np.sum(t * np.log(y + delta))

# gradient
def numerical_gradient(f, x):
  h = 1e-4 # 0.0001
  grad = np.zeros_like(x)

  it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
  while not it.finished:
    idx = it.multi_index
    tmp_val = x[idx]
    x[idx] = tmp_val + h
    fxh1 = f(x) # f(x+h)

    x[idx] = tmp_val - h
    fxh2 = f(x) # f(x-h)
    grad[idx] = (fxh1 - fxh2) / (2*h)

    x[idx] = tmp_val # 値を元に戻す
    it.iternext()

  return grad

def sigmoid_grad(x):
  return (1.0 - sigmoid(x)) * sigmoid(x)


# import pandas
import pandas as pd

# read CSV directly from URL and save results
df = pd.read_csv('http://www-bcf.usc.edu/~gareth/ISL/Advertising.csv', index_col=0)
df.head(3)
# check shape of dataframe
df.shape

# Visualization data using seaborn
import seaborn as sns

# visualize the relationship the features and response using scatterplots
sns.pairplot(df, x_vars=['TV', 'radio', 'newspaper'], y_vars='sales', size=7, aspect=0.7, kind='reg')

# Linear regression
# create a python list of feature names
feature_cols = ['TV', 'radio', 'newspaper']

# use the list to select a subset of the original DF
X = df[feature_cols]

## Equivalent is
# X = df[['TV', 'radio', 'newspaper']]
# X.shape
# type(X)
X.head()
y = df['sales']

y.head()
# type(y)
# y.shape

# Split X and y intro train/test
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)

# print(X_train.shape, X_test.shape)
# print(y_train.shape, y_test.shape)

# Linar regression in sklearn
# import and instantiate linear regression
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()

# fit the model to training data
linreg.fit(X_train, y_train)
# interprest model coeffiecents
print(linreg.intercept_)
print(linreg.coef_)
# pair feature names with coeffiecents
list(zip(feature_cols, linreg.coef_))
# making predictions
y_pred = linreg.predict(X_test)

# we need a new evaluation metric
# define true and predicted values
true = [100, 50, 30, 20]
pred = [90, 50, 50, 30]

# calculate the MAE by hand
print('MAE = %f' %((10+0+20+10)/4))
#or use sklean
from sklearn import metrics
print('MAE = %f' %metrics.mean_absolute_error(true,pred))

# now calc MSE
print('MSE = %f' %((10**2+0**2+20**2+10**2)/4))
print('MSE = %f' %metrics.mean_squared_error(true,pred))

# NOW RMSE!
import numpy as np
print('RMSE = %f' %(np.sqrt((10**2+0**2+20**2+10**2)/4)))
print('RMSE = %f' %np.sqrt(metrics.mean_squared_error(true,pred)))

# Compute RMSE for sales predictions
print(np.sqrt(metrics.mean_squared_error(y_test, y_pred)))

# What if we're over fitting?
# Choose less/features
feature_cols = ['TV', 'radio']
X = df[feature_cols]
y = df.sales
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
linreg.fit(X_train, y_train)
y_pred = linreg.predict(X_test)
print('RMSE = %f'%np.sqrt(metrics.mean_squared_error(y_test,y_pred)))


import numpy as np

print("\n Null Matrix : ")
c = np.zeros([3,4],dtype = int) # By default, values are in float
print(c)

print("\nUnit Matrix : ")
c = np.ones([3,4],dtype = int)
print(c)

print("\nCreating an array with a sequence of numbers :")
c = np.arange(5,70,4)
print(c)
x = 2*((4*2)-1)
c = np.arange(5,70,x)  # You can use complex equations as well
print(c)
c = np.arange(5,70,0.5) # You can use floating point values as well
print(c)

print("\nLinspace : ")
c = np.linspace(10,100,10)   # From range 10-100 with 10 divisions
print(c)

print("\nPerforming Logical Operations between arrays : ")
a = np.array([0,1,1,0])
b = np.array([1,1,1,0])
print("OR OPERATION  : ",np.logical_or(a,b))
print("AND OPERATION : ",np.logical_and(a,b))
print("XOR OPERATION : ",np.logical_xor(a,b))
print("NOT OEPRATION : ",np.logical_not(a))

print("\nTrignometry Functions : ")
a = np.linspace(0,2,9)
print("a : ", a)
print("COS : \n", np.cos(a))
print("SIN : \n", np.sin(a))
print("TAN : \n", np.tan(a))
print("INVERSE OF SIN : \n", np.arcsin(a))  # Similarly for cos and tan

print("\nMathematical Functions : ")
a = np.array([-1,3,5,-9,10,-7])
print("A : ", a)
b = np.array([6,4,5,5,6,10])
print("B : ", b)
print("Absolute of A : ",np.abs(a))
print("Adding A and B : ", np.add(a,b))
print("Exponents of B : ", np.exp(b))
print("Power of B with base 3 :", np.power(b,3))
print("Log Base 2 of B : ", np.log2(b))
print("Sum of all elements of A : ", np.add.reduce(a))
print("Multiple of all elements of A : ", np.multiply.reduce(a))

print("Finding Maximum and Minimum values of an Array : ")
a = np.array([2,5,8,1,99,23,12,14,2,21,45])
print("Maximum element in array :", np.max(a))
print("Location of maximum element in array :", np.argmax(a))
print("Minimum element in array :", np.min(a))
print("Location of Minimum element in array :", np.argmin(a))

input("Press Enter key to exit ")


# -*- coding: utf-8 -*-
"""
Created on Mon Apr  1 09:14:28 2019

@author: Miguel Ángel Vélez
"""

import numpy as np
#------------------------------------------------------------------------------------------------#
#-------------------------------------- Linear Regression ---------------------------------------#
#------------------------------------------------------------------------------------------------#

def get_xy(x, y):
    """
    """
    n = len(x)
    xy = [x[i] * y[i] for i in range(n)]
    return xy

def get_x2(x):
    """
    """
    x2 = [x**2 for x in x]
    return x2

def get_sc(x):
    """
    """
    n = len(x)
    x2 = get_x2(x)
    sc = sum(x2) - (sum(x))**2 / n
    return sc

def get_spc(x, y):
    """
    """
    n = len(x)
    xy = get_xy(x,y)
    spc = sum(xy) - (sum(x) * sum(y)) / n
    return spc

def get_sce(x, y):
    """
    """
    sce = get_sc(y) - (get_spc(x,y)**2) / get_sc(x)
    return sce

def get_cme(x, y):
    """
    """
    cme = get_sce(x, y) / (len(x) - 2)
    return cme

def get_se(x, y):
    """
    """
    se = get_cme(x, y)**0.5
    return se

def get_sb(x, y):
    """
    """
    sb = get_se(x,y) / (get_sc(x)**0.5)
    return sb

def get_sr(x, y):
    """
    """
    sr = (1 - get_r2(x, y) / (len(x) - 2))**0.5
    return sr

def get_r(x, y):
    """
    """
    r = get_spc(x, y) / ((get_sc(x) * get_sc(y))**0.5)
    return r

def get_r2(x, y):
    """
    """
    r2 = get_r(x, y)**2
    return r2

def get_t_beta(x, y, beta=0):
    """
    """
    t = (slope(x, y) - beta) / get_sb(x, y)
    return t

def get_t_rho(x, y, rho=0):
    """
    """
    t = (get_r(x, y) - rho) / get_sr(x, y)
    return t

def slope(x, y):
    """
    """
    m = get_spc(x, y) / get_sc(x)
    return m

def intercept(x, y):
    """
    """
    b = np.mean(y) - slope(x, y) * np.mean(x)
    return b

def regression(x, y):
    """
    """
    model = lambda xi : intercept(x,y) + slope(x, y) * xi
    model.shape = "ÿ = {} + {}x".format(round(intercept(x, y), 2), round(slope(x, y), 2))
    return model

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


# we are going to solve -u''(x) + 16*u(x)^p = 0
# initial condition of u(0) = 0 and u(1) = 2
# using Newton's method with an initial guess of 2x
# build a mesh on the domain of [0,1]

import numpy as np
import matplotlib.pyplot as plt

left_point = 0.0
right_endpoint = 1.0

p = 1.0  # the power on the u(x) term, the problem is nonlinear when p != 1
n = 3.0  # number of sub intervals
h = 1.0 / (n + 1.0)  # sub interval length

x = np.arange(left_point + h, right_endpoint, h)

u = 2.0 * x
print "this is u", u

for i in np.arange(0, 1):

    # Jacobian has -1 on both sides of the main diagonal
    diagonals = -1.0*np.ones(n-1)

    main_diagonal = np.zeros(len(x))

    for j in np.arange(n):
        # print x[i]
        main_diagonal[j] = 2.0 + 16.0 * p * np.power(h, 2.0) * np.power(u[j], p - 1.0)
        # print main_diagonal

    jacobian = np.diag(diagonals, -1) + np.diag(diagonals, 1) + np.diag(main_diagonal)
    print jacobian

    # but I think we also need an F(u) vector
    # making space to put this vector.
    F = np.zeros(n)

    for k in np.arange(0, n):
        print u[i]
        F[k] = -u[k] + (2.0 * u[k+1]) - u[k+2] + (16.0 * (h**2.0) * u[k+1]**p)

    # for k in np.arange(0, n):
    #     if k == 0:
    #         F[k] = u[k+1] - 2.0*u[k] + left_point + (16.0 * (h**2.0) * u[k]**p)
    #     elif k == n-1:
    #         F[k] = right_endpoint - 2.0*u[k] - u[k-1] + (16.0 * (h**2.0) * u[k]**p)
    #     else:
    #         F[k] = u[k+1] - 2.0*u[k] + u[k-1] + (16.0 * (h**2.0) * (u[k]**p))

    print 'This is F', F

    # now we want to solve the system for delta u
    delta_u = np.linalg.solve(jacobian, F)

    print "this is delta u", delta_u

    u += delta_u

    print "this is u.", u

    if np.linalg.norm(delta_u) < 10e-15:
        break

def hyperbolic_sin(x):
    return 2.0 * np.sinh(4.0*x) / np.sinh(4)

# x = np.arange(0, 1 + h, h)
y = hyperbolic_sin(x)
# print "this is y", y
plt.plot(x, u)
plt.plot(x, y)
# plt.show()


import math
import numpy as np
from collections import defaultdict

# Converts from adjacency matrix to adjacency list
def convert_matrix_to_list(a):
    adjList = defaultdict(list)
    for i in range(len(a)):
        for j in range(len(a[i])):
            if a[i][j] > 0:
                adjList[i].append(j)
    return adjList

def MST(G):
    """
    Find a Minimum Spanning Tree using Prim's Algorithm
        - G: an adjacency matrix representing a graph
    """

    tree = []

    INF = math.inf

    # Number of vertices in graph
    V = G.shape[-1]

    # Create a set S to track selected vertices
    # selected vertices will become true otherwise false
    S = np.zeros(V, dtype=bool)

    # Initialize number of edge to 0
    n_edges = 0

    # The number of edges in Minimum Spanning Tree will be
    # always less than (V - 1), where V is the number of vertices in the graph

    # Choose 0th vertex and make it true
    S[0] = True

    # For every selected vertex in the set S, find all adjacent vertices
    # that are not included in the set S.
    # Choose an adjacent vertex that is nearest to one of selected vertices.
    while (n_edges < V - 1):
        minimum = INF
        x = 0
        y = 0
        for i in range(V):
            if S[i]:
                for j in range(V):
                    if ((not S[j]) and G[i][j]):
                        if minimum > G[i][j]:
                            minimum = G[i][j]
                            x = i
                            y = j
        S[y] = True
        tree.append([x, y])
        n_edges += 1
    return np.array(tree)

if __name__ == "__main__":
    a = np.array(
          [[0, 9, 75, 2, 0, 10],
          [9, 0, 95, 19, 42, 99],
          [75, 95, 0, 51, 66, 12],
          [2, 19, 51, 0, 31, 22],
          [0, 42, 66, 31, 0, 89],
          [10, 99, 12, 22, 89, 0]]
        )
    adjList = convert_matrix_to_list(a)
    print("Adjacency List:")
    for i in adjList:
        print(i, end ="")
        for j in adjList[i]:
            print(" -> {}".format(j), end ="")
        print()

    print(MST(a))


"""
Objetivo: Resolver questão 1 do quarto laboratorio.
"""

from Funcoes import LU, Gauss_Siedel
import numpy as np

A = np.array([[1, 1, -1],
              [1, 1, 4],
              [2, -1, 2]], dtype='float16')
P = np.array([[1],
              [2],
              [3]], dtype='float16')

#Por LU:
s = LU(A, P)
print(f'O vetor solução pelo metodo da decomposição LU é: \n{s}')
#Por Gauss-Siedel
s = Gauss_Siedel(A, P, 10)
print(f'O vetor solução pelo metodo da Gauss-Siedel é: \n{s}')
print('Como vemos, o valor deu muito distante em comparação com o outro metodo, isso ocorre porque para essa matriz',
      ' o metodo não converge.')


# This test is a composition of various problems involving SE3.
# TODO add more cases of use, now it is an imcomplete test
# add path to local library mrob on bashr_rc: "export PYTHONPATH=${PYTHONPATH}:${HOME}/mrob/mrob/lib"
import mrob
import numpy as np

# Illustration of different orientations
# --------------------------------------------------------

print('Printing orientations')
w = np.zeros(3)
R = mrob.geometry.SO3(w)
R.print()
T = np.eye(4)
T[:3,:3] = R.R()

# Rotation on z axis
w[2] = -np.pi/4
R = mrob.geometry.SO3(w)
R.print()
T[:3,:3] = R.R()

# Rotation on z axis
w = np.random.randn(3)
R = mrob.geometry.SO3(w)
R.print()
T[:3,:3] = R.R()

# Interpolation
# --------------------------------------------------------
xi_ini = np.array([0,0,0,0,0,0], dtype='float64')
#xi_fin = np.array([np.pi/3,1,0,0,0,0], dtype='float64')
xi_fin = np.random.rand(6)*10
if np.linalg.norm ( xi_fin[0:3] ) > np.pi:
    xi_fin[0:3] = xi_fin[0:3] / np.linalg.norm ( xi_fin[0:3] ) * (np.pi-1e-5)
N = 20
xi = np.zeros((N,6))
t = np.zeros(N)
for i in range(6):
    xi[:,i] = np.linspace(xi_ini[i],xi_fin[i],N, dtype='float64')
t = np.linspace(0,1,N, dtype='float64')

# interpolation in the manifold of se(3)^vee
# and proper interpolation in SE(3)
T_0 = mrob.geometry.SE3(xi_ini)
T_0_inv = T_0.inv()
T_1 = mrob.geometry.SE3(xi_fin)
T_1.print()
print('direct T1\n',T_1.T())
mrob.geometry.SE3(T_1.T()).print()
#dxi = mrob.geometry.SE3( (T_1.T() @ T_0_inv.T()) ).Ln()
dxi = T_1.mul(T_0_inv).Ln()
for i in range(N):
    Ti = mrob.geometry.SE3(xi[i,:])
    print(Ti.T())

    Ts = mrob.geometry.SE3(t[i]*dxi).mul(T_0)
    print(Ts.T())

    # ploting and visualizing error
    #print(Ts.T())
    print(np.linalg.norm(Ti.Ln() - Ts.Ln()))
    #T.transform(np.array([0,0,0], dtype='float64'))

# inverse as the negate in the manifold -xi
e = np.zeros(1000)
for i in range(1000):
    xi = np.random.rand(6)*3
    Tr = mrob.geometry.SE3(xi)
    T = Tr.inv()
    Ti = mrob.geometry.SE3(-xi)
    e[i] = np.linalg.norm(T.T()- Ti.T())
    #print( np.linalg.norm(T.T()- Ti.T()))

print(np.max(e), np.min(e))

w = np.random.rand(3)
R = mrob.geometry.SO3(w)
print('SO3 matrix: \n', R.R() )
print('SO3 in the manifold: \n', R.Ln())


import numpy as np

def modular_sqrt(a, p):

    def legendre_symbol(a, p):
        """ Compute the Legendre symbol a|p using
            Euler's criterion. p is a prime, a is
            relatively prime to p (if p divides
            a, then a|p = 0)

            Returns 1 if a has a square root modulo
            p, -1 otherwise.
        """
        ls = np.power(a, (p - 1) // 2)
        return -1 if ls == p - 1 else np.mod(ls, p)

    """ Find a quadratic residue (mod p) of 'a'. p
        must be an odd prime.

        Solve the congruence of the form:
            x^2 = a (mod p)
        And returns x. Note that p - x is also a root.

        0 is returned is no square root exists for
        these a and p.

        The Tonelli-Shanks algorithm is used (except
        for some simple cases in which the solution
        is known from an identity). This algorithm
        runs in polynomial time (unless the
        generalized Riemann hypothesis is false).
    """
    # Simple cases
    #
    if legendre_symbol(a, p) != 1:
        return 0
    elif a == 0:
        return 0
    elif p == 2:
        return p
    elif p % 4 == 3:
        return np.mod(np.power(a, (p + 1) // 4), p)

    # Partition p-1 to s * 2^e for an odd s (i.e.
    # reduce all the powers of 2 from p-1)
    #
    s = p - 1
    e = 0
    while s % 2 == 0:
        s //= 2
        e += 1

    # Find some 'n' with a legendre symbol n|p = -1.
    # Shouldn't take long.
    #
    n = 2
    while legendre_symbol(n, p) != -1:
        n += 1

    # Here be dragons!
    # Read the paper "Square roots from 1; 24, 51,
    # 10 to Dan Shanks" by Ezra Brown for more
    # information
    #

    # x is a guess of the square root that gets better
    # with each iteration.
    # b is the "fudge factor" - by how much we're off
    # with the guess. The invariant x^2 = ab (mod p)
    # is maintained throughout the loop.
    # g is used for successive powers of n to update
    # both a and b
    # r is the exponent - decreases with each update
    #
    x = np.mod(np.power(a, (s + 1) // 2), p)
    b = np.mod(np.power(a, s), p)
    g = np.mod(np.power(n, s), p)
    r = e

    while True:
        t = b
        m = 0
        for m in range(r):
            if t == 1:
                break
            t = np.mod(np.power(t, 2), p)

        if m == 0:
            return x

        gs = np.mod(np.power(g, 2 ** (r - m - 1)), p)
        g = (gs * gs) % p
        x = (x * gs) % p
        b = (b * g) % p
        r = m


# Question: https://projecteuler.net/problem=697

"""
    . Let n be the number of random variables U_i.
    . We want to find c such that,
        Pr(c * U_1 * U_2 * ... * U_n < 1) = 0.25
      or,
        Pr(c * U_1 * U_2 * ... * U_n > 1) = 0.75
      or,
        Pr[ln(c) + ln(U_1) + ln(U_2) + ... + ln(U_n) > 0] = 0.75
      or,
        Pr[ln(U_1) + ln(U_2) + ... + ln(U_n) > -ln(c)] = 0.75
      or,
        Pr[-ln(U_1) - ln(U_2) - ... - ln(U_n) < ln(c)] = 0.75
    . From this answer here https://math.stackexchange.com/a/3079134, we have that,
      Pr(sum(-ln(U) < c)) follows the Gamma distribution with k = n, theta = 1,
                             i.e. the Gamma distribution with alpha = n, beta = 1
    . cdf = cumulative_distribution_function
    . So, Pr(sum(-ln(U)) < c) = gamma.cdf(x = c, alpha = n)
    . We know that, for a fixed variable n,
      * gamma.cdf(x=c, alpha=n) increases monotonically as variable c increases
    . This means that we can use binary search to find c.

"""

from scipy.stats import gamma
from numpy import log, log10, e

N = 10**7
P = 0.25

if __name__ == "__main__":
    target = 1.0 - P
    a = N

    l = 0
    r = 2*N

    m = 0

    while abs(l - r) >= 0.000001:
        m = (l + r) / 2
        cdf = gamma.cdf(m, a)
        print(m, cdf)
        if cdf > target:
            r = m
        else:
            l = m

    #ans = m / log(10)
    ans = m * log10(e) # m = ln(c), so m * log10(e) = log10(c)
    print(ans)


import numpy as np
import matplotlib.pyplot as plt

class DeterministicSIR:
    def __init__(self, beta, gamma, s_0, i_0, r_0=0):
        """
        Parameters
        ----------
        beta : float, >=0
            Infection rate.
        gamma : float, >=0
            Recovery rate.
        s_0 : int
            Number of susceptible individuals at the beginning.
        i_0 : int
            Number of infected individuals at the beginning.
        r_0 : int, default: 0
            Number of recovered individuals at the beginning.
        """
        self.beta = beta
        self.gamma = gamma
        self.s_0 = s_0
        self.i_0 = i_0
        self.r_0 = r_0
        self.n = s_0 + i_0 + r_0

    def solve_euler(self, t_end=10, n_steps=100):
        """
        Calculates S(t), I(t), and R(t) for :math:`t \in [0, t_end]`
        according to the Euler method. The intervall
        :math:`[0, t_end]` is partitioned into `n_steps` intervals.

        Parameters
        ----------
        t_end : int
            Time until which we want to calculate S(t), I(t), and
            R(t).
        n_steps : int
            Number of time steps to calculate.
        """
        s_, i_, r_ = [np.empty(n_steps + 1) for _ in range(3)]
        s_[0], i_[0], r_[0] = self.s_0, self.i_0, self.r_0

        delta_t = t_end / n_steps
        for t in range(1, n_steps + 1):
            s_[t] = s_[t - 1] - delta_t * \
                self.beta * s_[t - 1] * i_[t - 1] / self.n
            i_[t] = i_[t - 1] + delta_t * i_[t - 1] * \
                (self.beta * s_[t - 1] / self.n - self.gamma)
            r_[t] = r_[t - 1] + delta_t * i_[t - 1] * self.gamma
        self.s_, self.i_, self.r_ = s_, i_, r_
        self.t_end = t_end
        self.n_steps = n_steps
        return self

    def plot(self, width=5.51, height=4, n_xticks=6, fname=None):
        t = np.linspace(0, self.t_end, self.n_steps + 1)
        plt.figure(dpi=300, figsize=(width, height))
        plt.title("Deterministic SIR model with " +
                  "$\\beta=" + str(self.beta) + "$ and " +
                  "$\\gamma=" + str(self.gamma) + "$")
        plt.xticks(np.linspace(0, self.t_end, n_xticks))
        plt.xlabel("$t$")
        plt.ylabel("$S(t),\ I(t),\ R(t)$")
        plt.plot(t, self.s_, label="$S(t)$")
        plt.plot(t, self.i_, label="$I(t)$")
        plt.plot(t, self.r_, label="$R(t)$")

        plt.xlim([0, self.t_end])
        plt.ylim([0, self.n])
        plt.grid()
        plt.legend()

        if fname:
            plt.savefig(fname + ".pdf")


r"""
Solve Poisson equation in 2D with mixed Dirichlet and Neumann bcs

    \nabla^2 u = f,

The equation to solve is

     (\nabla^2 u, v)_w = (f, v)

Use any combination of Dirichlet and Neumann boundary conditions.

"""
import os
import sympy as sp
import numpy as np
from shenfun import inner, div, grad, TestFunction, TrialFunction, \
    Array, Function, FunctionSpace, dx, legendre, extract_bc_matrices, \
    TensorProductSpace, comm, la

# Use sympy to compute a rhs, given an analytical solution
# Choose a solution with non-zero values

xdomain = (-1, 1)
ydomain = (-1, 1)
x, y = sp.symbols("x,y", real=True)
#ue = sp.cos(2*sp.pi*x)*sp.cos(2*sp.pi*y)
ue = sp.chebyshevt(4, x)*sp.chebyshevt(4, y)
#ue = sp.legendre(4, x)*sp.legendre(4, y)
#ue = x**2 + sp.exp(x+2*y)
#ue = (0.5-x**3)*(0.5-y**3)
#ue = (1-y**2)*sp.sin(2*sp.pi*x)
fe = - ue.diff(x, 2) - ue.diff(y, 2)

# different types of boundary conditions
bcx = [
    {'left': ('D', ue.subs(x, xdomain[0])), 'right': ('D', ue.subs(x, xdomain[1]))},
    {'left': ('N', ue.diff(x, 1).subs(x, xdomain[0])), 'right': ('N', ue.diff(x, 1).subs(x, xdomain[1]))},
    {'left': ('N', ue.diff(x, 1).subs(x, xdomain[0])), 'right': ('D', ue.subs(x, xdomain[1]))},
    {'left': ('D', ue.subs(x, xdomain[0])), 'right': ('N', ue.diff(x, 1).subs(x, xdomain[1]))},
    #{'right': (('D', ue.subs(x, xdomain[1])), ('N', ue.diff(x, 1).subs(x, xdomain[1])))}
]

bcy = [
    {'left': ('D', ue.subs(y, ydomain[0])), 'right': ('D', ue.subs(y, ydomain[1]))},
    {'left': ('N', ue.diff(y, 1).subs(y, ydomain[0])), 'right': ('D', ue.subs(y, ydomain[1]))},
    {'left': ('D', ue.subs(y, ydomain[0])), 'right': ('N', ue.diff(y, 1).subs(y, ydomain[1]))},
    #{'right': (('D', ue.subs(y, ydomain[1])), ('N', ue.diff(y, 1).subs(y, ydomain[1])))},
    {'left': ('N', ue.diff(y, 1).subs(y, ydomain[0])), 'right': ('N', ue.diff(y, 1).subs(y, ydomain[1]))}
]

def main(N, family, bci, bcj, plotting=False):
    global fe, ue
    BX = FunctionSpace(N, family=family, bc=bcx[bci], domain=xdomain)
    BY = FunctionSpace(N, family=family, bc=bcy[bcj], domain=ydomain)
    T = TensorProductSpace(comm, (BX, BY))
    u = TrialFunction(T)
    v = TestFunction(T)

    # Get f on quad points
    fj = Array(T, buffer=fe)

    # Compare with analytical solution
    ua = Array(T, buffer=ue)

    constraint = ()
    if T.use_fixed_gauge:
        mean = dx(ua, weighted=True) / inner(1, Array(T, val=1))
        constraint = ((0, mean),)

    # Compute right hand side of Poisson equation
    f_hat = Function(T)
    f_hat = inner(v, fj, output_array=f_hat)

    # Get left hand side of Poisson equation
    A = inner(v, -div(grad(u)))

    u_hat = Function(T)

    sol = la.Solver2D(A)
    u_hat = sol(f_hat, u_hat, constraints=constraint)
    uj = u_hat.backward()

    assert np.allclose(uj, ua), np.linalg.norm(uj-ua)
    print("Error=%2.16e" %(np.sqrt(dx((uj-ua)**2))))

    if 'pytest' not in os.environ and plotting is True:
        import matplotlib.pyplot as plt
        X, Y = T.local_mesh(True)
        plt.contourf(X, Y, uj, 100);plt.colorbar()
        plt.figure()
        plt.contourf(X, Y, ua, 100);plt.colorbar()
        plt.figure()
        plt.contourf(X, Y, ua-uj, 100)
        plt.colorbar()
        #plt.show()

if __name__ == '__main__':
    import sys
    N = int(sys.argv[-1]) if len(sys.argv) == 2 else 16
    for family in ('C', 'L'):
        for bci in range(4):
            for bcj in range(4):
                main(N, family, bci, bcj)


#! /usr/bin/env python
"""
File: diff_func.py

Copyright (c) 2016 Michael Seaman

License: MIT

Description: a module for analyzing the approximated
derivatives of given functions, that have particularly
chaotic behavior
"""

import numpy as np
import matplotlib.pyplot as plt
from calculus import discrete_func

def f(x):
    return np.log(x + .01)

def g(x):
    return np.cos( np.exp(10 * x) )

def h(x):
    return x ** x

def f_prime(x):
    return 1 / (x + .01)

def g_prime(x):
    return -10 * np.exp(10 * x) * np.sin( np.exp(10 * x) )

def h_prime(x):
    return np.log(x) * h(x) + x* x** (x-1)

def linear_func(x):
    return 8*x - 12

def plot_approx_derivative(f, a, b, n):
    """
    Takes a function f and calculates its derivative with 'diff2'
    then plots it over the interval a to b.
    """
    xList = np.linspace(a, b, n+1)
    yList = diff2(f, a, b, n)
    plt.plot(xList, yList)
    plt.title(f.__name__ + "'(x)")
    plt.show()

def plot_analytic_and_discrete_derivatives(f, f_prime, a, b, n):
    """
    Takes original function f and it's found analyitic derivative. Evaluates
    the functions derivative according to the finite difference formula over a
    to b and plots the discrete values alongside the discretized f_prime.
    """
    xList_discrete = np.linspace(a, b, n+1)
    yList_discrete = diff2(f, a, b, n)
    plt.plot(xList_discrete, yList_discrete, 'r')
    xList_analytic = discrete_func(f_prime, a, b, n)[0]
    yList_analytic = discrete_func(f_prime, a, b, n)[1]
    plt.plot(xList_analytic, yList_analytic, 'g')
    plt.title("Analytic " + f.__name__ + "'(x) [green] vs Approximated " + f.__name__ + "'(x) [red]")
    plt.show()

def diff2(f, a, b, n):
    """
    Re-worked from CW 5

    Evaluates the derivative over a to b with n finite difference points
    Uses matrix multiplaction to sum the indivdual weights
    """
    x, y = discrete_func(f, a, b, n)
    h = ( b - a ) / float(n)

    ident_h = np.identity(n - 1) * 1 / (2 * h)
    ident_h = np.lib.pad(ident_h, ((1,1), (2,0)), 'constant', constant_values=(0))
    ident_neg_h = np.identity(n - 1) * -1 / (2 * h)
    ident_neg_h = np.lib.pad(ident_neg_h, ((1,1), (0,2)), 'constant', constant_values=(0))
    matrix =  ident_h + ident_neg_h

    matrix[0][0] = -1 / h
    matrix[0][1] = 1 / h
    matrix[-1][-1] = 1 / h
    matrix[-1][-2] = -1 / h
    return np.dot(matrix, y)

def test_diff2_linear():
    """
    Tests the matrix-multiplaction based differentiation method on a linear function
    which it should approximate perfectly, including the edges
    f(x) = 8x - 12
    f'(x) = 8
    """
    a = -20
    b = 20
    n = 1000
    exact_dfdx = np.zeros(n + 1) + 8
    print exact_dfdx
    print diff2(linear_func, a, b, n)
    assert np.allclose(exact_dfdx, diff2(linear_func, a, b, n))


import scipy.integrate as spi
import autograd.numpy as anp   # Thinly-wrapped version of Numpy
import autograd as ag

print('Compute length of an arc of planar curve by SciPy quad')
print('Example 1-03 quad arclength')
print('Length of arc of curve y=e^(-x^2) from x=-1 to x=1')

y = lambda x : anp.exp(-x**2)
dy_dx = ag.grad(y)
integrand = lambda x : anp.sqrt(1 + dy_dx(x) ** 2)
a = -1.
b = 1.

result, error = spi.quad(integrand, a, b)
print('Result is ', result, 'with error ', error)


# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
from random import randrange

def mapFeature(X1, X2):
# MAPFEATURE Feature mapping function to polynomial features
#
#   MAPFEATURE(X1, X2) maps the two input features
#   to quadratic features used in the regularization exercise.
#
#   Returns a new feature array with more features, comprising of
#   X1, X2, X1.^2, X2.^2, X1*X2, X1*X2.^2, etc..
#
#   Inputs X1, X2 must be the same size
    degree = 6
    out = np.ones([len(X1), (degree+1)*(degree+2)/2])
    idx = 1
    for i in range(1, degree+1):
        for j in range(0, i+1):
            a1 = X1 ** (i-j)
            a2 = X2 ** j
            out[:, idx] = a1*a2
            idx += 1
    return out

# Split a dataset into k folds
def cross_validation_split(dataset, n_folds):
    cross_validation_dataset = list()
    dataset_copy = list(dataset)
    fold_size = int(len(dataset_copy)/n_folds)

    for i in range(0, n_folds):
        fold = list()
        while len(fold) < fold_size:
            index = randrange(len(dataset_copy))
            fold.append(dataset_copy.pop(index))
        cross_validation_dataset.append(fold)
    return cross_validation_dataset

def sigmoid(X):
    return 1/(1 + np.exp(- X))

def pre_processing(matrix):
    range_ = 10
    b = np.apply_along_axis(lambda x: (x-np.mean(x))/range_, 0, matrix)
    return b

def cost_function(X, y, theta):
    h_theta = sigmoid(np.dot(X, theta))
    log_l = (-y)*np.log(h_theta) + (1 - y)*np.log(1 - h_theta)
    return log_l.mean()

def calculate_gradient(X, y, theta, index, X_count):
    dummy_theta = sigmoid(np.dot(X, theta))
    sum_ = 0.0
    for i in range(dummy_theta.shape[0]):
        sum_ = sum_ + (dummy_theta[i] - y[i]) * X[i][index]
    return sum_

def gradient_descent(training_set, alpha, max_iterations, plot_graph):
    iter_count = 0

    training_set = np.asarray(training_set)
    X = training_set.T[0:2].T
    y = training_set.T[2].T
    X_count = X.shape[1]

    theta = np.zeros(X_count)
    x_vals = []
    y_vals = []
    regularization_parameter = 1
    while(iter_count < max_iterations):
        iter_count += 1
        for i in range(X_count):
            prediction = calculate_gradient(X, y, theta, i, X_count)
            prev_theta = theta[i]
            if i != 0:
                prediction += (regularization_parameter/X_count)*prev_theta
            theta[i] = prev_theta - alpha * prediction

            if plot_graph:
                mean = cost_function(X, y, theta)
                x_vals.append(iter_count)
                y_vals.append(mean)

    return theta

def compute_efficiency(test_set, theta):
    test_set = np.asarray(test_set)
    X = test_set.T[0:2].T
    y = test_set.T[2].T
    X_count = X.shape[0]
    correct = 0

    for i in range(X_count):
        prediction = 0
        value  = np.dot(theta, X[i])
        if value >= 0.5:
            prediction = 1
        else:
            prediction = 0
        if prediction == y[i]:
            correct+=1
    return correct*100/X.shape[0]

def evaluate_algorithm(dataset, n_folds, alpha, max_iterations, plot_graph):
    folds = cross_validation_split(dataset, n_folds)
    results = []
    for fold in folds:
        train_set = list(folds)
        train_set.remove(fold)
        train_set = sum(train_set, [])
        test_set = list()

        for row in fold:
            row_copy = list(row)
            test_set.append(row_copy)

        theta = gradient_descent(train_set, alpha, max_iterations, plot_graph)
        results.append(compute_efficiency(test_set, theta))
    return np.asarray(results)

if __name__ == "__main__":
    with open('ex2data2.txt', 'rb') as csvfile:
        data = np.loadtxt(csvfile, delimiter=",")
        print ">>> data", data
        new_data = mapFeature(data[:,0], data[:,1])
        print new_data
    f_len = len(new_data[0])
    X = new_data[:, :f_len - 1]
    print "........", X
    y = new_data[:, f_len -1]
    print ",,,,,,,,,,,y", y
    X = pre_processing(X)
    reshaped_y = y.reshape(y.shape[0], -1)
    processed_dataset = np.concatenate((X, reshaped_y), axis=1)
    results = evaluate_algorithm(processed_dataset.tolist(), n_folds=10,
                                 alpha=0.01, max_iterations=500, plot_graph=False)
    print("Mean : ",np.mean(results))


import numpy as np

a = np.array([[1, 3], [5, 7]])
b = np.array([[1, 2], [3, 4]])

print(a * b) #乗算（アダマール積）：np.multiply(a, b) でも同様の結果が得られる

'''
[[ 1  6]
 [15 28]]
'''

print(np.square(a)) #二乗：a ** 2 でも同様の結果が得られる

'''
[[ 1  9]
 [25 49]]
'''

print(np.power(a, 3)) #べき乗：a ** 3 でも同様の結果が得られる

'''
[[  1  27]
 [125 343]]
'''


import numpy as np
from matplotlib import pyplot as plt

def shiftByMean(A):
    '''
    Shift the columns of the input array by their respective means.
    Inputs:
        A -- an (m,n) array
    Return:
        a (m,n) array whose columns are the mean-shifted counterparts to A.
    '''
    return A - A.mean(axis=0)

def computeVariance(A):
    '''
    Calculate the variance of each column of the input array.
    Inputs:
        A -- an (m,n) array, not necessarily mean-shifted.
    Return:
        a 1-d array with n entries, each giving the variance of the corresponding column.
    '''
    return (shiftByMean(A)**2).sum(axis=0)/np.float(A.shape[0])

def reportStDev():
    '''
    Print the answer to the question in problem 1.
    You may also include the necessary code to import and process the data, but this
    need not necessarily be in the body of this function.
    '''
    data = np.genfromtxt('weight_age_fat.txt', skip_header=1, usecols=[2,3,4])
    col_titles = ['weight', 'age', 'blood fat content']
    stds = np.sqrt(computeVariance(data))
    ind = np.argmin(stds)
    min_std = np.min(stds)
    print col_titles[ind], min_std

def corrMatrix(W):
    '''
    Compute the correlation matrix for the columns of input array W
    '''
    X = W - W.mean(axis=0)
    Y = X/np.sqrt((X**2).sum(axis=0))
    return np.dot(Y.T, Y)

def reportCorr():
    '''
    Print the answers to the questions in problem 3. Ther are three distinct questions,
    so there should be three distinct print statements, indicating which question is
    being answered. Report the columns as their number in the original data file. The first
    column, which we omitted, would be column 0, and the last column (giving the mortality)
    would be column 16.
    Finally, plot the data as described in the problem statement.
    '''
    data = np.genfromtxt('mortality.txt', skip_header=17, usecols=range(1,17))
    corr_mat = corrMatrix(data)

    # find the column whose correlation with the last column is closest to zero
    min_col = np.argmin(np.abs(corr_mat[:,-1]))
    print "The column most nearly uncorrelated with mortality rate is",  min_col + 1

    # now find the pair of distinct columns with highest correlation.
    # set diagonals to zero, since we want to consider only distinct columns
    np.fill_diagonal(corr_mat,0)
    max_rows = corr_mat.max(axis=1)
    max_row = np.argmax(max_rows)
    max_col = np.argmax(corr_mat[max_row,:])
    print "The pair of columns with largest correlation is", (max_row+1,max_col+1)

    # find column with highest correlation to mortality
    min_mort = np.argmin(corr_mat[:,-1])
    print "The column that is most negatively correlated with mortality is", min_mort + 1

    plt.subplot(311)
    plt.scatter(data[:,max_row], data[:, max_col])
    plt.subplot(312)
    plt.scatter(data[:,min_mort], data[:,-1])
    plt.subplot(313)
    plt.scatter(data[:,min_col], data[:,-1])
    plt.show()
    plt.clf()

def covariance():
    data = np.genfromtxt('mortality.txt', skip_header=17, usecols=range(1,17))
    return np.cov(data, rowvar=0)


# -*- coding: utf-8 -*-
"""
Amicable numbers
================
https://projecteuler.net/problem=21

Let d(n) be defined as the sum of proper divisors of n (numbers less than n
which divide evenly into n). If d(a) = b and d(b) = a, where a ≠ b, then a and b
are an amicable pair and each of a and b are called amicable numbers.

For example, the proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55
and 110; therefore d(220) = 284. The proper divisors of 284 are 1, 2, 4, 71 and
142; so d(284) = 220.

Evaluate the sum of all the amicable numbers under 10000.
"""
import numpy as np

from .utils import print_result

def divisor_sums(n: int) -> np.ndarray:
    """Generate a flat array of sums of proper divisors of numbers less than n."""
    sums = np.zeros(n, dtype=int)
    for i in range(1, n):
        j = 2 * i
        while j < n:
            sums[j] += i
            j += i
    return sums

@print_result
def solve() -> int:
    n = 10000
    sums = divisor_sums(n)
    total = 0
    for a, b in enumerate(sums):
        if b < n and b != a and sums[b] == a:
            total += a
    return total

if __name__ == "__main__":
    solve()


from math import cos, pi
from sympy import Poly, symbols, lambdify
import numpy as np

def dividedDiffernce(f, xlow, xhigh, deg=4, var_name='x'):
    """
    INPUT:
        f: The function to be interpolated as SymPy expression.
        xlow: The lower bound of the interval.
        xhigh: The upper bound of the interval.
        var_name(default='x'): The name of the varible of the
            interpolating polynomial.

    OUTPUT:
        P: An n degree polynomial that interpolates the function
            f with respect to the points (x_i, y_i), where n is
            the number of points minus one.
        R_bar_squared: The adjusted R-squared coefficient for the
            polynomial fit.

    Performs Newton's Divided Differences method to interpolate a function f,
    with respect to the x-values, x_0, x_1, ..., x_n, on the
    interval [xlow, xhigh]. These values are taken to be the n+1 Chebyshev points
    mapped to the given interval. The interpolating polynomaial P_n(x) takes the form,

    P_n(x) = a_0 + a_1*(x-x_0) + a_2*(x-x_0)*(x-x_1)
            + ... + a_n*(x-x_0)*...*(x-x_n-1),

    where each a_k is the kth divided difference coefficient. We can solve
    for each a_k by using the following notation,

    a_k = f[x_0,x_1,...,x_k],

    where each f[x_0,x_1,...,x_k] is recursivly calculated using the
    two previous coefficients as,

    f[x_i,x_i+1,...,x_i+k] = (f[x_i+1,x_i+2,...,x_i+k]
                            - f[x_i,x_i+1,...,x_i+k-1]) / (x_i+k - x_i),

    starting with f[x_0] = f(x_0).

    The recursion can be illustrated in the following way,

    f[x_0]
    f[x_1]   f[x_0,x_1]
    f[x_2]   f[x_1,x_2]   f[x_0,x_1,x_2]
    f[x_3]   f[x_2,x_3]   f[x_1,x_2,x_3]
    f[x_4]   f[x_3,x_4]   f[x_2,x_3,x_4]
    .         .            .               .
    .         .            .                 .
    .         .            .                   .
    f[x_n]   f[x_n-1,x_n] f[x_n-2,x_n-1,x_n] ... f[x_0,x_,...,x_n]

    where the kth coefficient along the diagonal is equal to a_k. Using
    the n coefficients, the n degree polynomial P_n(x) is generated
    for the set of given x values.
    """

    NUM_NODES = deg + 1
    xvals = chebNodes(xlow, xhigh, NUM_NODES)
    yvals = [f.subs(var_name, xi) for xi in xvals]

    x = symbols(var_name)

    # The 2-D list of divided-difference coefficients
    # (The coefficients that correspond to each a_k will be along
    # the diagonal of the list.
    coeffs = []

    # Fill each element in the first column, with the corresponding y
    # value, i.e., coeffs_{i,0} = f(x_{i}).
    for row in range(NUM_NODES):
        coeffs.append([])
        coeffs[row].append(yvals[row])

    # Iterate through every other column, and recursivly generate the
    # divided-difference coefficients.
    for col in range(1, NUM_NODES):
        for row in range(col, NUM_NODES):
            # coeffs_{i,j} = (coeffs_{i,j-1} - coeffs_{i-1,j-1}) / (x_{i} - x_{i-j})
            coeffs[row].append((coeffs[row][col-1] - coeffs[row-1][col-1])/(xvals[row]
                                                             - xvals[row-col]))

    # Using the coefficients, a_{n} = coeffs_{i} = coeffs[i][i], construct the
    # interpolating polynomial P(x), such that...,
    # P_{n}(x) = coeffs_{0} + coeffs_{1}*(x - x_{0}) + coeffs_{2}*(x - x_{0})*(x - x_{1})
    #           + ... + coeffs_{n}*(x - x_{0})*(x - x_{1})*...(x - x_{n-1})
    P = Poly([coeffs[0][0]], x)
    for i in range(1, NUM_NODES):
        term = coeffs[i][i]
        for k in range(i):
            term *= (x - xvals[k])

        P += term

    # Calculate the adjusted R-squared, using 50 test points.
    R_bar_sqr = _getRbarSquared(f, P, var_name, xlow, xhigh, n_steps=50)

    return P, R_bar_sqr

def chebNodes(xlow, xhigh, npoints):
    """
    Returns a set of Chebyshev nodes on the interval [xlow, xhigh].
    """

    cheb_nodes = [_kNode(i, npoints) for i in range(npoints)]

    # Translate nodes to the interval xlow to xhigh.
    cheb_nodes = list(map(lambda c: 0.5*(xlow + xhigh)
                          + 0.5*(xhigh - xlow)*c, cheb_nodes))
    cheb_nodes.sort()
    return cheb_nodes

def _kNode(k, n):
    """
    Returns the kth Chebyshev node for a given number of n
    points, for an interval of -1 to 1.
    """
    return cos((2*k + 1)*pi/(2*(n - 1) + 2))

def _getRbarSquared(f, polyfit, var_name, xmin, xmax, n_steps=50):
    endpoint_shift = 0.0001           # To ensure all domian boundaries yield real y values.
    step = abs(xmin - xmax)/n_steps
    x = np.arange(xmin + endpoint_shift, xmax - endpoint_shift, step)

    lam_f = lambdify(var_name, f, 'numpy')
    lam_poly = lambdify(var_name, polyfit.as_expr(), 'numpy')
    y = lam_f(x)
    yfit = lam_poly(x)

    yfit = yfit[np.isreal(y)]
    y = y[np.isreal(y)]

    y_resid = list(map(lambda yi, yfi: yi - yfi, y, yfit))

    SSresid = sum(map(lambda r: r**2, y_resid))
    SStotal = (len(y) - 1)*np.var(y)

    rsq_bar = 1 - SSresid/SStotal*(len(y) - 1)/(len(y) - polyfit.degree() - 1)
    return float(rsq_bar)


import numpy as np
import matplotlib.pyplot as plt
import os
figdir = os.path.join(os.environ["PYPROBML"], "figures")
def save_fig(fname): plt.savefig(os.path.join(figdir, fname))

x = np.linspace(0,1,10000)

H = lambda x: -(x*np.log2(x) + (1-x) * np.log2(1-x))

plt.plot(x, H(x), '-b', lw=3)
plt.xlim((-0.01, 1.01))
plt.ylim((0, 1.01))

plt.xlabel("p(X = 1)")
plt.ylabel("H(X)")

ticks = [0, 0.5, 1]
plt.xticks(ticks)
plt.yticks(ticks)

save_fig("bernoulliEntropy.pdf")
plt.show()


import numpy as np

def Jacobi(A, e):
    n = A.shape[1]
    Q = np.eye(N=n, M=n, dtype=np.float64)
    while np.sum([A[i][j]**2 for j in range(n) for i in range(n) if i != j]) > e:
    #for t in range(10):
        p = 0
        q = 1
        for i in range(n):
            for j in range(i + 1, n):
                if abs(A[p][q]) < abs(A[i][j]):
                    p, q = i, j
        s = (A[q][q] - A[p][p])/(2*A[p][q])
        if s == 0:
            t = 1
        else:
            t1 = -s-(s*s+1)**0.5
            t2 = -s+(s*s+1)**0.5
            if abs(t1) > abs(t2):
                t = t2
            else:
                t = t1
        c = 1/((t*t+1)**0.5)
        d = t/((t*t+1)**0.5)

        # 书上方法 开始
        for i in range(n):
            if i != p and i != q:
                A[i][p] = A[p][i] = c*A[p][i]-d*A[q][i]
                A[i][q] = A[q][i] = d*A[p][i]+c*A[q][i]
        A[p][p] = A[p][p]-t*A[p][q]
        A[q][q] = A[q][q]+t*A[p][q]
        A[p][q] = A[q][p] = 0
        # 书上方法 结束

        tempQ = np.eye(N=n, M=n, dtype=np.float64)
        tempQ[p][p] = tempQ[q][q] = c
        tempQ[p][q] = d
        tempQ[q][p] = -d
        Q = np.matmul(Q, tempQ)

        # 直接乘 开始
        # A = np.matmul(np.matmul(tempQ.T, A), tempQ)
        # 直接乘 结束

    eigenvalue = np.diag(A)
    vectors = Q.swapaxes(0, 1)
    return eigenvalue, vectors, Q

def main():
    A = np.array([[3,2,5,4,6],
                  [2,1,3,-7,8],
                  [5,3,2,5,-4],
                  [4,-7,5,1,3],
                  [6,8,-4,3,8]],dtype=np.float64)

    e = 1e-13
    eigenvalue, vectors, Q = Jacobi(A.copy(), e)
    for i in range(A.shape[1]):
        np.set_printoptions(precision=15)
        print('r{}={:.15e},\nv{}=({:.5e}'.format(i+1, eigenvalue[i], i+1, vectors[i][0]), end='')
        for j in range(1, A.shape[1]):
            print(', {:.5e}'.format(vectors[i][j]), end='')
        print(')')

if __name__ == '__main__':
    main()


"""
@file           qr_factorization.py
@description    QR facorization using Gram-Schmidt process
@author         Hiukong Dan
@version        1.0
@copyright      (c) Hiukong Dan 2021
@contact        ifsoboy9148@hotmail.com
"""

#!/bin/python
import numpy as np
from numpy import linalg
from gram_schmidt import *
from sympy import Matrix

def qr_factorization(A):
    """
    @description:
        QR Factorize a matrix A using gram schmidt process
    @param A:
        Matrix to be factored
    @return (Q, R):
        Q, R tuple of the result
    """
    # linear independence check
    assert np.linalg.matrix_rank(A) == A.shape[1], "The columns are not linear independent"

    Q = orthonormalize(gram_schmidt(A))
    R = np.matmul(Q.T, A)
    return (Q, R)

if __name__ == "__main__":
    """
    A = np.array([[-10,13,7,-11],[2,1,-5,3],[-6,3,13,-3],[16,-16,-2,5],[2,1,-5,-7]])
    print(A)
    print(Matrix.rref(Matrix(A)))
    ret = qr_factorization(A)
    print(ret)
    print(np.matmul(ret[0], ret[1]))
    """


import numpy as np
import matplotlib.pyplot as plt

## Interpolare polinomială

# Definesc funcția
def f(x):
    return np.cos(2 * x) - 2 * np.sin(3 * x)

# Definesc domeniul pe care fac interpolarea
left = -np.pi
right = +np.pi

# Gradul polinomului de interpolare
N = 10

# Definesc polii de interpolare
x = np.linspace(left, right, N + 1)
y = f(x)

# Construiesc matricea Vandermonde pentru sistemul pe care vreau să-l rezolv
A = np.vander(x, N=N + 1, increasing=True)

a = np.linalg.solve(A, y)

def polynomial(x):
    "Evaluează polinomul cu coeficienții `a` în punctul `x`"
    s = 0
    for i in range(N + 1):
        s += a[i] * (x ** i)
    return s

def polynomial_vector(v):
    "Evaluează polinomul cu coeficienții `a` pe vectorul `v`"
    return np.array([polynomial(x) for x in v])

# Afișez funcția
xs = np.linspace(left, right, 5000)
plt.plot(xs, f(xs), linestyle='-', label='funcția f')

# Afișez polii interpolării
plt.scatter(x, y, c='red')

# Afișez interpolarea
xs = np.linspace(left, right, 100)
plt.plot(xs, polynomial_vector(xs),
    c='orange',
    linestyle='--',
    label=f'aproximare cu polinom de gradul {N}')

# Afișez o legendă
plt.legend()

# Afișez tot graficul
plt.show()

# Afișăm eroarea aproximării
show_error = False
if show_error:
    y_real = f(xs)
    y_approx = polynomial_vector(xs)

    plt.plot(xs, np.abs(y_approx - y_real), label=f'eroare pentru N={N}')
    plt.legend()
    plt.show()


# Neural network has 2 inputs, 1 hidden layer with 2 nodes and 1 output layer with one node.
# x1,x2 - I/P, w1,w2,w3,w4 - I/P weights, b1,1 b1,2 - biases, w5,w6 - Hidden layer weights
# b2 - bias, a2 - O/P, z1,1 z1,2 z2 - linear combination of weights and biases

#Initializing weights and biases
import numpy as np
weights=np.around(np.random.uniform(size=6),decimals=2)
biases=np.around(np.random.uniform(size=3),decimals=2)

# Given x1 x2
x1=0.5
x2=0.85

with open ("Lab1_ANN.txt",'a') as f:
    print("The weights are: ", weights,file=f)
    print("The biases are: ", biases,file=f)
    print("x1 is {} and x2 is {}".format(x1,x2),file=f)

# Computing z1,1 z1,2

z11=x1*weights[0]+x2*weights[1]+biases[0]
z12=x1*weights[2]+x2*weights[3]+biases[1]

with open ("Lab1_ANN.txt",'a') as f:
    print('The weighted sum of the inputs at the first node in the hidden layer is {}'.format(z11, decimals=3),file=f)
    print('The weighted sum of the inputs at the second node in the hidden layer is {}'.format(z12, decimals=3),file=f)

#using sigmoid function to compute a1,1 a1,2

a11=1.0/(1.0+np.exp(-z11))
a12=1.0/(1.0+np.exp(-z12))

with open ("Lab1_ANN.txt",'a') as f:
    print('The activation of the first node in the hidden layer is {}'.format(a11, decimals=3),file=f)
    print('The activation of the second node in the hidden layer is {}'.format(a12, decimals=3),file=f)

# computing z2 for O/P layer using hidden layer inputs a1,1 a1,2
z2=a11*weights[4]+a12*weights[5]+biases[2]

# Computing O/P layer term a2
a2=1.0/(1.0+np.exp(-z2))

with open ("Lab1_ANN.txt",'a') as f:
    print('The weighted sum of the inputs at the node in the output layer is {}'.format(z2, decimals=3),file=f)
    print('The output of the network for x1 = 0.5 and x2 = 0.85 is {}'.format(a2, decimals=3),file=f)

Introduction to Deep Learning & Neural Networks with Keras/Module1/Lab1_Artificial_Neural_Networks_Simple_computation.py


import jax.numpy as np
from .normrow import normrow

def normalizerow(X):
	"""
	NORMALIZEROW normalizes the l2-norm of each row in a np array

	Input:
	  X: (n,m) numpy array
	Output:
	  X_normalized: (n,m) row normalized numpy array
	"""
	l2Norm = normrow(X)
	X_normalized = X / (l2Norm.reshape(X.shape[0],1))
	return X_normalized


import matplotlib.pyplot as plt
import numpy as np

class LinearRegressionUsingGD:
    """
    A class used to represent Gradient Decent for Linear Regression
    ...

    Attributes
    ----------
    n_iterations : int
        number of gradient decent iterations
    lr : float
        learning rate  - make sure to set this small e.g. < 0.001
    w : float
        weights variable, in this case w is the gradient tern in y = mx +c ---> y = wc + b
    b : float
        bias variable, in this case w is the gradient tern in y = mx +c ---> y = wc + b

    Public Methods
    -------
    fit(x, y)
        Fit model h(x) to the training data
    predict(x)
        Predict Y given the training data X, using the trained model h(x)
    """

    def __init__(self, lr=0.0005, n_iterations=100):
        self.n_iterations = n_iterations
        self.lr = lr
        self.w = np.random.rand(1)
        self.b = np.random.rand(1)

    def _cost_function(self, x: object, y: object) -> object:
        total = len(x)
        total_error = 0.0
        for i in range(total):
            total_error += (y[i] - (self.w * x[i] + self.b)) ** 2
        return total_error / total

    def _update_weights(self, x: object, y: object):
        weight_deriv = 0
        bias_deriv = 0
        length = len(x)
        for i in range(length):
            # Calculate partial derivatives

            # -2x(y - (mx + b))
            weight_deriv += -2 * x[i] * (y[i] - (self.w * x[i] + self.b))

            # -2(y - (mx + b))
            bias_deriv += -2 * (y[i] - (self.w * x[i] + self.b))

        # We subtract because the derivatives point in direction of steepest ascent
        self.w -= (weight_deriv / length) * self.lr
        self.b -= (bias_deriv / length) * self.lr

    def fit(self, x, y):
        """Fit model h(x) to the training data
        Parameters
        ----------
        x : array-like, shape = [n_samples, n_features]
            Training samples
        y : array-like, shape = [n_samples, n_target_values]
            Target values
        """
        cost_x = []
        cost_y = []

        for i in range(self.n_iterations):
            self._update_weights(x, y)

            # Calculate cost for auditing purposes
            cost = self._cost_function(x, y)
            cost_x.append(i)
            cost_y.append(cost)

            # Log Progress
            if i % 10 == 0:
                print(
                    "iter={},    weight={}    bias={}    cost={}".format(i, self.w, self.b, cost)
                )

        plt.subplots(1, 1)
        plt.plot(cost_x, cost_y)
        plt.xlabel('Iterations')
        plt.ylabel('J(\u03B80, \u03B81)')
        plt.show()

    def predict(self, x):
        """Predict Y given the training data X, using the trained model h(x)
        Parameters
        ----------
        x : array-like, shape = [n_samples, n_features]
          Training samples

        Returns
        ----------
        y : array-like, shape = [n_samples, n_target_values]
            Target values
        """
        return self.w * x + self.b


def scrambled_halton_sequence_generator(dimension=1, permutation=None):

    primes = prime_generator()
    bases = [next(primes) for _ in range(dimension)]
    if permutation is None:
        generators = [halton_sequence_generator(base) for base in bases]
    elif permutation == 'reverse':
        generators = [halton_sequence_generator(base, permutation=[0] + [base-i for i in range(1,base)]) for base in bases]
    elif permutation == 'Braaten-Weller':
        assert dimension<=16, "Braaten-Weller only supports dimensions up to 16"
        perms ={2: [0, 1],
                3: [0, 2, 1],
                5: [0, 2, 4, 1, 3],
                7: [0, 3, 5, 1, 6, 2, 4],
                11: [0 ,5 ,8 ,2 ,10 ,3, 6, 1, 9, 4, 7],
                13: [0, 6, 10, 2, 8, 4, 12, 1, 9, 5, 11, 3, 7],
                17: [0, 8, 13, 3, 11, 5, 16, 1, 10, 7, 14, 4, 12, 2, 15, 6, 9],
                19: [0, 9, 14, 3, 17, 6, 11, 1, 15, 7, 12, 4, 18, 8, 2, 16, 10, 5, 13],
                23: [0, 11, 17, 4, 20, 7, 13, 2, 22, 9, 15, 5, 18, 1, 14, 10, 21, 6, 16, 3, 19, 8, 12],
                29: [0, 14, 22, 5, 18, 9, 27, 2, 20, 11, 25, 7, 16, 3, 24, 13, 19, 6, 28, 10, 1, 23, 15, 12, 26, 4, 17, 8, 21],
                31: [0, 16, 8, 26, 4, 22, 13, 29, 2, 19, 11, 24, 6, 20, 14, 28, 1, 17, 9, 30, 10, 23, 5, 21, 15, 3, 27, 12, 25, 7, 18],
                37: [0, 18, 28, 6, 23, 11, 34, 3, 25, 14, 31, 8, 20, 36, 1, 16, 27, 10, 22, 13, 32, 4, 29, 17, 7, 35, 19, 2, 26, 12, 30, 9, 24, 15, 33, 5, 21],
                41: [0, 20, 31, 7, 26, 12, 38, 3, 23, 34, 14, 17, 29, 5, 40, 10, 24, 1, 35, 18, 28, 9, 33, 15, 21, 4, 37, 13, 30, 8, 39, 19, 25, 2, 32, 11, 22, 36, 6, 27, 16],
                43: [0, 21, 32, 7, 38, 13, 25, 3, 35, 17, 28, 10, 41, 5, 23, 30, 15, 37, 1, 19, 33, 11, 26, 42, 8, 18, 29, 4, 39, 14, 22, 34, 6, 24, 12, 40, 2, 31, 20, 16, 36, 9, 27],
                47: [0, 23, 35, 8, 41, 14, 27, 3, 44, 18, 31, 11, 37, 5, 25, 39, 16, 21, 33, 1, 46, 12, 29, 19, 42, 7, 28, 10, 36, 22, 4, 43, 17, 32, 13, 38, 2, 26, 45, 15, 30, 6, 34, 20, 40, 9, 24],
                53: [0, 26, 40, 9, 33, 16, 49, 4, 36, 21, 45, 12, 29, 6, 51, 23, 38, 14, 43, 1, 30, 19, 47, 10, 34, 24, 42, 3, 27, 52, 15, 18, 39, 7, 46, 22, 32, 5, 48, 13, 35, 25, 8, 44, 31, 17, 50, 2, 37, 20, 28, 11, 41],
        }
        generators = [halton_sequence_generator(base, permutation=perms[base]) for base in bases]
    elif permutation == 'random':
        generators = [halton_sequence_generator(base, permutation='pseudo-random') for base in bases]
    else:
        print("Permutation %s not supported"%permutation)
    while True:
        yield [next(gen) for gen in generators]

quasi_random_number_generator = scrambled_halton_sequence_generator

def prime_generator():
    D = {}
    q = 2
    while True:
        if q not in D:
            yield q
            D[q * q] = [q]
        else:
            for p in D[q]:
                D.setdefault(p + q, []).append(p)
            del D[q]
        q += 1

def vdc(n, q, base, permutation):
    vdc, denom = 0,1
    while n:
        denom *= base
        q /= base
        n, remainder = divmod(n, base)
        vdc += permutation[remainder] * q
    return vdc

def halton_sequence_generator(base, permutation=None, rational=False):
    if permutation is None:
        permutation = list(range(base)) #no permutation
    if permutation == 'pseudo-random':
        import random

    denominator = base
    while True:
        for i in range(denominator/base,denominator):
            if permutation == 'pseudo-random':
                l = list(range(1,base))
                random.shuffle(l)
                permutation = [0] + l

            numerator = vdc(i, denominator, base, permutation)
            #print numerator,denominator

            if rational:
                yield numerator,denominator
            else:
                yield numerator / float(denominator)
        denominator *= base

""" for comparison """
def pseudo_random_sequence_generator(dimension=1):
    import random
    while True:
        yield [random.random() for _ in range(dimension)]

if __name__=="__main__":

    """Plot the worst dimensions of the quasi-random number generators, together with a pseudo-random number generator"""

    import numpy as np
    import matplotlib.pyplot as plt
    d = 3
    points = 100
    plt.figure('Normal quasi-random')
    generator = scrambled_halton_sequence_generator(dimension = d)
    samples = np.array([next(generator) for _ in range(points)])
    plt.scatter(samples[:,-2],samples[:,-1],marker=',',edgecolor='none',s=1)
    plt.xlim([0,1])
    plt.ylim([0,1])
    plt.figure('quasi-random with reverse permutation')
    generator = scrambled_halton_sequence_generator(dimension = d, permutation='reverse')
    samples = np.array([next(generator) for _ in range(points)])
    #print samples[0,:]
    plt.scatter(samples[:,-2],samples[:,-1],marker=',',edgecolor='none',s=1)
    plt.xlim([0,1])
    plt.ylim([0,1])
    plt.figure('quasi-random with Braaten-weller permutation')
    generator = scrambled_halton_sequence_generator(dimension = d, permutation='Braaten-Weller')
    samples = np.array([next(generator) for _ in range(points)])
    plt.scatter(samples[:,-2],samples[:,-1],marker=',',edgecolor='none',s=1)
    plt.xlim([0,1])
    plt.ylim([0,1])
    plt.figure('quasi-random with pseudo-random permutation')
    generator = scrambled_halton_sequence_generator(dimension = d, permutation='random')
    samples = np.array([next(generator) for _ in range(points)])
    plt.scatter(samples[:,-2],samples[:,-1],marker=',',edgecolor='none',s=1)
    plt.xlim([0,1])
    plt.ylim([0,1])
    plt.figure('actual pseudo-random')
    generator = pseudo_random_sequence_generator(dimension = d)
    samples = np.array([next(generator) for _ in range(points)])
    plt.scatter(samples[:,-2],samples[:,-1],marker=',',edgecolor='none',s=1)
    plt.xlim([0,1])
    plt.ylim([0,1])
    plt.show()


import numpy as np
from scipy import special

#define sine integral -pi/2
def sine_integral_func(x):
    tmp = special.sici(x)
    tmp2 = -np.pi/2.0 + tmp[0]
    return tmp2

#construct sine integral over range 0<x<2*pi
x = np.arange(0.0,2.0*np.pi,0.001)
y = []
[y.append(sine_integral_func(i)) for i in x]

#save the x and y vectors to a file
save_list = [x,y]
path2file='example_data/root_finding_unknown_function.txt'
np.savetxt(path2file,save_list)
print "x and y data for unknown function saved in ",path2file
print "Name of unknown function is sine_integral_func"


# =============================================================================
#  ***** earth_orbit_sun_ch3.py *****
#  Python script to solve and plot numerical solution for Newtonian
#  orbit of Earth around Sun using RK4.
#
#  Author:     Ryan Clement
#  Created:    July 2021
#
#  Change Log:
#  Who:
#  Date:       MM/DD/YYY
#  What:
#
#  Who:
#  Date:       MM/DD/YYYY
#  What:
# =============================================================================

import numpy as np
from matplotlib import pyplot as plt

# Earth Orbit Parameters
aEarth = 1.0                                                # semi-major in AU
eEarth = 0.0167086                                          # eccentricity
bEarth = aEarth*np.sqrt(1 - eEarth**2)
mu     = 4.0*np.pi**2                                       # mu = 4Pi**2 (units!)
twoPi  = 2.0*np.pi
vEarth = twoPi*np.sqrt((1 + eEarth)/(1.0 - eEarth))     # VisViva @ Perihelion

# Earth Orbit as Ellipse
def rOrbit(a,e,t):
    return a*(1.0 - e**2)/(1.0 + e*np.cos(t))
def xOrbit(a,e,t):
    return rOrbit(a,e,t)*np.cos(t)
def yOrbit(a,e,t):
    return rOrbit(a,e,t)*np.sin(t)
t = np.linspace(0,twoPi,100)
xE = xOrbit(aEarth,eEarth,t)
yE = yOrbit(aEarth,eEarth,t)

# Earth Orbit Initial Conditions
x0  = 1.0 - eEarth
y0  = 0.0
vx0 = 0.0
vy0 = vEarth
nSteps = 12    # to complete one orbit
dt  = 1.0/nSteps
dt6 = dt/6.0

# Newton's Equations
def calcR3(x,y):
    return (x**2 + y**2)**(3/2)
# xD = vx
# yD = vy
# vxD = -mu*x/r3
# vyD = -mu*y/r3

# Earth Orbit via RK4
def update(x,y,vx,vy):
    # k1
    r3 = calcR3(x, y)
    k1x = vx
    k1y = vy
    k1vx = -mu*x/r3
    k1vy = -mu*y/r3
    xu = x + k1x*dt/2.0
    yu = y + k1y*dt/2.0
    # k2
    r3 = calcR3(xu, yu)
    k2x = vx + k1vx*dt/2.0
    k2y = vy + k1vy*dt/2.0
    k2vx = -mu*xu/r3
    k2vy = -mu*yu/r3
    # k3
    xu = x + k2x*dt/2.0
    yu = y + k2y*dt/2.0
    r3 = calcR3(xu, yu)
    k3x = vx + k2vx*dt/2.0
    k3y = vy + k2vy*dt/2.0
    k3vx = -mu*xu/r3
    k3vy = -mu*yu/r3
    # k4
    xu = x + k3x*dt
    yu = y + k3y*dt
    r3 = calcR3(xu, yu)
    k4x = vx + k3vx*dt
    k4y = vy + k3vy*dt
    k4vx = -mu*xu/r3
    k4vy = -mu*yu/r3
    # Weighted Sum
    kx = k1x + 2.0*k2x + 2.0*k3x + k4x
    ky = k1y + 2.0*k2y + 2.0*k3y + k4y
    kvx = k1vx + 2.0*k2vx + 2.0*k3vx + k4vx
    kvy = k1vy + 2.0*k2vy + 2.0*k3vy + k4vy
    # Updates
    xN = x + dt6*kx
    yN = y + dt6*ky
    vxN = vx + dt6*kvx
    vyN = vy + dt6*kvy
    return xN,yN,vxN,vyN

xN = x0
yN = y0
vxN = vx0
vyN = vy0
xArr = [x0]
yArr = [y0]
vxArr = [vx0]
vyArr = [vy0]
tArr = [0]
for i in range(nSteps):
    xN, yN, vxN, vyN = update(xN,yN,vxN,vyN)
    xArr.append(xN)
    yArr.append(yN)
    vxArr.append(vxN)
    vyArr.append(vyN)
    tArr.append(dt*(i+1))

print(f'xAnal: {x0}, xComp: {xArr[-1]}')
print('X Percent Difference: ', 100*(x0-xArr[-1])/x0)
print(f'yAnal: {y0}, yComp: {yArr[-1]}')
# print('Y Percent Difference: ', 100*(y0-yArr[-1])/y0)
print(f'vxAnal: {vx0}')
print(f'vyAnal: {vy0}')

# Orbit plot
figE, axE = plt.subplots()
axE.set_title('Earth Orbit')
axE.set_xlabel('x (AU)')
axE.set_ylabel('y (AU)')
axE.plot(xArr,yArr,'+',color='red',label='RK4')
axE.plot(xE, yE, color='blue',label='Analytic')
axE.plot(aEarth*eEarth,0,'o',color='orange',label='Sun')
axE.grid('true')
axE.axis('equal')
axE.set(xlim=(-1.1,1.1),ylim=(-1.1,1.1))
axE.legend()
# figE.savefig('earth_orbit.png')

# Angular momentum plot
xA = np.array(xArr)
yA = np.array(yArr)
vxA = np.array(vxArr)
vyA = np.array(vyArr)
rxvAnal = (x0*vy0 - y0*vx0)
rxvAnalArr = [rxvAnal]*len(tArr)
rxvAA = np.array(rxvAnalArr)
rxvCompArr = xA*vyA - yA*vxA
perDiffArr = 100*(rxvAA - rxvCompArr)/rxvAA
figL, axL = plt.subplots()
axL.set_title('Angular Momentum')
axL.set_xlabel('t (periods)')
axL.set_ylabel(r'r $x$ v')
axL.plot(tArr,rxvAA,color='blue',label='Exact')
axL.plot(tArr,rxvCompArr,color='red',label='Computed')
axL.legend()
# figL.savefig('earth_orbit_Lcon.png')

# Transformed Polar Example
eEarth = 0.0167086                                          # eccentricity
mu     = 4.0*np.pi**2                                       # mu = 4Pi**2 (units!)
aS     = mu*(1.0 - eEarth**2)
ma     = 1.0/(1.0 - eEarth**2)
twoPi  = 2.0*np.pi
print(f'Analytical Minimum Radius: {1.0-eEarth} au')
print(f'Analytical Maximum Radius: {1.0+eEarth} au')
def q2r(q):
    return 1.0/q
# IC
q0  = 1.0/(1.0 - eEarth)
z0  = 0.0
nSteps = 12
dTh = twoPi/nSteps
def newQZ_FE(dTh, q, z):
    c = 1.0/(1.0 - eEarth**2)
    qN  = q + z*dTh
    zN  = z + (c-q)*dTh
    return qN, zN
def newQZ_RK(dTh, q, z):
    c = 1.0/(1.0 - eEarth**2)
    dTh6 = dTh/6.0
    aq0 = q
    az0 = z
    kq1 = az0
    kz1 = c - aq0
    aq1 = aq0 + dTh*kq1/2.0
    az1 = az0 + dTh*kz1/2.0
    kq2 = az1
    kz2 = c - aq1
    aq2 = aq0 + dTh*kq2/2.0
    az2 = az0 + dTh*kz2/2.0
    kq3 = az2
    kz3 = c - aq2
    aq3 = aq0 + dTh*kq3
    az3 = az0 + dTh*kz3
    kq4 = az3
    kz4 = c - aq3
    kq  = kq1 + 2.0*kq2 + 2.0*kq3 + kq4
    kz  = kz1 + 2.0*kz2 + 2.0*kz3 + kz4
    qN  = aq0 + dTh6*kq
    zN  = az0 + dTh6*kz
    return qN, zN
rArr = [q2r(q0)]
thArr = [0.0]
qO = q0
zO = z0
for i in range(1,nSteps+1):
    qN, zN = newQZ_RK(dTh,qO,zO)
    rArr.append(q2r(qN))
    thArr.append(i*dTh)
    qO = qN
    zO = zN
figP, axP = plt.subplots(subplot_kw={'projection': 'polar'})
axP.plot(thArr,rArr,'.',color='blue',label='Earth')
axP.plot(0,0,'o',color='orange',label='Sun')
axP.set_title('Earth Orbit')
axP.legend(loc='best', bbox_to_anchor=(1.1, 1.2))
# figP.savefig('earth_orbit_PolarTrans.png')

print(f'Min computed radius: {min(rArr)} au')
print(f'Max computed radius: {max(rArr)} au')


from fenics import *
import numpy as np
from ufl import nabla_div, max_value
import sympy as sym

x, y = sym.symbols('x[0], x[1]')

# Creating mesh and defining function space
E = []
DOF = []
mesh = UnitSquareMesh(60, 60)
V = FunctionSpace(mesh, 'P', 1)

# Defining Exact Solution for Pressure Distribution
p_e = Expression('1 - x[0]*x[0]', degree=2)

# Defining Dirichlet boundary
p_L = Constant(1.0)

def boundary_L(x, on_boundary):
    return on_boundary and near(x[0], 0)

bc_L = DirichletBC(V, p_L, boundary_L)

p_R = Constant(0.0)

def boundary_R(x, on_boundary):
    return on_boundary and near(x[0], 1)

bc_R = DirichletBC(V, p_R, boundary_R)

bcs = [bc_L, bc_R]

# Defining variational problem
p = TrialFunction(V)
v = TestFunction(V)
d = 2
I = Identity(d)
x, y = SpatialCoordinate(mesh)
M = max_value(Constant(0.10), exp(-(10*y-1.0*sin(10*x)-5.0)**2))
K = M*I
a = dot(K*grad(p), grad(v))*dx
f1 = as_vector((-2*x, 0))
f = nabla_div(dot(-K, f1))
L = inner(f, v)*dx

# Computing solutions
p = Function(V)
solve(a == L, p, bcs)
u_bar = -K*grad(p)

# Projecting the Velocity profile
W = VectorFunctionSpace(mesh, 'P', 1)
u_bar1 = project(u_bar, W)

# Evaluating difference between Numerical pressure, p and Exact pressure, p_e
p_e_f = interpolate(p_e, V)
diff_p = Function(V)
diff_p.vector()[:] = p.vector() - p_e_f.vector()

# Computing Error in L2 norm for Pressure
E1 = errornorm(p_e_f, p, 'L2')
print('E1 =', E1)
E.append(E1)
DOF.append(len(V.dofmap().dofs()))

# Plotting Pressure Gradient, Difference_in_Numeric(p)_&_Exact_Pressure(p_e)_and Velocity_Profile
xdmf = XDMFFile('Numerical_Pressure_Gradient.xdmf')
xdmf.write(p)
xdmf.close()

xdmf = XDMFFile('Difference_in_Pressures.xdmf')
xdmf.write(diff_p)
xdmf.close()

xdmf = XDMFFile('Analytical_Pressure_Gradient.xdmf')
xdmf.write(p_e_f)
xdmf.close()

xdmf = XDMFFile('Velocity_Profile.xdmf')
xdmf.write(u_bar1)
xdmf.close()

print(E)
print(DOF)
Ea = np.array(E)
DOFa = np.array(DOF)
LogEa = np.log(Ea)
LogDOFa = np.log(DOFa)
print(LogEa)
print(LogDOFa)
print(type(p))
print(type(p_e_f))


import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-5, +5, 1000)

# Classification loss functions
y_error = (1 - np.sign(x)) / 2
y_hinge = np.maximum(1 - x, 0)
y_savage = 1 / np.square(1 + np.exp(x))
y_tangent = np.square(2 * np.arctan(x) - 1)
y_logistic = np.log(1 + np.exp(-x))
y_exponential = np.exp(-x)

fig = plt.figure()

ax = fig.add_subplot(1, 1, 1)
ax.set_xlim([-5.0,+5.0])
ax.set_ylim([-0.3,+8.0])
ax.set_title("classification loss functions")
ax.set_xlabel("edge = target * output")
ax.set_ylabel("loss(edge)")
ax.grid(color='grey', linestyle='-', linewidth=0.25, alpha=0.5)

plt.plot(x, y_error, 'k', label="0-1 loss", linewidth=2, linestyle="--")
plt.plot(x, y_hinge, 'r', label="hinge", linewidth=2)
plt.plot(x, y_savage, 'm', label="savage", linewidth=2)
plt.plot(x, y_tangent, 'c', label="tangent", linewidth=2)
plt.plot(x, y_logistic, 'g', label="logistic", linewidth=2)
plt.plot(x, y_exponential, 'b', label="exponential", linewidth=2)

plt.legend(loc='upper right')
plt.savefig("plot_losses_classification.png")
plt.clf()

# Regression loss functions
y_absolute = np.abs(x)
y_squared = np.square(x) / 2
y_cauchy = np.log(1 + np.square(x)) / 2

fig = plt.figure()

ax = fig.add_subplot(1, 1, 1)
ax.set_xlim([-5.0,+5.0])
ax.set_ylim([-0.3,+8.0])
ax.set_title("regression loss functions")
ax.set_xlabel("diff = target - output")
ax.set_ylabel("loss (diff)")
ax.grid(color='grey', linestyle='-', linewidth=0.25, alpha=0.5)

plt.plot(x, y_absolute, 'r', label="absolute", linewidth=2)
plt.plot(x, y_squared, 'g', label="squared", linewidth=2)
plt.plot(x, y_cauchy, 'b', label="cauchy", linewidth=2)

plt.legend(loc='upper right')
plt.savefig("plot_losses_regression.png")


# Bisection method root finding tests

from bisect import bisect
from math import sin, cos, exp

import numpy as np

# Get machine precision
eps = np.finfo(float).eps

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

print('-----------------------------------------------------------------------')
print('f(x) = sin(x)-cos(x)^2')
f = lambda x: sin(x)-cos(x)**2
x,steps = bisect(-1,1,f,eps)
print(" x = {}\n steps = {}\n error = {}".format(x,steps,f(x)))

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

print('-----------------------------------------------------------------------')
print('f(x) = x^2-8*x+2')
f = lambda x: x**2-8*x+2
x,steps = bisect(0,5,f,eps)
print(" x = {}\n steps = {}\n error = {}".format(x,steps,f(x)))

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

print('-----------------------------------------------------------------------')
print('f(x) = 2**x-cos(x+3)**2+exp(x+2)')
f = lambda x: 2**x-(cos(x+3))**2+exp(x+2)
x,steps = bisect(-10,10,f,eps)
print(" x = {}\n steps = {}\n error = {}".format(x,steps,f(x)))


import sys
from math import e, pi, sqrt
import random
import numpy as np
from numpy.core.numeric import Infinity

sys.path.insert(0, '../utilities')

import PlottingUtility as pu

# === Region Colors ===
# 0 : Red
# 1 : Orange
# 2 : Yellow
# 3 : Green

class Stats:
    def __init__(self, input_vect, region_colors):
        self.data = input_vect
        self.size = len(self.data)
        self.mean = np.average(self.data)

        # Calculate stdev
        acc = 0
        for i in range(0, self.size):
            acc += (self.data[i] - self.mean) ** 2
        acc = acc / self.size
        self.stdev = sqrt(acc)

        self.regions = {
            0 : (-float('inf'), self.mean - (3 * self.stdev)),
            1 : (self.mean - (3 * self.stdev), self.mean - (2 * self.stdev)),
            2 : (self.mean - (2 * self.stdev), self.mean - (self.stdev)),
            3 : (self.mean - (self.stdev), self.mean),
            4 : (self.mean, self.mean + (self.stdev)),
            5 : (self.mean + (self.stdev), self.mean + (2 * self.stdev)),
            6 : (self.mean + (2 * self.stdev), self.mean + (3 * self.stdev)),
            7 : (self.mean + (3 * self.stdev), float('inf')),
        }

        if(len(region_colors) != 8):
            sys.exit('region_colors parameter must be a list of 8 integers')
        self.region_colors = region_colors

    def display_dataset(self):
        for i in range(0, len(self.data)):
            print(i, ':', self.data[i])

    def plot_gauss_bell(self, ofile, title):
        xbell = np.array([])
        xdata = np.array([])
        ybell = np.array([])
        ydata = np.array([])

        low_range = self.mean - (self.stdev * 4)
        high_range = self.mean + (self.stdev * 4)
        increments = (high_range - low_range) / 1000
        count = low_range
        while (count < high_range):
            val = (1.0 / (self.stdev * sqrt(2 * pi))) * e ** (-0.5 * ((count - self.mean) / self.stdev) ** 2)
            xbell = np.append(xbell, count)
            ybell = np.append(ybell, val)
            count += increments

        max_y_curve = np.max(ybell)

        for i in range(0, len(self.data)):
            xdata = np.append(xdata, self.data[i])
            max_y = (1.0 / (self.stdev * sqrt(2 * pi))) * e ** (-0.5 * ((self.data[i] - self.mean) / self.stdev) ** 2)
            ydata = np.append(ydata, random.uniform(0, max_y))

        xmean = np.array([self.mean, self.mean])
        ymean = np.array([0, max_y_curve])
        xsd1 = np.array([self.mean - (self.stdev * 3), self.mean - (self.stdev * 3)])
        ysd1 = np.array([0, max_y_curve])
        xsd2 = np.array([self.mean - (self.stdev * 2), self.mean - (self.stdev * 2)])
        ysd2 = np.array([0, max_y_curve])
        xsd3 = np.array([self.mean - (self.stdev), self.mean - (self.stdev)])
        ysd3 = np.array([0, max_y_curve])
        xsd4 = np.array([self.mean + (self.stdev), self.mean + (self.stdev)])
        ysd4 = np.array([0, max_y_curve])
        xsd5 = np.array([self.mean + (self.stdev * 2), self.mean + (self.stdev * 2)])
        ysd5 = np.array([0, max_y_curve])
        xsd6 = np.array([self.mean + (self.stdev * 3), self.mean + (self.stdev * 3)])
        ysd6 = np.array([0, max_y_curve])

        n_datasets = 9
        colors_ds = ['#0743E8', '#E80730', '#009E1A', '#000000', '#000000',
                     '#000000', '#000000', '#000000', '#000000', '#000000']
        linestyle_ds = ['-', '', '-', '--', '--', '--', '--', '--', '--']
        markers_ds = ['', 'o', '', '', '', '', '', '', '']
        title_plot = title
        enable_rolling_avg_ds = [False, False, False, False, False, False, False, False, False]
        x_label = ''
        y_label = ''
        stitle = ''
        out_file = ofile
        ravg_days_ds = [None, None, None, None, None, None, None, None, None]
        ravg_labels_ds = [False, False, False, False, False, False, False, False, False]
        ravg_ydata_ds = [None, None, None, None, None, None, None, None, None]

        self.plot = pu.LayeredScatterPlot(
            n_datasets,
            colors_ds,
            linestyle_ds,
            markers_ds,
            title_plot,
            enable_rolling_avg_ds,
            x_label,
            y_label,
            [xbell, xdata, xmean, xsd1, xsd2, xsd3, xsd4, xsd5, xsd6],
            [ybell, ydata, ymean, ysd1, ysd2, ysd3, ysd4, ysd5, ysd6],
            stitle,
            out_file,
            ravg_days_ds,
            ravg_labels_ds,
            ravg_ydata_ds
        )
        self.plot.export()

    def plot_gauss_bell_datapoint(self, ofile, title, idx):
        xbell = np.array([])
        xdata = np.array([])
        ybell = np.array([])
        ydata = np.array([])

        low_range = self.mean - (self.stdev * 4)
        high_range = self.mean + (self.stdev * 4)
        increments = (high_range - low_range) / 1000
        count = low_range
        while (count < high_range):
            val = (1.0 / (self.stdev * sqrt(2 * pi))) * e ** (-0.5 * ((count - self.mean) / self.stdev) ** 2)
            xbell = np.append(xbell, count)
            ybell = np.append(ybell, val)
            count += increments

        max_y_curve = np.max(ybell)

        for i in range(0, len(self.data)):
            xdata = np.append(xdata, self.data[i])
            max_y = (1.0 / (self.stdev * sqrt(2 * pi))) * e ** (-0.5 * ((self.data[i] - self.mean) / self.stdev) ** 2)
            ydata = np.append(ydata, random.uniform(0, max_y))

        xmean = np.array([self.mean, self.mean])
        ymean = np.array([0, max_y_curve])
        xsd1 = np.array([self.mean - (self.stdev * 3), self.mean - (self.stdev * 3)])
        ysd1 = np.array([0, max_y_curve])
        xsd2 = np.array([self.mean - (self.stdev * 2), self.mean - (self.stdev * 2)])
        ysd2 = np.array([0, max_y_curve])
        xsd3 = np.array([self.mean - (self.stdev), self.mean - (self.stdev)])
        ysd3 = np.array([0, max_y_curve])
        xsd4 = np.array([self.mean + (self.stdev), self.mean + (self.stdev)])
        ysd4 = np.array([0, max_y_curve])
        xsd5 = np.array([self.mean + (self.stdev * 2), self.mean + (self.stdev * 2)])
        ysd5 = np.array([0, max_y_curve])
        xsd6 = np.array([self.mean + (self.stdev * 3), self.mean + (self.stdev * 3)])
        ysd6 = np.array([0, max_y_curve])

        xdatapoint = np.array([xdata[idx]])
        ydatapoint = np.array([ydata[idx]])

        n_datasets = 10
        colors_ds = ['#0743E8', '#E80730', '#009E1A', '#000000', '#000000',
                     '#000000', '#000000', '#000000', '#000000', '#000000']
        linestyle_ds = ['-', '', '', '-', '--', '--', '--', '--', '--', '--']
        markers_ds = ['', 'o', 'o', '', '', '', '', '', '', '']
        enable_rolling_avg_ds = [False, False, False, False, False, False, False, False, False, False]
        title = 'Datapoint x:' + str(xdata[idx])
        x_label = ''
        y_label = ''
        stitle = ''
        out_file = ofile
        ravg_days_ds = [None, None, None, None, None, None, None, None, None, None]
        ravg_labels_ds = [False, False, False, False, False, False, False, False, False, False]
        ravg_ydata_ds = [None, None, None, None, None, None, None, None, None, None]

        self.plot = pu.LayeredScatterPlot(
            n_datasets,
            colors_ds,
            linestyle_ds,
            markers_ds,
            title,
            enable_rolling_avg_ds,
            x_label,
            y_label,
            [xbell, xdata, xdatapoint, xmean, xsd1, xsd2, xsd3, xsd4, xsd5, xsd6],
            [ybell, ydata, ydatapoint, ymean, ysd1, ysd2, ysd3, ysd4, ysd5, ysd6],
            stitle,
            out_file,
            ravg_days_ds,
            ravg_labels_ds,
            ravg_ydata_ds
        )
        self.plot.export()

    def get_indicator(self, idx):
        if(idx < 0 or idx >= len(self.data)):
            sys.exit('idx cannot be < 0 or >= len(self.data) ->', str(len(self.data)))
        datapoint = self.data[idx]
        color_val = 0
        for i in range(0, len(self.regions)):
            if(datapoint >= self.regions[i][0] and datapoint < self.regions[i][1]):
                color_val = self.region_colors[i]
                break
        indicator = 0
        # return red circle
        if(color_val == 0):
            indicator = u'\U0001F534'
        # return orange circle
        elif(color_val == 1):
            indicator = u'\U0001F7E0'
        # return yellow circle
        elif(color_val == 2):
            indicator = u'\U0001F7E1'
        # return green circle
        elif(color_val == 3):
            indicator = u'\U0001F7E2'
        return indicator


import numpy as np
import pandas as pd
import scipy.stats
def drawdown(return_series: pd.Series):
    """
    Takes a Time Series of asset returns and computes and returns a dataframe that contains
    1) Wealth Idex
    2) Previous Peaks
    3) Percentage of drawdowns
    """
    wealth_index = 1000*(1+return_series).cumprod()
    previous_peaks = wealth_index.cummax()
    drawdowns = (wealth_index-previous_peaks)/previous_peaks
    return pd.DataFrame(dict(Wealth = wealth_index, Peaks = previous_peaks, Drawdowns = drawdowns))

def get_ffme_returns():
    """
    Load the Farma-French Dataset for the returns of the top and bottom deciles by Market Cap
    """
    me_m = pd.read_csv('Portfolios_Formed_on_ME_monthly_EW.csv', header=0, index_col=0, na_values = -99.99)
    rets = me_m[['Lo 10', 'Hi 10']]
    rets.columns = ['SmallCap', 'LargeCap']
    rets = rets/100
    rets.index = pd.to_datetime(rets.index, format="%Y%m").to_period('M')
    return rets

def get_hfi_returns():
    """
    Load the Edhec Hedge Fund Dataset for the returns of the top and bottom deciles by Market Cap
    """
    hfi = pd.read_csv('edhec-hedgefundindices.csv', header=0, index_col=0, parse_dates=True)
    hfi = hfi/100
    hfi.index = hfi.index.to_period('M')
    return hfi

def skewness(r):
    """
    Alternative method to scipy.stats.skew()
    Computes the skewness of the supplied Series or Dataframe
    Retruns a float or a series
    """
    demeaned_r = r - r.mean()
    #use the population standard deviation so set dof=0
    sigma_r = r.std(ddof=0)
    exp = (demeaned_r**3).mean()
    return exp/(sigma_r**3)

def kurtosis(r):
    """
    Alternative method to scipy.stats.kurtosis()
    Computes the kurtosis of the supplied Series or Dataframe
    Retruns a float or a series
    """
    demeaned_r = r - r.mean()
    #use the population standard deviation so set dof=0
    sigma_r = r.std(ddof=0)
    exp = (demeaned_r**4).mean()
    return exp/(sigma_r**4)

def is_normal(r, level = 0.01):
    """
    Applies the Jarque-Bera test to determine if a series is normal or not
    Test is applied at the 1% level by default
    Returns true if the hypothesis of normality is accepted otherwise returns False
    """
    statistic, p_value = scipy.stats.jarque_bera(r)
    return p_value>level