import numpy
import matplotlib.pyplot as plt

def interpolateCatmulRomeSegment(P0, P1, P2, P3, nPoints=20):
    """
    P0, P1, P2, and P3 should be (x,y) point pairs that define the Catmull-Rom spline.
    nPoints is the number of points to include in this curve segment.
    """
    # Convert the points to numpy so that we can do array multiplication
    P0, P1, P2, P3 = map(numpy.array, [P0, P1, P2, P3])

    # Calculate t0 to t4
    t0 = 0
    t1 = calculateT(t0, P0, P1)
    t2 = calculateT(t1, P1, P2)
    t3 = calculateT(t2, P2, P3)

    # Only calculate points between P1 and P2
    t = numpy.linspace(t1,t2,nPoints)

    # Reshape so that we can multiply by the points P0 to P3
    # and get a point for each value of t.
    t = t.reshape(len(t),1)

    A1 = (t1-t)/(t1-t0)*P0 + (t-t0)/(t1-t0)*P1
    A2 = (t2-t)/(t2-t1)*P1 + (t-t1)/(t2-t1)*P2
    A3 = (t3-t)/(t3-t2)*P2 + (t-t2)/(t3-t2)*P3
    print
    B1 = (t2-t)/(t2-t0)*A1 + (t-t0)/(t2-t0)*A2
    B2 = (t3-t)/(t3-t1)*A2 + (t-t1)/(t3-t1)*A3

    curve  = (t2-t)/(t2-t1)*B1 + (t-t1)/(t2-t1)*B2
    return curve

def calculateT(ti, Pi, Pj, alpha=0.5):
    xi, yi = Pi
    xj, yj = Pj
    return ( ( (xj-xi)**2 + (yj-yi)**2 )**0.5 )**alpha + ti

def interpolateCatmulRomeSpline(points):
    """
    Calculate Catmull Rom for a chain of points and return the combined curve.
    """
    pointsLen = len(points)

    # The curve curve(C) will contain an array of (x,y) points.
    curve = []
    for i in range(pointsLen-3):
        segment = interpolateCatmulRomeSegment(points[i], points[i+1], points[i+2], points[i+3])
        curve.extend(segment)

    return curve

def main():
    # Define a set of points for curve to go through
    points = [[0,1.5],[2,2],[3,1],[4,0.5],[5,1],[6,2],[7,3]]

    # Calculate the Catmull-Rom splines through the points
    c = interpolateCatmulRomeSpline(points)

    # Convert the Catmull-Rom curve points into x and y arrays and plot
    x,y = zip(*c)
    plt.plot(x,y)

    # Plot the control points
    px, py = zip(*points)
    plt.plot(px,py,'or')

    plt.show()

if __name__ == "__main__": main()


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

# ### Understanding Probability & Statistics…

# In[1]:

#Import Common Libraries
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('seaborn')
import seaborn as sns

# ### Bernoulli Distribution

# In[2]:

#Bernoulli Distribution
from scipy.stats import bernoulli
p = 0.7
x = np.arange(bernoulli.ppf(0.01, p), bernoulli.ppf(0.99, p)) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", bernoulli.stats(p, moments='m'))
print("Variance          : ", bernoulli.stats(p, moments='v'))
print("Prob. Mass Func.  : ", bernoulli.pmf(x, p).item())
print("Cum. Density Func.: ", bernoulli.cdf(x, p).item())

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, bernoulli.pmf(x, p), 'ro', ms=8, label='PMF=(1-p)')
plt.plot(1 - x, 1 - bernoulli.pmf(x, p), 'go', ms=8, label='PMF=p')
plt.vlines(x, 0, bernoulli.pmf(x, p), colors='r', lw=5, alpha=0.5)
plt.vlines(1 - x, 0, 1 - bernoulli.pmf(x, p), colors='g', lw=5, alpha=0.5)
plt.xlabel("Sample Space of Bernoulli Distribution", fontsize=14)
plt.ylabel("PMF", fontsize=14)
plt.title("Probability Distribution of Bernoulli(p=0.7) Distribution", fontsize=16)
plt.xticks(np.arange(0, 2, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.hlines(0, -2, 0, colors='b', lw=5, alpha=0.5, linestyle='dashed')
plt.plot(0, 0, 'bo', ms=8)
plt.plot(x, bernoulli.cdf(x, p), 'ro', ms=8, label='CDF')
plt.hlines(0.3, 0, 1, colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.plot(1, 0.3, 'bo', ms=8)
plt.plot(1 - x, 1, 'ro', ms=8)
plt.hlines(1, 1, 2, colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.vlines(0, 0, 0.3, colors='b', lw=5, alpha=0.5)
plt.vlines(1, 0.3, 1, colors='b', lw=5, alpha=0.5)
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Bernoulli(p=0.7) Distribution", fontsize=16)
plt.xticks(np.arange(-2, 3, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Binomial Distribution

# In[3]:

#Binomial Distribution
from scipy.stats import binom
n, p = 10, 0.4
x = np.arange(binom.ppf(0.01, n, p), binom.ppf(0.99, n, p)) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", binom.stats(n, p, moments='m'))
print("Variance          : ", binom.stats(n, p, moments='v'))
print("Prob. Mass Func.  : ", binom.pmf(x, n, p))
print("Cum. Density Func.: ", binom.cdf(x, n, p))

CDF = binom.cdf(x, n, p)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, binom.pmf(x, n, p), 'go', ms=8, label='PMF')
plt.vlines(x, 0, binom.pmf(x, n, p), colors='g', lw=5, alpha=0.5)
plt.xlabel("Sample Space of Binomial Distribution", fontsize=14)
plt.ylabel("PMF", fontsize=14)
plt.title("Probability Distribution of Binomial(n=10,p=0.4) Distribution", fontsize=16)
plt.xticks(np.arange(0, 8, 1))
plt.yticks(np.arange(0, 0.5, 0.1))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.hlines(0, -2, 1, colors='b', lw=5, alpha=0.5, linestyle='dashed')
plt.vlines(1, 0, CDF[0], colors='b', lw=5, alpha=0.5)
plt.plot(1, 0, 'bo', ms=8)
for i in range(len(CDF) - 1):
    plt.plot(i + 2, CDF[i], 'bo', ms=8)
    plt.vlines(i + 2, CDF[i], CDF[i + 1], colors='b', lw=5, alpha=0.5)
    plt.plot(i + 1, CDF[i], 'ro', ms=8)
    plt.hlines(CDF[i], i + 1, i + 2, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.plot(len(CDF), CDF[len(CDF) - 1], 'ro', ms=8, label='CDF')
plt.hlines(CDF[len(CDF) - 1], len(CDF), len(CDF) + 1, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.hlines(1, 7, 8, colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Binomial(n=10,p=0.4) Distribution", fontsize=16)
plt.xticks(np.arange(-2, 9, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Geometric Distribution

# In[4]:

#Geometric Distribution
from scipy.stats import geom
p = 0.6
x = np.arange(geom.ppf(0.01, p), geom.ppf(0.99, p)) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", geom.stats(p, moments='m'))
print("Variance          : ", geom.stats(p, moments='v'))
print("Prob. Mass Func.  : ", geom.pmf(x, p))
print("Cum. Density Func.: ", geom.cdf(x, p))

CDF = geom.cdf(x, p)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, geom.pmf(x, p), 'go', ms=8, label='PMF')
plt.vlines(x, 0, geom.pmf(x, p), colors='g', lw=5, alpha=0.5)
plt.xlabel("Sample Space of Geometric Distribution", fontsize=14)
plt.ylabel("PMF", fontsize=14)
plt.title("Probability Distribution of Geometric(p=0.6) Distribution", fontsize=16)
plt.xticks(np.arange(0, 6, 1))
plt.yticks(np.arange(0, 0.8, 0.1))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.hlines(0, -2, 1, colors='b', lw=5, alpha=0.5, linestyle='dashed')
plt.vlines(1, 0, CDF[0], colors='b', lw=5, alpha=0.5)
plt.plot(1, 0, 'bo', ms=8)
for i in range(len(CDF) - 1):
    plt.plot(i + 2, CDF[i], 'bo', ms=8)
    plt.vlines(i + 2, CDF[i], CDF[i + 1], colors='b', lw=5, alpha=0.5)
    plt.plot(i + 1, CDF[i], 'ro', ms=8)
    plt.hlines(CDF[i], i + 1, i + 2, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.plot(len(CDF), CDF[len(CDF) - 1], 'ro', ms=8, label='CDF')
plt.hlines(CDF[len(CDF) - 1], len(CDF), len(CDF) + 1, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.hlines(1, 5, 6, colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Geometric(p=0.6) Distribution", fontsize=16)
plt.xticks(np.arange(-2, 7, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Poisson Distribution

# In[5]:

#Poisson Distribution
from scipy.stats import poisson

loc, mu = 0, 10 # Mu is basically Lambda
x = np.arange(poisson.ppf(0.01, mu, loc), poisson.ppf(0.99, mu, loc)) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", poisson.stats(mu, loc, moments='m'))
print("Variance          : ", poisson.stats(mu, loc, moments='v'))
print("Prob. Dens. Func. : ", poisson.pmf(x, mu, loc))
print("Cum. Density Func.: ", poisson.cdf(x, mu, loc))

CDF = poisson.cdf(x, mu, loc)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, poisson.pmf(x, mu, loc), 'go', ms=8, label='PMF')
plt.vlines(x, 0, poisson.pmf(x, mu, loc), colors='g', lw=5, alpha=0.5)
plt.xlabel("Sample Space of Poisson Distribution", fontsize=14)
plt.ylabel("PMF", fontsize=14)
plt.title("Probability Distribution of Poisson(λ=10) Distribution", fontsize=16)
plt.xticks(np.arange(0, 20, 1))
plt.yticks(np.arange(0, 0.25, 0.05))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.hlines(0, -1, 3, colors='b', lw=5, alpha=0.5, linestyle='dashed')
plt.vlines(3, 0, CDF[0], colors='b', lw=5, alpha=0.5)
plt.plot(3, 0, 'bo', ms=8)
for i in range(len(CDF) - 1):
    plt.plot(i + 4, CDF[i], 'bo', ms=8)
    plt.vlines(i + 4, CDF[i], CDF[i + 1], colors='b', lw=5, alpha=0.5)
    plt.plot(i + 3, CDF[i], 'ro', ms=8)
    plt.hlines(CDF[i], i + 3, i + 4, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.plot(len(CDF) + 2, CDF[len(CDF) - 1], 'ro', ms=8, label='CDF')
plt.hlines(CDF[len(CDF) - 1], len(CDF) + 2, len(CDF) + 3, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.hlines(1, 17, 18, colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Poisson(λ=10) Distribution", fontsize=16)
plt.xticks(np.arange(-1, 20, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Uniform (Discrete) Distribution

# In[6]:

#Uniform (Discrete) Distribution
from scipy.stats import randint

low, high = 1, 10
x = np.arange(randint.ppf(0.01, low, high), randint.ppf(0.99, low, high)) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", randint.stats(low, high, moments='m'))
print("Variance          : ", randint.stats(low, high, moments='v'))
print("Prob. Mass Func.  : ", randint.pmf(x, low, high))
print("Cum. Density Func.: ", randint.cdf(x, low, high))

CDF = randint.cdf(x, low, high)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, randint.pmf(x, low, high), 'go', ms=8, label='PMF')
plt.vlines(x, 0, randint.pmf(x, low, high), colors='g', lw=5, alpha=0.5)
plt.xlabel("Sample Space of Discrete Uniform Distribution", fontsize=14)
plt.ylabel("PMF", fontsize=14)
plt.title("Probability Distribution of Discrete Uniform(a=1,b=10) Distribution", fontsize=16)
plt.xticks(np.arange(0, 10, 1))
plt.yticks(np.arange(0, 0.3, 0.05))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.hlines(0, -1, 1, colors='b', lw=5, alpha=0.5, linestyle='dashed')
plt.vlines(1, 0, CDF[0], colors='b', lw=5, alpha=0.5)
plt.plot(1, 0, 'bo', ms=8)
for i in range(len(CDF) - 1):
    plt.plot(i + 2, CDF[i], 'bo', ms=8)
    plt.vlines(i + 2, CDF[i], CDF[i + 1], colors='b', lw=5, alpha=0.5)
    plt.plot(i + 1, CDF[i], 'ro', ms=8)
    plt.hlines(CDF[i], i + 1, i + 2, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.plot(len(CDF), CDF[len(CDF) - 1], 'ro', ms=8, label='CDF')
plt.hlines(CDF[len(CDF) - 1], len(CDF), len(CDF) + 1, colors='r', lw=5, alpha=0.5, linestyle='dashed')

plt.plot(9, CDF[-1], 'bo', ms=8)
plt.vlines(9, CDF[-1], 1, colors='b', lw=5, alpha=0.5)

plt.hlines(1, 9, 10, colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Discrete Uniform(a=1,b=10) Distribution", fontsize=16)
plt.xticks(np.arange(-1, 12, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Exponential Distribution

# In[7]:

#Exponential Distribution
from scipy.stats import expon

loc, scale = 0, 0.67 # Scale is 1/Lambda
x = np.linspace(expon.ppf(0.01, loc, scale), expon.ppf(0.99, loc, scale), 25) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", expon.stats(loc, scale, moments='m'))
print("Variance          : ", expon.stats(loc, scale, moments='v'))
print("Prob. Dens. Func. : ", expon.pdf(x, loc, scale))
print("Cum. Density Func.: ", expon.cdf(x, loc, scale))

CDF = expon.cdf(x, loc, scale)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, expon.pdf(x, loc, scale), 'g', ms=8, label='PDF')
plt.xlabel("Sample Space of Exponential Distribution", fontsize=14)
plt.ylabel("PDF", fontsize=14)
plt.title("Probability Distribution of Exponential(λ=1.5) Distribution", fontsize=16)
plt.xticks(np.arange(0, 5, 1))
plt.yticks(np.arange(0, 1.7, 0.1))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.plot(x, expon.cdf(x, loc, scale), 'r', ms=8, label='CDF')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Exponential(λ=1.5) Distribution", fontsize=16)
plt.xticks(np.arange(-1, 5, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Uniform (Continuous) Distribution

# In[8]:

#Uniform (Continuous) Distribution
from scipy.stats import uniform

loc, scale = 1, 10
x = np.linspace(uniform.ppf(0.01, loc, scale), uniform.ppf(0.99, loc, scale), 100) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", uniform.stats(loc, scale, moments='m'))
print("Variance          : ", uniform.stats(loc, scale, moments='v'))
print("Prob. Dens. Func. : ", uniform.pdf(x, loc, scale))
print("Cum. Density Func.: ", uniform.cdf(x, loc, scale))

CDF = randint.cdf(x, loc, scale)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, uniform.pdf(x, loc, scale), 'g', ms=8, label='PDF')
plt.vlines(loc, 0, 0.1, colors='g', lw=5, alpha=0.5, linestyle='dashed')
plt.vlines(scale + 1, 0, 0.1, colors='g', lw=5, alpha=0.5, linestyle='dashed')
plt.xlabel("Sample Space of Continuous Uniform Distribution", fontsize=14)
plt.ylabel("PDF", fontsize=14)
plt.title("Probability Distribution of Continuous Uniform(a=1,b=10) Distribution", fontsize=16)
plt.xticks(np.arange(0, 12, 1))
plt.yticks(np.arange(0, 0.3, 0.05))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.hlines(0, -1, 1, colors='b', lw=5, alpha=0.5, linestyle='dashed')
plt.plot(loc, 0, 'bo', ms=8)
plt.plot(scale + 1, CDF[-1], 'bo', ms=8)
x_lab = [loc, scale + 1]
y_lab = [0, CDF[-1]]
plt.plot(x_lab, y_lab, color='red', label='CDF')
plt.hlines(1, 11, 12, colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.vlines(11, 0, CDF[-1], colors='r', lw=5, alpha=0.5, linestyle='dashed')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Continuous Uniform(a=1,b=10) Distribution", fontsize=16)
plt.xticks(np.arange(-1, 14, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Gaussian (Normal) Distribution

# In[9]:

#Gaussian (Normal) Distribution
from scipy.stats import norm

loc, scale = 1, 2 # Mean and Variance
x = np.linspace(norm.ppf(0.01, loc, scale), norm.ppf(0.99, loc, scale), 25) #Percent Point Function (inverse of cdf — percentiles)

print("Mean              : ", norm.stats(loc, scale, moments='m'))
print("Variance          : ", norm.stats(loc, scale, moments='v'))
print("Prob. Dens. Func. : ", norm.pdf(x, loc, scale))
print("Cum. Density Func.: ", norm.cdf(x, loc, scale))

CDF = norm.cdf(x, loc, scale)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(x, norm.pdf(x, loc, scale), 'g', ms=8, label='PDF')
plt.xlabel("Sample Space of Gaussian Distribution", fontsize=14)
plt.ylabel("PDF", fontsize=14)
plt.title("Probability Distribution of Gaussian(µ=1,σ=2) Distribution", fontsize=16)
plt.xticks(np.arange(-5, 7, 1))
plt.yticks(np.arange(0, 0.30, 0.05))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.plot(x, norm.cdf(x, loc, scale), 'r', ms=8, label='CDF')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Gaussian(µ=1,σ=2) Distribution", fontsize=16)
plt.xticks(np.arange(-5, 7, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Covariance and Correlation

# In[10]:

#Covariance and Correlation
from scipy.stats import pearsonr

np.random.seed(1)
data1 = 20 * np.random.randn(20000) + 100
data2 = data1 + 10 * np.random.randn(20000) - 50

print("data1: Mean=%.3f; Variance=%.3f" % (np.mean(data1), np.var(data1)))
print("data2: Mean=%.3f; Variance=%.3f" % (np.mean(data2), np.var(data2)))
print("Covariance between data1 and data2: \n", np.cov(data1, data2))

corr, p = pearsonr(data1, data2)
print("Pearson Correlation Coefficient is %.3f with p-value %.3f" % (corr, p))

plt.scatter(data1, data2)
plt.title("Correlation", fontsize=16)
plt.xlabel("data1", fontsize=14)
plt.ylabel("data2", fontsize=14)

plt.show()

# ### Law of Large Numbers

# In[11]:

#Generate Samples from Standard Normal Distribution and Multiply Them by 5 and Add 10;
#So the Resulting Distribution of 'data' is Also Gaussian

np.random.seed(1)
data = 5 * np.random.randn(10) + 10
print("Average when n=10 is    :", np.mean(data))

data = 5 * np.random.randn(1000) + 10
print("Average when n=1000 is  :", np.mean(data))

data = 5 * np.random.randn(10000) + 10
print("Average when n=10000 is :", np.mean(data))

data = 5 * np.random.randn(100000) + 10
print("Average when n=100000 is:", np.mean(data))

# ### Central Limit Theorem

# In[12]:

#Generate a Sample of Dice Rolls
np.random.seed(1)
T_n = []
mu = (1 + 2 + 3 + 4 + 5 + 6) / 6
n = 1000
for i in range(n):
    data = np.random.randint(low=1, high=7, size=1000) #Returns discrete uniform integers
    X_n  = np.sum(data)/1000 #Sample average
    X_c  = X_n - mu #Subtract true mean mu
    X_f  = X_c * np.sqrt(n) #Multiply by sqrt(n)
    T_n.append(X_f)

fig = plt.figure(figsize=(20,10))
plt.hist(T_n, bins=100)
plt.title("Histogram of Sample Means from Dice Roll Simulations", fontsize=16)
plt.xticks(np.arange(-5, 6, 1))

plt.show()

# ### Confidence Interval

# In[13]:

#Confidence Interval
from scipy.stats import norm

np.random.seed(1)
data = 5 * np.random.randn(100) + 50
q_a_2 = norm.ppf(0.90)

low  = np.mean(data) - (q_a_2 * np.std(data)) / np.sqrt(len(data))
high = np.mean(data) + (q_a_2 * np.std(data)) / np.sqrt(len(data))

print("90 percent Confidence Interval is: %.3f, %.3f" % (low, high))

# ### Student's t-Distribution

# In[14]:

#Student's t-Distribution
from scipy.stats import t

sample_space = np.arange(-5, 5, 0.001)
dof = len(sample_space) - 1 #Number of independent variables
pdf = t.pdf(sample_space, dof)
cdf = t.cdf(sample_space, dof)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(sample_space, pdf, 'g', ms=8, label='PDF')
plt.xlabel("Sample Space of t-Distribution", fontsize=14)
plt.ylabel("PDF", fontsize=14)
plt.title("Probability Distribution of t-Distribution", fontsize=16)
plt.xticks(np.arange(-5, 7, 1))
plt.yticks(np.arange(0, 0.50, 0.1))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.plot(sample_space, cdf, 'r', ms=8, label='CDF')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of t-Distribution", fontsize=16)
plt.xticks(np.arange(-5, 7, 1))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Chi-Squared Distribution

# In[15]:

#Chi-Squared Distribution
from scipy.stats import chi2

sample_space = np.arange(0, 50, 0.01)
dof = 20 #Number of independent variables
pdf = chi2.pdf(sample_space, dof)
cdf = chi2.cdf(sample_space, dof)

fig = plt.figure(figsize=(20,10))
plt.subplot(221)
plt.plot(sample_space, pdf, 'g', ms=8, label='PDF')
plt.xlabel("Sample Space of Chi Square Distribution", fontsize=14)
plt.ylabel("PDF", fontsize=14)
plt.title("Probability Distribution of Chi Square Distribution", fontsize=16)
plt.xticks(np.arange(0, 60, 10))
plt.yticks(np.arange(0, 0.07, 0.01))
plt.legend(loc='best', shadow=True)

plt.subplot(222)
plt.plot(sample_space, cdf, 'r', ms=8, label='CDF')
plt.xlabel("Observation", fontsize=14)
plt.ylabel("CDF", fontsize=14)
plt.title("Cumulative Density Function of Chi Square Distribution", fontsize=16)
plt.xticks(np.arange(0, 60, 10))
plt.yticks(np.arange(0, 1.1, 0.1))
plt.legend(loc='upper left', shadow=True)

plt.show()

# ### Student's t-Test

# In[16]:

#Student's t-Test
from scipy.stats import ttest_ind

np.random.seed(1)
#np.random.randn generates Standard Normal data
data1 = 20 * np.random.randn(200) + 50 # mean=50, standard-deviation=20
data2 = 10 * np.random.randn(200) + 51 # mean=51, standard-deviation=10

stat, p = ttest_ind(data1, data2)
print('Test Statistic=%.3f, p=%.3f' % (stat, p))

alpha = 0.05 #Our desired confidence interval is 0.95

if p > alpha:
    print('Same distributions (fail to reject H0)')
else:
    print('Different distributions (reject H0)')

# ### Paired Student's t-Test

# In[17]:

#Paired Student's t-Test
from scipy.stats import ttest_rel

np.random.seed(1)
#np.random.randn generates Standard Normal data
data1 = 20 * np.random.randn(200) + 50 # mean=50, standard-deviation=20
data2 = 10 * np.random.randn(200) + 51 # mean=51, standard-deviation=10

stat, p = ttest_rel(data1, data2)
print('Test Statistic=%.3f, p=%.3f' % (stat, p))

alpha = 0.05 #Our desired confidence interval is 0.95

if p > alpha:
    print('Same distributions (fail to reject H0)')
else:
    print('Different distributions (reject H0)')

# ### Analysis of Variance (ANOVA)

# In[18]:

#ANOVA
from scipy.stats import f_oneway

np.random.seed(1)

data1 = np.array([6, 8, 4, 5, 3, 4])
data2 = np.array([8, 12, 9, 11, 6, 8])
data3 = np.array([13, 9, 11, 8, 7, 12])

stat, p = f_oneway(data1, data2, data3)
print('Test Statistic=%.3f, p=%.3f' % (stat, p))

alpha = 0.05 #Our desired confidence interval is 0.95

if p > alpha:
    print('Same distributions (fail to reject H0)')
else:
    print('Different distributions (reject H0)')

# Native Method
print("==> Native Method To Show the Calculation Method <==")
# Mean within each group
mean_1 = np.mean(data1)
mean_2 = np.mean(data2)
mean_3 = np.mean(data3)
n = len(data1)

# Overall mean
mean_o = (mean_1 + mean_2 + mean_3) / 3

# Calculate the "between-group" sum of squared differences
S_B = n * (mean_1 - mean_o) ** 2 + n * (mean_2 - mean_o) ** 2 + n * (mean_3 - mean_o) ** 2
dof_B = 3 - 1

# Between-group mean square value
MS_B = S_B / dof_B

# "within-group" sum of squares
# Centering the data in each group
data1_C = data1 - mean_1
data2_C = data2 - mean_2
data3_C = data3 - mean_3

# Within-group sum of squares
S_W = (np.sum(data1_C ** 2) + np.sum(data2_C ** 2) + np.sum(data3_C ** 2)).item()

# Within-group degrees of freedom
dof_W = 3 * (n - 1)

# Within-group mean square value
MS_W = S_W / dof_W

# F-Ratio
F = MS_B / MS_W

print("F Statistic:", F)

# ### Chi-Squared Test

# In[19]:

#Chi-Squared Test

#We will use this table from Wikipedia
#-------------------------------------
#           	A	B	C	D	Total
#White collar	90	60	104	95	349
#Blue collar	30	50	51	20	151
#No collar  	30	40	45	35	150
#Total      	150	150	200	150	650

from scipy.stats import chi2, chi2_contingency
np.random.seed(1)
# contingency table
observed = np.array([[90, 60, 104, 95],[30, 50, 51, 20], [30, 40, 45, 35]], dtype=np.float64)
print("Observed Frequencies: \n", observed)
stat, p, dof, expected = chi2_contingency(observed)

print('dof=%d' % dof)
print("Expected Frequencies: \n", expected)
# interpret test-statistic
prob = 0.95
critical = chi2.ppf(prob, dof)
print('probability=%.3f, critical=%.3f, stat=%.3f' % (prob, critical, stat))
if abs(stat) >= critical:
    print('Dependent (reject H0)')
else:
    print('Independent (fail to reject H0)')
# interpret p-value
alpha = 1.0 - prob
print('significance=%.3f, p=%.3f' % (alpha, p))
if p <= alpha:
    print('Dependent (reject H0)')
else:
    print('Independent (fail to reject H0)')

# Native Method
print("==> Native Method <==")
for i in range(observed.shape[0]):
    for j in range(observed.shape[1]):
        expected[i, j] = (np.sum(observed, axis=1))[i] * (np.sum(observed, axis=0))[j] / np.sum(observed)

print("Observed: \n", observed)
print("Expected: \n", expected)

stat = ((observed - expected) ** 2) / expected

dof = (observed.shape[0] - 1) * (observed.shape[1] - 1)

print("Statistic, dof: ", (np.sum(stat)).item(), ",", dof)

# ### KDE Plot

# In[20]:

#KDE Plot
np.random.seed(1)
data = np.random.random(5000) + 50

fig = plt.figure(figsize=(20,10))
sns.kdeplot(data, shade=True, color="r", legend=True)
plt.title("Kernel Density Plot of the Data", fontsize=16)
plt.xticks(np.arange(49.5, 51.5, 0.2))
plt.yticks(np.arange(0, 1.2, 0.1))

plt.show()

# ### Q-Q Plot

# In[21]:

#Q-Q Plot
from statsmodels.graphics.gofplots import qqplot
np.random.seed(1)
data = np.random.random(5000) + 50

qqplot(data, line='s')

plt.show()

# #### Shapiro-Wilk Test|D'Agostino's K2 Test|Anderson-Darling Test

# In[22]:

#Shapiro-Wilk Test
from scipy.stats import shapiro, normaltest, anderson
np.random.seed(1)
data = np.random.random(5000) + 50
alpha = 0.05

print("\n ==> Shapiro-Wilk Test <==")
stat, p = shapiro(data)
print('Statistic=%.3f, p=%.3f' % (stat, p))

if p > alpha:
    print('Sample looks Gaussian (fail to reject H0)')
else:
    print('Sample does not look Gaussian (reject H0)')

#D'Agostino's K2 Test
print("\n ==> D'Agostino's K2 Test <==")
stat, p = normaltest(data)
print('Statistic=%.3f, p=%.3f' % (stat, p))

if p > alpha:
    print('Sample looks Gaussian (fail to reject H0)')
else:
    print('Sample does not look Gaussian (reject H0)')

#Anderson-Darling Test
print("\n ==> Anderson-Darling Test <==")
result = anderson(data, dist='norm')

print('Statistic, Critical Values: %.3f' % result.statistic, result.critical_values)
for i in range(len(result.critical_values)):
    sl, cv = result.significance_level[i], result.critical_values[i]
    if result.statistic < result.critical_values[i]:
        print('%.3f: %.3f, data looks normal (fail to reject H0)' % (sl, cv))
    else:
        print('%.3f: %.3f, data does not look normal (reject H0)' % (sl, cv))

import numpy,from scipy,from statsmodels


#!/usr/bin/env python
# vim: set fileencoding=utf-8
""" This file is a Python translation of the MATLAB file prony.m

 Python version by RDL 12 Jan 2012
 Copyright notice from prony.m:
 copyright 1996, by M.H. Hayes.  For use with the book
 "Statistical Digital Signal Processing and Modeling"
 (John Wiley & Sons, 1996).
"""

from __future__ import print_function,division
import sys
import numpy as np

from convm import convm

def prony(x, p, q):
    """Model a signal using Prony's method

    Usage: [b,a,err] = prony(x,p,q)

    The input sequence x is modeled as the unit sample response of
    a filter having a system function of the form
        H(z) = B(z)/A(z)
    The polynomials B(z) and A(z) are formed from the vectors
        b=[b(0), b(1), ... b(q)]
        a=[1   , a(1), ... a(p)]
    The input q defines the number of zeros in the model
    and p defines the number of poles. The modeling error is
    returned in err.

    This comes from Hayes, p. 149, 153, etc

    """
    x = x[:]
    N = len(x)
    if p+q >= len(x):
        print('ERROR: model order too large')
        print ("p q len(x) " + str(p) + " " + str(q) + " " + str(len(x)))
        sys.exit(1)

    # This formulation uses eq. 4.50, p. 153
    # Set up the convolution matrices
    X = convm(x, p+1)
    Xq = X[q:N+p-1, 0:p]
    xq1 = -X[q+1:N+p,0]

    # Solve for denominator coefficients
    if p>0:
        a = np.linalg.lstsq(Xq, xq1)[0]
        a = np.insert(a, 0, 1) # a(0) is 1
    else:
        # all-zero model
        a = np.array(1)

    # Solve for the model error
    err = np.dot(x[q+1:N].conj().T,X[q+1:N, 0:p+1])
    err = np.dot(err, a)

    # Solve for numerator coefficients
    if q>0:
        # (This is the same as for Pad?)
        b = np.dot(X[0:q+1,0:p+1], a)
    else:
        # all-pole model
        # b(0) is x(0), but a better solution is to match energy
        b = np.sqrt(err)

    return (b,a)

#function [a,b,err] = prony(x,p,q)
#x   = x(:);
#N   = length(x);
#if p+q>=length(x), error('Model order too large'), end
#X   = convm(x,p+1);
#Xq  = X(q+1:N+p-1,1:p);
#a   = [1;-Xq\X(q+2:N+p,1)];
#b   = X(1:q+1,1:p+1)*a;
#err = x(q+2:N)'*X(q+2:N,1:p+1)*a;

def main():
    """Test driver"""
    # From pp. 149-150
    x = np.ones(21)
    p = q = 1
    print('x: {}\np: {}\nq: {}'.format(x,p,q))
    b,a,err = prony(x, p, q)
    print('a: {}\nb: {}\nerr: {}'.format(a,b,err))

    # From pp. 152-153
    # Note that these results don't match the book, but they do match the
    # MATLAB version. So I'm either setting things up wrong or this is an
    # errata in the book.
    p = q = 5
    nd = 5
    n = np.arange(11)
    i = np.sinc((n-nd)/2)/2
    b,a,err = prony(i, p, q)
    print('a: {}\nb: {}\nerr: {}'.format(a,b,err))

if __name__ == '__main__':
    main()


from typing import NoReturn
from ...base import BaseEstimator
import numpy as np

# noinspection DuplicatedCode
class GaussianNaiveBayes(BaseEstimator):
    """
    Gaussian Naive-Bayes classifier
    """

    def __init__(self):
        """
        Instantiate a Gaussian Naive Bayes classifier

        Attributes
        ----------
        self.classes_ : np.ndarray of shape (n_classes,)
            The different labels classes. To be set in `GaussianNaiveBayes.fit`

        self.mu_ : np.ndarray of shape (n_classes,n_features)
            The estimated features means for each class. To be set in `GaussianNaiveBayes.fit`

        self.vars_ : np.ndarray of shape (n_classes, n_features)
            The estimated features variances for each class. To be set in `GaussianNaiveBayes.fit`

        self.pi_: np.ndarray of shape (n_classes)
            The estimated class probabilities. To be set in `GaussianNaiveBayes.fit`
        """
        super().__init__()
        self.classes_, self.mu_, self.vars_, self.pi_ = None, None, None, None

    def _fit(self, X: np.ndarray, y: np.ndarray) -> NoReturn:
        """
        fits a gaussian naive bayes model

        Parameters
        ----------
        X : ndarray of shape (n_samples, n_features)
            Input data to fit an estimator for

        y : ndarray of shape (n_samples, )
            Responses of input data to fit to
        """
        self.classes_ = np.unique(y)
        n_classes = self.classes_.shape[0]
        d_features = 1
        if X.ndim == 2:
            d_features = X.shape[1]

        m_samples = X.shape[0]
        n = np.zeros(n_classes).astype(int)
        for k in y:
            n[k] += 1  # Counting occurrences of each class/label
        self.pi_ = n / m_samples
        feature_sum = np.zeros(shape=(n_classes, d_features))
        for x_i, y_i in zip(X, y):
            feature_sum[y_i] += x_i  # Summing the feature vectors of each class
        self.mu_ = feature_sum / n[:, None]  # Dividing every feature by number of occurrences
        self.vars_ = np.zeros(shape=(n_classes, d_features))
        for k in self.classes_:
            x_k = np.zeros(shape=(n[k], d_features))
            fill_ind = 0
            for X_i, y_i in zip(X, y):
                if y_i == k:
                    x_k[fill_ind] = X_i
                    fill_ind += 1
            self.vars_[k] = np.var(x_k, axis=0, ddof=1)

    def _predict(self, X: np.ndarray) -> np.ndarray:
        """
        Predict responses for given samples using fitted estimator

        Parameters
        ----------
        X : ndarray of shape (n_samples, n_features)
            Input data to predict responses for

        Returns
        -------
        responses : ndarray of shape (n_samples, )
            Predicted responses of given samples
        """
        return np.argmax(self.likelihood(X), axis=1)

    def likelihood(self, X: np.ndarray) -> np.ndarray:
        """
        Calculate the likelihood of a given data over the estimated model

        Parameters
        ----------
        X : np.ndarray of shape (n_samples, n_features)
            Input data to calculate its likelihood over the different classes.

        Returns
        -------
        likelihoods : np.ndarray of shape (n_samples, n_classes)
            The likelihood for each sample under each of the classes

        """
        if not self.fitted_:
            raise ValueError("Estimator must first be fitted before calling `likelihood` function")

        # Using the expression derived in question 3b:
        m_samples = X.shape[0]
        d_features = X.shape[1] if X.ndim == 2 else 1
        n_classes = self.classes_.shape[0]
        lkl = np.zeros((m_samples, n_classes))
        for i, x_i in enumerate(X):
            for k in self.classes_:
                lkl[i, k] = np.log(self.pi_[k])
                for j in range(d_features):
                    lkl[i, k] += np.log(1 / (np.sqrt(self.vars_[k, j] * 2 * np.pi))) \
                                 - 0.5 * ((x_i[j] - self.mu_[k, j]) / np.sqrt(self.vars_[k, j])) ** 2
        return lkl

    def _loss(self, X: np.ndarray, y: np.ndarray) -> float:
        """
        Evaluate performance under misclassification loss function

        Parameters
        ----------
        X : ndarray of shape (n_samples, n_features)
            Test samples

        y : ndarray of shape (n_samples, )
            True labels of test samples

        Returns
        -------
        loss : float
            Performance under misclassification loss function
        """
        from ...metrics import misclassification_error
        return misclassification_error(y, self.predict(X))


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle, Arc
from matplotlib.collections import PatchCollection
import seaborn as sns
sns.set()

from check import *
from methods import compute_fibonacci_sequence

# -----------------------------------------------------------------------------
# Golden spiral approximation
# -----------------------------------------------------------------------------
def plot_golden_spiral_approximation(n):
    # check value of the argument
    if n < 1:
        raise ValueError("Argument n should be larger than 1")
    # compute F_i with i from 0 to n
    sequence = compute_fibonacci_sequence(n)

    # initialize variables
    x_ref, y_ref = 0, 0
    x_min, x_max, y_min, y_max = 0, 0, 0, 0
    angle = 180
    center = (1, 1)

    # initialize figure
    fig, ax = plt.subplots(1, figsize=(16, 16))
    rectangles = []
    for i, side in enumerate(sequence):
        if i == 0:
            previous_side = side
            continue
        # add a square of side F_i
        rectangles.append(Rectangle([x_ref, y_ref], side, side))
        # annotate the square if not too small
        if i > n - 8:
            ax.annotate(side, xy=(x_ref + 0.45 * side, y_ref + 0.45 * side), fontsize=10)
        # add the corresponding arc of the spiral
        ax.add_patch(
            Arc(center, 2 * side, 2 * side,
                angle=angle, theta1=0, theta2=90,
                edgecolor="black", antialiased=True)
            )

        # update variables
        angle += 90
        angle %= 360
        if i % 4 == 1:
            if i == 1:
                x_max, y_max = 1, 1
            else:
                y_min -= side
            x_ref += side
            center = (x_ref, y_ref + side + previous_side)
        elif i % 4 == 2:
            x_max += side
            x_ref -= previous_side
            y_ref += side
            center = (x_ref, y_ref)
        elif i % 4 == 3:
            y_max += side
            x_ref -= (side + previous_side)
            y_ref -= previous_side
            center = (x_ref + side + previous_side, y_ref)
        else:
            x_min -= side
            y_ref -= (side + previous_side)
            center = (x_ref + side + previous_side, y_ref + side + previous_side)
        previous_side = side

    # color the squares depending on their size and add them to the figure
    col = PatchCollection(rectangles, alpha=.95, edgecolor="black")
    col.set(array=np.asarray(range(n + 1)), cmap="Blues")
    ax.add_collection(col)

    # customize the axes
    ax.set_aspect("equal", "box")
    ax.set_xticks([])
    ax.set_yticks([])
    ax.set_xlim(x_min, x_max)
    ax.set_ylim(y_min, y_max)
    plt.tight_layout()
    plt.savefig("plots/golden_spiral_approximation.png")
    plt.show()

# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------
if __name__ == "__main__":

    n = 16
    check_fibonacci_argument(n)

    plot_golden_spiral_approximation(n)


import numpy as np

from ruleex.tree.ruletree import RuleTree
from ruleex.tree.rule import Leaf

def entropy(l0, l1):
    """
    computes entropy impurity for two list of labels l0 and l1
    :param l0: list of labels
    :param l1: list of labels
    :return: entropy impurity
    """
    _, p0 = np.unique(l0, return_counts=True)
    p0 = p0 / np.sum(p0)
    _, p1 = np.unique(l1, return_counts=True)
    p1 = p1 / np.sum(p1)
    return - np.sum(p0 * np.log2(p0)) - np.sum(p1 * np.log2(p1))

def gini(l0, l1):
    """
    computes gini impurity for two list of labels l0 and l1
    :param l0: list of labels
    :param l1: list of labels
    :return: gini impurity
    """
    _, p0 = np.unique(l0, return_counts=True)
    p0 = p0 / np.sum(p0)
    _, p1 = np.unique(l1, return_counts=True)
    p1 = p1 / np.sum(p1)
    return np.sum(p0 * (1 - p0)) + np.sum(p1 * (1 - p1))

def get_leaf(labels, class_num):
    """
    creates tŕee.Leaf object, i.e., subclass of tree.Rule
    class_set will be set to maximal occurring class in labels
    :param labels: a list of labels
    :param class_num: the number of classes
    :return: tree.Leaf with maximal occurring class as class_set
    """
    values, counts = np.unique(labels, return_counts=True)
    c = np.zeros(class_num)
    c[values] = counts
    max_label = np.argmax(c)
    node = Leaf({max_label})
    node.class_hits = c
    return node

def build_from_rules(rule_list, data, labels,
                     min_split_fraction: float = 0.98,
                     num_of_classes=None,
                     impurity=gini,
                     max_depth=None):
    """
    Builds tree.RuleTree from available splits from rule_list using data and its labels
    :param rule_list: a list of rules (subclass of tree.Rule)
    :param data: a list of inputs of the samples
    :param labels: a list of classificaitons for the samples
    :param min_split_fraction: minimal split fraction
    :param num_of_classes: number of classes
    :param impurity: impurity measure (function which takes two labels and return impurity value)
    :param max_depth: maximal depth of built tree
    :return: built RuleTree
    """
    if not num_of_classes:
        num_of_classes = np.max(labels)+1

    def build_from_rules_rek(rule_list, x, l, depth):
        if max_depth is not None and depth == max_depth:
            return get_leaf(l, num_of_classes)
        best_impurity = np.inf
        best_node_index = None
        best_node_mask = None
        for i, node in enumerate(rule_list):
            mask = node.eval_all(x)
            if np.all(mask) or not np.any(mask):
                continue # node do not provide any split for given data
            if np.mean(mask) > min_split_fraction or np.mean(mask) < 1 - min_split_fraction:
                continue
            node_imp = impurity(l[mask], l[~mask])
            if node_imp < best_impurity:
                best_impurity = node_imp
                best_node_index = i
                best_node_mask = mask
        if best_node_index is None:
            return get_leaf(l, num_of_classes)
        node = rule_list[best_node_index].copy()
        next_rule_list = rule_list.copy()
        next_rule_list.pop(best_node_index)

        node.true_branch = build_from_rules_rek(next_rule_list, x[best_node_mask], l[best_node_mask], depth + 1)
        node.false_branch = build_from_rules_rek(next_rule_list, x[~best_node_mask], l[~best_node_mask], depth + 1)
        return node

    rt = RuleTree(num_of_classes, data.shape[1])
    rt.root = build_from_rules_rek(rule_list, data, labels, 0)
    return rt


import numpy as np

def sigmoid(n):
    return 1.0 / (1.0 + np.exp(-n))

def sigmoid_derivative(n):
    return sigmoid(n) * (1 - sigmoid(n))


import numpy as np
from scipy.optimize import minimize

def direction(theta, phi):
    '''Return the direction vector of a cylinder defined
    by the spherical coordinates theta and phi.
    '''
    return np.array([np.cos(phi) * np.sin(theta), np.sin(phi) * np.sin(theta),
                     np.cos(theta)])

def projection_matrix(w):
    '''Return the projection matrix  of a direction w.'''
    return np.identity(3) - np.dot(np.reshape(w, (3,1)), np.reshape(w, (1, 3)))

def skew_matrix(w):
    '''Return the skew matrix of a direction w.'''
    return np.array([[0, -w[2], w[1]],
                     [w[2], 0, -w[0]],
                     [-w[1], w[0], 0]])

def calc_A(Ys):
    '''Return the matrix A from a list of Y vectors.'''
    return sum(np.dot(np.reshape(Y, (3,1)), np.reshape(Y, (1, 3)))
            for Y in Ys)

def calc_A_hat(A, S):
    '''Return the A_hat matrix of A given the skew matrix S'''
    return np.dot(S, np.dot(A, np.transpose(S)))

def preprocess_data(Xs_raw):
    '''Translate the center of mass (COM) of the data to the origin.
    Return the prossed data and the shift of the COM'''
    n = len(Xs_raw)
    Xs_raw_mean = sum(X for X in Xs_raw) / n

    return [X - Xs_raw_mean for X in Xs_raw], Xs_raw_mean

def G(w, Xs):
    '''Calculate the G function given a cylinder direction w and a
    list of data points Xs to be fitted.'''
    n = len(Xs)
    P = projection_matrix(w)
    Ys = [np.dot(P, X) for X in Xs]
    A = calc_A(Ys)
    A_hat = calc_A_hat(A, skew_matrix(w))

    u = sum(np.dot(Y, Y) for Y in Ys) / n
    v = np.dot(A_hat, sum(np.dot(Y, Y) * Y for Y in Ys)) / np.trace(np.dot(A_hat, A))

    return sum((np.dot(Y, Y) - u - 2 * np.dot(Y, v)) ** 2 for Y in Ys)

def C(w, Xs):
    '''Calculate the cylinder center given the cylinder direction and
    a list of data points.
    '''
    n = len(Xs)
    P = projection_matrix(w)
    Ys = [np.dot(P, X) for X in Xs]
    A = calc_A(Ys)
    A_hat = calc_A_hat(A, skew_matrix(w))

    return np.dot(A_hat, sum(np.dot(Y, Y) * Y for Y in Ys)) / np.trace(np.dot(A_hat, A))

def r(w, Xs):
    '''Calculate the radius given the cylinder direction and a list
    of data points.
    '''
    n = len(Xs)
    P = projection_matrix(w)
    c = C(w, Xs)

    return np.sqrt(sum(np.dot(c - X, np.dot(P, c - X)) for X in Xs) / n)

def fit(data, guess_angles=None):
    '''Fit a list of data points to a cylinder surface. The algorithm implemented
    here is from David Eberly's paper "Fitting 3D Data with a Cylinder" from
    https://www.geometrictools.com/Documentation/CylinderFitting.pdf

    Arguments:
        data - A list of 3D data points to be fitted.
        guess_angles[0] - Guess of the theta angle of the axis direction
        guess_angles[1] - Guess of the phi angle of the axis direction

    Return:
        Direction of the cylinder axis
        A point on the cylinder axis
        Radius of the cylinder
        Fitting error (G function)
    '''
    Xs, t = preprocess_data(data)

    # Set the start points

    start_points = [(0, 0), (np.pi / 2, 0), (np.pi / 2, np.pi / 2)]
    if guess_angles:
        start_points = guess_angles

    # Fit the cylinder from different start points

    best_fit = None
    best_score = float('inf')

    for sp in start_points:
        fitted = minimize(lambda x : G(direction(x[0], x[1]), Xs),
                    sp, method='Powell', tol=1e-6)

        if fitted.fun < best_score:
            best_score = fitted.fun
            best_fit = fitted

    w = direction(best_fit.x[0], best_fit.x[1])

    return w, C(w, Xs) + t, r(w, Xs), best_fit.fun


import numpy as np
from numpy import linalg as La
import matplotlib.pyplot as plt
import time

n =225
K = np.sqrt(n)
k = int(K)

# Here I set the Matrix

a = np.zeros((n,n))

for i in range(n):
    for j in range(n):
        if i == j:
            a[i,j] = -4
        elif i == j-3 or i ==j+3:
            a[i,j] = 1
        elif ((i+1) % 3 != 0 and i == j-1) or ((i+1) % 3 != 1 and i == j+1): # (i+1) because in Python we start from 0
            a[i,j] = 1

print('The coefficient Matrix is:')
print(a)
print('\n')

b = np.zeros(n)

for i in range(k):
    if i < k-1: # (k-1) because in Python we start from 0
        b[i] = -50
    else:
        b[i] = -150

for i in range(k,n-k):
    if (i+1)%k != 0: # (i+1) because in Python we start from 0
        b[i] = 0
    else:
        b[i] = -100

for i in range(n-k,n):
    if i < n-1: # (k-1) because in Python we start from 0
        b[i] = -50
    else:
        b[i] = -150

print('The result Matrix is:')
print(b)
print('\n')


import numpy as np

def QRDecomposition(A):
	n = np.shape(A)[0] #pegando o tamanho das linhas de A
	m = np.shape(A)[1] #pegando o tamanho das colunas de A
	Q = np.zeros((n,m)) #declarando a matriz Q
	R = np.zeros((m,m)) #declarando a matriz R

	for j in range(0, m):
		A_column = A[:, j] #pegando as colunas da matriz A
		V = np.zeros(n) #declarando o vetor V
		V = A_column #V igual a coluna j de A
		for i in range (0, j):
			R[i,j] = Q[:,i].dot(A_column) #fazendo o calculo do R[i,j] = coluna i de Q * coluna j de A ( i != j)
			V -= (Q[:,i].dot(A_column))*Q[:,i] #fazendo o calculo de V
		R[j,j] = np.linalg.norm(V) # R[j,j] = norma da coluna j de A (i == j)
		Q[:,j] = V/np.linalg.norm(V) #normalizando V e atribuindo a coluna j de Q

	return Q, R

def FrancisMethod(A, error):

	m = np.inf #declarando m como infinito
	Autovetores = np.eye(np.shape(A)[0]) #declarando a matriz de autovetores como uma matriz indentidade
	while m > error:
		(Q, R) = QRDecomposition(A) #fazendo a decomposicao QR de A
		A = R.dot(Q) #fazendo A = R*Q
		Autovetores = Autovetores.dot(Q) #pegando os autovetores V = Q1 * Q2 * Q3 * ...
		m = -np.inf #declarando m como menos infinito
		#pegando o maior valor da matriz A fora da diagonal principal
		for i in range (0, np.shape(A)[0]):
			for j in range (0, np.shape(A)[1]):
				if (i != j) and (m < np.abs(A[i,j])):
					m = np.abs(A[i,j])

	Autovalores = np.diag(A) #pegando a diagonal principal da matriz A

	return Autovalores, Autovetores #retornando o resultado

'''
A = np.array([[2,0,1], [0,1,0], [1,0,1]], dtype = 'double')
(Aut, Vet) = FrancisMethod(A, 0.01)
print(Aut)
'''
A = np.array([[2,1,1],[1,3,5], [1,5,14]], dtype = 'double')
(Aut, Vet) = FrancisMethod(A, 0.000001)
print('{}\n\n{}'.format(Aut, Vet))


import numpy as np
import scipy.spatial.distance

def compute_laplacian(adjacency: np.ndarray, normalize: bool):
    """ Return:
        L (n x n ndarray): combinatorial or symmetric normalized Laplacian.
    """
    D = np.diag(np.sum(adjacency, 1)) # Degree matrix
    combinatorial = D - adjacency
    if normalize:
        D_norm = np.diag(np.clip(np.sum(adjacency, 1), 1, None)**(-1/2))
        return D_norm @ combinatorial @ D_norm
    else:
        return combinatorial

def spectral_decomposition(laplacian: np.ndarray):
    """ Return:
        lamb (np.array): eigenvalues of the Laplacian
        U (np.ndarray): corresponding eigenvectors.
    """
    return np.linalg.eigh(laplacian)

def compute_number_connected_components(lamb: np.array, threshold: float):
    """ lamb: array of eigenvalues of a Laplacian
        Return:
        n_components (int): number of connected components.
    """
    return np.count_nonzero(lamb <= threshold)


#%% Modules

from data import get_mnist

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

#%% Train Three Layer (Input-Hidden-Output) Neural Network

# Nomenclature,
#
# w -> connection/link weights
# b -> bias values
# i -> input layer
# h -> hidden layer
# o -> output layer
# l -> labels

images, labels = get_mnist()  # 60000-by-784, 60000-by-1, respectively.

# Initialize input-to-hidden layer weights and set bias values to zero.
np.random.seed(0)
w_i_h = np.random.uniform( -0.5, 0.5, (20, 784) )  # 20-by-784
b_i_h = np.zeros((20, 1))  # 20-by-1

# Initialize hidden-to-output layer weights and set bias values to zero.
np.random.seed(0)
w_h_o = np.random.uniform( -0.5, 0.5, (10, 20) )  # 10-by-20
b_h_o = np.zeros((10, 1))  # 20-by-1

print( "\n\n" )

learn_rate = 0.01;  epochs = 50

nr_correct = 0;  accuracy = list()

for epoch in range(epochs):  # From 0 to (epochs - 1)

    for img, l in zip(images, labels):  # Group a row from images and labels

        img.shape += (1,)  # Make the second dimension of the 1-Tuple (i.e. 1) explicit.
        l.shape += (1,)  # Make the second dimension of the 1-Tuple (i.e. 1) explicit.

        # Forward Propagation -> Input Layer to Hidden Layer
        h_pre = b_i_h  +  w_i_h @ img
        h = 1 / (1 + np.exp(-h_pre))  # Activation

        # Forward Propagation -> Hidden Layer to Output Layer
        o_pre = b_h_o  +  w_h_o @ h
        o = 1 / (1 + np.exp(-o_pre))  # Activation

        # Compute Cost/Error/Performance Metric
        e = 1 / len(o) * np.sum( (o - l) ** 2, axis=0 )
        #
        # e -> 1-by-1, a scalar -> Average squared difference between predicted and expected output.
        # o, l -> 10-by-1#
        #
        nr_correct = nr_correct + int( np.argmax(o) == np.argmax(l) )

        # Backpropagation -> Output Layer to Hidden Layer -> The cost function derivative.
        delta_o = o - l  # 10-by-1
        #
        w_h_o = w_h_o  +  -1.0*learn_rate*delta_o @ np.transpose(h)  # 10-by-20 + (1-by-1 * 10-by-1 * 1-by-20) -> 10-by-20
        b_h_o = b_h_o  +  -1.0*learn_rate*delta_o  # 10-by-1 + (1-by-1 * 10-by-1) -> 10-by-1

        # Backpropagation -> Hidden Layer to Input Layer -> The activation function derivative.
        delta_h = np.transpose(w_h_o) @ delta_o * (h * (1 - h))  # 20-by-10 @ 10-by-1 * 20-by-1 -> 20-by-1 (@ -> matrix multiplication; * -> element-by-element multiplication)
        #
        w_i_h = w_i_h  +  -1.0*learn_rate*delta_h @ np.transpose(img)  # 20-by-784 + (1-by-1 * 20-by-1 @ 1-by-784) -> 20-by-784
        b_i_h = b_i_h  +  -1.0*learn_rate*delta_h  # 20-by-1 + (1-by-1 *20-by-1) -> 20-by-1

    # Show accuracy for this epoch.
    print( f"Epoch {epoch + 1} of {epochs} -> Accuracy: {round((nr_correct / images.shape[0]) * 100, 2)}% ({nr_correct}/{images.shape[0]})" )

    accuracy.append( nr_correct / images.shape[0] * 100 )
    nr_correct = 0  # Reset counter for next epoch.

#%% Plot Accuracy Versus Epoch

epochValues = list(range(epochs));

fig, ax = plt.subplots()
ax.plot( [x+1 for x in epochValues], accuracy)

ax.set(xlabel='Training Epoch', ylabel='Accuracy (%)', title='Accuracy Versus Training Epoch')
ax.grid()
fig.savefig('50 Epochs of Training MNIST February 14, 2021.png')
plt.show()

# https://matplotlib.org/3.1.1/gallery/lines_bars_and_markers/simple_plot.html

#%% Predict Selected Digit

# index = int(input("Enter a number (0 - 59999): "))
index = 50  # Digit 3

img = images[index]
plt.imshow( img.reshape(28, 28), cmap="Blues" )

img.shape += (1,)  # Make the second dimension of the 1-Tuple (i.e. 1) explicit.

# Forward Popagation -> Input Layer to Hidden Layer
h_pre = b_i_h  +  w_i_h @ img.reshape(784, 1)
#
# b_i_h -> Array of type float64, 20-by-1
# w_i_h -> Array of type float64, 20-by-784
# img -> Array of float32, 784-by-1
#
# 20-by-1 + 20-by-784 * 784-by-1 -> 20-by-1 + 20-by-1 -> 20-by-1
#
h = 1 / ( 1 + np.exp(-h_pre) )  # Apply activation function.

# Forward Propagation -> Hidden Layer to Output Layer
o_pre = b_h_o  +  w_h_o @ h
#
# b_h_o -> Array of type float64, 10-by-1
# w_h_o -> Array of type float64, 10-by-20
# h -> Array of type float64, 20-by-1
#
# 10-by-1 + 10-by-20 * 20-by-1 -> 10-by-1 + 10-by-1 -> 10-by-1
#
o = 1 / (1 + np.exp(-o_pre))  # Apply activation function.

plt.title( f"Predicted Digit: {o.argmax()}" ); plt.show()


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

matplotlib.rc('font', size=32)
lw = 6
s = 200

def kernel_comparison():
    fig = plt.figure()

    loc = 0.0
    scale = 3.0

    x = np.linspace(-20, 20, 1000)
    plt.plot(x, stats.norm.pdf(x, loc=loc, scale=scale), lw=lw, color='dimgrey', label='Gaussian')
    plt.plot(x, stats.cauchy.pdf(x, loc=loc, scale=scale), lw=lw, color='black', label='Cauchy')
    plt.plot(x, stats.uniform.pdf(x, loc=loc-scale, scale=loc+2*scale), lw=lw, color='crimson', label='Uniform')

    plt.legend()
    plt.title('Kernel comparison')
    plt.xticks([loc], ['y'])
    plt.yticks([])
    plt.show()

def kernel_tuning():
    y = 5.0
    u = np.array([-1.0, 0.0, 2.0, 6.0, 8.0, 10.0])
    u_alpha = 6.0 + 1

    p = 0.95
    eps = abs(u_alpha - y) / stats.norm.ppf((1+p)/2)

    fig = plt.figure()

    x = np.linspace(-5, 15, 1000)
    plt.plot(x, stats.norm.pdf(x, loc=y, scale=eps), lw=lw, color='black')

    plt.vlines(y, ymin=0.0, ymax=stats.norm.pdf(y, loc=y, scale=eps), lw=lw, color='crimson')
    plt.vlines(u_alpha, ymin=0.0, ymax=stats.norm.pdf(u_alpha, loc=y, scale=eps), lw=lw, color='crimson')
    plt.scatter(u, np.zeros(u.size), s=s, color='dimgrey', zorder=1000)
    plt.scatter(u_alpha, 0, s=s, color='crimson', zorder=1000)
    plt.scatter(y, 0, s=s, color='crimson', zorder=1000)

    shaded_x = x[(x >= y) & (x <= u_alpha)]
    plt.fill_between(shaded_x, stats.norm.pdf(shaded_x, loc=y, scale=eps), color='black', alpha=0.4, linewidth=0)

    plt.xticks([y, u_alpha], ['$y_t$', r'$u_t^{[\alpha]}$'])
    plt.yticks([])
    plt.title('Kernel tuning')
    plt.show()

if __name__ == '__main__':
    #kernel_comparison()
    kernel_tuning()


import numpy as np
import matplotlib.pyplot as plt
#Solution of tridiagonal amtrix from 2.6 Eperson "An Introduction to Numerical Methods and Analysis"
#Of the form Ax=f
#l is lower diagonal, d is diagonal and u is the upper diagonal

#n=4
#l=np.array([np.NaN,1.0,1.0,1.0])
#d=np.array([4.0,4.0,4.0,4.0])
#u=np.array([1.0,1.0,1.0,np.NaN])
#f=np.array([6.0,12.0,18.0,19.0])
#x=np.array([0.0,0.0,0.0,0.0])
#
##Elimination stage
#for i in range(1,(n)):
#    d[i] = d[i] - u[i-1] *l[i] / d[i-1]
#    f[i] = f[i] - f[i-1] *l[i] / d[i-1]
#
##backsolve stage
#x[(n-1)]= f[(n-1)]/d[(n-1)]
#for i in range((n-2),-1,-1):
#    x[i] = (f[i] - u[i] * x[i+1])/d[i]
#
#print(x)

#Calculate true values and plot
x_true=np.linspace(0,1)
y_true=(x_true)-np.sin(np.pi*x_true)

plt.plot(x_true,y_true,'b',label='True')

#Edit for given function
def f(x):
    return (np.pi**2.0)*np.sin(np.pi*x)
#Setting up the problem
alpha=0
beta=1
for m in [3,9,19]:
    h=1/(m+1)
    u=(1/(h**2))*np.ones(m-1)
    d=(1/(h**2))*(-2.0)*np.ones(m)
    l=(1/(h**2))*np.ones(m-1)
    F=np.empty(m)
    U=np.empty(m)
    x=np.arange(0,(1+h),h)

    #Creating F
    F[0]=f(x[1]) - ( alpha/(h **2) )
    F[m-1]=f(x[m-1]) - ( beta/(h **2) )
    for i in range(1,m-1):
        F[i]=f(x[i+1])

    #Solving the tridiagonal problem
    #Elimination stage
    for i in range(1,(m)):
        d[i] = d[i] - u[i-1] *l[i-1] / d[i-1]
        F[i] = F[i] - F[i-1] *l[i-1] / d[i-1]

    #backsolve stage
    U[(m-1)]= F[(m-1)]/d[(m-1)]
    for i in range((m-2),-1,-1):
        U[i] = (F[i] - u[i] * U[i+1])/d[i]

    #Insert end values
    U=np.insert(U,0,alpha)
    U=np.insert(U,m+1,beta)
    #Print answer
    #print(U)
    x_approx=np.linspace(0,1,num=m+2)

    plt.plot(x_approx,U,'o-',label=f'{h}',linewidth=0.9)
plt.legend(loc=0)
plt.xlabel('x')
plt.ylabel('u(x)')
plt.show()


import numpy as np

from zero2ml.supervised_learning._base import BaseModel
from zero2ml.utils.activation_functions import Sigmoid
from zero2ml.utils.evaluation_metrics import CrossEntropyLoss

class LogisticRegression(BaseModel):
    """
    Logistic Regression classifier.

    Parameters
    ----------
    learning_rate: scalar
        Learning rate.

    Attributes
    ----------
    X: array_like
        Training features.
    y: array_like
        Training labels.
    samples_num: scalar
        Number of training samples.
    features_num: scalar
        Number of features.
    self.W: array_like
        Weights.
    self.b: array_like
        Intercept term.
    self.training_loss: list
        List containing training loss for each iteration of model training.
    """
    def __init__(self, learning_rate=0.01):

        # Specify model type
        self.model_type = "classifier"

        # Training data
        self.X = None

        # Training targets
        self.y = None

        # Number of training samples
        self.samples_num = None

        # Number of features
        self.features_num = None

        # Weights and intercept
        self.W = None
        self.b = None

        # Sigmoid function
        self.__sigmoid = Sigmoid()

        # Learning rate
        self.learning_rate = learning_rate

        # Loss and loss function
        self.training_loss = None
        self.__loss_function = CrossEntropyLoss()

    def fit(self, X, y, iterations=5000):
        """
        Fit the logistic regression model with given training feature inputs.

        Parameters
        ----------
        X: array_like
            Training features.
        y: array_like
            Training labels.
        iterations: scalar
            Number of iterations for gradient descent to converge.
        """
        # Save X and y into model object
        self.X = X.copy()
        self.y = y.copy()

        # Calculate number of samples and features
        self.samples_num, self.features_num = self.X.shape

        # Initiate weights and intercept
        self.W = np.zeros(self.features_num)
        self.b = 0

        # Initiate loss
        self.training_loss = []

        # Gradient descent
        for iteration in range(iterations):

            # Make prediction
            prob = self.__sigmoid( np.dot(self.X, self.W) + self.b)

            # Calculate loss and save to training loss list
            self.training_loss.append( self.__loss_function(prob, self.y) )

            # Calculate gradients
            dW = 1 / self.samples_num * np.dot(self.X.T, prob - self.y)
            db = 1 / self.samples_num * np.sum(prob - self.y)

            # Update weights and intercept
            self.W -= self.learning_rate * dW
            self.b -= self.learning_rate * db

    def predict(self, X):
        """
        Predict the label(s) with given feature inputs.

        Parameters
        ----------
        X: array_like
            Training features.

        Returns
        -------
        pred: array_like
            Label predictions. Could be 0 or 1.
        """
        # Calculate probabilities
        prob = self.__sigmoid( np.dot(X, self.W) + self.b )

        # Calculate actual predictions
        pred = (prob > 0.5).astype(int)

        return pred


import numpy as np
import matplotlib.pyplot as plt

omega = 2
P = 2*np.pi/omega
dt = P/20
T = 40*P
T = P
N_t = int(round(T/dt))
t = np.linspace(0, N_t*dt, N_t+1)
print('N_t:', N_t)

u = np.zeros(N_t+1)
v = np.zeros(N_t+1)

# Initial condition
X_0 = 2
u[0] = X_0
v[0] = 0

# Step equations forward in time
for n in range(N_t):
    v[n+1] = v[n] - dt*omega**2*u[n]
    u[n+1] = u[n] + dt*v[n+1]

# Plot the last four periods to illustrate the accuracy
# in long time simulations
N4l = int(round(4*P/dt))  # No of intervals to be plotted
fig = plt.figure()
l1, l2 = plt.plot(t[-N4l:], u[-N4l:], 'b-',
                  t[-N4l:], X_0*np.cos(omega*t)[-N4l:], 'r--')
fig.legend((l1, l2), ('numerical', 'exact'), 'upper left')
plt.xlabel('t')
plt.savefig('tmp.pdf'); plt.savefig('tmp.png')
plt.show()
print('{:.16f} {:.16f}'.format(u[-1], v[-1]))


import numpy as np
import math

'''
Different permutation methods using python
'''

# Using raw mathematics
def perm(n, r):
  num = denom = 1

  if n >= 1:
    for i in range (1,n+1):
      num=num*i

  if r < n:
    for i in range (1,n-r+1):
      denom=denom*i

  return num/denom

# Using factorial
def perm_fact(n, r):
  return math.factorial(n)/math.factorial(n-r)

# Using Stirling Approximation
def perm_stir(n,r):
  def stirling(n):
      return math.sqrt(2*math.pi*n)*(n/math.e)**n
  return stirling(n)/stirling(n-r)

# Using list
def perm_list(n, r):
  num_list = []
  denom_list = []

  if n >= 1:
    for i in range (1,n+1):
      num_list.append(i)

  if r < n:
    for i in range (1,n-r+1):
      denom_list.append(i)

  new_num = [x for x in num_list if x not in denom_list]

  return np.prod(new_num)

# Using list (shortened)
def perm_list_v2(n, r):
  num_list = []
  denom_list = []

  if n >= 1:
    for i in range (n-r+1,n+1):
      num_list.append(i)

  return np.prod(num_list)


import scipy as sp
import math

#Hypothesis Testing Variables
Null_Mean = 3
Sample_Mean = 3.38
Sample_Variance = 1.769
Sample_Standard_Deviation = 5.237
Sample_Size = 50

#Finds the T value for a specific significance level for the data
def FindTValue(x, u, s, n):
    t = (x-u)/(s / math.sqrt(n))
    return abs(t)

#T-Test using sample variance
print(FindTValue(Sample_Mean, Null_Mean, Sample_Variance, Sample_Size))

#T-Test using sample deviation
print(FindTValue(Sample_Mean, Null_Mean, Sample_Standard_Deviation, Sample_Size))


import numpy as np

def pei_fib(n, ta, tb, a, b):
    if n == 0:
        return tb
    if n & 1:
        return pei_fib(n / 2, a * ta + b * tb, b * ta + tb * (a - b), a * a + b * b, b * (2 * a - b))
    return pei_fib(n / 2, ta, tb, a * a + b * b, b * (2 * a - b))

# if number of bits is odd, we multiply a
def q_pow(a, b):
    t = 1
    while b > 0:
        if b & 1:
            t *= a
        a = a * a
        b /= 2
    return t

def yche_pow(a, b):
    if b == 0:
        return 1
    if b == 1:
        return a
    else:
        return yche_pow(a, b / 2) * yche_pow(a, (b + 1) / 2)

def yche_matrix_pow(a, b):
    if b == 1:
        return a
    else:
        return np.dot(yche_pow(a, b / 2), yche_pow(a, (b + 1) / 2))

def fib(n):
    primitive_matrix = np.matrix([[1, 1], [1, 0]])
    if n < 2:
        return n
    else:
        return yche_matrix_pow(primitive_matrix, n - 1).item(0, 0)

def naive_fib(n):
    if n < 2:
        return n
    else:
        return naive_fib(n - 1) + naive_fib(n - 2)

def fib_mat_pow(pow_num, idx):
    if pow_num < 2:
        return 1
    else:
        a = fib_mat_pow(pow_num / 2, 0)
        b = fib_mat_pow(pow_num / 2, 1)
        a_plus = fib_mat_pow((pow_num + 1) / 2, 0)
        b_plus = fib_mat_pow((pow_num + 1) / 2, 1)
        if idx < 1:
            return a * a_plus + b * b_plus
        else:
            return a * b_plus + b * (a_plus - b_plus)

def fast_fib(idx):
    if idx < 2:
        return idx
    else:
        return fib_mat_pow(idx - 1, 0)

print q_pow(2, 4)
print yche_pow(2, 4)
print yche_pow(2, 5)
print yche_pow(2, 0)

print fib(10)
print naive_fib(10)
print 'fib demo:'
# for i in range(12):
#     print fast_fib(i),
# print fast_fib(1000)pei_fib
#
# print fib(1000000)

# print pei_fib(1000000,1,1,1,1)
print yche_matrix_pow([[1,1],[1,0]],4)


import numpy as np
from scipy import stats

def kmeans(X, n, n_iter=100, centroids=None):
    """
    simple k-means implemenmtation

    Parameters:
    -----------
    X: array (n_samples, n_dim)
        the data
    n : int
        number of clusters
    n_iter : int
        number of iterations
    centroids : array (optional)

    Returns:
    --------

    centroids : array
    labels : array
    """

    def assign(centroids):
        dist = np.average(np.square(X[:, :, np.newaxis] - centroids.T), axis=1)
        return np.argmin(dist, axis=1)

    def get_centroids(labels):
        centroids = []
        for i in range(np.max(labels)+1):
            centroids.append(np.average(X[labels==i], axis=0))
        return np.stack(centroids)

    if centroids is None:
        # start with random seed
        centroids = np.random.rand(n, X.shape[1])
        # scale to roughly match the data
        centroids *= np.std(X, axis=0)
        centroids += np.mean(X, axis=0)

    # iterate
    for i in range(n_iter):
        labels = assign(centroids)
        centroids = get_centroids(labels)

    return centroids, labels

def gmm(X, n, n_iter=100, mus=None, covs=None):
    """
    simple GMM implemenmtation (2d right now)

    Parameters:
    -----------
    X: array (n_samples, n_dim)
        the data
    n : int
        number of gaussians
    n_iter : int
        number of iterations
    mus : array (optional)
    covs = array (optional)

    Returns:
    --------
    mus : array
        mean values
    covs : array
        covariances
    exps : array
        probabilities
    """

    def E(mus, covs):

        probs = []
        exps = []

        for i in range(n):
            probs.append(stats.multivariate_normal(mus[i], covs[i]).pdf(X))

        probs = np.array(probs)
        tot_prob = np.sum(probs, axis=0)

        for i in range(n):
            exps.append(probs[i] / tot_prob)

        return np.nan_to_num(exps)

    def M(exps):

        mus = []
        covs = []

        for i in range(n):
            mus.append(np.average(X, weights=exps[i], axis=0))
            covs.append(np.cov(X.T, aweights=exps[i]))

        return mus, covs

    if mus is None:
        std = np.std(X, axis=0)
        mus = np.random.rand(n, X.shape[1])
        # scale to roughly match the data
        mus *= std
        mus += np.mean(X, axis=0)
        # some random covariances
        covs = np.random.rand(n, X.shape[1], X.shape[1])
        covs = covs @ np.swapaxes(covs, 1, 2)

    for i in range(n_iter):
        exps = E(mus, covs)
        mus, covs = M(exps)

    return mus, covs, np.array(E(mus, covs)).T


#!/usr/bin/env python

# see https://medium.com/@dhwajraj/python-regression-analysis-part-4-multiple-linear-regression-ed09a0c31c74

from pandas.core import datetools
import numpy as np
import statsmodels.api as sm

import pandas as pd
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import statsmodels.formula.api as smf

X= [[150,100],[159,200],[170,350],[175,400],[179,500],[180,180],[189,159],[199,110],[199,400],[199,230],[235,120],[239,340],[239,360],[249,145],[249,400]]

Y= [0.73,1.39,2.03,1.45,1.82,1.32,0.83,0.53,1.95,1.27,0.49,1.03,1.24,0.55,1.3]

# perform linear regression
X_1=sm.add_constant(X)
results=sm.OLS(Y,X_1).fit()

# regression coefficients
# Y= c + a.X1 + b.X2
# c=1.63384178, a=-0.00637932 and b=0.00316077
print(results.params)

# now using pandas
df2=pd.DataFrame(X,columns=['Price','AdSpends'])
df2['Sales']=pd.Series(Y)

# We have created the DataFrame with our input data. And now in the steps below, we will invoke ols method of formula api
model = smf.ols(formula='Sales ~ Price + AdSpends', data=df2)
results_formula = model.fit()
print(results_formula.params)

x_surf, y_surf = np.meshgrid(np.linspace(df2.Price.min(), df2.Price.max(), 100),np.linspace(df2.AdSpends.min(), df2.AdSpends.max(), 100))
onlyX = pd.DataFrame({'Price': x_surf.ravel(), 'AdSpends': y_surf.ravel()})
fittedY=results_formula.predict(exog=onlyX)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(df2['Price'],df2['AdSpends'],df2['Sales'],c='blue', marker='o', alpha=0.5)
ax.plot_surface(x_surf,y_surf,fittedY.reshape(x_surf.shape), color='None', alpha=0.01)
ax.set_xlabel('Price')
ax.set_ylabel('AdSpends')
ax.set_zlabel('Sales')
#plt.show()

X_new= [[180,100],[199,200],[170,370],[195,400],[279,400],[280,280]]
df2_new= pd.DataFrame(X_new,columns=['Price','AdSpends'])
results_new = results_formula.predict(df2_new)
print(results_new)


# Computational Linear Algebra Ep#3 Uppper Triangle Algorithm
# By: Nick Space Cowboy

import numpy as np

class Cowboy_Lin_Alg(object):
	def solve_utri(self, Utri, b):
		n = len(Utri) # row dimension of the Utri matrix
		x = np.zeros_like(b, dtype=float)
		for i in range(n - 1, -1, -1):	# loop to iterate through row index
			x[i] += b[i] / Utri[i,i]
			for j in range(n-1, i, -1):	# loop to iterate through the off diagonal Sum part
				x[i] += (- (Utri[i, j] * x[j])) / Utri[i,i]
		return x

if __name__ == "__main__":
	cla = Cowboy_Lin_Alg()
	A = np.array(np.random.randint (0,100,(4,4)))
	U = np.triu(A)
	print("U: " + str(U))
	b = np.array(np.random.randint(0, 100, (4,1)))
	print("b:" + str(b))
	x = cla.solve_utri(U,b)
	print("x: " + str(x))
	print("Check: " + str(U.dot(x)))


import numpy as np

MAX_ITERATIONS = 50
TOLERANCE = 0.5e-10

def bisection(func, lower, upper, tolerance=TOLERANCE, max_iter=MAX_ITERATIONS):
    if lower > upper:
        lower, upper = upper ,lower

	midpoints = np.empty(max_iter)
    iteration = 0

    while iteration < max_iter:
    	midpoints[iteration] = lower + (upper - lower) / 2.0
    	feval = func(midpoints[iteration])

        if abs(feval) < tolerance and abs(upper - lower) < 2.0 * tolerance:
            break
        elif feval * func(lower) < 0.0:
            upper = midpoints[iteration]
        else:
            lower = midpoints[iteration]

    midpoints = midpoints[:midpoints]
    errors = np.abs(midpoints[1:] - midpoints[:-1])
    return midpoints, errors, iterations

def fixed_point(func, guess, tolerance=TOLERANCE, max_iter=MAX_ITERATIONS):
    fixed_points = np.empty(max_iter + 1)
    fixed_points[0] = guess
    iteration = 1

    while iteration < max_iter:
        fixed_points[iteration] = func(fixed_points[iteration - 1])
        if np.abs(fixed_points[iteration] - fixed_points[iteration-1]) < tolerance:
            break
        iteration += 1

    fixed_points = fixed_points[:iterations + 1]
    errors = np.abs(fixed_points[1:] - fixed_points[:-1])
    return fixed_points, errors, iterations

def newton(f, fprime, guess, tolerance=TOLERANCE, max_iter=MAX_ITERATIONS):
	def func(x):
		return x - f(x) / fprime(x)
	return fixed_point(func, guess, tolerance, max_iter)


import numpy as np
import modern_robotics as mr
import math

print("Ex 1: What torques must be aplied at each of the joints?")
Fs = np.array([0, 0, 0, 2, 0, 0]) # tip generates a wrench in x direction
theta = np.array([0, math.pi/4, 0])
Ss = np.array([[0,  0,  0],
               [0,  0,  0],
               [1,  1,  1],
               [0,  0,  0],
               [0, -1, -2],
               [0,  0,  0]])
Js = mr.JacobianSpace(Ss, theta)
Ts = np.around(np.dot(Js.T, Fs), decimals=2)
print(Ts)
# [0,0,1.41]

print("Ex 2: What are the torques at each of the joints")
Fb = np.array([0, 0, 10, 10, 10, 0])
theta = np.array([0, 0, math.pi/2, -math.pi/2])
Bs = np.array([[0, 0, 0, 0],
               [0, 0, 0, 0],
               [1, 1, 1, 1],
               [0, 0, 0, 0],
               [4, 3, 2, 1],
               [0, 0, 0, 0]])
Jb = mr.JacobianBody(Bs, theta)
Tb = np.around(np.dot(Jb.T, Fb), decimals=2)
print(Tb)
# [30,20,10,20]

print("Ex 3: Use JacobianSpace to calculate the 6x3 space Jacobian")
theta = np.array([math.pi/2, math.pi/2, 1])
Ss = np.array([[0, 1, 0],
              [0, 0, 0],
              [1, 0, 0],
              [0, 0, 0],
              [0, 2, 1],
              [0, 0, 0]])
Js = np.around(mr.JacobianSpace(Ss, theta), decimals=2)
print(Js)
# [[0,0,0],[0,1,0],[1,0,0],[0,-2,-0],[0,0,0],[0,0,1]]

print("Ex 4: Use JacobianBody to calculate the 6x3 body Jacobian")
theta = np.array([math.pi/2, math.pi/2, 1])
Bs = np.array([[0, -1, 0],
              [1,  0, 0],
              [0,  0, 0],
              [3,  0, 0],
              [0,  3, 0],
              [0,  0, 1]])
Jb = np.around(mr.JacobianBody(Bs, theta), decimals=2)
print(Jb)
# [[0,-1,0],[0,0,0],[1,0,0],[0,0,0],[0,4,0],[0,0,1]]

print("Ex 5: Calculate the directions and lengths of the principal semi-axes of three-dimensional linear velocity manipulability ellipsoid")

Jb = np.array([[     0,     -1,     0,      0,    -1,     0, 0],
               [     0,      0,     1,      0,     0,     1, 0],
               [     1,      0,     0,      1,     0,     0, 1],
               [-0.105,      0, 0.006, -0.045,     0, 0.006, 0],
               [-0.889,  0.006,     0, -0.844, 0.006,     0, 0],
               [     0, -0.105, 0.889,      0,     0,     0, 0]])
Jv = Jb[3:] # extract linear velocity
A = np.dot(Jv, Jv.T)
w, v = np.linalg.eig(A)
max_id = np.where(w == np.amax(w))[0][0]
vec_prin_axis = np.around(v[max_id], decimals=2)
print(vec_prin_axis)
# [0.09,1,-0]

print("Ex 6: gi the length of the longest principal semi-axis of the previus exercise")
longest = np.around(math.sqrt(w[max_id]), decimals=2)
print(longest)
# 1.23


# -*- coding: utf-8 -*-
"""
Created on Sat Apr 11 11:13:53 2020

@author: login
"""

#Import Libraries
import pandas as pd
import matplotlib.pyplot as plt
import pylab as lp
import numpy as np
from sklearn import linear_model

#File Address
file_Address="F:\\KamyabJawan Program\\Machine Learning\\Practice\\Files\\FuelConsumption.csv"
#Reading File
df=pd.read_csv(file_Address)
#Printing Files Rows
print(df.head(10))
#Lets Select Some Features
some_features=df[['ENGINESIZE','CYLINDERS','FUELCONSUMPTION_CITY',
                  'FUELCONSUMPTION_HWY','FUELCONSUMPTION_COMB','CO2EMISSIONS']]
#Printing Rows of Some Features
print(some_features.head(10))

"""
#Ploting CO2Emission vs Engine Size
plt.scatter(df[["ENGINESIZE"]], df[["CO2EMISSIONS"]], color="blue")
plt.xlabel("Engine Size")
plt.ylabel("CO2 Emission")
plt.title("CO2 Emission vs Engine Size")
"""

#Create Train and Test Data sets
msk=np.random.rand(len(df))<0.8
train=some_features[msk]
test=some_features[~msk]

#Ploting Train Data Distribution
plt.scatter(train[["ENGINESIZE"]], train[["CO2EMISSIONS"]], color="blue")
plt.xlabel("Engine Size")
plt.ylabel("CO2 Emission")
plt.title("Train Data Distribution")

#Ploting Test Data Distribution
plt.scatter(test[["ENGINESIZE"]], test[["CO2EMISSIONS"]], color="y")
plt.xlabel("Engine Size")
plt.ylabel("CO2 Emission")
plt.title("Test Data Distribution")

#Creating Multiple Linear Regression Model
regr=linear_model.LinearRegression()
x=np.asanyarray(train[["ENGINESIZE","CYLINDERS","FUELCONSUMPTION_COMB"]])
y=np.asanyarray(train.CO2EMISSIONS)
regr.fit(x, y)
#Printing Coefficients
print("Coefficeints: ",regr.coef_)
print("Intercept: ",regr.intercept_)

#Prediction (Testing Data Set to predict Output)
y_hat=regr.predict(test[["ENGINESIZE","CYLINDERS","FUELCONSUMPTION_COMB"]])
x=np.asanyarray(test[["ENGINESIZE","CYLINDERS","FUELCONSUMPTION_COMB"]])
y=np.asanyarray(test[["CO2EMISSIONS"]])
#Printing Residual Sum of Square
print("Residual Sum of Square %.2f"% np.mean(y_hat-y)**2)
#Explained Variace Score. 1 is Best Prediction
print("Variance Score: %.2f"% regr.score(x, y))

"""
𝚎𝚡𝚙𝚕𝚊𝚒𝚗𝚎𝚍𝚅𝚊𝚛𝚒𝚊𝚗𝚌𝚎(𝑦,𝑦̂ )=1−(𝑉𝑎𝑟{𝑦−𝑦̂ }/𝑉𝑎𝑟{𝑦})
"""


#Import the required libraries and the sigmoid function(expit)
from scipy.special import expit
import numpy as np
import math

#Import our data
data = np.array([[1,0],[2,0],[3,0],[4,1],[5,1],[6,1],[7,1]])

class Classification(object):
    #Setting some of our parameters
    def __init__(self, alpha, num_parameter, data):
        self.alpha = alpha
        self.num_parameter = np.zeros((num_parameter, 1))
        self.data = data
        self.m = 1 / len(data)
    #This method cleans our data and make it ready for the training
    def cleanData(self):
        ones = np.ones((len(data),1))
        x = np.concatenate((ones, data[:,0].reshape(-1,1)), axis=1)
        y = data[:,1].reshape(-1,1)
        return (x,y)
    #We can train our model using gradient descent
    def train(self,x, y):
        z = x @ self.num_parameter
        h = expit(z).reshape((-1,1))
        j = self.m * ((-y.T @ np.log(h)) - (((1 - y).T) @ (np.log(1-h))))
        dj = (self.alpha/self.m) * (x.T @ (h - y))
        self.num_parameter = self.num_parameter - dj
    #We can query our model for a specific answer
    def query(self, x):
        answer = x @ self.num_parameter
        answer = expit(answer)
        return(answer)

#Exaple use of a model
model = Classification(0.01, 2, data)
#Cleaning the data
x,y = model.cleanData()
#Training loop
iteration = 0
while iteration < 1000:
    iteration += 1
    model.train(x,y)

#Asking an answer for a specific problem
answer = model.query([-0,-0])


import numpy as np
# from math import gamma
import matplotlib.pyplot as plt
from scipy.special import gamma
from scipy import stats
import numpy as np
from scipy.optimize import minimize
import matplotlib.pyplot as plt
from scipy.stats import beta

data = np.random.normal(0,2,size=30)
def gaussian(params):
    mean = params[0]
    sd = params[1]
    # Calculate negative log likelihood
    nll = -np.sum(stats.norm.logpdf(data, loc=mean, scale=sd))
    return nll

initParams = [1, 1]

results = minimize(gaussian, initParams, method='L-BFGS-B')
print(results.x)

def student(params):
    mean = params[0]
    sd = params[1]
    df = params[2]
    # Calculate negative log likelihood
    nll = -np.sum(stats.t.logpdf(data, df=df, loc=mean, scale=sd))
    return nll

initParams = [1, 1, 1]

results = minimize(student, initParams, method='L-BFGS-B')
print(results.x)

from scipy.stats import norm, t
x = np.arange (-10, 10, 0.01)
y = norm.pdf(x,0.32852566,2.0401025)
plt.plot(x,y, label="Gaussian")
y = t.pdf(x, loc=0.32932744, scale=2.01161381, df=70.2)
plt.plot(x,y, '--', label="Students' t")
plt.title("Compare Distributions")
plt.legend()

data = np.append(data,8)
data = np.append(data,9)
data = np.append(data,10)

def gaussian(params):
    mean = params[0]
    sd = params[1]
    # Calculate negative log likelihood
    nll = -np.sum(stats.norm.logpdf(data, loc=mean, scale=sd))
    return nll

initParams = [1, 1]

results = minimize(gaussian, initParams, method='L-BFGS-B')
print(results.x)

def student(params):
    mean = params[0]
    sd = params[1]
    df = params[2]
    # Calculate negative log likelihood
    nll = -np.sum(stats.t.logpdf(data, df=df, loc=mean, scale=sd))
    return nll

initParams = [1, 1, 1]

results = minimize(student, initParams, method='L-BFGS-B')
print(results.x)

from scipy.stats import norm, t
x = np.arange (-10, 10, 0.01)
y = norm.pdf(x,1.11684099, 3.17154201)
plt.plot(x,y, label="Gaussian")
y = t.pdf(x, loc=0.44950388, scale=1.52333538, df=1.70111095)
plt.plot(x,y, '--', label="Students' t")
plt.scatter(data,np.zeros(len(data)), label="Data")
plt.title("Compare Distributions")
plt.legend()


##
#   Copyright: Copyright (c) MOSEK ApS, Denmark. All rights reserved.
#
#   File:      gp1.py
#
#   Purpose:   Demonstrates how to solve a simple Geometric Program (GP)
#              cast into conic form with exponential cones and log-sum-exp.
#
#              Example from
#                https://gpkit.readthedocs.io/en/latest/examples.html#maximizing-the-volume-of-a-box
#
from numpy import log, exp, array
from mosek.fusion import *
import sys

# Models log(sum(exp(Ax+b))) <= 0.
# Each row of [A b] describes one of the exp-terms
def logsumexp(M, A, x, b):
    k = int(A.shape[0])
    u = M.variable(k)
    M.constraint(Expr.sum(u), Domain.equalsTo(1.0))
    M.constraint(Expr.hstack(u,
                             Expr.constTerm(k, 1.0),
                             Expr.add(Expr.mul(A, x), b)), Domain.inPExpCone())

# maximize     h*w*d
# subjecto to  2*(h*w + h*d) <= Awall
#              w*d <= Afloor
#              alpha <= h/w <= beta
#              gamma <= d/w <= delta
#
# Variable substitutions:  h = exp(x), w = exp(y), d = exp(z).
#
# maximize     x+y+z
# subject      log( exp(x+y+log(2/Awall)) + exp(x+z+log(2/Awall)) ) <= 0
#                              y+z <= log(Afloor)
#              log( alpha ) <= x-y <= log( beta )
#              log( gamma ) <= z-y <= log( delta )
def max_volume_box(Aw, Af, alpha, beta, gamma, delta):
    with Model('max_vol_box') as M:
        xyz = M.variable(3)
        M.objective('Objective', ObjectiveSense.Maximize, Expr.sum(xyz))

        logsumexp(M, array([[1,1,0],[1,0,1]]), xyz, array([log(2.0/Aw), log(2.0/Aw)]))

        M.constraint(Expr.dot([0, 1, 1], xyz), Domain.lessThan(log(Af)))
        M.constraint(Expr.dot([1,-1, 0], xyz), Domain.inRange(log(alpha),log(beta)))
        M.constraint(Expr.dot([0,-1, 1], xyz), Domain.inRange(log(gamma),log(delta)))

        M.setLogHandler(sys.stdout)
        M.solve()

        return exp(xyz.level())

Aw, Af, alpha, beta, gamma, delta = 200.0, 50.0, 2.0, 10.0, 2.0, 10.0
h,w,d = max_volume_box(Aw, Af, alpha, beta, gamma, delta)
print("h={0:.3f}, w={1:.3f}, d={2:.3f}".format(h, w, d))


import matplotlib.pyplot as plt
from matplotlib import style
import numpy as np

style.use('classic')

r = np.linspace(0.01, 100.0, 100000)

def E_LJ(r, epsilon, sigma):
    return 4 * epsilon * ((sigma / r) ** 12 - (sigma / r) ** 6)

def F_LJ(r, epsilon, sigma):
    return 24 * epsilon * ((sigma / r) ** 6 - 2 * (sigma / r) ** 12)

epsilon = 30
sigma = 30
r0 = sigma * 2 ** (1 / 6)

plt.figure(facecolor='white', figsize=(6, 6))
plt.title(r"$Lennard-Jones\ Potential$", fontsize=16)
plt.plot(r, E_LJ(r, epsilon, sigma), color='red', label="$LJ\ potential$")
plt.plot(r, F_LJ(r, epsilon, sigma), color='blue', label=r"$LJ\ force$")
plt.scatter(r0, 0, color='black', marker='o', s=30)
plt.xlim([0.0, 3*sigma])
plt.ylim([-1.5*epsilon, 1.5*epsilon])
plt.xlabel(r"$r$", fontsize=12)
plt.ylabel(r"$E_{LJ}(r)$", fontsize=12)
plt.axvline(r0, color='black', linestyle='--', linewidth=1.2)
plt.axhline(0, color='black', linestyle='--', linewidth=1.2)
plt.grid(color='grey', linestyle='solid', linewidth=0.3)
plt.legend()
plt.show()
# plt.savefig('mm.png', dpi=300)


from sympy import diag, sin, symbols

from einsteinpy.symbolic import constants
from einsteinpy.symbolic.metric import MetricTensor

def MinkowskiCartesian(c=constants.c):
    """
    Minkowski(flat) space-time in Cartesian coordinates. Space-time without any curvature or matter.

    Parameters
    ----------
    c : ~sympy.core.basic.Basic or int or float
        Any value to assign to speed of light. Defaults to 'c'.

    """
    coords = symbols("t x y z")
    metric = diag(-1, 1 / (c ** 2), 1 / (c ** 2), 1 / (c ** 2)).tolist()
    return MetricTensor(metric, coords, "ll", name="MinkowskiMetric")

Minkowski = MinkowskiCartesian

def MinkowskiPolar(c=constants.c):
    """
    Minkowski(flat) space-time in Polar coordinates. Space-time without any curvature or matter.

    Parameters
    ----------
    c : ~sympy.core.basic.Basic or int or float
        Any value to assign to speed of light. Defaults to 'c'.

    """
    coords = symbols("t r theta phi")
    t, r, th, ph = coords
    c2 = c ** 2
    metric = diag(-1, 1 / c2, (r ** 2) / c2, (r ** 2 * sin(th) ** 2) / c2).tolist()
    return MetricTensor(metric, coords, "ll", name="MinkowskiMetricPolar")


from hetdesrun.component.registration import register
from hetdesrun.datatypes import DataType

import datetime
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression

def rul_regression_linear(
    train_series: pd.Series,
    limit: float,
    num_pred_series_future_days: int,
    pred_series_frequency: str = "min",
):
    """Linear Regression for univariate Remaining Useful Life (RUL) prediction

    train-series: pd.Series with datetime index and float values. The input data to train
        the regression model.
    limit: the limit value against which rul should be made.

    returns: Tuple (pred_y, timestamp_limit_reached, intercept, slope)
    """

    train_x_vals = pd.Series(train_series.index, index=train_series.index)

    min_timestamp, max_timestamp = train_x_vals.min(), train_x_vals.max()

    train_x_diffs = (
        train_x_vals - min_timestamp
    )  # time_deltas to chronologically first timestamp

    lg = LinearRegression()
    lg.fit(
        train_x_diffs.dt.total_seconds().values.reshape(-1, 1),
        train_series.values.reshape(-1, 1),
    )
    intercept, slope = lg.intercept_[0], lg.coef_[0]

    max_timestamp_preds = max_timestamp + datetime.timedelta(
        days=num_pred_series_future_days
    )
    pred_x_vals = pd.date_range(
        start=min_timestamp, end=max_timestamp_preds, freq=pred_series_frequency
    )
    pred_x_diffs = pd.Series(pred_x_vals - min_timestamp)
    pred_y = pd.Series(
        lg.predict(pred_x_diffs.dt.total_seconds().values.reshape(-1, 1)).reshape(
            1, -1
        )[0],
        index=pred_x_vals,
    )

    if slope == 0:
        limit_reached_secs_from_min_timestamp = None
    else:

        limit_reached_secs_from_min_timestamp = ((limit - intercept) / slope)[0]

    if limit_reached_secs_from_min_timestamp is not None:
        timestamp_limit_reached = min_timestamp + datetime.timedelta(
            seconds=limit_reached_secs_from_min_timestamp
        )
    else:
        timestamp_limit_reached = pd.NaT
    return pred_y, timestamp_limit_reached, intercept, slope

# ***** DO NOT EDIT LINES BELOW *****
# These lines may be overwritten if input/output changes.
@register(
    inputs={
        "num_pred_series_future_days": DataType.Integer,
        "pred_series_frequency": DataType.String,
        "timeseries": DataType.Series,
        "limit": DataType.Float,
    },
    outputs={
        "intercept": DataType.Float,
        "limit_violation_prediction_timestamp": DataType.String,
        "pred_series": DataType.Series,
        "slope": DataType.Float,
    },
)
def main(*, num_pred_series_future_days, pred_series_frequency, timeseries, limit):
    """entrypoint function for this component"""
    # ***** DO NOT EDIT LINES ABOVE *****
    # write your function code here.
    pred_y, timestamp_limit_reached, intercept, slope = rul_regression_linear(
        timeseries, limit, num_pred_series_future_days, pred_series_frequency
    )
    return {
        "pred_series": pred_y,
        "intercept": intercept,
        "slope": slope,
        "limit_violation_prediction_timestamp": timestamp_limit_reached.to_pydatetime().isoformat()
        if timestamp_limit_reached != pd.NaT
        else None,
    }


"""
Solve some matrix operations
"""
from numpy import array

from ace.solvers import gauss_jacobi, gauss_seidel, lu_decomposition

def part_a(a, b):
    """
    Solve using LU decomposition
    """
    x = lu_decomposition(a, b)
    print x
    return x

def part_b(a, b, x_exact):
    """
    Solve using Gauss-Jacobi
    """
    for iterations in xrange(1, 100):
        x = gauss_jacobi(a, b, iterations)
        if _check_for_significant_digits(x, x_exact, 4):
            print iterations, x
            return

def part_c(a, b, x_exact):
    """
    Solve using Gauss-Seidel
    """
    for iterations in xrange(1, 100):
        x = gauss_seidel(a, b, iterations)
        if _check_for_significant_digits(x, x_exact, 4):
            print iterations, x
            return

def _check_for_significant_digits(x, x_exact, desired_digits):
    number_validated = 0
    for i, xi in enumerate(x_exact):
        comparator = int(xi * 10 ** desired_digits)
        if int(x[i] * 10 ** desired_digits) == comparator:
            number_validated += 1
    if number_validated == len(x_exact):
        return True
    return False

if __name__ == "__main__":
    a = array([[54, 14, -11, 2],
               [14, 50, -4, 29],
               [-11, -4, 55, 22],
               [2, 29, 22, 95]])
    b = array([1, 1, 1, 1])
    x_exact = part_a(a, b)
    part_b(a, b, x_exact)
    part_c(a, b, x_exact)


## Kernel Density Estimation

import numpy as np
from scipy import stats
import statsmodels.api as sm
import matplotlib.pyplot as plt
from statsmodels.distributions.mixture_rvs import mixture_rvs

##### A univariate example.

np.random.seed(12345)

obs_dist1 = mixture_rvs([.25,.75], size=10000, dist=[stats.norm, stats.norm],
                kwargs = (dict(loc=-1,scale=.5),dict(loc=1,scale=.5)))

kde = sm.nonparametric.KDEUnivariate(obs_dist1)
kde.fit()

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
ax.hist(obs_dist1, bins=50, normed=True, color='red')
ax.plot(kde.support, kde.density, lw=2, color='black');

obs_dist2 = mixture_rvs([.25,.75], size=10000, dist=[stats.norm, stats.beta],
            kwargs = (dict(loc=-1,scale=.5),dict(loc=1,scale=1,args=(1,.5))))

kde2 = sm.nonparametric.KDEUnivariate(obs_dist2)
kde2.fit()

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
ax.hist(obs_dist2, bins=50, normed=True, color='red')
ax.plot(kde2.support, kde2.density, lw=2, color='black');

# The fitted KDE object is a full non-parametric distribution.

obs_dist3 = mixture_rvs([.25,.75], size=1000, dist=[stats.norm, stats.norm],
                kwargs = (dict(loc=-1,scale=.5),dict(loc=1,scale=.5)))
kde3 = sm.nonparametric.KDEUnivariate(obs_dist3)
kde3.fit()

kde3.entropy

kde3.evaluate(-1)

##### CDF

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
ax.plot(kde3.support, kde3.cdf);

##### Cumulative Hazard Function

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
ax.plot(kde3.support, kde3.cumhazard);

##### Inverse CDF

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
ax.plot(kde3.support, kde3.icdf);

##### Survival Function

fig = plt.figure(figsize=(12,8))
ax = fig.add_subplot(111)
ax.plot(kde3.support, kde3.sf);

import numpy,from scipy,import statsmodels,from statsmodels


import numpy as np
import matplotlib.pyplot as plt
import Chapter5.Sigmoid as sigmoid
import Chapter5.Tanh as tanh
import Chapter5.Relu as relu
import Chapter5.Linear as linear
import Chapter5.LossFunction as lf

# from pprint import pprint
# from sklearn import datasets
plt.style.use('fivethirtyeight')

def graphTransferFunction(function):
    x = np.arange(-2.0, 2.0, 0.01)
    plt.figure(figsize=(18, 8))
    ax = plt.subplot(121)
    ax.set_title(function.__name__)
    plt.plot(x, function.getTransferFunction(x))
    ax = plt.subplot(122)
    ax.set_title('Derivative of ' + function.__name__)
    plt.plot(x, function.getTransferFunctionDerivative(x))
    plt.show()

graphTransferFunction(sigmoid.Sigmoid)

ws = np.arange(-1.0, 1.0, 0.2)
bs = np.arange(-2.0, 2.0, 0.2)
xs = np.arange(-4.0, 4.0, 0.1)
plt.figure(figsize=(20, 10))
ax = plt.subplot(121)
for i in ws:
    plt.plot(xs, sigmoid.Sigmoid.getTransferFunction(i * xs), label=str(i))
ax.set_title('Sigmoid variants in w')
plt.legend(loc='upper left')

ax = plt.subplot(122)
for i in bs:
    plt.plot(xs, sigmoid.Sigmoid.getTransferFunction(i + xs), label=str(i))
ax.set_title('Sigmoid variants in b')
plt.legend(loc='upper left')
plt.show()

graphTransferFunction(tanh.Tanh)

graphTransferFunction(relu.Relu)

graphTransferFunction(linear.Linear)

# L1 vs L2 loss functions
sampley_ = np.array([.1, .2, .3, -.4, -1, -3, 6, 3])
sampley = np.array([.2, -.2, .6, .10, 2, -1, 3, -1])

ax.set_title('Sigmoid variants in b')
plt.figure(figsize=(10, 10))
ax = plt.subplot()
plt.plot(sampley_ - sampley, label='L1')
plt.plot(np.power((sampley_ - sampley), 2), label="L2")
ax.set_title('L1 vs L2 initial comparison')
plt.legend(loc='best')
plt.show()

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

# output dataset
y = np.array([[0, 0, 1, 1]])

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

errorlist=np.empty(3)
weighthistory=np.array(0)
resultshistory=np.array(0)

for iter in range(100):
    # forward propagation
    l0 = X
    l1 = sigmoid.Sigmoid.getTransferFunction(np.dot(l0, W))
    resultshistory = np.append(resultshistory, l1)

    # Error calculation
    l1_error = y - l1
    errorlist = np.append(errorlist, l1_error)

    # Back propagation 1: Get the deltas
    l1_delta = l1_error * sigmoid.Sigmoid.getTransferFunctionDerivative(l1)

    # update weights
    W = W + np.dot(l0.T, l1_delta)
    weighthistory = np.append(weighthistory, W)

print(l1)

# To better understand the process, let's have a look at how the parameters change over time. First, let's graph the
# neuron weights. As you can see, they go from a random state to accepting the whole values of the first column
# (which is always right), going to almost 0 for the second column (which is right 50% of the time),
# and then going to -2 for the third (mainly because it has to trigger 0 in the first two elements of the table):

plt.figure(figsize=(20, 20))
print(W)
plt.imshow(np.reshape(weighthistory[1:], (-1, 3))[:40], cmap=plt.cm.gray_r, interpolation='nearest')
plt.show()

# Let's also review how our solutions evolved (during the first 40 iterations) until we reached the last iteration;
# we can clearly see the convergence to the ideal values:

plt.figure(figsize=(20, 20))
plt.imshow(np.reshape(resultshistory[1:], (-1, 4))[:40], cmap=plt.cm.gray_r, interpolation='nearest')
plt.show()

# We can see how the error evolves and tends to be zero through the different epochs. In this case, we can observe
# that it swings from negative to positive, which is possible because we first used an L1 error function:
plt.figure(figsize=(10, 10))
plt.plot(errorlist)
plt.show()


import Expr
from Expr import V
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

#Checking code
def check_true(x, msg=None):
    if not x:
        if msg is None:
            print("Error: assertion is false")
        else:
            print("Error in", msg, ": false")
    assert x
    print("Success")

def fit(loss, points, params, delta=0.0001, num_iterations=5000):
    """
    @param loss: expression giving the loss as a function of variables and parameters.
    @param points: list of (x, y) values to which we have to fit the expression.
    @param params: list of parameters whose value we can tune.
    @param delta: learning step size.
    @param num_iterations: number of learning iterations.
    """
    for iteration_idx in range(num_iterations):
        loss.zero_gradient()
        total_loss = 0.
        for x, y in points:
            # Here, you have to assign values to vx and vy, forward propagate,
            # then backpropagate the gradient.  4 lines are enough; it is not
            # a trick question.
            vx.assign(x)
            vy.assign(y)
            loss.eval()
            loss.compute_gradient()
            total_loss += loss.eval()
        if (iteration_idx + 1) % 100 == 0:
            print("Loss:", total_loss)
        for vv in params:
            vv.assign(vv.eval() - delta * vv.gradient)
    return total_loss

def plot_points(points):
    """Plots points"""
    fig, ax = plt.subplots()
    xs, ys = zip(*points)
    ax.plot(xs, ys, 'r+')
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()

def plot_points_and_y(points, vx, oy):
    """Plots points and a line"""
    fig, ax = plt.subplots()
    xs, ys = zip(*points)
    ax.plot(xs, ys, 'r+')
    x_min, x_max = np.min(xs), np.max(xs)
    step = (x_max - x_min) / 100
    x_list = list(np.arange(x_min, x_max + step, step))
    y_list = []
    for x in x_list:
        vx.assign(x)
        y_list.append(oy.eval())
    ax.plot(x_list, y_list)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()

points = [
    (-2, 2.7),
    (-1, 3),
    (0, 1.3),
    (1, 2.4),
    (3, 5.5),
    (4, 6.2),
    (5, 9.1),
]

matplotlib.rcParams['figure.figsize'] = (8.0, 3.)
params = {'legend.fontsize': 'large',
          'axes.labelsize': 'large',
          'axes.titlesize':'large',
          'xtick.labelsize':'large',
          'ytick.labelsize':'large'}
matplotlib.rcParams.update(params)

plot_points(points)

#Linear Regression
#y = ax + b

# Parameters
va = V(1.)
vb = V(1.)

# x and y
vx = V(0.)
vy = V(0.)

# Predicted y
oy = va * vx + vb

# Loss
loss = (vy - oy) * (vy - oy)

#Start
final_loss = fit(loss, points, [va, vb])
check_true(final_loss < 15)

#Let's display the parameter values after the training:
print("a:", va.eval(), "b:", vb.eval())

#Plot linear regression line
plot_points_and_y(points, vx, oy)

#Quadratic Regression
# y = ax^2 + bx + c

#Initial Values
va = V(0.)
vb = V(0.)
vc = V(0.)
vx = V(0.)
vy = V(0.)

#Predicted Values
oy = va * vx * vx + vb * vx + vc
loss = (vy - oy) * (vy - oy)

#Start
final_loss = fit(loss, points, [va, vb, vc])
check_true(final_loss < 2.5)

#Let's display the parameter values after the training:
print("a:", va.eval(), "b:", vb.eval(), "c:", vc.eval())

#The line fitted to points
plot_points_and_y(points, vx, oy)

#Cubic Regression
# y=ax^3+bx^2+cx+d

# Some random initializations.
vx = V(0.)
vy = V(0.)
va = V(-0.1)
vb = V(0.2)
vc = V(-0.3)
vd = V(0.4)
# Define below what is the prediction oy and loss.
oy = va * vx * vx * vx + vb * vx * vx + vc * vx + vd
loss = (vy - oy) * (vy - oy)
final_loss = fit(loss, points, [va, vb, vc, vd], delta=2e-5, num_iterations=10000)
check_true(final_loss < 5)

#Let's display the parameter values after the training:
print("a:", va.eval(), "b:", vb.eval(), "c:", vc.eval(), "d:", vd.eval())

#Plot line
plot_points_and_y(points, vx, oy)


def sim_normal(nums, mean = 600, sd = 30):
    import numpy as np
    import numpy.random as nr
    for n in nums:
        dist = nr.normal(loc = mean, scale = sd, size = n)
        titl = 'Normal distribution with ' + str(n) + ' values'
        print('Summary for ' + str(n) + ' samples')
        print(dist_summary(dist, titl))
        print('Emperical 95% CIs')
        print(np.percentile(dist, [2.5, 97.5]))
        print(' ')
    return('Done!')

def sim_poisson(nums, mean = 600):
    import numpy as np
    import numpy.random as nr
    for n in nums:
        dist = nr.poisson(lam = mean, size = n)
        titl = 'Poisson distribution with ' + str(n) + ' values'
        print(dist_summary(dist, titl))
        print('Emperical 95% CIs')
        print(np.percentile(dist, [2.5, 97.5]))
        print(' ')
    return('Done!')

def dist_summary(dist, names = 'dist_name'):
    import pandas as pd
    import matplotlib.pyplot as plt
    ser = pd.Series(dist)
    fig = plt.figure(1, figsize=(9, 6))
    ax = fig.gca()
    ser.hist(ax = ax, bins = 120)
    ax.set_title('Frequency distribution of ' + names)
    ax.set_ylabel('Frequency')
    plt.show()
    return(ser.describe())

def gen_profits(num):
    import numpy.random as nr
    unif = nr.uniform(size = num)
    out = [5 if x < 0.3 else (3.5 if x < 0.6 else 4) for x in unif]
    return(out)

def gen_tips(num):
    import numpy.random as nr
    unif = nr.uniform(size = num)
    out = [0 if x < 0.5 else (0.25 if x < 0.7
      else (1.0 if x < 0.9 else 2.0)) for x in unif]
    return(out)

def sim_lemonade(num, mean = 600, sd = 30, pois = False):
  ## Simulate the profits and tips for
  ## a lemonade stand.
  import numpy.random as nr

  ## number of customer arrivals
  if pois:
    arrivals = nr.poisson(lam = mean, size = num)
  else:
   arrivals = nr.normal(loc = mean, scale = sd, size = num)

  print(dist_summary(arrivals, 'customer arrivals per day'))

  ## Compute distibution of average profit per arrival
  proft = gen_profits(num)
  print(dist_summary(proft, 'profit per arrival'))

  ## Total profits are profit per arrival
  ## times number of arrivals.
  total_profit = arrivals * proft
  print(dist_summary(total_profit, 'total profit per day'))

  ## Compute distribution of average tips per arrival
  tps = gen_tips(num)
  print(dist_summary(tps, 'tips per arrival'))

  ## Compute average tips per day
  total_tips = arrivals * tps
  print(dist_summary(total_tips, 'total tips per day'))

  ## Compute total profits plus total tips.
  total_take = total_profit + total_tips
  return(dist_summary(total_take, 'total net per day'))