import numpy as np
from numpy.linalg import inv

def polyfit2d(x, y, z, order):
    if order == 1: # Linear
        G = np.vstack([np.ones(len(x)), x, y]).T
    if order == 2: # BiLinear
        G = np.vstack([np.ones(len(x)), x, y, x*y]).T
    if order == 3: #BiQuadratic6
        G = np.vstack([np.ones(len(x)), x, y, x*y, x**2, y**2]).T
    if order == 4: #BiQuadratic9
        G = np.vstack([np.ones(len(x)), x, y, x*y, x**2, y**2, x**2 * y**2, x**2 * y, y**2 * x]).T
    if order == 5: #BiCubic
        G = np.vstack([np.ones(len(x)), x, y, x*y, x**2, y**2, x**3, y**3, x**2 * y, y**2 * x, x**3 * y, y**3 * x, x**2 * y**2, y**3 * x**3, y**3 * x**2, y**2 * x**3]).T

    m = np.matmul(inv(G), z)
    return m

def polyval2d(x, y, m):

    if len(m) == 3:
        z = np.dot(np.array([1, x, y]),m)
    if len(m) == 4:
        z = np.dot(np.array([1, x, y, x*y]),m)
    if len(m) == 6:
        z = np.dot(np.array([1, x, y, x*y, x**2, y**2]),m)
    if len(m) == 9:
        z = np.dot(np.array([1, x, y, x*y, x**2, y**2, x**2 * y**2, x**2 * y, y**2 * x]),m)
    if len(m) == 16:
        z = np.dot(np.array([1, x, y, x*y, x**2, y**2, x**3, y**3, x**2 * y, y**2 * x, x**3 * y, y**3 * x, x**2 * y**2, y**3 * x**3, y**3 * x**2, y**2 * x**3]),m)

    return z


# 逻辑斯谛回归模型
# 2020/09/04
import numpy as np

def sigmoid(z):
    if z >= 0:
        return 1.0 / (1 + np.exp(-z))
    else:
        return np.exp(z) / (1 + np.exp(z))

def logistic_regression(trainDataArr, trainLabelArr, max_iter=500):
    # 梯度步长
    h = 0.001

    w = np.zeros(trainDataArr.shape[1])
    # 迭代
    for epoch in range(max_iter):
        for i in range(len(trainDataArr)):
            xi = trainDataArr[i]
            yi = trainLabelArr[i]
            wx = np.dot(xi, w)
            w += h * (yi - sigmoid(wx)) * xi

        if epoch % 100 == 0:
            print(f"epoch = {epoch }\t w = {w}")
    return w

def score(X_test, y_test, w):
    errorCnt = 0
    for i in range(len(X_test)):
        xi = X_test[i]
        y = sigmoid(np.dot(xi, w))
        yi = y_test[i]
        if (y >= 0.5 and yi == 0) or (y < 0.5 and yi == 1):
            errorCnt += 1
    return 1 - errorCnt / len(X_test)

if __name__ == '__main__':
    from sklearn.datasets import load_breast_cancer
    from sklearn.model_selection import train_test_split
    # from sklearn.linear_model import LogisticRegression

    X, y = load_breast_cancer(return_X_y=True)
    X = X.tolist()
    for x in X:
        x.append(1)
    X = np.array(X)
    X_train, X_test, y_train, y_test = train_test_split(X, y)

    w = logistic_regression(X_train, y_train)
    print(f"准确率为: {score(X_test, y_test, w)}")


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

# The Function we Solve
def f(x):
    y = x**4 + 2*x**3 - 5*x**2 - 7*x - 5
    return y

# (a,b): the interval we suspect to find the root
# N: number of repetitions
def RegulaFalsi(a, b, N):

    for i in range(N):
        y = (f(b)*a-f(a)*b)/(f(b)-f(a))
        if np.sign(f(a))*np.sign(f(y)) == -1: b = y
        else: a = y

    solution = y

    return solution

if __name__ == '__main__':

    # Visualize the Function
    x = np.linspace(1,3,100)
    y = f(x)

    plt.plot(x,y)
    plt.xlabel("x")
    plt.ylabel("y")
    plt.tight_layout
    plt.show()

    print(RegulaFalsi(1.5,3,30))


import numpy as np

def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum()

class SoftmaxLayer(object):

    def __init__(self, n_in, n_out):
        self.n_in = n_in
        self.n_out = n_out
        # Initialize weights and biases
        self.weights = np.zeros((n_in, n_out))
        self.biases = np.zeros(n_out)

    def calculate(self, input_images):
        self.input_images = input_images
        out = [(np.dot(im,self.weights) + self.biases) for im in input_images]
        self.out = [softmax(im) for im in out]
        return self.out

    def BP(self,eta, RefResults, previous_layer_out):
        # return delta using log-likehood cost function
        # and update weights / biases
        # 'next_layer_delta' value is not used, just to keep the same API for different layers
        self.delta = [(a-y) for a,y in zip(self.out,RefResults)]
        nabla_w = [np.dot(a.reshape(len(a),1),d.reshape(1,len(d))) for d,a in zip(self.delta,previous_layer_out)]
        nabla_w = np.sum(nabla_w,axis=0) / len(nabla_w)
        nabla_b = np.sum(self.delta,axis=0) / len(self.delta)

        # update network parameters
        self.weights = self.weights - eta * nabla_w
        self.biases = self.biases - eta * nabla_b

        return self.delta


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

def fun(x,y):
    ydot = y - x*x + 1.0
    return ydot

def main():
    xn   = np.linspace( 0.0, 5.0, 20 )     # Grid
    y0   = np.array( [ 0.5 ] )            # Initial condition
    y_ef = ode.euler( fun, xn, y0 )       # Forward Euler
    y_mp = ode.midpoint( fun, xn, y0 )    # Explicit Midpoint
    y_rk = ode.rk4( fun, xn, y0 )         # Runge-Kutta 4
    y_an = xn**2 + 2.0*xn + 1.0 - 0.5*np.exp(xn) # Analytical

    for i in range(0,xn.size):
        print xn[i], y_an[i], y_ef[i,0], y_mp[i,0], y_rk[i,0]

    plt.figure(1)
    plt.plot( xn, y_ef, 'ro-', label='Forward Euler (1st)' )
    plt.plot( xn, y_mp, 'go-', label='Explicit Mid-Point (2nd)' )
    plt.plot( xn, y_rk, 'bx-', label='Runge-Kutta (4th)' )
    plt.plot( xn, y_an, 'k-',  label='Analytical Solution' )
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend(loc=3)
    plt.savefig('ex02_ode_solution.png')
    plt.show()

if __name__ == '__main__':
   main()


import numpy as np
import time

def simulateCircleTask(iterations):
    """
        Simulates the following:
        Sample three points uniformly on a circle. Connect all three points to a triangle.
        What is the likelihhod that the center of the circle is covered in the area of the triangle?

        Args:
        iterations: Number of experiements

        Returns:
        Prints the occupied time, as well as the approximated probability of above question.

    """
    start_time = time.time()
    start = 0
    ende = 2*np.pi
    inside = 0
    outside = 0
    for k in range(0, iterations):
        a = np.random.uniform(start, ende)
        b = np.random.uniform(start, ende)
        c = np.mod(np.random.uniform(start, ende) + np.pi, ende)
        if(np.abs(a - b) <= np.pi):
            q1 = np.minimum(a, b)
            q2 = np.maximum(a, b)
            q3 = 0
            q4 = 0
        else:
            q1 = np.maximum(a, b)
            q2 = ende
            q3 = start
            q4 = np.minimum(a, b)
        if((c >= q1 and c <= q2) or (c >= q3 and c <= q4)):
            inside += 1
        else:
            outside += 1
    end_time = time.time()
    print("Elapsed Time: " + str(end_time - start_time) + " seconds")
    print("Approximated Probability: " + str(float(inside) / float(iterations)))

simulateCircleTask(100000)


import numpy as np

# fitSolution {1,2,3,4}
fitSolution = 1

# how many times of experiment to conduct
EXTIMES = 1

# two rate (parameter)
CROSSOVER_RATE = 0.5
MUTATION_RATE = 0.08

# to record every max fitness in every iteration
maxFitnessIter = []

# in the crossover_rate experiment, record every max fitness
maxFitnessCrs = []

# in the mutation_rate experiment, record every max fitness
maxFitnessMut = []

# size of DNA (1111)
M = 4
# size of  population
P = 100
# number of generations
N = 100

# domain of x1,x2,x3
xDomain = [0,15]

def getFitness(pop):
    x1, x2, x3 = encodeDNA(pop)
    ans = compFitness(x1, x2, x3)

    # Fitness solution1: move linearly
    if (fitSolution == 1):
        return ans + 1e-3 - np.min(ans)

    # Fitness solution2: square
    if (fitSolution ==2):
        return ans ** 2

    # Fitness solution3: root + move linearly
    if (fitSolution ==3):
        return (ans + 1e-3 - np.min(ans)) ** 0.5

    # Fitness solution4: minimal
    if (fitSolution ==4):
        return -(ans - np.max(ans) - 1e-3)

def compFitness(x1, x2, x3):
    return (2*x1*x1 - 3*x2*x2 - 4*x1 + 5*x2 + x3)

# binary to decimal
def encodeDNA(pop):
    #cut a line into 3 pieces, x1,x2,x3
    x1Pop = pop[:, 0:M]
    x2Pop = pop[:, M:M * 2]
    x3Pop = pop[:, M * 2:]

    # pop:(P,M)*(M,1) --> (P,1)   2 to 10
    x1 = x1Pop.dot(2 ** np.arange(M)[::-1]) / float(2 ** M - 1) * (xDomain[1] - xDomain[0]) + xDomain[0]
    x2 = x2Pop.dot(2 ** np.arange(M)[::-1]) / float(2 ** M - 1) * (xDomain[1] - xDomain[0]) + xDomain[0]
    x3 = x3Pop.dot(2 ** np.arange(M)[::-1]) / float(2 ** M - 1) * (xDomain[1] - xDomain[0]) + xDomain[0]
    return x1,x2,x3

def mutation(child, MUTATION_RATE):
    if np.random.rand() < MUTATION_RATE:
        # decide which point to be mutated by randomly pick up
        mutate_point = np.random.randint(0, M * 3)
        # reverse binaryly
        child[mutate_point] = child[mutate_point] ^ 1

def crossover_and_mutation(pop, CROSSOVER_RATE):
    new_pop = []
    # pick a father and a mother to corssover
    for father in pop:
        child = father
        # crossover happens under CROSS_RATE
        if np.random.rand() < CROSSOVER_RATE:
            mother = pop[np.random.randint(P)]
            # select the crossover point randomly
            cross_points = np.random.randint(low=0, high=M * 3)
            # the latter part is from mother
            child[cross_points:] = mother[cross_points:]
        # every child has possbility to mutate
        mutation(child,MUTATION_RATE)
        # new population
        new_pop.append(child)

    return new_pop

def roulette(pop, fitness):
    # roulette by pick index with weight(fitness/fitness.sum())
    idx = np.random.choice(np.arange(P), size=P, replace=True,
                           p=fitness/fitness.sum())
    return pop[idx]

    # sumFits = sum(fitness)
    # # generate a random number
    # rndPoint = np.random.uniform(0, sumFits)
    # # calculate the index: O(N)
    # accumulator = 0.0
    # inx = []
    # for ind, val in enumerate(fitness):
    #     accumulator += val
    #     if accumulator >= rndPoint:
    #     	inx.append(ind)
    #     	return pop[inx]
    #     else:
    #     	inx.append(ind)

def printPop(pop):
    fitness = getFitness(pop)
    max_fitness_index = np.argmax(fitness)
    x1, x2, x3 = encodeDNA(pop)
    x1=x1[max_fitness_index]
    x2=x2[max_fitness_index]
    x3=x3[max_fitness_index]

    print(pop)
    print("x1: ",x1)
    print("x2: ",x2)
    print("x3: ",x3)
    print("Max Fitness: ", compFitness(x1,x2,x3))

if __name__ == "__main__":

    for _ in range(EXTIMES):
        # generate population matrix with random number
        pop = np.random.randint(0, 2, size=(P, M * 3))
        # run iterations
        for i in range(N):
            pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE))
            fitness = getFitness(pop)
            pop = roulette(pop, fitness)

            if EXTIMES==1:
                max_fitness_index = np.argmax(fitness)
                x1, x2, x3 = encodeDNA(pop)
                x1=x1[max_fitness_index]
                x2=x2[max_fitness_index]
                x3=x3[max_fitness_index]
                maxFitnessIter.append(compFitness(x1,x2,x3))

        if EXTIMES==1:
            print(maxFitnessIter)
        else:
            fitness = getFitness(pop)
            max_fitness_index = np.argmax(fitness)
            x1, x2, x3 = encodeDNA(pop)
            x1=x1[max_fitness_index]
            x2=x2[max_fitness_index]
            x3=x3[max_fitness_index]
            maxFitnessCrs.append(compFitness(x1,x2,x3))
    if EXTIMES!=1:
        print(maxFitnessCrs)


import csv
import numpy as np

from numpy import sqrt, exp, pi

from scipy.special import erfcinv, betaincinv
from scipy.stats.distributions import  t

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

path = '/home/renato/Dropbox/Machine Learning/PLD/VaR/'

#################################################################
#################################################################
def csv_to_array(filename, type_):
	with open(filename, 'r') as f:
		next(f)
		reader = csv.reader(f)
		list_ = list(reader)
	f.close()

	return np.array(list_).astype(type_)

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

def gaussian(x, K, x0, sigma):
    return K * exp(-(x-x0)**2/(2*sigma**2))

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

def VaR_gaussian(quantity, mean, stddev, alpha, log_returns = True):
    var_log = mean - sqrt(2) * stddev * erfcinv(2 * alpha)

    if log_returns == False:
        var = var_log
    else:
        var = quantity * (exp(var_log) -1)

    return var

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

def CVaR_gaussian(quantity, mean, stddev, alpha, log_returns = True):

    K = 2 * mean - 2 * alpha * mean + sqrt(2 / pi) * stddev * exp(erfcinv(2 * alpha)**2)
    N = 2 - 2 * alpha

    cvar_log = K / N

    if log_returns == False:
        cvar = cvar_log
    else:
        cvar = quantity * (exp(cvar_log) - 1)

    return cvar

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

def student_t(x, K, mean, stddev, nu):
    return K * t.pdf(x, nu, mean, stddev)

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

def VaR_T(mean, stddev, nu, alpha):
    var = mean - stddev * sqrt(nu) * sqrt(-1 + 1/betaincinv(nu / 2, 1/2, 2 * alpha))
    return var

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


# Example of polynomial regression on synthetic dataset

import numpy as np
import pandas as pd
import seaborn as sn
import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
from sklearn.preprocessing import MinMaxScaler
from sklearn.linear_model import Lasso
from sklearn.preprocessing import PolynomialFeatures

# synthetic dataset for more complex regression
from sklearn.datasets import make_friedman1
plt.figure()
plt.title('Complex regression problem with one input variable')
X_F1, y_F1 = make_friedman1(n_samples = 100, n_features = 7, random_state=0)
plt.scatter(X_F1[:, 2], y_F1, marker= 'o', s=50)
plt.show()

# make train test split
X_train, X_test, y_train, y_test = train_test_split(X_F1, y_F1, random_state = 0)

# standard linear regression
linreg = LinearRegression().fit(X_train, y_train)

print('linear model coeff (w): {}'.format(linreg.coef_))
print('linear model intercept (b): {:.3f}'.format(linreg.intercept_))
print('R-squared score (training): {:.3f}'.format(linreg.score(X_train, y_train)))
print('R-squared score (test): {:.3f}'.format(linreg.score(X_test, y_test)))

# add polynomial features to dataset and do polynomial regression
print('\nNow we transform the original input data to add\n\
polynomial features up to degree 2 (quadratic)\n')
poly = PolynomialFeatures(degree=2)
X_F1_poly = poly.fit_transform(X_F1)

# do polynomial regression
X_train, X_test, y_train, y_test = train_test_split(X_F1_poly, y_F1, random_state = 0)
linreg = LinearRegression().fit(X_train, y_train)

print('(poly deg 2) linear model coeff (w):\n{}'.format(linreg.coef_))
print('(poly deg 2) linear model intercept (b): {:.3f}'.format(linreg.intercept_))
print('(poly deg 2) R-squared score (training): {:.3f}'.format(linreg.score(X_train, y_train)))
print('(poly deg 2) R-squared score (test): {:.3f}\n'.format(linreg.score(X_test, y_test)))

# polynomial regression with ridge regularization
print('\nAddition of many polynomial features often leads to\n\
overfitting, so we often use polynomial features in combination\n\
with regression that has a regularization penalty, like ridge\n\
regression.\n')

X_train, X_test, y_train, y_test = train_test_split(X_F1_poly, y_F1, random_state = 0)
linreg = Ridge().fit(X_train, y_train)

print('(poly deg 2 + ridge) linear model coeff (w):\n{}'.format(linreg.coef_))
print('(poly deg 2 + ridge) linear model intercept (b): {:.3f}'.format(linreg.intercept_))
print('(poly deg 2 + ridge) R-squared score (training): {:.3f}'.format(linreg.score(X_train, y_train)))
print('(poly deg 2 + ridge) R-squared score (test): {:.3f}'.format(linreg.score(X_test, y_test)))


# Bellman-Ford Algorithm
import numpy as np
import math

def Path_Relaxation(u, v, w, d, parent):
	# u and v are positions in d and w that represent nodes.
	# d is a list distances and each node is represented by its index in d
	# w is a matrix of weights
	if d[v] > d[u] + w[u,v]:
		d[v] = d[u] + w[u,v]
		parent[v] = u

	return d, parent

def Bellman_Ford(adjacency_list, source, out = None):
	w = adjacency_list
	if out is None:
		print('Distance, Parent')
	parent = []
	d = []
	neg = True
	for i in range(len(w[0,:])):
		parent.append(None)
		d.append(math.inf)
	d[source] = 0
	for i in range(len(d)):
		for u in range(len(d)):
			for v in range(len(d)):
				d, parent = Path_Relaxation(u,v,w,d, parent)
				if out is None:
					print(d, parent)
	for u in range(len(d)):
		for v in range(len(d)):
			if d[v] <= d[u] + w[u,v]:
				neg = False
	return neg, d, parent

def All_Paths_Bellman_Ford(adjacency_list):
	d_lists = []
	p_lists = []
	temp_d = []
	temp_p = []
	f = True
	for i in range(len(adjacency_list)):
		flag, temp_d, temp_p = Bellman_Ford(adjacency_list, i, out= False)
		d_lists.append(np.array(temp_d))
		p_lists.append(np.array(temp_p))
		if flag == False:
			f = False
	return f, np.array(d_lists), np.array(p_lists)

w1 = np.array([[0,-2,3,math.inf],[math.inf,0,-10,-1], [-4,-4,0,-4], [11, math.inf, math.inf, 0]])
w2 = np.array([[0,-2,3,math.inf, math.inf],[math.inf,0,-10,-1,math.inf], [-4,-4,0,-4, 5], [11, math.inf, math.inf, 0, 5], [-1,-1,-1,-1,0]])

print('Shortest path from Node 0')
flag, d, parent = Bellman_Ford(w1,0)
print(d)
print(parent)
print(flag)
print('Shortest path from Node 0')
flag, d, parent = Bellman_Ford(w2, 0)
print(d)
print(parent)
print(flag)
print('All Paths for the first list')
flag, d, parent = All_Paths_Bellman_Ford(w1)
print(d)
print(flag)
print('All paths for the second list')
flag, d, parent = All_Paths_Bellman_Ford(w2)
print(d)
print(flag)


# coding: utf-8
"""Sample Variance Example

@author: Liz
@modified: 11-20-2016

"""

import numpy as np

data1 = np.array([1, 5, 18])
data2 = np.array([2, 4, 6, 9, 12, 15, 20])

data1_ssd = sum(i ** 2 for i in (data1 - np.ones_like(data1) * data1.mean()))
data2_ssd = sum(i ** 2 for i in (data2 - np.ones_like(data2) * data2.mean()))

data1_sd = (data1_ssd / (len(data1) - 1)) ** 0.5
data2_sd = (data2_ssd / (len(data2) - 1)) ** 0.5

print("standard deviation 1: {}".format(data1_sd))
print("standard deviation 2: {}".format(data2_sd))


import numpy as _np
from math import pi as _pi
from fractions import Fraction as _Fraction

def generate_pi_axis(start=0, end=2 * _pi, jumps=5):
    """
    Generates an evenly spaced scale, in Pi multiplicities.
    :param start: A number to start the scale.
    :param end: A number to end the scale.
    :param jumps: Number of slices of the scale.
    :return: A tuple made of two lists, one for actual numbers and one for nicely formatted LaTeX scale.
    """

    jump_size = (end - start) / (jumps - 1)
    y_ticks = []
    y_ticks_labels = []
    for y_tick in range(0, jumps):
        cur_tick = start + jump_size * y_tick
        y_ticks.append(cur_tick)
        cur_tick = _Fraction(cur_tick / _pi).limit_denominator(max_denominator=10)
        if cur_tick.numerator == 0:
            y_ticks_labels.append("0")
        elif cur_tick.denominator == 1:
            y_ticks_labels.append("$%s\\pi$" % (str(cur_tick.numerator)))
        elif cur_tick.numerator < 0:
            y_ticks_labels.append("$-\\frac{%s}{%s}\\pi$" % (str(-cur_tick.numerator), str(cur_tick.denominator)))
        else:
            y_ticks_labels.append("$\\frac{%s}{%s}\\pi$" % (str(cur_tick.numerator), str(cur_tick.denominator)))
    return y_ticks, y_ticks_labels

def expand_linspace(lin_min, lin_max, chunks):
    """
    Uniformly expands a numpy linspace by 10%.
    :param lin_min: A number to start the scale.
    :param lin_max: A number to end the scale.
    :param chunks: Number of slices of the scale.
    :return: Expanded numpy linspace.
    """
    return _np.linspace(lin_min - _np.abs(lin_min * 0.1), lin_max + _np.abs(lin_max * 0.1), chunks)


# from __future__ import division

import os, sys
import numpy as np
import math
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib.colors import LogNorm
import matplotlib as mpl

from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerLine2D

from scipy.constants import pi
from scipy.constants import speed_of_light as clight
from scipy.constants import epsilon_0 as eps0
from scipy.constants import mu_0 as mu0
from scipy.constants import elementary_charge as qe
from scipy.constants import electron_mass as me
from scipy.constants import proton_mass as mp
from scipy.constants import Boltzmann as kB

import scipy.integrate as integrate
from scipy.integrate import quad, nquad, dblquad

#
# 1D integrals (function integrate.quad)
#

#
#  1) int_0^inf exp(-x^2):
#
def integrand1(x):
   return np.exp(-x**2)

result1=2./np.sqrt(pi)*quad(integrand1,0,np.inf)[0]
print 'result1=%e' % result1

# result1=1.00000+00, i.e.OK!

result2=2./np.sqrt(pi)*quad(lambda x: integrand1(x), 0, np.inf)[0]
print 'result2=%e' % result2

# result2=1.00000+00, i.e.OK!

#
#  2) sqrt(pi)/2.*(int_0^inf exp(-x^2)*erf(x)):
#
def integrand3(x):
   return np.exp(-x**2)*math.erf(x)

result3=np.sqrt(pi)/2.*quad(integrand3,0,np.inf)[0]
print 'result3=%e' % result3

# result3=3.926991-01, i.e. OK (see example 2) for 2D integation)

#
# 1D integral with parameter (function quad)
#
#  3) sqrt(pi/a)/2.*(int_0^inf exp(-x^2)*erf(sqrt(a)*x)):
#     if a=1 example moves to examples 2) for 1D):
#

# Repetition without parameter, but using quad inside def (works!):
#
# def integrand3a(x):
#    return np.exp(-x**2)*math.erf(x)
#
# def int_integrand3a():
#    return quad(integrand3a,0,np.inf)[0]
#
# result3a=np.sqrt(pi)/2.*int_integrand3a()
# print 'result3a=%e' % result3a

# Now with parameter:
#
def integrand3a(x,a):
   return np.exp(-x**2)*math.erf(np.sqrt(a)*x)

def int_integrand3a(a):
   intgrl=quad(lambda x: integrand3a(x,a), 0, np.inf)[0]
   return np.sqrt(pi/a)/2.*intgrl

for p in (0.5,1.0,1.5):
   result3a=int_integrand3a(p)
   print 'result3a=%e' % result3a

#
# 2D integrals (function integrate.dblquad)
#

#
#  1) int_0^inf exp(-x^2-y^2):
#
def integrand4(x,y):
   return np.exp(-x**2-y**2)

result4=4./pi*dblquad(lambda x,y: integrand4(x,y), 0, np.inf, \
                      lambda x: 0, lambda x: np.inf)[0]
print 'result4=%e' % result4

#
#  2) int_x_0^inf int_y_0^x exp(-x^2-y^2)
#     (= sqrt(pi)/2*(int_0^inf exp(-x^2)*erf(x))):
#
timeStart=os.times()
for i in range(10):
   result5=dblquad(lambda x,y: integrand4(x,y), 0, np.inf, \
                   lambda x: 0, lambda x: x)[0]
timeEnd=os.times()
print 'result5=%e' % result5
#
# result5=3.926991-01, i.e. OK (see example 2) for 1D integation)
#

# "time games": os.times() returns tuple with CPU time, system time,
# children's CPU time, children's system time, and elapsed time (from
# year's begin  ?); all times in seconds

print 'timeStart=',timeStart
print 'timeEnd=',timeEnd
delta1=float(timeEnd[0])-float(timeStart[0])   # CPU time
delta2=float(timeEnd[4])-float(timeStart[4])   # elapsed real time
print 'delta1=%e, delta2=%e' % (delta1, delta2)
#
#delta1=1.121000e+01, delta2=1.119000e+01 (for 1000 cycles)
#

#
# 2D integrals (function integrate.nquad)
#

#
#  3) int_x_0^inf int_y_0^x exp(-x^2-y^2)
#     (= sqrt(pi)/2*(int_0^inf exp(-x^2)*erf(x))):
#
def integrand6(x,y):
   return np.exp(-x**2-y**2)

def bounds_x():
   return [0,np.inf]

def bounds_y(x):
   return [0,x]

timeStart=os.times()
for i in range(10):
   result6=nquad(integrand6,[bounds_y,bounds_x])[0]
timeEnd=os.times()
print 'result6=%e' % result6
#
# result6=3.926991-01, i.e. OK (see example 2) for 1D integation)
#
print 'timeStart=',timeStart
print 'timeEnd=',timeEnd
delta3=float(timeEnd[0])-float(timeStart[0])   # CPU time
delta4=float(timeEnd[4])-float(timeStart[4])   # elapsed real time
print 'delta3=%e, delta4=%e' % (delta3, delta4)
#
#delta3=1.149000e+01, delta4=1.149000e+01 (for 1000 cycles)
#
#--------------------------------------------
#  So, nquad some slower than dblquad!!!
#--------------------------------------------

#
# 2D integrals with parameter (function integrate.dblquad)
#

#
#  1) int_x_0^inf int_y_0^x exp(-x^2-a*y^2)
#     (= sqrt(pi/a)/2*(int_0^inf exp(-x^2)*erf(sqrt(a)*x));
#     if a=1 example moves to examples 2),3) for 2D):
#

sys.exit()


from __future__ import division
from scipy.misc import factorial#, floor, sqrt
from numpy import arange, floor, sqrt, round

__all__ = ['wigner3j', 'wigner6j']

def TriaCoeff(a,b,c):
    # Calculating the triangle coefficient
    return factorial(a+b-c)*factorial(a-b+c)*factorial(-a+b+c)/(factorial(a+b+c+1))

def wigner3j(j1,j2,j3,m1,m2,m3):
    """Return the value of the 3-j symbol for the given values of j and m using the Racah formula [1].
        / j1 j2 j3 \
        |          |
        \ m1 m2 m3 /
        Reference: Wigner 3j-Symbol entry of Eric Weinstein's Mathworld:
        http://mathworld.wolfram.com/Wigner3j-Symbol.html

        Usage
        wigner = Wigner3j(j1,j2,j3,m1,m2,m3)

    Args:
        j1 (float): j1
        j2 (float): j2
        j3 (float): j3
        m1 (float): m1
        m2 (float): m2
        m3 (float): m3

    Returns:
        float: value of the 3-j symbol
    """
    # Error checking
    if ( ( 2*j1 != floor(2*j1) ) | ( 2*j2 != floor(2*j2) ) | ( 2*j3 != floor(2*j3) ) | ( 2*m1 != floor(2*m1) ) | ( 2*m2 != floor(2*m2) ) | ( 2*m3 != floor(2*m3) ) ):
        print('All arguments must be integers or half-integers.')
        return -1

    # Additional check if the sum of the second row equals zero
    if ( m1+m2+m3 != 0 ):
        print('3j-Symbol unphysical')
        return 0

    if ( j1 - m1 != floor ( j1 - m1 ) ):
        print('2*j1 and 2*m1 must have the same parity')
        return 0

    if ( j2 - m2 != floor ( j2 - m2 ) ):
        print('2*j2 and 2*m2 must have the same parity')
        return; 0

    if ( j3 - m3 != floor ( j3 - m3 ) ):
        print('2*j3 and 2*m3 must have the same parity')
        return 0

    if ( j3 > j1 + j2)  | ( j3 < abs(j1 - j2) ):
        print('j3 is out of bounds.')
        return 0

    if abs(m1) > j1:
        print('m1 is out of bounds.')
        return 0

    if abs(m2) > j2:
        print('m2 is out of bounds.')
        return 0

    if abs(m3) > j3:
        print('m3 is out of bounds.')
        return 0

    t1 = j2 - m1 - j3
    t2 = j1 + m2 - j3
    t3 = j1 + j2 - j3
    t4 = j1 - m1
    t5 = j2 + m2

    tmin = max( 0, max( t1, t2 ) )
    tmax = min( t3, min( t4, t5 ) )
    tvec = arange(tmin, tmax+1, 1)

    wigner = 0

    for t in tvec:
        wigner += (-1)**t / ( factorial(t) * factorial(t-t1) * factorial(t-t2) * factorial(t3-t) * factorial(t4-t) * factorial(t5-t) )

    return wigner * (-1)**(j1-j2-m3) * sqrt( factorial(j1+j2-j3) * factorial(j1-j2+j3) * factorial(-j1+j2+j3) / factorial(j1+j2+j3+1) * factorial(j1+m1) * factorial(j1-m1) * factorial(j2+m2) * factorial(j2-m2) * factorial(j3+m3) * factorial(j3-m3) )

def wigner6j(j1,j2,j3,J1,J2,J3):
    """Return the value of the 6-j symbol for the given values of j and m using the Racah formula.
        / j1 j2 j3 \
        <          >
        \ J1 J2 J3 /
        Based upon Wigner3j.m from David Terr, Raytheon
        Reference: http://mathworld.wolfram.com/Wigner6j-Symbol.html

        Usage
        wigner = Wigner6j(j1,j2,j3,J1,J2,J3)

    Args:
        j1 (float): j1
        j2 (float): j2
        j3 (float): j3
        J1 (float): J1
        J2 (float): J2
        J3 (float): J3

    Returns:
        float: value of the 6-j symbol
    """
    # Check that the js and Js are only integer or half integer
    if ( ( 2*j1 != round(2*j1) ) | ( 2*j2 != round(2*j2) ) | ( 2*j2 != round(2*j2) ) | ( 2*J1 != round(2*J1) ) | ( 2*J2 != round(2*J2) ) | ( 2*J3 != round(2*J3) ) ):
        print('All arguments must be integers or half-integers.')
        return -1

# Check if the 4 triads ( (j1 j2 j3), (j1 J2 J3), (J1 j2 J3), (J1 J2 j3) ) satisfy the triangular inequalities
    if ( ( abs(j1-j2) > j3 ) | ( j1+j2 < j3 ) | ( abs(j1-J2) > J3 ) | ( j1+J2 < J3 ) | ( abs(J1-j2) > J3 ) | ( J1+j2 < J3 ) | ( abs(J1-J2) > j3 ) | ( J1+J2 < j3 ) ):
        print('6j-Symbol is not triangular!')
        return 0

    # Check if the sum of the elements of each traid is an integer
    if ( ( 2*(j1+j2+j3) != round(2*(j1+j2+j3)) ) | ( 2*(j1+J2+J3) != round(2*(j1+J2+J3)) ) | ( 2*(J1+j2+J3) != round(2*(J1+j2+J3)) ) | ( 2*(J1+J2+j3) != round(2*(J1+J2+j3)) ) ):
        print('6j-Symbol is not triangular!')
        return 0

    # Arguments for the factorials
    t1 = j1+j2+j3
    t2 = j1+J2+J3
    t3 = J1+j2+J3
    t4 = J1+J2+j3
    t5 = j1+j2+J1+J2
    t6 = j2+j3+J2+J3
    t7 = j1+j3+J1+J3

    # Finding summation borders
    tmin = max(0, max(t1, max(t2, max(t3,t4))))
    tmax = min(t5, min(t6,t7))
    tvec = arange(tmin,tmax+1,1)

    # Calculation the sum part of the 6j-Symbol
    WignerReturn = 0
    for t in tvec:
        WignerReturn += (-1)**t*factorial(t+1)/( factorial(t-t1)*factorial(t-t2)*factorial(t-t3)*factorial(t-t4)*factorial(t5-t)*factorial(t6-t)*factorial(t7-t) )

    # Calculation of the 6j-Symbol
    return WignerReturn*sqrt( TriaCoeff(j1,j2,j3)*TriaCoeff(j1,J2,J3)*TriaCoeff(J1,j2,J3)*TriaCoeff(J1,J2,j3) )


import math
import numpy as np
import re
import entropy_time_bin

def rand_entropy(sequence):
    """
    Compute the "random entropy", that is, the entropy of a uniform distribution.
    Equation:
        S_{rand} = \log_{2}(n), where n is the number of unique symbols in the input sequence.
    Args:
        sequence: 1-D array-like sequence of symbols.
    Returns:
        A float representing the random entropy of the input sequence.
    Reference:
        Limits of Predictability in Human Mobility. Chaoming Song, Zehui Qu,
        Nicholas Blumm1, Albert-László Barabási. Vol. 327, Issue 5968, pp. 1018-1021.
        DOI: 10.1126/science.1177170
    """
    alphabet_size = len(np.unique(sequence))
    return np.log2(alphabet_size)

def unc_entropy(sequence):
    """
    Compute temporal-uncorrelated entropy (Shannon entropy).
    Equation:
    S_{unc} = - \sum p(i) \log_2{p(i)}, for each symbol i in the input sequence.
    Args:
        sequence: the input sequence of symbols.
    Returns:
        temporal-uncorrelated entropy of the input sequence.
    Reference:
        Limits of Predictability in Human Mobility. Chaoming Song, Zehui Qu,
        Nicholas Blumm1, Albert-László Barabási. Vol. 327, Issue 5968, pp. 1018-1021.
        DOI: 10.1126/science.1177170
    """
    _, counts = np.unique(sequence, return_counts=True)
    probabilities = counts / counts.sum()
    return -np.sum(probabilities * np.log2(probabilities))

def lambdas_naive(sequence):
    """
    Compute the lambdas in the following equation:

    Equation:
        S_{real} = \left( \frac{1}{n} \sum \Lambda_{i} \right)^{-1}\log_{2}(n)

    Args:
        sequence: the input sequence of symbols.
    Returns:
        The sum of the average length of sub-sequences that
        (up to a certain point) do not appear in the original sequence.
    Reference:
        Kontoyiannis, I., Algoet, P. H., Suhov, Y. M., & Wyner, A. J. (1998).
        Nonparametric entropy estimation for stationary processes and random
        fields, with applications to English text. IEEE Transactions on Information
        Theory, 44(3), 1319-1327.
    """
    lambdas = 0
    for i in range(len(sequence)):
        current_sequence = ','.join(sequence[0:i])
        match = True
        k = i
        while match and k < len(sequence):
            k += 1
            match = ','.join(sequence[i:k]) in current_sequence
        lambdas += (k - i)
    if lambdas==0:
        lambdas=1
    return lambdas

def real_entropy(lambdas, n):
    """
    Estimate the entropy rate of the symbols encoded in the input sequence.

    Equation:
        S_{real} = \left( \frac{1}{n} \sum \Lambda_{i} \right)^{-1}\log_{2}(n)

    Args:
        sequence: the input sequence of symbols.
    Returns:
        A float representing the entropy rate of the input sequence.
    Reference:
        Kontoyiannis, I., Algoet, P. H., Suhov, Y. M., & Wyner, A. J. (1998).
        Nonparametric entropy estimation for stationary processes and random
        fields, with applications to English text. IEEE Transactions on Information
        Theory, 44(3), 1319-1327.
    """
    return (1.0 * n / lambdas) * np.log(n)

def compute_f(p,S,N):
    if p<=0 or p>=1 :
        print(p)
    h = -p * np.log2(p) - (1 - p) * np.log2(1 - p)
    pi_max = h + (1 - p) * np.log2(N - 1) - S
    return pi_max

def getapproximation(p,S,N) :
    f= compute_f(p,S,N)
    d1 = np.log2(1-p) - np.log2(p) - np.log2(N-1)
    d2 = 1 / ((p-1)*p)
    return f/(d1-f*d2/(2*d1))

def max_predictability(S, N):
    """
    Estimate the maximum predictability of a sequence with
    entropy S and alphabet size N.
    Equation:
    $S = - H(\Pi) + (1 - \Pi)\log(N - 1),$
        where $H(\Pi)$ is given by
    $H(\Pi) = \Pi \log_2(\Pi) + (1 - \Pi) \log_2(1 - \Pi)$
    Args:
        S: the entropy of the input sequence of symbols.
        N: the size of the alphabet (number of unique symbols)
    Returns:
        the maximum predictability of the sequence.
    Reference:
        Limits of Predictability in Human Mobility. Chaoming Song, Zehui Qu,
        Nicholas Blumm1, Albert-László Barabási. Vol. 327, Issue 5968, pp. 1018-1021.
        DOI: 10.1126/science.1177170
    """
    if S>np.log2(N) :
        return 0
    if S<=0.01 :
        return 0.999
    p = (N+1)/(2*N)
    while(abs(compute_f(p,S,N))>0.0000001):
        p = p - 0.8*getapproximation(p,S,N)
    return p

def regularity(sequence):
    """
    Compute the regularity of a sequence.
    The regularity basically measures what percentage of a user's
    visits are to a previously visited place.
    Parameters
    ----------
    sequence : list
        A list of symbols.
    Returns
    -------
    float
        100 minus the percentage of the symbols in the sequence that are unique.
    """
    if len(set(sequence)) <= 1:
        return 100.0

    if len(set(sequence)) == len(sequence):
        return .0

    return round(100.0 - len(set(sequence)) * 100 / len(sequence), 2)

def stationarity(sequence):
    """
    Compute the stationarity of a sequence.
    A stationary transition is one whose source and destination symbols
    are the same. The stationarity measures the percentage of transitions
    to the same location.
    Parameters
    ----------
    sequence : list
        A list of symbols.
    Returns
    -------
    float
        Percentage of the sequence that is stationary.
    """
    if len(sequence) <= 1:
        return 100.0

    if len(sequence) == len(set(sequence)):
        return .0

    stationary_transitions = 0
    for i in range(1, len(sequence)):
        if sequence[i - 1] == sequence[i]:
            stationary_transitions += 1
    return round(stationary_transitions * 100 / (len(sequence) - 1), 2)

def diversity(locations, user_home):
    """
    Compute the of trajectories of a user's mobility trace.
    The diversity of trajectories is the ratio of unique home-home
    trajectories and their sizes compared to the total length of
    the trace.
    Parameters
    ----------
    locations : list
        A list of locations that a user visited.
    user_home : str
        A string representing the ID of the location of the user's home.
    Returns
    -------
    float
        The percentage of the overall trajectories that is accounted for
        by the unique trajectories.
    """
    if not locations:
        return .0

    # We assume that the user's trajectory starts and ends at their home location.
    if not locations[0].startswith(user_home):
        locations = [user_home] + locations
    if not locations[-1].startswith(user_home):
        locations.append(user_home)

    # Split home-to-home trajectories into groups.
    trajectories = re.split('(' + str(user_home) + ')', ''.join(str(loc) for loc in locations))

    # Counts home-to-home trajectories.
    trajectories = [traj for traj in trajectories if traj != '' and traj != user_home]

    if len(set(trajectories)) <= 1:
        return .0

    if len(set(trajectories)) == len(trajectories):
        return 100.0

    # Compute the diversity of trajectories: number of unique trajectories
    # times average size of unique trajectories as a percentage of the
    # total number of trajectories.
    if trajectories:
        unique_trajectories = len(set(trajectories))
        mean_unique_trajectory_size = np.mean([max(1, len(traj) // len(str(user_home))) for traj in set(trajectories)])
        return (unique_trajectories * mean_unique_trajectory_size) * 100 / len(locations)

    return .0

if __name__ == '__main__':
    b= [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
    a= [str(num) for num in b]
    lam = lambdas_naive(a)
    print(lam)
    print(real_entropy(lam,len(a)),unc_entropy(a))
    print(max_predictability(real_entropy(lam,len(a)),len(np.unique(a))))


from beacon.tensor import Tensor
from beacon.tensor import functions as fn
import numpy as np

########################
### Activation functions
########################

def sigmoid(t: Tensor):
    """
    Sigmoid activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.sigmoid(t)
    ```
    """
    return 1/ (1 + fn.exp(-t))

def softplus(t: Tensor):
    """
    Softplus activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.softplus(t)
    ```
    """
    return fn.log(1 + fn.exp(t))

def softsign(t: Tensor):
    """
    Softsign activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.softign(t)
    ```
    """
    return t / (1 + fn.abs(t))

def hard_sigmoid(t: Tensor):
    """
    Hard sigmoid activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.hard_sigmoid(t)
    ```
    """
    value = 0.2 * t + 0.5
    return fn.clip(value, 0.0, 1.0)

def relu(t: Tensor, alpha=None):
    """
    ReLU activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    alpha: `float` - scale factor, defaults to None (0.0)

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.relu(t)
    ```
    """
    return t * (t >= 0.0) + alpha * t * (t < 0.0) if alpha else t * (t >= 0.0)

def leaky_relu(t: Tensor, alpha = 0.01):
    """
    Leaky ReLU activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    alpha: `float` - scale factor, defaults to 0.01

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.leaky_relu(t)
    ```
    """
    return relu(t, alpha=alpha)

def softmax(t: Tensor):
    """
    Softmax activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.softmax(t)
    ```
    """
    y = fn.exp(t - fn.max(t, axis=-1, keepdims=True))
    return y / fn.sum(y, axis=-1, keepdims=True)

def elu(t: Tensor, alpha=1.0):
    """
    ELU activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    alpha: `float` - scale factor, defaults to 1.0

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.elu(t)
    ```
    """
    return t * (t >= 0.0) + alpha * (fn.exp(t) - 1.0) * (t < 0.0)

def tanh(t: Tensor):
    """
    Tanh activation function.

    ## Parameters
    t: `Tensor` - tensor on which to apply activation function

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    t = Tensor([[1, 2], [3, 4], [5, 6]], requires_grad=True)
    a = F.tanh(t)
    ```
    """
    return fn.tanh(t)

##############
### Reductions
##############

def sum_over_batch_size(loss_function):
    """
    Decorator which reduces loss function over batch size.

    ## Parameters
    loss_function: `callable` - loss function

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.tensor import functions as fn
    from beacon.functional import functions as F

    @F.sum_over_batch_size
    def my_loss(output: Tensor, target: Tensor):
        return fn.sin(output - target)
    ```
    """
    def wrapper(*args, **kwargs):
        batch_loss = fn.sum(loss_function(*args, **kwargs))
        batch_loss.data /= np.size(args[0].data)
        return batch_loss
    return wrapper

########################
### Loss functions
########################

@sum_over_batch_size
def mean_squared_error(output: Tensor, target: Tensor):
    """
    Mean squared error loss function.

    ## Parameters
    output: `Tensor` - model's prediction

    target: `Target` - training sample targets

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    output = Tensor([[0.2, 0.7, 0.1], [0.4, 0.45, 0.15]], requires_grad=True)
    target = Tensor([[0, 1, 0], [1, 0, 0]], requires_grad=True)
    loss = F.mean_squared_error(output, target)
    ```
    """
    output, target = fn.to_tensor(output), fn.to_tensor(target)
    return fn.mean(fn.square(output - target), axis=-1)

@sum_over_batch_size
def mean_absolute_error(output: Tensor, target: Tensor):
    """
    Mean absolute error loss function.

    ## Parameters
    output: `Tensor` - model's prediction

    target: `Target` - training sample targets

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    output = Tensor([[0.2, 0.7, 0.1], [0.4, 0.45, 0.15]], requires_grad=True)
    target = Tensor([[0, 1, 0], [1, 0, 0]], requires_grad=True)
    loss = F.mean_absolute_error(output, target)
    ```
    """
    output, target = fn.to_tensor(output), fn.to_tensor(target)
    return fn.mean(fn.abs(output - target), axis=-1)

@sum_over_batch_size
def categorical_crossentropy(output: Tensor, target: Tensor):
    """
    Cross entropy loss function.

    ## Parameters
    output: `Tensor` - model's prediction

    target: `Target` - training sample targets

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    output = Tensor([[0.2, 0.7, 0.1], [0.4, 0.45, 0.15]], requires_grad=True)
    target = Tensor([[0, 1, 0], [1, 0, 0]], requires_grad=True)
    loss = F.categorical_crossentropy(output, target)
    ```
    """
    output, target = fn.to_tensor(output), fn.to_tensor(target)
    output = fn.clip(output, 1e-7, 1 - 1e-7)
    return target * -fn.log(output)

@sum_over_batch_size
def binary_crossentropy(output: Tensor, target: Tensor):
    """
    Binary cross entropy loss function.

    ## Parameters
    output: `Tensor` - model's prediction

    target: `Target` - training sample targets

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    output = Tensor([[0.89], [0.76], [0.1]], requires_grad=True)
    target = Tensor([[1], [1], [0]], requires_grad=True)
    loss = F.binary_crossentropy(output, target)
    ```
    """
    output, target = fn.to_tensor(output), fn.to_tensor(target)
    output = fn.clip(output, 1e-7, 1 - 1e-7)
    return (target * -fn.log(sigmoid(output)) + (1 - target) * -fn.log(1 - sigmoid(output)))

@sum_over_batch_size
def nll_loss(output: Tensor, target: Tensor):
    """
    Negative log likelihood loss function.

    ## Parameters
    output: `Tensor` - model's prediction

    target: `Target` - training sample targets

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    output = Tensor([[0.2, 0.7, 0.1], [0.4, 0.45, 0.15]], requires_grad=True)
    target = Tensor([[0, 1, 0], [1, 0, 0]], requires_grad=True)
    loss = F.nll_loss(output, target)
    ```
    """
    output, target = fn.to_tensor(output), fn.to_tensor(target)
    output = fn.clip(output, 1e-7, 1 - 1e-7)
    return -target * fn.log(output)

@sum_over_batch_size
def quadratic(output: Tensor, target: Tensor):
    """
    Quadratic loss function.

    ## Parameters
    output: `Tensor` - model's prediction

    target: `Target` - training sample targets

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    output = Tensor([[0.2, 0.7, 0.1], [0.4, 0.45, 0.15]], requires_grad=True)
    target = Tensor([[0, 1, 0], [1, 0, 0]], requires_grad=True)
    loss = F.quadratic(output, target)
    ```
    """
    output, target = fn.to_tensor(output), fn.to_tensor(target)
    return fn.square(output - target)

@sum_over_batch_size
def half_quadratic(output: Tensor, target: Tensor):
    """
    Half quadratic loss function.

    ## Parameters
    output: `Tensor` - model's prediction

    target: `Target` - training sample targets

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F

    output = Tensor([[0.2, 0.7, 0.1], [0.4, 0.45, 0.15]], requires_grad=True)
    target = Tensor([[0, 1, 0], [1, 0, 0]], requires_grad=True)
    loss = F.half_quadratic(output, target)
    ```
    """
    output, target = fn.to_tensor(output), fn.to_tensor(target)
    return 0.5 * fn.square(output - target)

#####################
### Pooling functions
#####################

def max_pool(x: Tensor, kernel_size: tuple, stride: tuple=None, padding: tuple=(0, 0)):
    """
    Performs max pooling.

    ## Parameters
    x: `Tensor` - input tensor

    kernel_size: `tuple` - shape of the kernel

    stride: `tuple` - stride, if not set default shape is same as kernel_size

    padding: `tuple` - padding, defaults to (0, 0)

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F
    import numpy as np

    x = Tensor(data=np.random.rand(32, 10, 24, 24), requires_grad=True)
    sample = F.max_pool(x, kernel_size=(2, 2))
    output = F.max_pool(x, 2)
    ```
    """
    kernel_size = kernel_size if isinstance(kernel_size, tuple) else (kernel_size, kernel_size)
    stride = stride if stride else kernel_size
    return fn.max_pool(x, kernel_size, stride, padding)

def average_pool(x: Tensor, kernel_size: tuple, stride: tuple=None, padding: tuple=(0,0)):
    """
    Performs average pooling.

    ## Parameters
    x: `Tensor` - input tensor

    kernel_size: `tuple` - shape of the kernel

    stride: `tuple` - stride, if not set default shape is same as kernel_size

    padding: `tuple` - padding, defaults to (0, 0)

    ## Example usage
    ```python
    from beacon.tensor import Tensor
    from beacon.functional import functions as F
    import numpy as np

    x = Tensor(data=np.random.rand(32, 10, 24, 24), requires_grad=True)
    sample = F.average_pool(x, kernel_size=(2, 2))
    output = F.average_pool(x, 2)
    ```
    """
    kernel_size = kernel_size if isinstance(kernel_size, tuple) else (kernel_size, kernel_size)
    stride = stride if stride else kernel_size
    return fn.average_pool(x, kernel_size, stride, padding)


import numpy as np
import math, time, sys

__author__ = 'Lujing Cen'

EPSILON = sys.float_info.epsilon

def fabrik(p, d, t, tolerance, step=False):
    if step:
        ret = []

    # The distance between root and target.
    dist = np.linalg.norm(t - p[0])

    # Check if target is within reach.
    if dist > np.sum(d):
        # Target is unreachable.

        for i in range(len(p) - 1):
            # Find the distance r, between the target t and the joint position p_i.
            r = np.linalg.norm(p[i] - t)
            delta = d[i] / r

            # Find the new joint positions p_i.
            p[i+1] = (1-delta)*p[i] + delta*t

        return None
    else:
        # The target is reachable; thus, set as b the initial position of the joint p_i.
        b = p[0].copy()

        # Check whether the distance between the end effector pn and the target t is greater than a tolerance.
        dif = np.linalg.norm(t - p[-1])

        while dif > tolerance:
            # STAGE 1: FORWARD REACHING.
            # Set the end effector p_n as target t.
            p[-1] = t

            if step:
                ret.append(p.copy())

            for i in reversed(range(len(p) - 1)):
                # Find the distance ri between the new joint position p_i+1 and the joint p_i.
                r = np.linalg.norm(p[i+1] - p[i])
                delta = d[i] / r

                # Find the new joint position p_i.
                p[i] = (1-delta)*p[i+1] + delta*p[i]
                if step:
                    ret.append(p.copy())

            # STAGE 2: BACKWARD REACHING.
            # Set the root p_1 its initial position.
            p[0] = b
            if step:
                ret.append(p.copy())

            for i in range(len(p) - 1):
                # Find the distance ri between the new joint position p_i and the joint p_i+1.
                r = np.linalg.norm(p[i+1] - p[i])
                delta = d[i] / r

                # Find the new joint positions p_i.
                p[i+1] = (1-delta)*p[i] + delta*p[i+1]
                if step:
                    ret.append(p.copy())

            dif = np.linalg.norm(t - p[-1])
    if step:
        return ret
    else:
        return p


import numpy as np

def coor_trans(point, theta):
	"""
		coordinate transformation (坐标转换)

		theta方向：以顺时针旋转为正
	"""
	point = np.transpose(point)
	k = np.array([[np.cos(theta), np.sin(theta)],
				  [-np.sin(theta), np.cos(theta)]])
	print(point)
	# return np.dot(k, point)
	return np.round(np.dot(k, point),6)

if __name__ == "__main__":
	point = np.array([[1,0],[1,2],[2,0],[1,0]])
	print(point)
	point_trans = coor_trans(point, np.pi / 2)
	print(point_trans)


#from __future__ import division
import matplotlib.pyplot as plt
import numpy as np

def outlierDetection(Q1,Q3,list_of_numbers):
    #this function takes a list of numbers and prints out those numbers that are considered outliers
    IQR= float(Q3-Q1)
    print ("IQR= ",IQR)
    lowerthreshold=Q1-(IQR*1.5)
    print ("Lowerthreshold= ",lowerthreshold)
    upperthreshold=Q3+(IQR*1.5)
    print ("Upperthreshold= ",upperthreshold)
    for i in list_of_numbers:
        lowflag=0
        highflag=0
        if (i <lowerthreshold):
            lowflag=1
        if (i>upperthreshold):
            highflag=1
        if (lowflag):
            print (i , "is an outlier because it is lower than than the lowerthreshold")
        if (highflag):
            print (i , "is an outlier because it is higher than than the upperthreshold")

# different lists
list_of_numbers=[53,79,80,82,87,91,93,98]
#list_of_numbers=[53,79,80,82,87,91,93,98,57,79,99,66]
#list_of_numbers=[1,1,4,4,9,11]

#the numbers need to be sorted first
list_of_numbers.sort()
print ("The observations after sorting: ", list_of_numbers,'\n')

# printing the number of observations
print  ("Number of observations =  ",len(list_of_numbers),'\n')

# getting the minimum number of the list
Min=list_of_numbers[0]

#getting the maximum number of the list
Max=list_of_numbers[-1]

# getting the Q2 of the list
median = np.median(list_of_numbers)
# getting the Q3 of the list
upper_quartile = np.percentile(list_of_numbers, 75)
# getting the Q1 of the list
lower_quartile = np.percentile(list_of_numbers, 25)

# printing the five number summary
print ("Five Number Summary ",Min, lower_quartile, median, upper_quartile, Max,'\n')

# getting the outliers
outlierDetection(lower_quartile, upper_quartile,list_of_numbers)

# plotting the BOXPLOT verticaly with outliers as  diamond shape
plt.figure()
#plt.boxplot(list_of_numbers, 0, 'gD',0.50)
# plotting the BOXPLOT horizontal
plt.boxplot(list_of_numbers, 0, 'rs',0)
'''
# plotting the BOXPLOT with an outliers as a +
plt.boxplot(list_of_numbers)
# don't show outlier points
plt.figure()
plt.boxplot(list_of_numbers, 0, '')

# horizontal boxes
plt.figure()
plt.boxplot(list_of_numbers, 0, 'rs', 0)
'''

plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#活性化関数

import numpy as np
import matplotlib.pylab as plt

def step_function(x):
    return np.array(x > 0, dtype=np.int)

def sigmoid_function(x):
    return 1/(1+np.exp(-x))

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

def main():

    x = np.arange(-5.0, 5.0, 0.1)

    step_y = step_function(x)
    sigmoid_y = sigmoid_function(x)
    relu_y = relu_function(x)

    plt.plot(x, step_y, linestyle="dashed", label="$step$")
    plt.plot(x, sigmoid_y, 'r-', label="$sigmoid$")
    plt.plot(x, relu_y, 'g-', label="$relu")
    plt.xlim(-6.0, 6.0)
    plt.ylim(-0.1, 1.1) #y range
    plt.legend()
    plt.grid()
    plt.show()

if __name__ == '__main__':
    main()


# Description: Functions to fit statistical models to data series.
# Author:      André Palóczy
# E-mail:      paloczy@gmail.com
# Description: Functions to fit statistical models to data series.

__all__ = ['sinfitn',
           'fourfilt']

import numpy as np
import matplotlib.pyplot as plt
from numpy.fft import fft, ifft

def sinfitn(x, t, periods, constant=True, line=True, return_misfit=False, return_params=False):
	"""
	USAGE
	-----
	xm = sinfitn(d, t, periods, constant=True, line=True, return_misfit=False, return_params=False)

	Returns a statistical model 'xm(t)' with M periodic components. The period of each sinusoid
	is specified in the array 'period'. The model parameters are obtained by solving the
	overdetermined least-squares problem that minimizes the model misfit as measured by
	the Euclidean norm L2 = ||Gm - d||^2:

	m = (G^{T}*G)^{-1} * G^{T}*d,

	where 'd(t)'' is the data vector (N x 1) specified at the coordinates 't', m is the model
	parameter vector and G is the data kernel matrix.

	If 'constant'=True (default), a constant term is added to the model. If 'line'=True (default),
	a linear term is added to the model.

	If return_misfit=True (defaults to False), the model misfit L2 is also returned.

	If 'return_params'=True (defaults to False), the model parameter vector 'm' is returned
	instead of the statistical model 'xm'.

	REFERENCES
	----------
	Strang, G.: Introduction to Linear Algebra. 4th edition (2009).

	EXAMPLE
	-------
	>>> import numpy as np
	>>> import matplotlib.pyplot as plt
	>>> from ap_tools.fit import sinfitn
	>>> t = np.linspace(0., 200., 300.)
	>>> periods = [25., 50., 100.]
	>>> f1, f2, f3 = 2*np.pi/np.array(periods)
	>>> x = 50. + 0.8*t + 12.5*sin(f1*t) + 10*sin(f2*t) + 30*sin(f3*t) + 5.0*np.random.randn(t.size)
	>>> xm = sinfitn(x, t, periods)
	>>> fig, ax = plt.subplots()
	>>> ax.plot(t, x, 'g', label='Data')
	>>> ax.plot(t, xm, 'm', label='Sinusoidal model')
	>>> ax.grid(True)
	>>> ax.legend(loc='upper left')
	>>> ax.set_xlabel('Time [s]', fontsize=20)
	>>> ax.set_ylabel('Signal [arbitrary units]', fontsize=20)
	>>> plt.show()
	"""
	d = np.matrix(x)
	periods = list(periods)
	N = d.size       # Number of data points.
	M = len(periods) # Number of model parameters.

	## The data must be a row vector.
	if d.shape==(1,N):
		d = d.T

	## Setting up the data kernel matrix G.
	## Contains model functions evaluated at data points.
	G = np.matrix(np.zeros((N, 0)))
	if constant:
		x0 = np.expand_dims(np.repeat(1., N), 1)
		G = np.concatenate((G,x0), axis=1)
		M = M + 1
	if line:
		x1 = np.expand_dims(t, 1)
		G = np.concatenate((G,x1), axis=1)
		M = M + 1

	for period in periods:
		fn = 2*np.pi/period
		xn = np.matrix([np.sin(fn*t), np.cos(fn*t)]).T
		G = np.concatenate((G,xn), axis=1)

	## Solution to the overdetermined least-squares problem
	## to obtain the model parameters that minimize the
	## L2 norm of the model misfit vector, ||Gm - d||^2.
	## e.g., Strang (2009), pg. 218.
	m = (G.T*G).I*G.T*d

	## Assemble the statistical model using the parameters in the vector m.
	xm = G*m

	## Compute the L2 norm, ||Gm - d||^2.
	err = xm - d
	L2 = np.sqrt(err.T*err)
	L2 = np.float(L2)
	print("")
	print("Model-data misfit: %.1f"%L2)

	if return_params:
		if return_misfit:
			return m, L2
		else:
			return m
	else:
		xm = np.array(xm).squeeze()
		if return_misfit:
			return xm, L2
		else:
			return xm

def fourfilt(x, dts, Tmax, Tmin):
    # See the docstring of the original MATLAB function.
    # The usage is the same, see the docstring for
    # low-pass, high-pass and band-pass filter examples.
    #
    # In the Python version, the variable names
    # have been changed as follows:
    #
    # MATLAB      Python
    #  delt   ->   dts
    #  tmax   ->   Tmax
    #  tmin   ->   Tmin
    # filtdat ->   xfilt
    #
    # Translated from the MATLAB function fourfilt.m
    # by André Palóczy (github.com/apaloczy).
    #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    # function [filtdat]=fourfilt(x,delt,tmax,tmin)
    #  FOURFILT  Fourier low, high, or bandpass filter.
    #
    #     [filtdat]=fourfilt(x,delt,tmax,tmin)
    #
    #     where:   x:      data series to be filtered
    #              delt:   sampling interval
    #              tmax:   maximum period filter cutoff
    #              tmin:   minimum period filter cutoff
    #
    #     usage:  lowpassdata=fourfilt(data,0.5,2000,20)
    #
    #               gives lowpass filter with cutoff at 20.0 sec
    #               tmax set > (length(x)*delt) for no cutoff at low freq end
    #
    #     usage:  highpassdata=fourfilt(x,0.5,20,0.9)
    #
    #               gives highpass filter with cutoff at 20.0 sec
    #               tmin set < (2*delt) for no cutoff at high freq end
    #
    #     usage:  bandpassdata=fourfilt(x,0.5,20,10)
    #
    #               gives bandpass filter passing 10-20 sec. band
    #
    # Reference:
    # Walters, R. A.  and Heston, C., 1982. Removing the tidal-period variations from time-series
    # data using low-pass digital filters. Journal of Physical Oeanography, 12 112-115 .
    #
    #############################
    # Version 1.0  (12/4/96)  Jeff List (jlist@usgs.gov)
    # Version 1.1  (1/8/97)  Rich Signell (rsignell@usgs.gov)
    #     removed argument for number of points and add error trapping for matrices
    # Version 1.1b (12/1/2005) Rich Signell (rsignell@usgs.gov)
    #     added reference
    # (3/18/2019)
    # Translated to Python by André Palóczy.
    #############################
    npts = x.size
    # if npts%2==0: # N is even.
    nby2 = npts//2
    # else:
        # nby2 = (npts-1)//2

    tfund = npts*dts
    ffund = 1.0/tfund

    xmean = x.mean()
    x -= xmean # Remove the mean from data.
    coeffs = np.fft.fft(x) # Fourier-transform data.

    # Filter coefficients.
    f = ffund
    for i in range(1, nby2+2):
        t = 1.0/f
        if np.logical_or(t>Tmax, t<Tmin):
            coeffs[i] = coeffs[i]*0
        f += ffund

    # Calculate the remaining coefficients.
    for i in range(1, nby2+1):
        coeffs[npts-i] = coeffs[i].conj()

    # Back-transform data and take real part.
    xfilt = np.fft.ifft(coeffs).real
    xfilt += xmean # Add back the mean.

    return xfilt


# -*- coding: utf-8 -*-
"""10_locally_weighted_regression.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1XHCUgoBRqFn5LzQgzgpLZc8nvgfTCqYR

**10. Implement the non-parametric Locally Weighted Regression algorithm in order to fit data
points. Select appropriate data set for your experiment and draw graphs.**
"""

from math import ceil
import numpy as np
from scipy import linalg

def lowess(x, y, f, iterations):
    n = len(x)
    r = int(ceil(f * n))
    h = [np.sort(np.abs(x - x[i]))[r] for i in range(n)]
    w = np.clip(np.abs((x[:, None] - x[None, :]) / h), 0.0, 1.0)
    w = (1 - w ** 3) ** 3
    yest = np.zeros(n)
    delta = np.ones(n)
    for iteration in range(iterations):
        for i in range(n):
            weights = delta * w[:, i]
            b = np.array([np.sum(weights * y), np.sum(weights * y * x)])
            A = np.array([[np.sum(weights), np.sum(weights * x)],[np.sum(weights * x), np.sum(weights * x * x)]])
            beta = linalg.solve(A, b)
            yest[i] = beta[0] + beta[1] * x[i]

        residuals = y - yest
        s = np.median(np.abs(residuals))
        delta = np.clip(residuals / (6.0 * s), -1, 1)
        delta = (1 - delta ** 2) ** 2

    return yest

import math
n = 100
x = np.linspace(0, 2 * math.pi, n)
y = np.sin(x) + 0.3 * np.random.randn(n)
f =0.25
iterations=3
yest = lowess(x, y, f, iterations)

import matplotlib.pyplot as plt
plt.plot(x,y,"r.")
plt.plot(x,yest,"b-")

10.Locally Weighted Regression Algorithm/10_locally_weighted_regression.py


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 25 10:28:55 2019

@author: alankar
"""

import numpy as np

def RK4(f,x0,t,*args): #f must be a matrix of order (dim,1)
    if isinstance(t,list):
        t = np.array(t)
    elif not(isinstance(t,np.ndarray) or isinstance(t,list)):
        t = np.array([0,t])

    if isinstance(x0,list):
        x0 = np.array(x0)
    elif not(isinstance(x0,np.ndarray) or isinstance(x0,list)):
        x0 = np.array([x0])

    x = np.zeros((x0.shape[0],t.shape[0],),dtype=np.float64)
    h = t[1] - t[0]
    x[:,0] = x0 #Initial Condition
    dim = x0.shape[0]

    for i in range(1,t.shape[0]):
        k1, k2, k3, k4 = None, None, None, None

        if (dim==1):
            k1 = f(t[i-1],x[:,i-1],*args)*h
            k2 = f(t[i-1]+h/2,x[:,i-1]+k1/2,*args)*h
            k3 = f(t[i-1]+h/2,x[:,i-1]+k2/2,*args)*h
            k4 = f(t[i-1]+h,x[:,i-1]+k3,*args)*h

            x[:,i] = x[:,i-1] + (k1+2*(k2+k3)+k4)/6
        else:
            k1 = f(t[i-1],x[:,i-1],*args)*h
            k2 = f(t[i-1]+h/2,x[:,i-1]+k1[:,0]/2,*args)*h
            k3 = f(t[i-1]+h/2,x[:,i-1]+k2[:,0]/2,*args)*h
            k4 = f(t[i-1]+h,x[:,i-1]+k3[:,0],*args)*h

            x[:,i] = x[:,i-1] + (k1[:,0]+2*(k2[:,0]+k3[:,0])+k4[:,0])/6

    if (x.shape[0]==1): return x[0]
    return x


# Author: Sylvain Lapeyrade (sylla801)
# File: TSKS11-Lab2: Task 4

# ***************************** TASK 4 *****************************
# Calculate the Google PageRank score of each article in your network
# with parameter alpha = 0.85. List the top five articles and their
# PageRank score. Use the version of PageRank explained in the lecture
# notes. Also try some other values of alpha and comment on the result.

import numpy as np

# The calculations being too expensive, only one file
#  will be dealt with at the same time

network_number = 1  # Number of the file wanted

title_file = open(
    '/courses/TSKS11/ht2019/data_and_fcns/session2/titles/{}.txt'
    .format(network_number), 'r')
link_file = open(
    '/courses/TSKS11/ht2019/data_and_fcns/session2/links/{}.txt'
    .format(network_number), 'r')

title_list = []
titles = title_file.read().splitlines()  # Array of the titles
for title in titles:
    title_list.append(title)

degree = np.loadtxt(link_file, dtype=int)  # Loads all links
n = max(map(max, degree))  # Number of nodes

m = np.zeros((n, n), dtype=float)  # Matrix M initialized with 0
for j in range(len(degree)):  # Put 1 for every links
    m[degree[j][1] - 1][degree[j][0] - 1] = 1

totals_colums = np.sum(m, axis=0)  # totals of the colums
for i in range(n):
    if totals_colums[i] == 0:  # If a column total is 0
        totals_colums[i] = 1/n  # it is replaced by 1/n

for j in range(n):
    for i in range(n):
        m[j][i] /= totals_colums[i]  # Normalisation to obtain B

# Vector with only ones (3000, 1)
vector_I = np.ones((n, 1), dtype=int)

identity_matrix = np.identity(n)  # Identity Matrix 3000x3000

alpha = 0.85  # 0.85 by default

# Close formed PageRank formula
page_rank_score = (1 / n) * \
    np.matmul(np.linalg.inv(identity_matrix - (alpha * m)), vector_I)

# Sum of all page rank scores
total_page_rank = float(np.sum(page_rank_score, axis=0))

for i in range(n):
    page_rank_score[i] /= total_page_rank  # Normalisation

# Arguments of the fives largest PageRank score
five_argmax_pagerank = page_rank_score.argsort(axis=None)[-5:][::-1]

print("\n\nNetwork {}: \n".format(network_number))
print("Alpha = {}: \n".format(alpha))
print("Nodes with the highest PageRank Score:")
for i in range(5):
    print(str(i + 1) + '.', "PageRank Score: {0:.6f}"
          .format(round(float(page_rank_score[five_argmax_pagerank[i]]), 6)),
          "| Title:", title_list[five_argmax_pagerank[i]])

# Exact solution for Task 5
for i in range(5):
    print("Exact values", i+1, ":",
          float(page_rank_score[five_argmax_pagerank[i]]))


# -*- coding: utf-8 -*-
"""KFMO.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1NNjtUdUx-mh3swT5tVs9i0_GmOfzaD0z

#**Kalman Filter For Moving Object**
"""

! pip install pykalman

import numpy as np
import pylab as pl
from pykalman import KalmanFilter

"""**Let’s assume an object moves up and down over time, and the censor detects it with a small error. I postulate a perfect sin wave with randomness for the movement over time. When the location is plotted over time, it looks like the following**"""

rnd = np.random.RandomState(0)
n_timesteps = 100
x = np.linspace(0, 3 * np.pi, n_timesteps)
y = 20 * (np.sin(x) + 0.5 * rnd.randn(n_timesteps))
pl.figure(figsize=(40, 10))
pl.scatter(x,y, marker='x', color='b', label='observations')
pl.xlabel('time')
pl.ylabel('Position')
pl.show()

"""**Construction of Kalman Filter with transition_covariance**"""

kf = KalmanFilter(transition_matrices=np.array([[1, 1], [0, 1]]),
                  transition_covariance=0.01 * np.eye(2))
states_pred = kf.em(y).smooth(y)[0]

"""**Here,the state vector Xt can have two elements: position and velocity, and both are unobservable and hence the transition matrix would also consist of the same ,when passing the same through the kalman filter the output would be a perfect sine curve**"""

pl.figure(figsize=(40, 10))
obs_scatter = pl.scatter(x, y, marker='x', color='b',
                         label='observations')
position_line = pl.plot(x, states_pred[:, 0],markersize=2,
                        linestyle='-', marker='o', color='r',
                        label='position est.')
velocity_line = pl.plot(x, states_pred[:, 1],markersize=2,
                        linestyle='-', marker='o', color='g',
                        label='velocity est.')
pl.legend(loc='lower left',fontsize=14)
pl.xlim(xmin=0, xmax=x.max())
pl.xlabel('time')
pl.show()

"""**If in case there is only a single element in the  transition matrix , then this would be the result for the same , it would not be a perfect sinecurve but would resemble the same**"""

kf = KalmanFilter(transition_matrices=[1],
                  transition_covariance=0.01)
states_pred = kf.em(y).smooth(y)[0]
pl.figure(figsize=(40, 10))
obs_scatter = pl.scatter(x, y, marker='x', color='b',
                         label='observations')
position_line = pl.plot(x, states_pred,markersize=2,
                        linestyle='-', marker='o', color='r',
                        label='position est.')
pl.legend(loc='lower left',fontsize=14)
pl.xlim(xmin=0, xmax=x.max())
pl.xlabel('time')
pl.show()


def bgd(w, X_train, y_train, learning_rate=1e-3, num_iters=1):
    """Return weights and errors after given iterations of batch GD.

    Args:
        w -- M x 1 -- float: Weights.
        X_train -- N -- float: Inputs for training.
        y_train -- N -- float: Labels for training.
        learning_rate -- 1 -- float: Learning rate.
        num_iters -- 1 -- int: # of iterations.

    Returns:
        w -- M -- float: Updated weights.
        errors -- num_iters -- float: Errors after each iteration.
    """
    from numpy import concatenate, ones, newaxis, sum

    # Convert X_train to X to use it in GD,
    # i.e. concatenate [1, ... , 1] to its first row.
    N = len(y_train) # # of data points
    X = concatenate((ones((1, N)), X_train[newaxis, :]), axis=0)
    errors = []

    for iter in range(num_iters):
        w = w - learning_rate * X @ (w.T @ X - y_train[newaxis, :]).T / N
        MSE = sum((w.T @ X - y_train[newaxis, :]) ** 2) / N
        errors.append(MSE)

    return w, errors

def sgd(w, X_train, y_train, learning_rate=1e-3, num_iters=1):
    """Return weights and errors after given iterations of stochastic GD.

    One iteration uses all the data points.

    Args:
        w -- M x 1 -- float: Weights.
        X_train -- N -- float: Inputs for training.
        y_train -- N -- float: Labels for training.
        learning_rate -- 1 -- float: Learning rate.
        num_iters -- 1 -- int: # of iterations.

    Returns:
        w -- M -- float: Updated weights.
        errors -- num_iters -- float: Errors after each iteration.
    """
    from numpy import concatenate, ones, newaxis, sum

    # Convert X_train to X to use it in GD,
    # i.e. concatenate [1, ... , 1] to its first row.
    N = len(y_train) # # of data points
    X = concatenate((ones((1, N)), X_train[newaxis, :]), axis=0)
    errors = []

    for iter in range(num_iters):
        for idx in range(N):
            Xcur = X[:, idx, newaxis] # Data to use now.
            w = w - learning_rate * (w.T @ Xcur - y_train[idx]) * Xcur
        MSE = sum((w.T @ X - y_train[newaxis, :]) ** 2) / N
        errors.append(MSE)

    return w, errors

def main_a():
    """ Find the coefficients of a first degree polynomial using BGD and SGD.
    """
    from numpy import load, ones
    from matplotlib.pyplot import subplots, savefig, show

    # Load training data.
    X_train = load("data/q1xTrain.npy")
    y_train = load("data/q1yTrain.npy")

    # Set parameters.
    M = 2 # Define M, the # of features.
    w = ones((M, 1)) # Initialize the weights.
    num_iters = 100

    # Run BGD and SGD.
    wB, errB = bgd(w, X_train, y_train, learning_rate=1.5, num_iters=num_iters)
    wS, errS = sgd(w, X_train, y_train, learning_rate=0.1, num_iters=num_iters)

    # Find convergence iteration of BGD and SGD.
    # Define convergence if error <= 0.2
    # or decrease of error <= 0.0001.
    for idx in range(len(errB) - 1):
        if errB[idx] > 0.2 and errB[idx + 1] <= 0.2:
            thB = idx + 1
            break
        elif errB[idx] - errB[idx + 1] < 0.0001:
            thB = idx + 1
            break
    for idx in range(len(errS) - 1):
        if errS[idx] > 0.2 and errS[idx + 1] <= 0.2:
            thS = idx + 1
            break
        elif errS[idx] - errS[idx + 1] < 0.0001:
            thS = idx + 1
            break

    # Print weights and plot errors of BGD and SGD.
    print("Problem 1-(a)")
    print("Weight of BGD after {} iterations: {}".format(num_iters, wB.T))
    print("Weight of SGD after {} iterations: {}".format(num_iters, wS.T))
    fig, ax = subplots()
    ax.plot(errB, label="BGD Error")
    ax.title.set_text("MSE of Batch and Stochastic Gradient Descent\nBGD Weights: {}\nSGD Weights: {}".format(wB.T, wS.T))
    ax.set_xlabel("Iterations")
    ax.set_ylabel("Mean Squared Error")
    ax.scatter(thB, errB[thB], label="BGD Convergence: After {}th iteration".format(thB))
    ax.plot(errS, label="SGD Error")
    ax.scatter(thS, errS[thS], label="SGD Convergence: After {}th iteration".format(thS))
    ax.legend()
    savefig("q1-a-ii.png")
    show()

def make_design_matrix(X, M):
    """ Return a design matrix.

    Args:
        X -- N -- float: Inputs for training or testing.
        M -- 1 -- int: # of features to use.

    Returns:
        Phi -- N x M -- float: Design matrix.
    """
    assert M > 0 and type(M) == int, "M should be a positive integer."

    from numpy import zeros

    N = len(X)
    Phi = zeros((N, M))
    for col in range(M):
        Phi[:, col] = X ** col

    return Phi

def CFS(Phi, y_train):
    """ Return weights of linear regression using closed form solution.

    Args:
        Phi -- N x M -- float: Design matrix.
        y_train -- N -- float: Labels for training.

    Returns:
        w -- M -- float: Updated weights.
    """
    from numpy.linalg import pinv

    # Calculate closed form solution.
    w = pinv(Phi.T @ Phi) @ (Phi.T @ y_train)

    return w

def main_b():
    """ Find the coefficients of an M degree polynomial
    and check if overfitting happens.
    """
    from numpy import load, sqrt
    from matplotlib.pyplot import subplots, savefig, show

    # Load training and test data.
    X_train = load("data/q1xTrain.npy")
    y_train = load("data/q1yTrain.npy")
    X_test = load("data/q1xTest.npy")
    y_test = load("data/q1yTest.npy")

    RMSE_train = []
    RMSE_test = []
    for degree in range(10): # Iterate over polynomial degrees
        # Find closed form solutions with different # of features.
        Phi_train = make_design_matrix(X_train, M=degree+1)
        w = CFS(Phi_train, y_train)

        # Get "sum of squared error" of training data.
        SSE_train = (w.T @ Phi_train.T - y_train.T) @ (Phi_train @ w - y_train) / 2

        # Get RMSE of training data.
        N_train = len(y_train)
        RMSE_train.append(sqrt(2 * SSE_train / N_train))

        # Get "sum of squared error" and RMSE of testing data.
        Phi_test = make_design_matrix(X_test, M=degree+1)
        SSE_test = (w.T @ Phi_test.T - y_test.T) @ (Phi_test @ w - y_test) / 2
        N_test = len(y_test)
        RMSE_test.append(sqrt(2 * SSE_test / N_test))

    _, best_idx = min((val, idx) for (idx, val) in enumerate(RMSE_test))

    # Plot RMSE of training and testing data.
    print("Problem 1-(b)")
    fig, ax = subplots()
    ax.title.set_text("RMSE Plot for Under- and Over-fitting Check")
    ax.set_xlabel("M")
    ax.set_ylabel("RMSE")
    ax.plot(RMSE_train, label="Training Data")
    ax.plot(RMSE_test, label="Testing Data")
    ax.scatter(best_idx, RMSE_test[best_idx], label="{}th degree is the best".format(best_idx), color="orange")
    ax.legend()
    print("{}th degree is the best".format(best_idx))
    savefig("q1-b-i.png")
    show()

def CFS_ridge(Phi, reg, y_train):
    """ Return weights of ridge regression using closed form solution.

    Args:
        Phi -- N x M -- float: Design matrix.
        reg -- 1 -- float: Regularization coefficient.
        y_train -- N -- float: Labels for training.

    Returns:
        w -- M -- float: Updated weights.
    """
    from numpy import identity
    from numpy.linalg import pinv

    # Calculate closed form solution.
    w = pinv(Phi.T @ Phi + reg * identity(len(Phi.T))) @ (Phi.T @ y_train)

    return w

def main_c():
    """ Apply regularization.
    """
    from numpy import load, arange, sqrt
    from matplotlib.pyplot import subplots, savefig, show

    # Load training and test data.
    X_train = load("data/q1xTrain.npy")
    y_train = load("data/q1yTrain.npy")
    X_test = load("data/q1xTest.npy")
    y_test = load("data/q1yTest.npy")

    RMSE_train = []
    RMSE_test = []
    reg_list = [0] + [10 ** exp for exp in range(-8, 1)]
    for reg in reg_list:
        # Find closed form solutions of ridge regression.
        Phi_train = make_design_matrix(X_train, M=10)
        w = CFS_ridge(Phi_train, reg, y_train)

        # Get "sum of squared error" of training data.
        SSE_train = (w.T @ Phi_train.T - y_train.T) @ (Phi_train @ w - y_train) / 2

        # Get RMSE of training data.
        N_train = len(y_train)
        RMSE_train.append(sqrt(2 * SSE_train / N_train))

        # Get "sum of squared error" and RMSE of testing data.
        Phi_test = make_design_matrix(X_test, M=10)
        SSE_test = (w.T @ Phi_test.T - y_test.T) @ (Phi_test @ w - y_test) / 2
        N_test = len(y_test)
        RMSE_test.append(sqrt(2 * SSE_test / N_test))

    _, best_idx = min((val, idx) for (idx, val) in enumerate(RMSE_test))

    # Plot RMSE of training and testing data.
    reg_list = [str(elem) for elem in reg_list]
    print("Problem 1-(c)")
    fig, ax = subplots()
    ax.title.set_text("RMSE Plot to Check Regularization Effect")
    ax.set_xlabel("Regularization Coefficient")
    ax.set_ylabel("RMSE")
    ax.plot(reg_list, RMSE_train, label="Training Data")
    ax.plot(reg_list, RMSE_test, label="Testing Data")
    ax.scatter(best_idx, RMSE_test[best_idx], label="Reg. coeff. {} is the best".format(reg_list[best_idx]), color="orange")
    ax.legend()
    print("Regularization coefficient {} is the best".format(reg_list[best_idx]))
    savefig("q1-c-i.png")
    show()

if __name__ == "__main__":
    main_a()
    main_b()
    main_c()


"""Test a uniform permutation algorithm against a non-uniform one."""
import typing as t

import matplotlib.pyplot as plt
import numpy as np

def uniform_permutation(num_elements: int,
                        random_state: t.Optional[int] = None) -> np.ndarray:
    r"""Uniformly distributed permutation algorithm.

    A permutation algorithm being uniformily distributed means that every
    permutation of ``n`` elements has exactly $\frac{1}{n!}$ probability to
    happen.
    """
    if random_state is not None:
        np.random.seed(random_state)

    vals = np.arange(num_elements)

    for i in np.arange(num_elements):
        j = np.random.randint(i, num_elements)
        vals[i], vals[j] = vals[j], vals[i]

    return vals

def non_uniform_permutation(
        num_elements: int, random_state: t.Optional[int] = None) -> np.ndarray:
    """Produces an non-uniform permutation."""
    if random_state is not None:
        np.random.seed(random_state)

    vals = np.arange(num_elements)

    for i in np.arange(num_elements):
        j = np.random.randint(num_elements)
        vals[i], vals[j] = vals[j], vals[i]

    return vals

def _uniformity_test(num_elements: int,
                     permutation_func: t.Callable[[int, int], t.Sequence[int]],
                     num_samples: int = int(1e+6),
                     random_state: int = 16) -> np.ndarray:
    """Count the frequencies of each permutation of ``num_elements`` distinct elements."""
    # This test quality is inversely proportional to num_elements!
    hash_counter = {}  # type: t.Dict[t.Tuple[int, ...], int]

    for i in np.arange(num_samples):
        config = tuple(
            permutation_func(num_elements, int(random_state * (1 + i))))

        if config not in hash_counter:
            hash_counter[config] = 0

        hash_counter[config] += 1

    print(hash_counter)

    return np.array(list(hash_counter.values()), dtype=int)

def _test():
    """Compare a non-uniform permutation algorithm against a uniform one."""

    def fac(n: int):
        fac = 1
        while n:
            fac *= n
            n -= 1

        return fac

    num_elements = 3
    n_fac = fac(num_elements)

    plt.subplot(1, 2, 1)
    vals = _uniformity_test(
        num_elements=num_elements, permutation_func=non_uniform_permutation)
    plt.plot(vals / vals.sum(), label="Relative frequency")
    plt.hlines(y=1 / n_fac, xmin=0, xmax=n_fac - 1, linestyle='--')
    plt.ylim(0, 1)
    plt.title("Non-uniform permutation")
    plt.legend()

    plt.subplot(1, 2, 2)
    vals = _uniformity_test(
        num_elements=num_elements, permutation_func=uniform_permutation)
    plt.plot(vals / vals.sum(), label="Relative frequency")
    plt.hlines(y=1 / n_fac, xmin=0, xmax=n_fac - 1, linestyle='--')
    plt.ylim(0, 1)
    plt.title("Uniform permutation")
    plt.legend()

    plt.show()

if __name__ == "__main__":
    _test()


import numpy as np
from random import shuffle
import scipy as sc

def softmax_loss_naive(W, X, y, reg):
  """
  Softmax loss function, naive implementation (with loops)

  Inputs have dimension D, there are C classes, and we operate on minibatches
  of N examples.

  Inputs:
  - W: A numpy array of shape (D, C) containing weights.
  - X: A numpy array of shape (N, D) containing a minibatch of data.
  - y: A numpy array of shape (N,) containing training labels; y[i] = c means
    that X[i] has label c, where 0 <= c < C.
  - reg: (float) regularization strength

  Returns a tuple of:
  - loss as single float
  - gradient with respect to weights W; an array of same shape as W
  """
  # Initialize the loss and gradient to zero.
  loss = 0.0
  dW = np.zeros_like(W)
  num_train = X.shape[0]
  num_classes = dW.shape[1]

  for i in range(num_train):
    scores_i = W.T.dot(X[i, :])

    maximum = np.max(scores_i) # trick to deal with numerical instability
    scores_i -= maximum

    # compute the denominator in the log part
    suma = 0
    for el in scores_i:
      suma += np.exp(el)

    nominator = np.exp(scores_i[y[i]]) # compute the nominator in the log part
    loss -= np.log(nominator/suma)

    # compute the graient
    for j in range(num_classes):
      p = np.exp(scores_i[j])/suma
      dW[:, j] += (p-(j == y[i])) * X[i, :]

  # divide the loss/gradient with the number of examples and add the regularization term
  loss /= num_train
  loss += 0.5 * reg * np.sum(W * W)
  dW /= num_train
  dW += reg * W

  return loss, dW

def softmax_loss_vectorized(W, X, y, reg):
  """
  Softmax loss function, vectorized version.

  Inputs and outputs are the same as softmax_loss_naive.
  """
  # Initialize the loss and gradient to zero.
  loss = 0.0
  dW = np.zeros_like(W)
  num_train = X.shape[0]

  scores = W.T.dot(X.T)
  scores -= np.max(scores)
  correct_scores = scores[y, range(num_train)]

  nominator = np.exp(correct_scores)
  denominator = np.exp(scores)
  denominator = np.sum(denominator, axis = 0)

  loss -= np.log(nominator/denominator)
  loss = np.mean(loss)

  p = np.exp(scores)/np.sum(np.exp(scores), axis=0)
  ind = np.zeros(p.shape)
  ind[y, range(num_train)] = 1
  dW = np.dot((p-ind), X)
  dW /= num_train
  dW = dW.T

  loss += 0.5 * reg * np.sum(W * W)
  dW += reg * W
  return loss, dW


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

df = pd.read_csv('data1.csv', header = None)

plt.scatter(df[0], df[1])
plt.xticks(np.arange(0, 30, 5))
plt.yticks(np.arange(0, 30, 5))
plt.title("Food truck and their profit")
plt.show()

def computeCost(X, y, theta):

    m, n = X.shape

    X = np.hstack((np.ones((m,1)), X))

    predictions = X@theta
    error = sum((predictions-y)**2)
    J = (1/(2*m))*error

    grad = (1/m) * (X.T @ (predictions-y))

    return J, grad

X = df.iloc[:,0:1].values
y = df.iloc[:,1:2].values
theta = np.zeros((X.shape[1]+1, 1))

J, grad = computeCost(X, y, theta);
print('Cost J: ',J)
print('grad value: ', grad)

def gradientDescent(X, y, alpha, number_iterations):

    m, n = X.shape
    j_history = []
    theta = np.zeros((n+1, 1))
    for i in range(number_iterations):

        J, grad = computeCost(X, y, theta)

        theta = theta - (alpha * grad)
        j_history.append(J)

    return j_history, theta
j_history, theta_final = gradientDescent(X, y, alpha = 0.01, number_iterations=1500)
print('Cost function j_history size: ', np.size(j_history))
print('Final value of Theta size: ', theta_final)

plt.plot(j_history)
plt.xlabel('Number of iterations')
plt.ylabel('Cost values J')
plt.title('Cost Vs Iterations')
plt.show()

X_values = [X for X in range(25)]
y_values = [y*theta_final[1]+theta_final[0] for y in X_values]
plt.plot(X_values, y_values)
plt.xlabel('Goods vslues')
plt.ylabel('Profit')
plt.title('Fitting prediction line on Data')
plt.show()


import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import quad
from scipy.interpolate import UnivariateSpline
from scipy.optimize import minimize_scalar
import scipy.stats as ss
from randomvars._continuous import Cont, _detect_finite_supp, _combine_grids
from randomvars.options import config

N_GRID_PLOT = 1001

def cdf_grid(rv, n_grid):
    x_left, x_right = _detect_finite_supp(rv, supp=None, small_prob=1e-6)

    # Construct equidistant grid
    x_equi = np.linspace(x_left, x_right, n_grid)

    # Construct quantile grid
    prob_left, prob_right = rv.cdf([x_left, x_right])
    prob_equi = np.linspace(prob_left, prob_right, n_grid)
    x_quan = rv.ppf(prob_equi)

    # Combine equidistant and quantile grids into one sorted array
    return _combine_grids(x_equi, x_quan)

def create_cdf_spline(rv, n_grid, **kwargs):
    x_grid = cdf_grid(rv, n_grid)
    return UnivariateSpline(x=x_grid, y=rv.cdf(x_grid), **kwargs)

def cont_from_cdf_spline(rv, n_grid, **kwargs):
    cdf_spline = create_cdf_spline(rv, n_grid, **kwargs)
    x_grid_spline = cdf_spline.get_knots()
    y_grid_spline = cdf_spline.derivative(n=1)(x_grid_spline)
    return Cont(x=x_grid_spline, y=np.clip(y_grid_spline, a_min=0, a_max=None))

def plot_spline(spline, **kwargs):
    knots = spline.get_knots()
    x_grid = np.linspace(knots[0], knots[-1], N_GRID_PLOT)
    plt.plot(x_grid, spline(x_grid), **kwargs)

def plot_spline_deriv(spline, **kwargs):
    knots = spline.get_knots()
    x_grid = np.linspace(knots[0], knots[-1], N_GRID_PLOT)
    plt.plot(x_grid, spline.derivative(n=1)(x_grid), **kwargs)

def plot_rv(rv, fun_name="cdf", *args, **kwargs):
    f = getattr(rv, fun_name)
    p_grid = np.linspace(1e-6, 1 - 1e-6, N_GRID_PLOT)
    x_grid = rv.ppf(p_grid)
    plt.plot(x_grid, f(x_grid), *args, **kwargs)

def fun_diff(f, g, method="L2"):
    if method == "L1":
        integrand = lambda x: np.abs(f(x) - g(x))
    elif method == "L2":
        integrand = lambda x: (f(x) - g(x)) ** 2

    res = quad(integrand, -np.inf, np.inf, limit=100)[0]
    res = np.sqrt(res) if method == "L2" else res
    return res

rv = ss.norm()
# rv = ss.gamma(a=10)

# rv = ss.beta(a=0.5, b=0.5)
# rv = ss.chi2(df=1)
# rv = ss.chi2(df=2)
# rv = ss.weibull_max(c=0.5)

# rv = ss.cauchy()

n_grid = 1001
s = 1e-8
k = 2
cdf_spline = create_cdf_spline(rv, n_grid, s=s, k=k)
x_grid_spline = cdf_spline.get_knots()
y_grid_spline = cdf_spline.derivative(n=1)(x_grid_spline)
cump_grid_spline = cdf_spline(x_grid_spline)

plot_spline(cdf_spline, label="spline")
plot_rv(rv, label="original")
plt.plot(x_grid_spline, cump_grid_spline, "ok")
plt.legend()
plt.show()

plot_spline_deriv(cdf_spline, label="spline")
plot_rv(rv, fun_name="pdf", label="original")
plt.plot(x_grid_spline, y_grid_spline, "ok")
plt.legend()
plt.show()

# Comparing with current `Cont`
with config.context({"n_grid": n_grid}):
    rv_cont = Cont.from_rv(rv)
rv_spline = cont_from_cdf_spline(rv, n_grid, s=s, k=k)

print(rv_cont)
print(rv_spline)

plot_rv(rv, "pdf", color="black", label="original")
plot_rv(rv_cont, "pdf", color="blue", label="Cont")
plt.plot(rv_cont.x, rv_cont.y, color="blue", marker="o")
plot_rv(rv_spline, "pdf", color="red", label="spline")
plt.plot(rv_spline.x, rv_spline.y, color="red", marker="o")
plt.legend()
plt.show()

fun_diff(rv.pdf, rv_cont.pdf)
fun_diff(rv.pdf, rv_spline.pdf)
fun_diff(rv_cont.pdf, rv_spline.pdf)

fun_diff(rv.cdf, rv_cont.cdf)
fun_diff(rv.cdf, rv_spline.cdf)
fun_diff(rv_cont.cdf, rv_spline.cdf)

# Timings
# with config.context({"n_grid": n_grid}):
#     %timeit Cont.from_rv(rv)

# %timeit cont_from_cdf_spline(rv, n_grid, s=s, k=k)

# CURRENT CONCLUSION: using splines to find xy-grid (by approximating CDF with
# quadratic spline) with `s=1e-8` gives:
# - Pro++: around 8 to 10 times fewer grid elements.
# - Pro: approximates CDF on par with current method.
# - Con: not so well approximates density (L2 distance is around 1e-4 against 1e-5).
# - Con: takes about 8 to 10 times more computation time (around 10 ms vs around 1 ms).
# - Cont: it doesn't scale with `n_grid` very well in terms of execution time.


"""

A perfect square binomial is a quadratic function that can be factored into the following

a*x^2 + b*x + c = (u*x + v)^2

If we are less strict we can allow

a*x^2 + b*x + c = w*(u*x + v)^2

The first condition can be satisfied when the discriminant is 0 and the gcd of a, b, c is 1
d = b*b - 4*a*c = 0
gcd(a, gcd(a, b)) = 1

If we want the second form, we can get rid of the requirement of the gcd

"""

from sympy.abc import x
import sympy
import numpy as np
import sys

def str2bool(s):
    return s.lower() in ['true', '1', 't', 'y']

def is_perfect_square_binomial(a, b, c, strict):
    d = b*b - 4*a*c
    if d != 0:
        return False

    if strict and np.gcd(a, np.gcd(b, c)) != 1:
        return False

    return True

def find(n, strict):
    for a in range(1, n+1):
        for b in range(1, n+1):
            for c in range(1, n+1):
                if is_perfect_square_binomial(a, b, c, strict):
                    s = a*x*x + b*x + c
                    print("{} | {} | ({},{},{})".format(sympy.factor(s), s, a, b, c))

if len(sys.argv) < 3:
    print("usage: <n> <strict>")
    sys.exit(2)

find(int(sys.argv[1]), str2bool(sys.argv[2]))


#
# Author : Francesco Seccamonte
# Copyright (c) 2020 Francesco Seccamonte. All rights reserved.
# Licensed under the MIT License. See LICENSE file in the project root for full license information.
#

#
# Internal implementation of the Theta method (including Backward Euler) for ODEs numerical solution.
#

import numpy as np

def _Theta_step(f, df, xi, ti, h, theta, TOL, MAXITER):
	"""Internal function implementing one step of the theta (including Backward Euler) method.

	The ODE to be solved is of the form: x' = f(t,x), x being a vector in n-dimensions

	- **parameters**, **types**, **return** and **return types**::
		:param f: function in x' = f(t,x)
		:param df: Jacobian of f
		:param xi: initial condition at time ti
		:param ti: current time
		:param h: step size
		:param theta: value between 0 and 1
		:param TOL: Numerical tolerance for convergence
		:param MAXITER: Maximum number of Newton iterations to be performed
		:type f: Callable
		:type df: Callable
		:type xi: np.array[float]
		:type ti: np.float
		:type h: np.float
		:type theta: np.float
		:type TOL: np.float
		:type NEWTITER: (unsigned) int
		:return: Vector x containing solution of component j at next time ti+h (x[j])
		:rtype: np.array[float]

	"""

	# xinu represents the \nu step of the Newton iteration algorithm
	# xinu's first guess initialized as previous solution
	xinu = np.copy(xi);

	# Newton iteration
	for i in range(MAXITER):
		A = (np.identity(xi.size) - (1-theta)*h*df(ti+h,xinu));
		b = -(xinu - xi -theta*h*f(ti,xi) -(1-theta)*h*f(ti+h,xinu));

		# delta = xinu+1 - xinu
		# Solving the linear system of equations A delta = b, that is,
		# (I - (1-theta)*h*df)*delta = -(xinu - xi -theta*h*f(ti,xi) -(1-theta)*h*f(ti+h,xinu))
		delta = np.linalg.solve(A, b);

		xinu += delta;

		# check for convergence
		if np.linalg.norm(delta) <= TOL:
			return xinu;

	raise ArithmeticError('Newton iteration has not converged')


def find_rigid_transform(a, b, visualize=False):
    """
    Args:
        a: a 3xN array of vertex locations
        b: a 3xN array of vertex locations

    Returns: (R,T) such that R.dot(a)+T ~= b
    Based on Arun et al, "Least-squares fitting of two 3-D point sets," 1987.
    See also Eggert et al, "Estimating 3-D rigid body transformations: a
    comparison of four major algorithms," 1997.
    """
    import numpy as np
    import scipy.linalg
    from blmath.numerics.matlab import col

    if a.shape[0] != 3:
        if a.shape[1] == 3:
            a = a.T
    if b.shape[0] != 3:
        if b.shape[1] == 3:
            b = b.T
    assert a.shape[0] == 3
    assert b.shape[0] == 3

    a_mean = np.mean(a, axis=1)
    b_mean = np.mean(b, axis=1)
    a_centered = a - col(a_mean)
    b_centered = b - col(b_mean)

    c = a_centered.dot(b_centered.T)
    u, s, v = np.linalg.svd(c, full_matrices=False)
    v = v.T
    R = v.dot(u.T)

    if scipy.linalg.det(R) < 0:
        if np.any(s == 0): # This is only valid in the noiseless case; see the paper
            v[:, 2] = -v[:, 2]
            R = v.dot(u.T)
        else:
            raise ValueError("find_rigid_transform found a reflection that it cannot recover from. Try RANSAC or something...")

    T = col(b_mean - R.dot(a_mean))

    if visualize != False:
        from lace.mesh import Mesh
        from lace.meshviewer import MeshViewer
        mv = MeshViewer() if visualize is True else visualize
        a_T = R.dot(a) + T
        mv.set_dynamic_meshes([
            Mesh(v=a.T, f=[]).set_vertex_colors('red'),
            Mesh(v=b.T, f=[]).set_vertex_colors('green'),
            Mesh(v=a_T.T, f=[]).set_vertex_colors('orange'),
        ])

    return R, T

def find_rigid_rotation(a, b, allow_scaling=False):
    """
    Args:
        a: a 3xN array of vertex locations
        b: a 3xN array of vertex locations

    Returns: R such that R.dot(a) ~= b

    See link: http://en.wikipedia.org/wiki/Orthogonal_Procrustes_problem
    """
    import numpy as np
    import scipy.linalg
    from blmath.numerics.matlab import col

    assert a.shape[0] == 3
    assert b.shape[0] == 3

    if a.size == 3:
        cx = np.cross(a.ravel(), b.ravel())
        a = np.hstack((col(a), col(cx)))
        b = np.hstack((col(b), col(cx)))

    c = a.dot(b.T)
    u, _, v = np.linalg.svd(c, full_matrices=False)
    v = v.T
    R = v.dot(u.T)

    if scipy.linalg.det(R) < 0:
        v[:, 2] = -v[:, 2]
        R = v.dot(u.T)

    if allow_scaling:
        scalefactor = scipy.linalg.norm(b) / scipy.linalg.norm(a)
        R = R * scalefactor

    return R


#
#	Solved Problems in Geostatistics
#
# ------------------------------------------------
#	Script for lesson 4.3
#	"Transfer of Uncertainty"
# ------------------------------------------------

import sys
sys.path.append(r'../shared')

from numpy import *
from geo import *
from statistics import *
from matplotlib import *
from pylab import *
from scipy import *
from scipy.interpolate import *

# ---------------------------------------------------
#	Problem:
#
#	Evaluate the uncertainty in NVP for the first 5 years of a proposed project given the following parameter distributions provided by a finance model: Annual revenue, R, may be modeled by a normal distribution with mean and variance of $10 million and 2 million, respectively. Annual costs, C, are also assumed to follow a normal distribution with mean and variance of $8 million and 2 million. Choose a constant discount factor, r, say 10%. Calculate the P10, P50, and P90 of NPV. What is the probability of negative NPV?
#
# ----------------------------------------------------

# Mean and variance of annual revenue, R.
mean_R = 10
var_R = 2

# Mean and variance of annual costs, C.
mean_C = 8
var_C = 2

# Constant discount factor, r.
r = 0.1

# Number of years.
n = 5

# Number of realizations.
l = 1000

# Function for calculating NPV:
def npv_calculate(R, C, r, n):
	npv = 0.0
	for i in xrange(n):
		npv = npv + ((R[i] - C[i]) / (1 + r)**i)
	return npv

npv_array = []

# Repeat l times to assemble the distribution for NPV.
for i in xrange(l):
	#Simulate random R
	R = random.normal(mean_R, sqrt(var_R), n)

	#Simulate random C
	C = random.normal(mean_C, sqrt(var_C), n)

	npv_array.append(npv_calculate(R, C, r, n))
print "NPV", npv_array

[array_bins, array_hist] = histogram(npv_array, l)

for i in xrange(l-1):
	array_bins[i+1] = array_bins[i+1] + array_bins[i]

array_bin = zeros( (l), order = 'F', dtype = float)

for i in xrange(l):
	array_bin[i] =  float(array_bins[i]) / l

array_hist = delete(array_hist, [0])
z = []

# Interpolation
int_obj = interp1d(array_bin, array_hist, kind = 'linear')
z.append(int_obj(0.1))
z.append(int_obj(0.5))
z.append(int_obj(0.9))
print "P10 = ", z[0]
print "P50 = ", z[1]
print "P90 = ", z[2]

# Calculate the probability of a negative NPV.

negative_npv = 0.0
for i in xrange(l):
	if (npv_array[i] < 0):
		negative_npv = negative_npv + 1.0

prob_npv = negative_npv / l
print "Probability of negative NPV = ", prob_npv

# Histogram (1) and cumulative histogram (2) of simulated NPV assuming independence between the input variables.

figure()
hist(npv_array, 50, normed = True)
xlabel("NPV")
ylabel("Frequency")
title("Histogram of simulated NPV")

figure()
plot(array_hist, array_bin)
xlabel("NPV")
ylabel("Cumulative Frequency")
title("Cumulative histogram of simulated NPV")
show()

src/sample-scripts/solved_problems/4.3. Transfer of Uncertainty/1_npv.py


"""
measure.py
Analyzing and Visualizing Molecules (MOLSSI)

Handles the primary functions
"""

import numpy as np

def calculate_distance(Atom_A, Atom_B):

    """
    Distance Between Two Atoms.

    Parameters
    __________

    Atom_A, Atom_B : np.ndarray
        The Coordinates for Atom_A and Atom_B.

    Returns
    _______

    distance : float
        The Distance from Atom_A to Atom_B.

    Examples
    ________

    >>> r1 = np.array([0.0, 0.0, 0.0])
    >>> r2 = np.array([1.0, 0.0, 0.0])
    >>> calculate_distance(r1, r2)
    1.0
    """

    difference = (Atom_A - Atom_B)
    distance = np.linalg.norm(difference)
    return distance

def calculate_angle(rA, rB, rC, degrees=False):
    # Calculate the angle between three points. Answer is given in radians by default, but can be given in degrees
    # by setting degrees=True
    AB = rB - rA
    BC = rB - rC
    theta=np.arccos(np.dot(AB, BC)/(np.linalg.norm(AB)*np.linalg.norm(BC)))

    if degrees:
        return np.degrees(theta)
    else:
        return theta