import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import datasets
from math import exp

# the logistic function
def logistic_func(theta, x):
    t = x.dot(theta)
    g = np.zeros(t.shape)
    # split into positive and negative to improve stability
    g[t>=0.0] = 1.0 / (1.0 + np.exp(-t[t>=0.0]))
    g[t<0.0] = np.exp(t[t<0.0]) / (np.exp(t[t<0.0])+1.0)
    return g

# function to compute log-likelihood
def neg_log_like(theta, x, y):
    g = logistic_func(theta,x)
    return -sum(np.log(g[y>0.5])) - sum(np.log(1-g[y<0.5]))

# function to compute the gradient of the negative log-likelihood
def log_grad(theta, x, y):
    g = logistic_func(theta,x)
    return -x.T.dot(y-g)

# implementation of gradient descent for logistic regression
def grad_desc(theta, x, y, alpha, tol, maxiter):
    nll_vec = []
    nll_vec.append(neg_log_like(theta, x, y))
    nll_delta = 2.0*tol
    iter = 0
    while (nll_delta > tol) and (iter < maxiter):
        theta = theta - (alpha * log_grad(theta, x, y))
        nll_vec.append(neg_log_like(theta, x, y))
        nll_delta = nll_vec[-2]-nll_vec[-1]
        iter += 1
    return theta, np.array(nll_vec)

# function to compute output of LR classifier
def lr_predict(theta,x):
    # form Xtilde for prediction
    shape = x.shape
    Xtilde = np.zeros((shape[0],shape[1]+1))
    Xtilde[:,0] = np.ones(shape[0])
    Xtilde[:,1:] = x
    return logistic_func(theta,Xtilde)

## Generate dataset
np.random.seed(2017) # Set random seed so results are repeatable
x,y = datasets.make_blobs(n_samples=100,n_features=2,centers=2,cluster_std=6.0)

## build classifier
# form Xtilde
shape = x.shape
xtilde = np.zeros((shape[0],shape[1]+1))
xtilde[:,0] = np.ones(shape[0])
xtilde[:,1:] = x

# Initialize theta to zero
theta = np.zeros(shape[1]+1)

# Run gradient descent
alpha = ????
tol = 1e-3
maxiter = 10000
theta,cost = grad_desc(theta,xtilde,y,alpha,tol,maxiter)

## Plot the decision boundary.
# Begin by creating the mesh [x_min, x_max]x[y_min, y_max].
h = .02  # step size in the mesh
x_delta = (x[:, 0].max() - x[:, 0].min())*0.05 # add 5% white space to border
y_delta = (x[:, 1].max() - x[:, 1].min())*0.05
x_min, x_max = x[:, 0].min() - x_delta, x[:, 0].max() + x_delta
y_min, y_max = x[:, 1].min() - y_delta, x[:, 1].max() + y_delta
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = lr_predict(theta,np.c_[xx.ravel(), yy.ravel()])

# Create color maps
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00'])

# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, Z, cmap=cmap_light)

## Plot the training points
plt.scatter(x[:, 0], x[:, 1], c=y, cmap=cmap_bold)

## Show the plot
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title("Logistic regression classifier")
plt.show()


import numpy as np

def gaussian(x, y, mean, cov):

	sigmax = np.sqrt(cov[0,0])
	sigmay = np.sqrt(cov[1,1])
	mux = mean[0]
	muy = mean[1]

	max_f = (2*np.pi*sigmax*sigmay)**(-1)

	ex = -(x-mux)**2/(2*sigmax**2)
	ey = -(y-muy)**2/(2*sigmay**2)

	return max_f*np.exp(ex + ey)

def generate_gaussian(mean, cov, N):
	'''
	Sample the 2d Gaussian distribution
	with independent variables.
	'''
	sigmax = np.sqrt(cov[0,0])
	sigmay = np.sqrt(cov[1,1])
	mux = mean[0]
	muy = mean[1]

	max_f = (2*np.pi*sigmax*sigmay)**(-1)

	result = []

	while len(result) < N:

		x = 8*sigmax*np.random.rand() - 4*sigmax + mux
		y = 8*sigmay*np.random.rand() - 4*sigmay + muy
		z = max_f*np.random.rand()

		if z < gaussian(x,y,mean,cov):
			result.append([x,y])

	return np.array(result)


'''
ANKIT KHANDELWAL
15863
Exercise 8
'''

from math import exp

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

blur = pd.read_csv("blur.txt", sep=' ', header=None)

def G(x, y):
    return exp(-(x ** 2 + y ** 2) / (2 * 25 ** 2))

gauss = np.ones((1024, 1024))
for i in range(1024):
    for j in range(1024):
        gauss[i - 512][j - 512] = G(i - 512, j - 512)

plt.imshow(blur)
plt.title('Blur')
plt.figure()
plt.imshow(gauss)
plt.title('Gauss')
plt.figure()
blur_fft = np.fft.rfft2(blur)
gauss_fft = np.fft.rfft2(gauss)
unblur = np.ones((1024, 513), complex)

for i in range(1024):
    for j in range(513):
        if gauss_fft[i][j] > 10 ** -3:
            unblur[i][j] = blur_fft[i][j] / gauss_fft[i][j] / 1024 ** 2
        else:
            unblur[i][j] = blur_fft[i][j] / 1024 ** 2

unblur_fft = np.fft.irfft2(unblur)
plt.imshow(unblur_fft)
plt.title('Un-Blur')
plt.show()

'''
There are two reasons limiting our ability to un-blur a photo:
    1. We don't always know the point spread function (PSF).
    2. Even when we approximate the PSF, we can not get arbitrary accuracy
       as we can not divide by very small numbers (or zero) which we get
       from FFT of the PSF.
'''

Ankit Khandelwal_HW4/Exercise 8/exercise 8.py


import numpy as np

def fdaxis(TimeAxis=None,*args,**kwargs):
    '''
    fdaxis, Frequency domain axis
    -----------------------------
    Returns a vector FreqAxis containing the frequency-
    domain axis of the FFT of a N-point time-
    domain vector TimeAxis sampled with period dT.

    This script is freely inspired by the easyspin suite from the Stefan Stoll lab
    (https://github.com/StollLab/EasySpin/)
    (https://easyspin.org/easyspin/)

    Script written by Timothée Chauviré (https://github.com/TChauvire/EPR_ESR_Suite/), 09/09/2020

    Parameters
    ----------
    TimeAxis : time-domain vector TimeAxis, TYPE numpy 1D data array, optional
        DESCRIPTION. The default is None.

    Returns
    -------
    FreqAxis : Frequency axis associated to the input time axis after Fourier Transformation.
        DESCRIPTION.

    '''
    if (TimeAxis.shape[0] != np.ravel(TimeAxis).shape[0]):
        raise ValueError('The file data must be a column vector')
    else:
        TimeAxis = np.ravel(TimeAxis)
    dT=TimeAxis[1] - TimeAxis[0]
    N=len(TimeAxis)
    NyquistFrequency=1/(2*dT)
    UnitAxis=np.multiply(2/N,np.arange(0,N)-np.fix(N/2))
    FreqAxis=NyquistFrequency*UnitAxis
    return FreqAxis


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

def XPx(x,px):
	soma = 0
	sum = 0
	for i in range(len(x)):
		soma += x[i] * px[i]
		sum += px[i]
	print("Soma de P(x) = %.2f" %sum)
	return soma

def VAR(media, x, px):
	var = 0
	for i in range(len(x)):
		sigma = ((media - x[i])**2) * px[i]
		var += sigma
	return var

def DP(var):
	return math.sqrt(var)

def desvio(media, dp):
	min = media - dp
	max = media + dp

	min2 = media - (2*dp)
	max2 = media + (2*dp)

	min3 = media - (3*dp)
	max3 = media + (3*dp)
	print("\n")
	print("Desvio 1 - 68%%   - Min %.2f Max %.2f" %(min, max))
	print("Desvio 2 - 95%%   - Min %.2f Max %.2f" %(min2, max2))
	print("Desvio 3 - 99.7%% - Min %.2f Max %.2f" %(min3, max3))
	return (min, max, min2, max2, min3, max3)

def graph(x, px, media, var, dp, desvio):
	plt.figure(figsize=(8, 6))
	plt.title("[Media  %.2f]   [VAR  %.2f]   [DP  %.2f]" %(media, var, dp))
	#plt.xlabel("X")
	plt.ylabel("P(x)")
	plt.grid(True)

	plt.bar(x, px, color='purple', width=.97, edgecolor='gray')
	m = sum(px) / float(len(px))

	plt.plot(desvio[0:2], [m+(m/2), m+(m/2)], ls='--', color = '#10A0DF', label="68%% Min %.2f Max %.2f"%(desvio[0], desvio[1]))
	plt.plot(desvio[2:4], [m, m], ls='--', color = 'red',  label="95%% Min %.2f Max %.2f"%(desvio[2], desvio[3]))
	plt.plot(desvio[4:6], [(m/2), (m/2)], ls='--', color = '#E68400', label="99.7%% Min %.2f Max %.2f"%(desvio[4], desvio[5]))
	plt.legend()
	plt.show()

x = list(range(-4, 5))
px = [.02, .07, .1, .15, .3, .18, .1, .06, .02]

media = XPx(x, px)
var = VAR(media, x, px)
dp = DP(var)
print("Media - %.2f" %media)
print("VAR - %.2f" %var)
print("DP - %.2f" %dp)

d = desvio(media, dp)
# Descomentar para visualizar o grafico
graph(x, px, media, var, dp, d)


#T# the common multiples of a given set of numbers, are themselves multiples of the least common multiple of said set

#T# to calculate the least common multiple, the numpy package is used
import numpy as np

#T# the lcm function from the numpy package calculates the least common multiple of two numbers
num1 = 8
num2 = 12
num3 = np.lcm(num1, num2) # 24

#T# the reduce function from the lcm module of the numpy package calculates the least common multiple of a set of numbers inside a one dimensional array
arr1 = np.array([2, 5, 2, 1])
num1 = np.lcm.reduce(arr1) # 10


import math
import numpy as np, pandas as pd
from scipy.stats import t
from scipy.stats import norm
import statistics as s
import matplotlib.pyplot as plt

def confidence_intervals():
    np.random.seed(1234)
    replications = 100
    n = 30
    x = range(replications)
    y = np.random.normal(0, 1, size=(replications, n)) # realisations
    alpha = 0.95 # confidence level
    z = t.ppf(1-(1-alpha)/2, n-1) # inverse t distribution
    y_mean = [s.mean(y[r]) for r in range(replications)]
    e = [z*s.stdev(y[r])/math.sqrt(n) for r in range(replications)]
    ec = ['red' if (y_mean[r]+z*s.stdev(y[r])/math.sqrt(n) < 0 or
                    y_mean[r]-z*s.stdev(y[r])/math.sqrt(n) > 0)
                else 'black' for r in range(replications)]
    plt.errorbar(x, y_mean, yerr=e, ecolor=ec, fmt='none')
    plt.grid(True)
    plt.show()

def prediction_intervals_known_parameters():
    np.random.seed(4321)
    replications = 100
    x = range(replications)
    mu, sigma = 10, 2
    y = np.random.normal(mu, sigma, replications) # realisations
    alpha = 0.95 # confidence level
    z = norm.ppf(1-(1-alpha)/2) # inverse standard normal distribution
    plt.plot(x,[mu-z*sigma for k in x], color='blue', linestyle='dashed')
    plt.plot(x,[mu+z*sigma for k in x], color='blue', linestyle='dashed')
    ec = ['red' if y[r]>mu+z*sigma or y[r]<mu-z*sigma
                else 'blue' for r in range(replications)]
    plt.scatter(x, y, color=ec)
    plt.grid(True)
    plt.show()

def prediction_intervals_unknown_parameters():
    np.random.seed(4321)
    replications = 100
    mu, sigma = 10, 2
    x = range(replications)
    y = np.random.normal(mu, sigma, replications) # realisations
    alpha = 0.95 # confidence level
    z = lambda n: t.ppf(1-(1-alpha)/2, n-1) # inverse t distribution
    y_mean = [s.mean(y[0:r+1]) for r in range(replications)]
    e = [z(r-1)*s.stdev(y[0:r+1])*math.sqrt(1+1/r)
        if r > 2 else 30*sigma for r in range(replications)]
    plt.errorbar(x[:-1], y_mean[:-1], yerr=e[:-1], fmt='none')
    ec = ['red' if y[1:][r]>y_mean[:-1][r]+e[:-1][r] or
                y[1:][r]<y_mean[:-1][r]-e[:-1][r]
                else 'blue' for r in range(replications-1)]
    plt.scatter(x[:-1], y[1:], color=ec)
    plt.grid(True)
    plt.show()

def sample_random_walk(X0, realisations):
    np.random.seed(1234)
    errors = np.random.normal(0, 1, realisations)
    Xt = X0
    for e in errors:
        Xt = Xt + e
        yield Xt

def naive(series, t):
    """Forecasts periods t+1, t+2, ... of series
    """
    forecasts = np.empty(len(series))
    forecasts[:t+1] = np.nan
    forecasts[t+1:] = series[t]
    return forecasts

def naive_rolling(series):
    return series.shift(periods=1)

def residuals(realisations, forecasts):
    return realisations - forecasts

def plot(realisations, forecasts, stdev, alpha):
    f = plt.figure(1)
    plt.title("Naïve method")
    plt.xlabel('Period')
    first, last = next(x for x, val in enumerate(forecasts) if ~np.isnan(val)), len(forecasts)-1
    plt.axvspan(first, last, alpha=0.2, color='blue')
    plt.plot(forecasts, "r", label="Naïve forecasts")
    plt.plot(realisations, "b", label="Actual values")
    z = t.ppf(1-(1-alpha)/2, len(realisations)-1) # inverse t distribution
    plt.fill_between(range(first, last+1),
                     [forecasts[first+k]-z*stdev*math.sqrt(k) for k in range(last-first+1)],
                     [forecasts[first+k]+z*stdev*math.sqrt(k) for k in range(last-first+1)],
                     color='r', alpha=0.1)
    plt.legend(loc="upper left")
    plt.grid(True)
    f.show()

def prediction_intervals_naive():
    N, t, window, alpha = 200, 160, 1, 0.95
    realisations = pd.Series(list(sample_random_walk(0, N)), range(N))
    forecasts = naive(realisations, t)
    forecasts_roll = naive_rolling(realisations)
    res = residuals(realisations[window:], forecasts_roll[window:])
    plot(realisations, forecasts, s.stdev(res), alpha)
    print("E[e_t] = "+str(s.mean(res)))
    print("Stdev[e_t] = "+str(s.stdev(res)))
    plt.show()

#confidence_intervals()
#prediction_intervals_known_parameters()
#prediction_intervals_unknown_parameters()
prediction_intervals_naive()


"""
In the DFP example we will search for z=(a, b, c, d)
that minimizes Sum_i || F(z, X_i) - Y_i ||^2
for the function
F(x0, x1) = a^3 + b * x0 + c * x1 + d * (x0^2+x1^2)

Suppose we have the following measurements
X_0 = [0, 1]; Y_0 = 15
X_1 = [1, 0]; Y_1 = 8
X_2 = [1, 1]; Y_2 = 80
X_3 = [3, 4]; Y_3 = 100
X_4 = [1, 15]; Y_4 = 150

subjected to a>=4, c<=30
(we could handle other constraints as well: Ax <= b, Aeq x = beq, c(x) <= 0, h(x) = 0)
"""
from openopt import DFP
from numpy import inf

f = lambda z, X: z[0]**3 + z[1]*X[0] + z[2]*X[1] + z[3]*(X[0]+X[1])**2
df = lambda z, X: [3*z[0]**2, X[0], X[1], (X[0]+X[1])**2]
initEstimation = [0] * 4 # start point for solver: [0, 0, 0, 0]
X = ([0, 1], [1, 0], [1, 1], [3, 4], [1, 15]) # list, tuple, numpy array or array-like are OK as well
Y = [15, 8, 80, 100, 150]
lb = [4, -inf, -inf, -inf]
ub = [inf, inf, 30, inf]
p = DFP(f, initEstimation, X, Y, df = df, lb=lb, ub=ub)

r = p.solve('nlp:ralg', plot=0, iprint = 10)
print('solution: '+str(r.xf)+'\n||residuals||^2 = '+str(r.ff)+'\nresiduals: '+str([f(p.xf, X[i])-Y[i] for i in xrange(len(Y))]))
#solution: [  3.99999936   5.99708861 -12.25696614   1.04221073]
#||residuals||^2 = 5992.63887806
#residuals: [37.785213926923028, 63.039268675751572, -18.091065285780857, -15.968303801844399, 2.9485118103557397]


# Author:       Brian Murphy
# Date started: 07/05/2020
# Last updated: <06/05/2020 05:49:32 (BrianM)>

import numpy as np
import PSO

def find_the_centre_of_a_circle():
    """
    Find the centre of a circle of the form (x-a)^2 + (y-b)^2 = r^2 where x, y and r equal 3, 4 and 5 respectfully

    Example - how to run:
        import demos
        demos.find_the_centre_of_a_circle()

    """
    # Define the cost function
    def circle_cost(positions, args):
        return np.abs(25 - ((3 - positions[0]) ** 2 + (4 - positions[1]) ** 2))

    cost_function = circle_cost

    # Set maximum values of a and b
    varmin = [-1000, -1000]  # a min, b min
    varmax = [1000, 1000]  # a max, b max

    # Create problem dictionary
    problem = {'cost_function': cost_function, 'varmin': varmin, 'varmax': varmax}

    # Create PSO parameters dictionary
    params = {'maxit': 15, 'n_part': 30, 'c1': 2, 'c2': 2, 'w': 0.9, 'wdamp': 0.2, 'con': 1, 'display_info': 1,
              'early_stopping': 1, 'early_stopping_rounds': 7}

    # Run PSO and return lowest cost, a,b values and the costs per iteration
    gbest_value, gbest_position, best_costs = PSO.PSO(problem, params)

    print('Found the centre of the circle as a = %f and b = %f' % (gbest_position[0], gbest_position[1]))
    print('The error was %f' % gbest_value)


import numpy as np

def euclidean(x, y):
    """
    Compute the Euclidean ("L2") distance between two vectors

    :param x: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :param y: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :return:  float, the L2 distance between 'x' vector and 'y' vector

    ----------
    Example:
    >>> x = np.array([1, 2, 3, 4, 5])
    >>> y = np.array([6, 7, 8, 9, 10])
    >>> euclidean(x, y)
    11.180339887498949
    """

    return np.sqrt(np.sum((x - y) ** 2))

def manhattan(x, y):
    """
    Compute the Manhattan ('L1') distance between two vectors

    :param x: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :param y: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :return:  float, the L1 distance between 'x' vector and 'y' vector

    ----------
    Example:
    >>> x = np.array([1, 2, 3, 4, 5])
    >>> y = np.array([6, 7, 8, 9, 10])
    >>> manhattan(x, y)
    25
    """
    return np.sum(np.abs(x - y))

def chebyshev(x, y):
    """
    Compute the Chebyshev ($$ L_\infty $$ ) distance between two vectors

    :param x: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :param y: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :return:  float, the Chebyshev distance between 'x' vector and 'y' vector

    ----------
    Example:
    >>> x = np.array([1, 2, 3, 4, 5])
    >>> y = np.array([6, 7, 8, 9, 10])
    >>> chebyshev(x, y)
    5
    """
    return np.max(np.abs(x - y))

def hamming(x, y):
    """
    Compute the Hamming distance between two integer-valued vectors

    :param x: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :param y: {array-like} 'ndarray <numpy ndarray>' of shape: [vector_length, ]
    :return:  float, the Hamming distance.

    ----------
    Example:
    >>> x = np.array([1, 2, 3, 4, 5])
    >>> y = np.array([6, 7, 8, 9, 10])
    >>> hamming(x, y)
    1.0
    """
    return np.sum(x != y) / len(x)


import numpy as np
import scipy.stats

'''
log(sum(exp(z))) = M + log(sum(exp(z - M)))
z is a matrix of shape (p, k)
Sum is over k
'''
def log_sum_exponent(z, axis = 1):
    zmax = np.max(z, axis = axis)
    if axis == 0:
        sub_zmax = zmax.reshape(1, -1)
    elif axis == 1:
        sub_zmax = zmax.reshape(-1, 1)
    logsum = np.log(np.sum(np.exp(z - sub_zmax), axis = axis)) + zmax
    return logsum

def logpdf(X, sk, xzero = 1e-4):
    p = X.shape[0]
    k = sk.shape[0]
    delta_logprob_nonzeroX = np.repeat(-5e23, p) # scipy.stats.norm(0, 1e-12).logpdf(1)
    delta_logprob_zeroX = np.repeat(26.7121, p)  # scipy.stats.norm(0, 1e-12).logpdf(0)
    nonzero_Xmask = np.array(np.abs(X) >= xzero, dtype = bool)
    nonzero_smask = np.array(sk != 0, dtype = bool)
    assert (np.sum(~nonzero_smask) <= 1)
    log_prob = np.zeros((p, k))
    if np.sum(~nonzero_smask) == 1:
        log_prob[nonzero_Xmask, ~nonzero_smask] = delta_logprob_nonzeroX[nonzero_Xmask]
        log_prob[~nonzero_Xmask, ~nonzero_smask] = delta_logprob_zeroX[~nonzero_Xmask]
    nzk = np.sum(nonzero_smask)
    nzSK = sk[nonzero_smask].reshape(1, nzk)
    log_prob[:, nonzero_smask]  = - 0.5 * np.square(X.reshape(p, 1) / nzSK)
    log_prob[:, nonzero_smask] += - 0.5 * np.log(2 * np.pi * np.square(nzSK))
    return log_prob

def em_one_step(X, sk, wk, xzero = 1e-4):
    p = X.shape[0]
    k = wk.shape[0]
    nonzero_widx  = np.where(wk != 0)[0]
    logLjk = logpdf(X, sk, xzero = xzero)
    wknew = np.zeros(k)
    logwkLjk = logLjk[:, nonzero_widx] + np.log(wk[nonzero_widx])
    log_partition_func = log_sum_exponent(logwkLjk, axis = 1).reshape(-1, 1)
    log_nonzeroFjk = logwkLjk - log_partition_func
    sum_Fjk = log_sum_exponent(log_nonzeroFjk, axis = 0)
    wknew[nonzero_widx] = np.exp(sum_Fjk) / p
    return wknew

def emfit(X, sk, wk = None,
          max_iter = 1000, tol = 1e-3,
          xzero = 1e-4):
    k = sk.shape[0]
    if wk is None: wk = np.repeat(1/k, k)
    for itr in range(max_iter):
        wknew = em_one_step(X, sk, wk, xzero = xzero)
        diff = np.sum(np.abs(wk - wknew))
        wk = wknew
        if diff <= tol:
            break
    return wk


from mpmath import asin, floor, ellipfun, mp

def jacobi_am_f(x, m):
    """Borrowed from sagemath."""
    ctx = mp
    prec = ctx.prec
    try:
        # print(x)
        # print(m)
        x = ctx.convert(x)
        m = ctx.convert(m)
        if not isinstance(x, ctx.mpf) or not isinstance(m, ctx.mpf):
            raise ValueError("arguments must be real")
        if abs(m) == 1:
            # gd(x)
            ctx.prec += 10
            tanhx = ctx.tanh(x)
            ctx.prec += 10
            return ctx.asin(tanhx)
        elif abs(m) > 1:
            ctx.prec += 10
            # Real values needed for atan2; as per "Handbook of Elliptic
            # Integrals for Engineers and Scientists" 121.02, sn is real for
            # real x. The imaginary components can thus be safely discarded.
            snx = ctx.ellipfun("sn", x, m).real
            cnx = ctx.ellipfun("cn", x, m).real
            ctx.prec += 10
            return ctx.atan2(snx, cnx)
        else:
            ctx.prec += 10
            K = ctx.ellipk(m)
            if abs(x) <= K:
                snx = ctx.ellipfun("sn", x, m).real
                cnx = ctx.ellipfun("cn", x, m).real
                ctx.prec += 10
                return ctx.atan2(snx, cnx)
            else:
                # Do argument reduction on x to end up with z = x - 2nK, with
                # abs(z) <= K
                ctx.prec += 10
                tK = 2 * K
                ctx.prec += 10
                n = ctx.floor(x / tK)
                ctx.prec += 10
                tnK = n * tK
                npi = n * ctx.pi()
                ctx.prec += 10
                z = x - tnK
                ctx.prec += 10
                # z (and therefore sn(z, m) and cn(z, m)) is real because K(m)
                # is real for abs(m) <= 1.
                snz = ctx.ellipfun("sn", z, m).real
                cnz = ctx.ellipfun("cn", z, m).real
                ctx.prec += 10
                return ctx.atan2(snz, cnz) + npi
    finally:
        ctx.prec = prec

def am(x, m):
    """
    Jacobi amplitude function for real input parameters

    (JacobiAmplitude[] in Mathematica)

    Parameters:
        x (float)
        m (float)

    Returns:
        am (float)
    """
    if m == 0:
        return x
    elif x == 0:
        return 0
    else:
        return jacobi_am_f(x, m)


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

def calc_e_small(x):
    n = 10
    f = np.arange(1, n+1).cumprod()
    b = np.array([x]*n).cumprod()
    return np.sum(b / f) + 1

def calc_e(x):
    reverse = False
    if x < 0:                           #处理负数
        x = -x
        reverse = True
    ln2 = 0.69314718055994530941723212145818
    c = x / ln2
    a = int(c + 0.5)
    b = x - a * ln2
    y = (2 ** a) * calc_e_small(b)
    if reverse:
        return 1 / y
    return y

if __name__ == "__main__":
    t1 = np.linspace(-2, 0, 10, endpoint= False)
    t2 = np.linspace(0, 2, 20)
    t = np.concatenate((t1, t2))
    print(t1)
    print(t2)
    print(t)                             #横轴数据
    y = np.empty_like(t)
    for i, x in enumerate(t):
        y[i] = calc_e(x)
        print( 'e^', x, '=', y[i], '(近似值)\t', math.exp(x))
        # print '误差' , y[i] - math.exp(x)

    mpl.rcParams['font.sans-serif'] = [u'SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    plt.plot(t, y, 'r-', t, y, 'go', linewidth = 2)
    plt.title(u'Taylor展式的应用', fontsize = 18)
    plt.xlabel('x', fontsize = 15)
    plt.ylabel('exp(x)', fontsize = 15)
    plt.grid(True)
    plt.show()


#!/usr/bin/env python

import sys
import time
import math
import numpy
import random
import scipy.linalg

#=================
def ellipsePoints(angleinc, center, a, b, alpha):
	'''
	Generate a sequence of x,y points given the parameters of an
	ellipse, and an angular increment.

	convention note: ellipse points are created as x,y coordinates, so alpha
		is measured as positive values towards the y-axis

	note: generate_ellipse() below is a faster version of this
	'''
	cosa = numpy.cos(alpha)
	sina = numpy.sin(alpha)
	points = []
	for angle in numpy.arange(0, 2*numpy.pi, angleinc):
		acosangle = a * numpy.cos(angle)
		bsinangle = b * numpy.sin(angle)
		row = center[0] + acosangle * cosa - bsinangle * sina
		col = center[1] + acosangle * sina + bsinangle * cosa
		points.append((row,col))
	return points

#=================
def ellipseKeyPoints(center, a, b, alpha):
	'''
	Calulate the points at each end of the ellipse axes.

	convention note: ellipse points are created as x,y coordinates, so alpha
		is measured as positive values towards the y-axis
	'''
	points = ellipsePoints(numpy.pi/2.0, center, a, b, alpha)
	keypoints = {}
	center = tuple(center)
	keypoints[center] = {'axis': 'center', 'angle': None}
	axes = ['a','b']
	for i in range(4):
		axis = axes[i%2]
		angle = alpha+i*numpy.pi/2.0
		while angle < 0:
			angle += 2*numpy.pi
		keypoints[points[i]] = {'axis': axis, 'angle': angle}
	return keypoints

#=================
def drawEllipse(shape, angleinc, center, a, b, alpha):
	'''
	Generate a zero initialized image array with an ellipse drawn
	by setting pixels to 1.

	convention note: ellipse points are x,y coordinates, so alpha
		is measured as positive values towards the y-axis
	'''
	result = numpy.zeros(shape, numpy.int)
	points = ellipsePoints(angleinc, center, a, b, alpha)
	for point in points:
		point = map(int, point)
		try:
			result[int(point[0]), int(point[1])] = 1
		except:
			continue
	return result

#=================
def algebraic2parametric(coeff):
	'''
	Based on matlab function "ellipse_param.m" which accompanies
	"Least-Squares Fitting of Circles and Ellipses", W. Gander, G. H. Golub, R. Strebel,
		BIT Numerical Mathematics, Springer 1994

	convert the coefficients (a,b,c,d,e,f) of the algebraic equation:
		ax^2 + bxy + cy^2 + dx + ey + f = 0
	to the parameters of the parametric equation.  The parameters are
	returned as a dictionary containing:
		center - center of the ellipse
		a - major axis
		b - minor axis
		alpha - angle of major axis

	convention note: alpha is measured as positive values towards the y-axis
	'''
	#print coeff
	#print ("A=%.3f B=%.3f C=%.3f D=%.3f E=%.3f F=%.3f"
	#	%(coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5],))

	if numpy.any(numpy.isnan(coeff)) or numpy.any(numpy.isinf(coeff)):
		return None

	A   = numpy.array((coeff[0], coeff[1]/2, coeff[1]/2, coeff[2]))
	A.shape = 2,2
	bb  = numpy.asarray(coeff[3:5])
	c   = coeff[5]

	D,Q = scipy.linalg.eig(A)
	D = D.real
	det = D[0]*D[1]
	if det <= 0:
		return None
	else:
		bs = numpy.dot(Q.transpose(), bb)
		alpha = numpy.arctan2(Q[1,0], Q[0,0])

		zs = scipy.linalg.solve(-2*numpy.diagflat(D), bs)
		z = numpy.dot(Q, zs)
		h = numpy.dot(-bs.transpose(), zs) / 2 - c

		a = numpy.sqrt(h/D[0])
		b = numpy.sqrt(h/D[1])

	## correct backwards major/minor axes
	## 'major axis as a, minor axis as b'
	if b > a:
		temp = b
		b = a
		a = temp
		alpha = math.pi/2 + alpha

	#print "alpha", alpha
	if alpha <= -math.pi/2:
		alpha += math.pi
	elif alpha > math.pi/2:
		alpha -= math.pi

	return {'center':z, 'a':a, 'b':b, 'alpha':alpha}

#=================
def solveEllipseB2AC(points):
	'''
	Based on Matlab code from:  "Direct Least Square Fitting of Ellipses"
	Andrew Fitzgibbon, Maurizio Pilu, Robert B. Fisher.  Tern Analysis
	and Machine Intelligence, Vol 21, No 5, May 1999.

	This method has a tendency to crash, but is very fast
	probably should use QR decomposition to avoid crashing on singularities

	convention note: ellipse points are x,y coordinates, so alpha
		is measured as positive values towards the y-axis
	'''
	X = numpy.array(points, numpy.float)
	D = numpy.column_stack((X[:,0]**2, X[:,0]*X[:,1], X[:,1]**2, X[:,0], X[:,1], numpy.ones(X.shape[0])))
	S = numpy.dot(D.transpose(), D)
	C = numpy.zeros((6,6), numpy.float)
	C[0,2] = -2
	C[1,1] = 1
	C[2,0] = -2
	### replace eig with QR decomp
	geval,gevec = scipy.linalg.eig(a=S, b=C)
	geval = geval.real
	gevec = gevec.real

	Neg = numpy.nonzero(numpy.logical_and(geval<0, numpy.logical_not(numpy.isinf(geval))))
	a = gevec[:,Neg]
	a = numpy.ravel(a)

	if len(a) == 0:
		return None
	return algebraic2parametric(a)

##========================
##========================
def solveEllipseByQRdecomp(points, center=(0,0)):
	"""
	QR decomposition is not the fastest method
	but it is by far the most stable
	"""
	t0 = time.time()
	xy = numpy.array(points, dtype=numpy.float64) - numpy.array(center, dtype=numpy.float64)
	X = numpy.column_stack((
			xy[:,0]**2,
			xy[:,0]*xy[:,1],
			xy[:,1]**2,
		))
	Y = numpy.ones(xy.shape[0])
	### solve it by QR decomposition
	Q, R = numpy.linalg.qr(X)
	if numpy.linalg.det(R) == 0:
		print "Singular matrix in calculation"
		return None
	QT = numpy.transpose(Q)
	Rinv = numpy.linalg.inv(R)
	beta = numpy.dot(numpy.dot(Rinv, QT), Y)

	algebraic = (beta[0], beta[1], beta[2], 0, 0, -1)

	params = algebraic2parametric(algebraic)
	if params is None:
		return None

	params['center'] = center

	return params

##========================
def weightedLeastSquares(X, Y, W):
	"""
	solve using the normal equations with no manipulation
	"""
	### solve it
	XTW = numpy.transpose(X)*W
	XTWX = numpy.dot(XTW, X)
	if numpy.linalg.det(XTWX) == 0:
		print "Singular matrix in calculation"
		return None
	XTWXinv = numpy.linalg.inv(XTWX)
	beta = numpy.dot(numpy.dot(XTWXinv, XTW), Y)
	return beta

#=================
def totalLeastSquareEllipse(points, center=(0,0), weights=None, epsilon=1e-5, maxiter=10):
	'''
	This was implemented by Neil Voss

	uses simple linear least squares to solve the general equation for
	an ellipse, but implements the total least squares algorithm.

	http://en.wikipedia.org/wiki/Total_least_squares

	total least squares assumes some points are better than others
	so it uses an iterative approach to
	down weight points with higher fit error
	and points with smaller error are weighed higher

	takes a (N,2) numpy array containing ellipse points and
	return the best least square fit for an ellipse
	values A,B,C
	where
	Ax^2 + Bxy +Cy^2 + Dx + Ey + F = 0
	D = E = 0 to center the ellipse on the origin
	F = -1 to force the general conic equation to be an ellipse

	convention note: ellipse points are x,y coordinates, so alpha
		is measured as positive values towards the y-axis
	'''
	t0 = time.time()
	xy = numpy.array(points, dtype=numpy.float64) - numpy.array(center, dtype=numpy.float64)
	X = numpy.column_stack((
			xy[:,0]**2,
			xy[:,0]*xy[:,1],
			xy[:,1]**2,
		))
	Y = numpy.ones(xy.shape[0])

	### setup weights if necessary
	W = weights
	if W is None:
		W = numpy.ones(Y.shape) # even weights for the observations

	### solve it
	sys.stderr.write("total least squares")
	err0 = None
	for i in range(maxiter):
		sys.stderr.write(".")
		beta = weightedLeastSquares(X, Y, W)
		if beta is None:
			return None

		## calculate the absolute mean error
		err = numpy.absolute(numpy.dot(X, beta) - Y).ravel()
		#print "totalLeastSquares iter %d error: %.4f"%(i, err.mean())
		## fit to a normal distribution
		normerr = ( err - err.min() )/err.std()
		## calculate new weights based on
		W = numpy.exp( -1 * normerr**2 )
		if W.sum() == 0:
			apDisplay.printWarning("Failed to set weights")
			return beta
		## see if we can stop
		if err0 is not None:
			change = numpy.absolute(err-err0).mean()
			if change < epsilon:
				break
		err0 = err

	algebraic = (beta[0], beta[1], beta[2], 0, 0, -1)

	params = algebraic2parametric(algebraic)
	if params is None:
		return None

	params['center'] = center

	return params

#=================
def solveEllipseGander(points):
	'''
	Solve the ellipse that best fits the given points.
	Based on the matlab function "algellipse.m" in the files that
	accompany:  "Least-Squares Fitting of Circles and Ellipses", W. Gander, G. H. Golub, R. Strebel,
		BIT Numerical Mathematics, Springer 1994

	This method seems to go O(n^2), so can be slow with lots of points

	convention note: ellipse points are x,y coordinates, so alpha
		is measured as positive values towards the y-axis
	'''
	X = numpy.array(points)
	a = numpy.column_stack((X[:,0]**2, X[:,0]*X[:,1], X[:,1]**2, X[:,0], X[:,1], numpy.ones(X.shape[0])))
	U, S, Vh = scipy.linalg.svd(a)
	V = Vh.transpose()
	u = numpy.ravel(V[:,5:6])
	return algebraic2parametric(u)

#=================
def solveEllipseOLS(points, center=(0,0)):
	"""
	Solve Ellipse using oridinary least squares (OLS) closed form equation

	Note: this method is designed to have the center to be 0,0
		because the CTF is always centered

	This was implemented by Neil Voss for use in the ACE2 program in 2010
	* Algebra was performed using the maxima program
	* Designed to have a fixed center point

	takes a (N,2) numpy array containing ellipse points and
	return the best least square fit for an ellipse
	values A,B,C
	where
	Ax^2 + Bxy +Cy^2 + Dx + Ey + F = 0
	D = E = 0 to center the ellipse on the origin
	F = -1 to force the general conic equation to be an ellipse

	convention note: ellipse points are x,y coordinates, so alpha
		is measured as positive values towards the y-axis
	"""

	### power twos
	X = numpy.array(points, numpy.float) - numpy.array(center, numpy.float)

	### power twos
	p2 = numpy.power(X, 2.0)
	Sx2 = p2[:,0].sum()
	Sy2 = p2[:,1].sum()
	Sxy = (X[:,0]*X[:,1]).sum()
	### power fours
	p4 = numpy.power(X, 4.0)
	Sx4 = p4[:,0].sum()
	Sy4 = p4[:,1].sum()
	Sx2y2 = (p2[:,0]*p2[:,1]).sum()
	Sx3y = (numpy.power(X[:,0], 3.0)*X[:,1]).sum()
	Sxy3 = (X[:,0]*numpy.power(X[:,1], 3.0)).sum()

	### Calculate ellipse parameters
	A = (Sx3y*(Sxy3*Sy2-Sxy*Sy4)+Sx2y2*(Sx2*Sy4+Sxy*Sxy3)
		-numpy.power(Sx2y2,2.0)*Sy2-Sx2*numpy.power(Sxy3,2.0))/(Sx4*(Sx2y2*Sy4-numpy.power(Sxy3,2.0))
		-numpy.power(Sx3y,2.0)*Sy4+2.0*Sx2y2*Sx3y*Sxy3-numpy.power(Sx2y2,3.0));

	B = -(Sx4*(Sxy3*Sy2-Sxy*Sy4)+Sx3y*(Sx2*Sy4-Sx2y2*Sy2)-Sx2*Sx2y2*Sxy3
		+numpy.power(Sx2y2,2.0)*Sxy)/(Sx4*(Sx2y2*Sy4-numpy.power(Sxy3,2.0))
		-numpy.power(Sx3y,2.0)*Sy4+2.0*Sx2y2*Sx3y*Sxy3-numpy.power(Sx2y2,3.0));

	C = (Sx4*(Sx2y2*Sy2-Sxy*Sxy3)-numpy.power(Sx3y,2.0)*Sy2+Sx3y*(Sx2*Sxy3+Sx2y2*Sxy)
		-Sx2*numpy.power(Sx2y2,2.0))/(Sx4*(Sx2y2*Sy4-numpy.power(Sxy3,2.0))
		-numpy.power(Sx3y,2.0)*Sy4+2.0*Sx2y2*Sx3y*Sxy3-numpy.power(Sx2y2,3.0));

	algebraic = (A, B, C, 0, 0, -1)

	params = algebraic2parametric(algebraic)
	if params is None:
		return None

	params['center'] = center

	return params

#=================
def generate_ellipse(a, b, alpha, center=(0,0), numpoints=3, noise=None,
		method="step", integers=False):
	"""
	a - major axis radius
	b - minor axis radius
	alpha - angle (in radians)
	center = x0,y0 - position of center of ellipse
	numpoints - # of points that make an ellipse
	noise - float of the amount of noise to add

	this is a faster version of ellipsePoints() function above
		without the "for" loop and with extra features

	convention note: ellipse points are created as x,y coordinates, so alpha
		is measured as positive values towards the y-axis
	"""

	cosa = numpy.cos(alpha)
	sina = numpy.sin(alpha)

	if method == "step":
		thetas = numpy.linspace(0, 2*math.pi, numpoints)
	elif method == "random":
		thetas = numpy.random.random(numpoints) * 2*math.pi
	else:
		print "unknown method", method
		return None
	rows = center[0] + a* numpy.cos(thetas) * cosa -  b* numpy.sin(thetas) * sina
	cols = center[1] + a* numpy.cos(thetas) * sina +  b* numpy.sin(thetas) * cosa

	points = numpy.vstack((rows,cols)).T
	#print points[:5,:]

	if noise is not None:
		rand = numpy.random.standard_normal(points.shape)
		points += rand * noise
	#print points[0]

	## use only integers
	if integers is True:
		points = numpy.array(numpy.around(points, 0), dtype=numpy.int)
	#print points[0]
	#print points[:5,:]

	return points

#=================
def printParamsDict(params):
	printParams(params['center'], params['a'], params['b'], params['alpha'])
	return

#=================
def printParams(center, a, b, alpha):
	print ("%.3f %.3f < %.2f (%.1f, %.1f)"%
		(a, b, alpha*180/math.pi, center[0], center[1]))
	return

"""
Speed and accuracy notes:

NumPoints = 3777 ; Noise = 0.1 pixels
orig   5.829 1.737 < -76.84 (4.0, 16.0)
b2ac   5.813 1.747 < -76.83 (4.0, 16.0)
gander 5.834 1.740 < -76.60 (4.0, 16.0)
ols    5.833 1.753 < -76.83 (4.0, 16.0)

b2ac   complete in 8.585 millisec  ** crashes sometimes
gander complete in 924.305 millisec ** way too slow for more than 500 points
ols    complete in 5.268 millisec ** has fixed center
"""

### test code
if __name__ == '__main__':
	## randomly generate a noisy ellipse
	# note: center is (col,row) i.e. (x,y) while shape is (row,col)
	xdim = numcol = 32
	ydim = numrow = 16
	shape = (numrow,numcol)
	alpha = random.random()*math.pi - math.pi/2
	center = numpy.array((numrow, numcol), dtype=numpy.float)/2.0
	majormax = min( abs(numrow/math.cos(alpha)) , abs(numcol/math.sin(alpha)) )/3.0 - 1
	minormax = min( abs(numrow/math.sin(alpha)) , abs(numcol/math.cos(alpha)) )/3.0 - 1
	print alpha, majormax, minormax
	major = (majormax-2) * random.random() + 2
	minor = (min(minormax,major)-1) * random.random() + 1
	numpoints = 8 + int(100000*random.random()*random.random()*random.random())
	noise = 0.2 #random.random()
	print "NumPoints = %d ; Noise = %.1f"%(numpoints, noise)
	printParams(center, major, minor, alpha)

	### draw real ellipse
	points = generate_ellipse(major, minor, alpha, center, numpoints,
		noise, method="step", integers=False)
	params = {'center':center, 'a':major, 'b':minor, 'alpha':alpha}
	grid = numpy.zeros(shape, dtype=numpy.int)
	intpoints = numpy.array(points, dtype=numpy.int)
	print intpoints
	grid[intpoints[:,0], intpoints[:,1]] = 1
	#for point in points:
	#	p = numpy.floor(point)
	#	grid[p[0],p[1]] = 1
	print grid
	print ""

	print drawEllipse(shape, 4*numpy.pi/180.0, **params)

	### draw b2ac ellipse
	t0 = time.time()
	params1 = solveEllipseB2AC(points)
	print '\nB2AC', params1
	if params1 is not None:
		print drawEllipse(shape, 4*numpy.pi/180.0, **params1)
	b2actime = time.time() - t0

	### draw gander ellipse
	t0 = time.time()
	if numpoints < 10000:
		params2 = solveEllipseGander(points)
		print '\nGANDER', params2
		print drawEllipse(shape, 4*numpy.pi/180.0, **params2)
	else:
		print "skipping GANDER"
		params2 = None
	gandertime = time.time() - t0

	### draw ols ellipse
	t0 = time.time()
	params3 = solveEllipseOLS(points, center)
	print '\nORDINARY LEAST SQUARES', params3
	print drawEllipse(shape, 4*numpy.pi/180.0, **params3)
	olstime = time.time() - t0

	### draw QR ellipse
	t0 = time.time()
	params4 = solveEllipseByQRdecomp(points, center)
	print '\nQR DECOMP', params4
	if params4 is not None:
		print drawEllipse(shape, 4*numpy.pi/180.0, **params4)
	qrdecomp = time.time() - t0

	### draw Total Least Squares ellipse
	t0 = time.time()
	params5 = totalLeastSquareEllipse(points, center)
	print '\nTotal Least Squares', params5
	if params5 is not None:
		print drawEllipse(shape, 4*numpy.pi/180.0, **params5)
	totallsq = time.time() - t0

	print majormax, minormax
	print "NumPoints = %d ; Noise = %.1f"%(numpoints, noise)
	print "Actual values"
	printParams(center, major, minor, alpha)
	print "Fit values"
	if params1 is not None:
		printParams(**params1)
	else:
		print "b2ac failed"
	if params2 is not None:
		printParams(**params2)
	else:
		print "gander skipped"
	printParams(**params3)
	if params4 is not None:
		printParams(**params4)
	else:
		print "qr decomp failed"
	if params5 is not None:
		printParams(**params5)
	else:
		print "total lsq failed"
	print "b2ac   complete in %.3f millisec"%(b2actime*1000)
	print "gander complete in %.3f millisec"%(gandertime*1000)
	print "ols    complete in %.3f millisec"%(olstime*1000)
	print "qr     complete in %.3f millisec"%(qrdecomp*1000)
	print "total  complete in %.3f millisec"%(totallsq*1000)


import random as ra
import numpy as np
import math

simulations = 10000
runs = 10
final_counts = []

#Lenght of the line segment is 2 *sqrt( radius^2 - distance^2 )

for j in range(runs):
    count = 0
    actual_count = 0
    for i in range(simulations):

        x_0 = (ra.random()*100) - 50
        y_0 = (ra.random()*100) - 50
        tita = (ra.random() * math.pi) - (math.pi/2)
        m = math.tan(tita)
        distance = abs((y_0 - m * x_0) / (math.sqrt(m**2 + 1)))

        if distance < 1:
            actual_count += 1
            length = 2 * math.sqrt(1 - distance**2)
            if length > math.sqrt(3):
                count += 1
    final_counts.append(count/actual_count)

print(" The probability is ", np.mean(final_counts))


from sympy import ( symbols, solve, diff, integrate, exp, sqrt, lambdify, Integral, ln, pprint, oo )
# Researchers have shown that the number of successive dry days that occur after a rainstorm for a particular region is a random variable that is distributed exponentially with a mean of 9 days
mu = 9

t = symbols( 't' )
a = 1/mu
pdf = a * exp( -a*t )

# What is the probability that 11 or more successive dry days occur after a rainstorm?

prob = integrate( pdf, ( t, 11, oo ) ).doit()
round( prob, 4 )

# What is the probability that fewer than 4 dry days occur after a rainstorm?

prob = integrate( pdf, ( t, 0, 2 ) ).doit()
round( prob, 4 )


import os

""" First change the following directory link to where all input files do exist """

os.chdir("D:\Book writing\Codes\Chapter 1")

import numpy as np
from scipy import stats

data = np.array([4,5,1,2,7,2,6,9,3])

# Calculate Mean
dt_mean = np.mean(data) ; print ("Mean :",round(dt_mean,2))

# Calculate Median
dt_median = np.median(data) ; print ("Median :",dt_median)

# Calculate Mode
dt_mode =  stats.mode(data); print ("Mode :",dt_mode[0][0])

# Deviance calculations

import numpy as np
from statistics import variance,stdev

game_points = np.array([35,56,43,59,63,79,35,41,64,43,93,60,77,24,82])

# Calculate Variance
dt_var = variance(game_points) ; print ("Sample variance:", round(dt_var,2))

# Calculate Standard Deviation
dt_std = stdev(game_points) ; print ("Sample std.dev:",round(dt_std,2))

# Calculate Range
dt_rng = np.max(game_points,axis=0) - np.min(game_points,axis=0) ; print ("Range:",dt_rng)

#Calculate percentiles
print ("Quantiles:")
for val in [20,80,100]:
    dt_qntls = np.percentile(game_points,val)
    print (str(val)+"%" ,dt_qntls)

# Calculate IQR
q75, q25 = np.percentile(game_points, [75 ,25]); print ("Inter quartile range:",q75-q25 )

# Hypothesis testing
#import scipy

from scipy import stats

xbar = 990; mu0 = 1000; s = 12.5; n = 30
# Test Statistic
t_smple  = (xbar-mu0)/(s/np.sqrt(float(n))); print ("Test Statistic:",round(t_smple,2))
# Critical value from t-table
alpha = 0.05
t_alpha = stats.t.ppf(alpha,n-1); print ("Critical value from t-table:",round(t_alpha,3))
#Lower tail p-value from t-table
p_val = stats.t.sf(np.abs(t_smple), n-1); print ("Lower tail p-value from t-table", p_val)

# Normal Distribution
from scipy import stats
xbar = 67; mu0 = 52; s = 16.3

# Calculating z-score
z = (67-52)/16.3

# Calculating probability under the curve
p_val = 1- stats.norm.cdf(z)
print ("Prob. to score more than 67 is ",round(p_val*100,2),"%")

# Chi-square independence test
import pandas as pd
from scipy import stats

survey = pd.read_csv("survey.csv")
# Tabulating 2 variables with row & column variables respectively
survey_tab = pd.crosstab(survey.Smoke, survey.Exer, margins = True)
# Creating observed table for analysis
observed = survey_tab.ix[0:4,0:3]

contg = stats.chi2_contingency(observed= observed)
p_value = round(contg[1],3)
print ("P-value is: ",p_value)

#ANOVA
import pandas as pd
from scipy import stats

fetilizers = pd.read_csv("fetilizers.csv")

one_way_anova = stats.f_oneway(fetilizers["fertilizer1"], fetilizers["fertilizer2"], fetilizers["fertilizer3"])

print ("Statistic :", round(one_way_anova[0],2),", p-value :",round(one_way_anova[1],3))

# Train & Test split
import pandas as pd
from sklearn.model_selection import train_test_split

original_data = pd.read_csv("mtcars.csv")

train_data,test_data = train_test_split(original_data,train_size = 0.7,random_state=42)

# Linear Regressio vs. Gradient Descent

import numpy as np
import pandas as pd

train_data = pd.read_csv("mtcars.csv")

X = np.array(train_data["hp"])  ; y = np.array(train_data["mpg"])
X = X.reshape(32,1); y = y.reshape(32,1)

from sklearn.linear_model import LinearRegression
model = LinearRegression(fit_intercept = True)

model.fit(X,y)
print ("Linear Regression Results")
print ("Intercept",model.intercept_[0] ,"Coefficient",model.coef_[0])

def gradient_descent(x, y,learn_rate, conv_threshold,batch_size,max_iter):
    converged = False
    iter = 0
    m = batch_size

    t0 = np.random.random(x.shape[1])
    t1 = np.random.random(x.shape[1])

    MSE = (sum([(t0 + t1*x[i] - y[i])**2 for i in range(m)])/ m)

    while not converged:
        grad0 = 1.0/m * sum([(t0 + t1*x[i] - y[i]) for i in range(m)])
        grad1 = 1.0/m * sum([(t0 + t1*x[i] - y[i])*x[i] for i in range(m)])

        temp0 = t0 - learn_rate * grad0
        temp1 = t1 - learn_rate * grad1

        t0 = temp0
        t1 = temp1

        MSE_New = (sum( [ (t0 + t1*x[i] - y[i])**2 for i in range(m)] ) / m)

        if abs(MSE - MSE_New ) <= conv_threshold:
            print ('Converged, iterations: ', iter)
            converged = True

        MSE = MSE_New
        iter += 1

        if iter == max_iter:
            print ('Max interactions reached')
            converged = True

    return t0,t1

if __name__ == '__main__':
    Inter, Coeff = gradient_descent(x = X,y = y,learn_rate=0.00003 ,conv_threshold=1e-8, batch_size=32,max_iter=1500000)
    print ("Gradient Descent Results")
    print (('Intercept = %s Coefficient = %s') %(Inter, Coeff))

# Train Validation Test split

import pandas as pd
from sklearn.model_selection import train_test_split

original_data = pd.read_csv("mtcars.csv")

def data_split(dat,trf = 0.5,vlf=0.25,tsf = 0.25):
    nrows = dat.shape[0]
    trnr = int(nrows*trf)
    vlnr = int(nrows*vlf)

    tr_data,rmng = train_test_split(dat,train_size = trnr,random_state=42)
    vl_data, ts_data = train_test_split(rmng,train_size = vlnr,random_state=45)

    return (tr_data,vl_data,ts_data)

train_data, validation_data, test_data = data_split(original_data,trf=0.5,vlf=0.25,tsf=0.25)

# Grid search on Decision Trees
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.metrics import classification_report,confusion_matrix,accuracy_score
from sklearn.pipeline import Pipeline

input_data = pd.read_csv("ad.csv",header=None)

X_columns = set(input_data.columns.values)
y = input_data[len(input_data.columns.values)-1]
X_columns.remove(len(input_data.columns.values)-1)
X = input_data[list(X_columns)]

X_train, X_test,y_train,y_test = train_test_split(X,y,train_size = 0.7,random_state=33)

pipeline = Pipeline([
    ('clf', DecisionTreeClassifier(criterion='entropy'))
])
parameters = {
    'clf__max_depth': (50,100,150),
    'clf__min_samples_split': (2, 3),
    'clf__min_samples_leaf': (1, 2, 3)
}

grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1, scoring='accuracy')
grid_search.fit(X_train, y_train)

y_pred = grid_search.predict(X_test)

print ('\n Best score: \n', grid_search.best_score_)
print ('\n Best parameters set: \n')
best_parameters = grid_search.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
    print ('\t%s: %r' % (param_name, best_parameters[param_name]))
print ("\n Confusion Matrix on Test data \n",confusion_matrix(y_test,y_pred))
print ("\n Test Accuracy \n",accuracy_score(y_test,y_pred))
print ("\nPrecision Recall f1 table \n",classification_report(y_test, y_pred))

Chapter01/Chapter 01_Journey from Statistics to Machine Learning.py


from pyomo.environ import exp, log, tanh

def softplus_activation_function(x):
    r"""
    Applies the softplus function.

    .. math::

        \begin{align*}
        y &= log(exp(\hat x) + 1)
        \end{align*}

    """
    return log(exp(x) + 1)

def sigmoid_activation_function(x):
    r"""
    Applies the sigmoid function.

    .. math::

        \begin{align*}
        y &= \frac{1}{1 + exp(-\hat x)}
        \end{align*}

    """
    return 1 / (1 + exp(-x))

def tanh_activation_function(x):
    r"""
    Applies the tanh function.

    .. math::

        \begin{align*}
        y &= tanh(x)
        \end{align*}

    """
    return tanh(x)

def softplus_activation_constraint(net_block, net, layer_block, layer):
    r"""
    Softplus activation constraint generator

    Generates the constraints for the softplus activation function.

    .. math::

        \begin{align*}
        z_i &= log(exp(\hat z_i) + 1) && \forall i \in N
        \end{align*}

    """
    return smooth_monotonic_activation_constraint(net_block, net, layer_block, layer, softplus_activation_function)

def sigmoid_activation_constraint(net_block, net, layer_block, layer):
    r"""
    Sigmoid activation constraint generator

    Generates the constraints for the sigmoid activation function.

    .. math::

        \begin{align*}
        z_i &= \frac{1}{1 + exp(-\hat z_i)} && \forall i \in N
        \end{align*}

    """
    return smooth_monotonic_activation_constraint(net_block, net, layer_block, layer,
                                                  sigmoid_activation_function)

def tanh_activation_constraint(net_block, net, layer_block, layer):
    r"""
    tanh activation constraint generator

    Generates the constraints for the tanh activation function.

    .. math::

        \begin{align*}
        z_i &= tanh(\hat z_i) && \forall i \in N
        \end{align*}

    """
    return smooth_monotonic_activation_constraint(net_block, net, layer_block, layer, tanh_activation_function)

def smooth_monotonic_activation_constraint(net_block, net, layer_block, layer, fcn):
    r"""
    Activation constraint generator for a smooth monotonic function

    Generates the constraints for the activation function fcn if it
    is smooth and monotonic

    .. math::

        \begin{align*}
        z_i &= fcn(\hat z_i) && \forall i \in N
        \end{align*}

    """
    @layer_block.Constraint(layer.output_indexes)
    def _smooth_monotonic_activation_constraint(b, *output_index):
        zhat_lb, zhat_ub = b.zhat[output_index].bounds
        if zhat_lb is not None:
            b.z[output_index].setlb(fcn(zhat_lb))
        if zhat_ub is not None:
            b.z[output_index].setub(fcn(zhat_ub))
        return b.z[output_index] == fcn(b.zhat[output_index])


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

#t is the independent variable
P = 3. #period value
BT=-6. #initian value of t (begin time)
ET=6. #final value of t (end time)
FS=1000 #number of discrete values of t between BT and ET

#the periodic real-valued function f(t) with period equal to P
f = lambda t: ((t % P) - (P / 2.)) ** 3

#all discrete values of t in the interval from BT and ET
t_range = np.linspace(BT, ET, FS)
y_true = f(t_range) #the true f(t)

#function to integrate on complex field
def complex_quad(func, a, b, **kwargs):
    def real_func(x):
        return np.real(func(x))
    def imag_func(x):
        return np.imag(func(x))
    real_integral = spi.quad(real_func, a, b, **kwargs)
    imag_integral = spi.quad(imag_func, a, b, **kwargs)
    integral = (real_integral[0] + 1j*imag_integral[0], real_integral[1:], imag_integral[1:])
    return integral

#function that computes the complex fourier coefficients c-N,.., c0, .., cN
def compute_complex_fourier_coeffs(func, N):
    result = []
    for n in range(-N, N+1):
        cn = (1./P) * complex_quad(lambda t: func(t) * np.exp(-1j * 2 * np.pi * n * t / P), 0, P)[0]
        result.append(cn)
    return np.array(result)

#function that computes the complex form Fourier series using cn coefficients
def fit_func_by_fourier_series_with_complex_coeffs(t, C):
    result = 0. + 0.j
    L = int((len(C) - 1) / 2)
    for n in range(-L, L+1):
        c = C[n+L]
        result +=  c * np.exp(1j * 2. * np.pi * n * t / P)
    return result

maxN=8
COLs = 2 #cols of plt
ROWs = 1 + (maxN-1) // COLs #rows of plt
plt.rcParams['font.size'] = 8
fig, axs = plt.subplots(ROWs, COLs)
fig.tight_layout(rect=[0, 0, 1, 0.95], pad=3.0)
fig.suptitle('f(t) = ((t % P) - (P / 2.)) ** 3 where P=' + str(P))

#plot, in the range from BT to ET, the true f(t) in blue and the approximation in red
for N in range(1, maxN + 1):
    C = compute_complex_fourier_coeffs(f, N)
    #C contains the list of cn complex coefficients for n in 1..N interval.

    y_approx = fit_func_by_fourier_series_with_complex_coeffs(t_range, C)
    #y_approx contains the discrete values of approximation obtained by the Fourier series

    row = (N-1) // COLs
    col = (N-1) % COLs
    axs[row, col].set_title('case N=' + str(N))
    axs[row, col].scatter(t_range, y_true, color='blue', s=1, marker='.')
    axs[row, col].scatter(t_range, y_approx, color='red', s=2, marker='.')
plt.show()


from math import factorial

from numpy import ones, copy, cos, tan, linspace
from numpy import sqrt, pi, exp

def gaussxw(N):
    # Initial approximation to roots of the Legendre polynomial
    a = linspace(3, 4 * N - 1, N) / (4 * N + 2)
    x = cos(pi * a + 1 / (8 * N * N * tan(a)))

    # Find roots using Newton's method
    epsilon = 1e-15
    delta = 1.0
    while delta > epsilon:
        p0 = ones(N, float)
        p1 = copy(x)
        for k in range(1, N):
            p0, p1 = p1, ((2 * k + 1) * x * p1 - k * p0) / (k + 1)
        dp = (N + 1) * (p0 - x * p1) / (1 - x * x)
        dx = p1 / dp
        x -= dx
        delta = max(abs(dx))

    # Calculate the weights
    w = 2 * (N + 1) * (N + 1) / (N * N * (1 - x * x) * dp * dp)

    return x, w

def gaussxwab(N, a, b):
    x, w = gaussxw(N)
    return 0.5 * (b - a) * x + 0.5 * (b + a), 0.5 * (b - a) * w

def H(n, x):
    def H_iter(a, b, count):
        if count == 0:
            return b
        else:
            return H_iter(2 * x * a - 2 * (count - 1) * b, a, count - 1)

    return H_iter(2 * x, 1, n)

def wave_func(n, z):
    p = z / (1 - (z ** 2))
    return ((1 + (z ** 2)) / ((1 - (z ** 2)) ** 2)) * (p ** 2) * (
            ((1 / (sqrt((2 ** n) * factorial(n) * sqrt(pi)))) * exp(-0.5 * (p ** 2)) * H(n, p)) ** 2)

n = int(input("Enter the order of the wave function: "))
N = 100
a = -1.0
b = 1.0
x, w = gaussxw(N)
xp = 0.5 * (b - a) * x + 0.5 * (b + a)
wp = 0.5 * (b - a) * w
s = 0.0
for k in range(N):
    s += wp[k] * wave_func(n, xp[k])

print("Uncertainty for the ", n, "th order state:", sqrt(s))

Ankit Khandelwal_HW2/exercise 5/exercise 5c.py


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

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

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

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

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

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

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

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


import numpy as np
from scipy.special import binom

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

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

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

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

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

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

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

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

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


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

import numpy as np

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

Copyright (c) 2016 Michael Seaman

License: MIT

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

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

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

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

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

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


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

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

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

import numpy as np

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


import numpy as np
import warnings

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

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

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

    Returns
    -------
    p_evenness : float

    between 0 and 1

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

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

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

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

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

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

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

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

    array = array / np.sum(array)

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

    p_evenness =  -1 * (numerator/denominator)

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

    return p_evenness


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

import numpy as np

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

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

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


import numpy as np

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

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

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

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

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

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

  return y

def identity_function(x):
  return x

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

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

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

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

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

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

  return grad

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


import numpy as np

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

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

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

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

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

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

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

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

input("Press Enter key to exit ")


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

import numpy as np
import matplotlib.pyplot as plt

left_point = 0.0
right_endpoint = 1.0

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

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

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

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

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

    main_diagonal = np.zeros(len(x))

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

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

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

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

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

    print 'This is F', F

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

    print "this is delta u", delta_u

    u += delta_u

    print "this is u.", u

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

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

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


import math
import numpy as np
from collections import defaultdict

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

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

    tree = []

    INF = math.inf

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

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

    # Initialize number of edge to 0
    n_edges = 0

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

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

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

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

    print(MST(a))


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

from Funcoes import LU, Gauss_Siedel
import numpy as np

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

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


import numpy as np

def modular_sqrt(a, p):

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

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

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

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

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

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

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

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

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

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

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

        if m == 0:
            return x

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


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

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

"""

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

N = 10**7
P = 0.25

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

    l = 0
    r = 2*N

    m = 0

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

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


import numpy as np
import matplotlib.pyplot as plt

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

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

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

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

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

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

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


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

    \nabla^2 u = f,

The equation to solve is

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

Use any combination of Dirichlet and Neumann boundary conditions.

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

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

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

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

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

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

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

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

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

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

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

    u_hat = Function(T)

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

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

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

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


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

Copyright (c) 2016 Michael Seaman

License: MIT

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

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

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

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

def h(x):
    return x ** x

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

    return theta

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

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

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

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

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

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


import numpy as np

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

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

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

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

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

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

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