'''
Created on Oct 31, 2017

@author: udit.gupta
'''

import math
import numpy as np
import time

#Not used since it cannot perform operations on vectors and we require to perform functions over the entire vectors
def basic_sigmoid(x):
    """
    Compute sigmoid of x.

    Arguments:
    x -- A scalar number

    Return:
    s -- sigmoid(x)
    """

    s = 1 / (1 + math.exp(-x))

    return s

def sigmoid(x):
    """

    Compute sigmoid of x (x can be a vector or scalar)

    Arguments:
    x -- A scalar, vector or matrix

    Return:
    s -- sigmoid(x)
    """
    s = 1 / (1 + np.exp(-x))
    return s

def sigmoid_derivative(x):
    """
    Compute the gradient (also called the slope or derivative) of the sigmoid function with respect to its input x.

    Arguments:
    x -- A scalar or numpy array

    Return:
    ds -- Your computed gradient.
    """

    s = 1 / (1 + np.exp(x))
    ds = s * (1 - s)

    return ds

def image2vector(image):

    """
    This function will reshape a given image of type (length, height, depth) to (length*height*depth,1)

    Argument:
    image -- a numpy array of shape (length, height, depth)

    Returns:
    v -- a vector of shape (length*height*depth, 1)
    """
    v = image.reshape((image.shape[0]*image.shape[1]*image.shape[2],1))

    return v

def normalizeRows(x):
    """
    a function that normalizes each row of the matrix x (to have unit length).

    Argument:
    x -- A numpy matrix of shape (n, m)

    Returns:
    x -- The normalized (by row) numpy matrix. Y
    """

    # Compute x_norm
    x_norm = np.linalg.norm(x,axis=1,keepdims=True)

    # Divide x by its norm.
    x = x / x_norm

    return x

def softmax(x):
    """Calculates the softmax for each row of the input x.

    This code works for a row vector and also for matrices of shape (n, m).

    Argument:
    x -- A numpy matrix of shape (n,m)

    Returns:
    s -- A numpy matrix equal to the softmax of x, of shape (n,m)
    """

    x_exp = np.exp(x)

    # Create a vector x_sum that sums each row of x_exp. Use np.sum(..., axis = 1, keepdims = True).
    x_sum = np.sum(x_exp,axis=1,keepdims=True)

    # Compute softmax(x) by dividing x_exp by x_sum. It should automatically use numpy broadcasting and divide each row by
    # its corrosponding row value in x_sum. This is basically an element wise division but with broadcasting/
    s = x_exp / x_sum

    return s

def vectorized_product_examples():
    x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
    x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]

    ### VECTORIZED DOT PRODUCT OF VECTORS ###
    tic = time.time()
    dot = np.dot(x1,x2)
    toc = time.time()
    print ("dot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

    ### VECTORIZED OUTER PRODUCT ###
    tic = time.time()
    outer = np.outer(x1,x2)
    toc = time.time()
    print ("outer = " + str(outer) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

    ### VECTORIZED ELEMENTWISE MULTIPLICATION ###
    tic = time.time()
    mul = np.multiply(x1,x2)
    toc = time.time()
    print ("elementwise multiplication = " + str(mul) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

    ### VECTORIZED GENERAL DOT PRODUCT ###
    W=np.zeros(3,x1.shape[1])
    tic = time.time()
    dot = np.dot(W,x1)
    toc = time.time()
    print ("gdot = " + str(dot) + "\n ----- Computation time = " + str(1000*(toc - tic)) + "ms")

print(softmax(np.zeros((3,2))))


# Lab 08, Question 01
# AB Satyaprakash, 180123062

# imports
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from math import pow, pi, cos, sin

# functions
# define these as per requirement!

def P(x):
    return 0

def Q(x):
    return 1

def R(x):
    return 1 + x

def A(i):
    return 1-h*P(x[i])/2

def B(i):
    return -2+(pow(h, 2)*Q(x[i]))

def C(i):
    return 1+h*P(x[i])/2

def y(x):
    return 1+x-cos(x)-(sin(x)*(1+pi/2))

def L(n):
    LArray = np.zeros((n-1, n-1))
    for i in range(n-1):
        if i == 0:
            LArray[0][0], LArray[0][1] = B(1), C(1)
        elif i == n-2:
            LArray[n-2][n-3], LArray[n-2][n-2] = A(n-1), B(n-1)
        else:
            LArray[i][i-1], LArray[i][i], LArray[i][i +
                                                    1] = A(i+1), B(i+1), C(i+1)
    return LArray

def F(n):
    FArray = []
    for i in range(n-1):
        if i == 0:
            FArray.append((pow(h, 2)*R(x[1]))-(alpha*(1-h*P(x[1])/2)))
        elif i == n-2:
            FArray.append((pow(h, 2)*R(x[n-1]))-(beta*(1+h*P(x[n-1])/2)))
        else:
            FArray.append(pow(h, 2)*R(x[i+1]))
    return FArray

# program body
# BVP : y' + y = 1 + x. Thus P = 1, Q = 1, R = 1 + x

a, b = 0, pi/2
alpha, beta = 0, 0
act = [y(1/2)]*5
sol, err, errratio = [], [], []
# dummy values
x = []
h = 0

HArray = [1/4, 1/8, 1/16, 1/32, 1/64]
for i in range(len(HArray)):
    h = HArray[i]
    x = np.arange(a, b+h/2, h)
    n = len(x)-1
    LArray, FArray = L(n), F(n)
    UArray = np.linalg.inv(LArray).dot(FArray)
    sol.append(UArray[int(1/(2*h))-1])
    err.append(abs(sol[i]-act[i]))
    errratio.append(abs(err[i]/sol[i]))

df = pd.DataFrame()
df['h'] = pd.Series(HArray)
df['y(1/2)'] = pd.Series(act)
df['f.d. solution at  1/2'] = pd.Series(sol)
df['error'] = pd.Series(err)
df['ratio of error (absolute)'] = pd.Series(errratio)
print()
print(df)
print()

# plot graph
h = 1/64
x = np.arange(a, b+h/2, h)
n = len(x)-1
LArray, FArray = L(n), F(n)
UArray = np.linalg.inv(LArray).dot(FArray)
UArray = np.append([0], UArray)
UArray = np.append(UArray, [0])
Act = []
for val in x:
    Act.append(y(val))

plt.plot(x, UArray, label='Finite Differences Solution')
plt.plot(x, Act, label='Exact Solution')
plt.xlabel('Value of x')
plt.ylabel('Exact Value / FD Value')
plt.title('Exact Solution and Finite Differences Solution for h = 1/64')
plt.legend()
plt.show()

Semester 6/MA 322 (Scientific Computing Theory)/Labs/Lab 8/Code/q1.py


import numpy as np
import statistics
import time

def hms2dec(h, m, s):
  return 15*(h + m/60 + s/3600)

def dms2dec(d, m, s):
  if (d >= 0):
    return d + m/60 + s/3600
  else:
    return d - m/60 - s/3600

def angular_dist(a1, d1, a2, d2):
  p1 = np.sin(abs(d1-d2)/2)**2
  p2 = np.cos(d1)*np.cos(d2)*np.sin(abs(a1-a2)/2)**2
  p3 = 2*np.arcsin(np.sqrt(p1+p2))
  return np.degrees(p3)

def crossmatch(cat1, cat2, max_dist):
  matches, nomatches = [], []
  cat1id, cat2id = 0, 0
  max_dist_rad = np.radians(max_dist)

  start = time.perf_counter()

  cat1 = np.radians(cat1)
  cat2 = np.radians(cat2)
  sorted_dec_idxs = np.argsort(cat2[:, 1])

  for cat1line in cat1:
    best_match = (0,0,max_dist+1)

    cat2id = 0
    for sorted_idx in sorted_dec_idxs:
      # optimization
      if(cat2[sorted_idx][1] > max_dist_rad + cat1line[1]):
        break

      dist = angular_dist(cat1line[0], cat1line[1], cat2[sorted_idx][0], cat2[sorted_idx][1])

      # update best match
      if(dist <= best_match[2]):
        best_match = (cat1id, sorted_idx, dist)

    #process best match and outputs
    if(best_match[2] <= max_dist):
      matches.append(best_match)
    else:
      nomatches.append(cat1id)

    cat1id += 1

  return (matches, nomatches, time.perf_counter() - start)

# You can use this to test your function.
# Any code inside this `if` statement will be ignored by the automarker.
if __name__ == '__main__':
  # The example in the question
  cat1 = np.array([[180, 30], [45, 10], [300, -45]])
  cat2 = np.array([[180, 32], [55, 10], [302, -44]])
  matches, no_matches, time_taken = crossmatch(cat1, cat2, 5)
  print('matches:', matches)
  print('unmatched:', no_matches)
  print('time taken:', time_taken)

  # A function to create a random catalogue of size n
  def create_cat(n):
    ras = np.random.uniform(0, 360, size=(n, 1))
    decs = np.random.uniform(-90, 90, size=(n, 1))
    return np.hstack((ras, decs))

  # Test your function on random inputs
  np.random.seed(0)
  cat1 = create_cat(10)
  cat2 = create_cat(20)
  matches, no_matches, time_taken = crossmatch(cat1, cat2, 5)
  print('matches:', matches)
  print('unmatched:', no_matches)
  print('time taken:', time_taken)

wk2/Crossmatching with k-d trees/03_skip_large_declinations.py


"""
Problem 11
==========
"""

import numpy as np

GRID = '''08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08
49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00
81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65
52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91
22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80
24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50
32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70
67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21
24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72
21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95
78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92
16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57
86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58
19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40
04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66
88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69
04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36
20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16
20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54
01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48'''

def grid_to_matrix(grid):
    lines = grid.split('\n')

    for i, line in range(len(lines)):
        line = line.split(' ')
        lines[i] = [int(x) for x in line]

    return np.array(lines)

def max_list_prod(L):
    if len(L) < 4:
        return 0, None

    m_prod = L[0] * L[1] * L[2] * L[3]
    nums = (L[0], L[1], L[2], L[3])

    for i in range(1, len(L) - 3):
        prod = L[i] * L[i + 1] * L[i + 2] * L[i + 3]

        if prod > m_prod:
            m_prod = prod
            nums = (L[i], L[i + 1], L[i + 2], L[i + 3])

    return m_prod, nums

def max_line_prod(matrix, i):
    line = matrix[i]

    return max_list_prod(line)

def max_col_prod(matrix, j):
    col = matrix[:, j]

    return max_list_prod(col)

def max_down_diag_prod(matrix, i, j):
    diag = []
    m, n = i, j

    while m < len(matrix) and n < len(matrix):
        diag.append(matrix[m, n])
        m += 1
        n += 1

    return max_list_prod(diag)

def max_up_diag_prod(matrix, i, j):
    diag = []
    m, n = i, j

    while m > 0 and n < len(matrix):
        diag.append(matrix[m, n])
        m -= 1
        n += 1

    return max_list_prod(diag)

def max_prod(prod_list):
    m = float('-inf')
    nums = None

    for prod in prod_list:
        if prod[0] > m:
            m = prod[0]
            nums = prod[1]

    return m, nums

def max_grid_prod(matrix):
    n = len(matrix)
    L = [None] * 6
    L[0] = max_prod(max_line_prod(matrix, i) for i in range(n))
    L[1] = max_prod(max_col_prod(matrix, j) for j in range(n))
    L[2] = max_prod(max_down_diag_prod(matrix, 0, j) for j in range(n))
    L[3] = max_prod(max_down_diag_prod(matrix, i, 0) for i in range(n))
    L[4] = max_prod(max_up_diag_prod(matrix, n-1, j) for j in range(n))
    L[5] = max_prod(max_up_diag_prod(matrix, i, 0) for i in range(n))

    return max_prod(L)

def main():
    matrix = grid_to_matrix(GRID)
    m_prod = max_grid_prod(matrix)

    print(m_prod)

if __name__ == "__main__":
    main()


import numpy as np
import matplotlib.pyplot as plt
from p_controller import P_Controller
from quad1d_eom import ydot

##################################################################################
##################################################################################
# This code is what will be executed and what will produce your results
# For this quiz you need to set kp below to your desired value
# Then modify p_controller.py to build out your P controller
kp = 0.76
# Note that kp needs to be set to 0.76 in order to pass the project
# You are encouraged to change Kp in order to observe the effects
# What happens when Kp is really small?
# What happens when Kp is really large?
# Do we notice anything relating Kp and the control effort?
# Observe the steady state offset and the percent overshoot!
##################################################################################
##################################################################################

# Simulation parameters
N = 500 # number of simultion points
t0 = 0  # starting time, (sec)
tf = 30 # end time, (sec)
time = np.linspace(t0, tf, N)
dt = time[1] - time[0] # delta t, (sec)

##################################################################################
# Core simulation code
# Inital conditions (i.e., initial state vector)
y = [0, 0]
   #y[0] = initial altitude, (m)
   #y[1] = initial speed, (m/s)

# Initialize array to store values
soln = np.zeros((len(time),len(y)))

# Create instance of P_Controller class
p = P_Controller()

# Set the Kp value of the controller
p.setKP(kp)

# Set altitude target
r = 10 # meters
p.setTarget(r)

# Simulate quadrotor motion
j = 0 # dummy counter
for t in time:
    # Evaluate state at next time point
    y = ydot(y,t,p)
    # Store results
    soln[j,:] = y
    j += 1

##################################################################################
# Plot results
SP = np.ones_like(time)*r # altitude set point
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.plot(time, soln[:,0],time,SP,'--')
ax1.set_xlabel('Time, (sec)')
ax1.set_ylabel('Altitude, (m)')

ax2 = fig.add_subplot(212)
ax2.plot(time, soln[:,1])
ax2.set_xlabel('Time, (sec)')
ax2.set_ylabel('Speed, (m/s)')
plt.tight_layout()
plt.show()

fig2 = plt.figure()
ax3 = fig2.add_subplot(111)
ax3.plot(time, p.u_p, label='u_p', linewidth=3, color = 'red')
ax3.set_xlabel('Time, (sec)')
ax3.set_ylabel('Control Effort')
h, l = ax3.get_legend_handles_labels()
ax3.legend(h, l)
plt.tight_layout()
plt.show()
##################
y0 = soln[:,0] #altitude
rise_time_index =  np.argmax(y0>r)
RT = time[rise_time_index]
print("The rise time is {0:.3f} seconds".format(RT))

OS = (np.max(y0) - r)/r*100
if OS < 0:
    OS = 0
print("The percent overshoot is {0:.1f}%".format(OS))

print ("The steady state offset at 30 seconds is {0:.3f} meters".format(abs(soln[-1,0]-r)))


# Bifn.py: plot a bifurcation diagram for piecewise maps.

from scipy import arange
from pylab import *

# Example: Tent map, a in [1,2]
def TentMap(a,x):
	if x < 0.5:
		return a*x
	else:
		return a*(1-x)

plow  = 1.0
phigh = 2.0

figure(1,(8,6))
# Stuff parameter range into a string via the string formating commands.
TitleString = 'Tent map bifurcation diagram for r in [%g,%g]' % (plow,phigh)
title(TitleString)
xlabel('Control parameter r')
ylabel('x')

# Set the initial condition used across the different parameters
ic = 0.2
# Establish the arrays to hold the set of iterates at each parameter value
psweep = [ ] # The parameter value
x = [ ] # The iterates
# The iterates we'll throw away
nTransients = 250
# This sets how much the attractor is filled in
nIterates = 500
# This sets how dense the bifurcation diagram will be
nSteps = 200.0
# Sweep the control parameter over the desired range
for p in arange(plow,phigh,(phigh-plow)/nSteps):
	# Set the initial condition to the reference value
	state = ic
	# Throw away the transient iterations
	for i in range(nTransients):
		state = TentMap(p,state)
	# Now store the next batch of iterates
	for i in range(nIterates):
		state = TentMap(p,state)
		psweep.append(p)
		x.append( state )

plot(psweep, x, 'k,')

# Use this to save figure as a bitmap png file
#savefig('TentBifn', dpi=600)

show()


import matplotlib.pyplot as plt
import numpy as np
from fractions import Fraction

def create_pi_labels(a=0, b=2, step=0.5, ax=None, direction='x'):
    """
    A function that gives back ticks an labels in radians

    Keyword arguments:
    a -- lower limit is a*pi (default 0.0)
    b -- upper limit is b*pi (default 2.0)
    step -- step is step*pi  (default 0.5)
    ax -- if ax is not None then ticks and labels are set for this axes (default None)
    direction -- 'x' or 'y' or 'z' (default 'x') which axis you want to label

    return value is ticks, labels
    """

    max_denominator = int(1/step)
    values = np.arange(a, b+0.1*step, step)
    fracs = [Fraction(x).limit_denominator(max_denominator) for x in values]
    ticks = values*np.pi

    if plt.rcParams["text.usetex"] is True:
        vspace = r"\vphantom{\frac{1}{2}}"
    else:
        vspace = ""

    labels = []

    for frac in fracs:
        if frac.numerator==0:
            labels.append(r"$0" + vspace + "$")
        elif frac.numerator<0:
            if frac.denominator==1 and abs(frac.numerator)==1:
                labels.append(r"$-\pi" + vspace + "$")
            elif frac.denominator==1:
                labels.append(r"$-{}\pi".format(abs(frac.numerator)) +vspace + "$")
            else:
                labels.append(r"$-\frac{{{}}}{{{}}} \pi$".format(abs(frac.numerator), frac.denominator))
        else:
            if frac.denominator==1 and frac.numerator==1:
                labels.append(r"$\pi" + vspace + "$")
            elif frac.denominator==1:
                labels.append(r"${}\pi".format(frac.numerator) + vspace + "$")
            else:
                labels.append(r"$\frac{{{}}}{{{}}} \pi$".format(frac.numerator, frac.denominator))

    if ax is not None:
        if direction == 'x':
            ax.set_xticks(ticks)
            ax.set_xticklabels(labels)
        elif direction == 'y':
            ax.set_yticks(ticks)
            ax.set_yticklabels(labels)
        elif direction == 'z':
            ax.set_zticks(ticks)
            ax.set_zticklabels(labels)
        else:
            print("direction ", direction, "is not a proper argument")

    return ticks, labels

if __name__ == '__main__':
    x = np.linspace(-np.pi, 2*np.pi, 1000)

    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    ax.set_title("Automatically create Labels as Multiples of $\pi$")

    ax.plot(x, np.sin(x), 'r-', label=r"$\sin(x)$")
    ax.plot(x, np.cos(x), 'b-', label=r"$\cos(x)$")

    ax.grid()
    ax.set_xlim(-np.pi, 2*np.pi)
    ax.set_ylim(-1.1, 1.1)

    ax.set_xlabel(r"$x$")
    ax.set_ylabel(r"$f(x)$")

    create_pi_labels(-1, 2, 1/3, ax, 'x')

    ax.legend(loc="best")
    # ax.xaxis.labelpad = 50

    fig.tight_layout()
    fig.savefig("../images/create_pi_labels.png", dpi=300)


# imports
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_regression

def euclidean_distance_calc(y, data_y):
    """Calculate the euclidean distance between two points"""
    euclidean_l = []

    for i in range(len(data_y)):
        e = (y[i] - data_y[i]) ** 2
        euclidean_l.append(e)
    score = np.sum(np.array(euclidean_l))
    return np.sqrt(score)

def ploting(x, y, data_y, data_x, Loss):
    """This Function plots all the points"""
    plt.plot(x, y, color="r", label=f"Score is {Loss}")
    plt.xlabel('x')
    plt.ylabel('y')
    plt.scatter(data_x, data_y, color="b", label="Data")
    plt.legend(loc='upper left')
    plt.axis("equal")
    plt.grid()

def main(grid_search):
    #Generate data
    x, y = make_regression(n_samples=100, n_features=1, noise=10,random_state=1000)
    y = y*.1

    if grid_search:
        """
        Grid search method:

        """
        result = []
        best_loss = []
        m_array = np.arange(5, 15, .01)
        b_array = np.arange(-4, 4, .1)
        for m in m_array:
            for b in b_array:
                line_y = (m * x) + b
                Loss = euclidean_distance_calc(line_y, y)
                d = {"Slope": f"{m:.2f}", "Y-Intercept": f"{b:.2f}", "Y": line_y, "X": x, "Loss": f"{Loss:.3f}", }
                result.append(d)
        for i in result:
            best_loss.append(i["Loss"])

        best_loss = np.array(best_loss)
        index = np.argmin(best_loss)
        bestLine = result[index]

        print(type(result[index]))
        with open("Data.txt", "w") as f:
            f.write(str(result[index]))
        ploting(bestLine["X"], bestLine["Y"], y, x, bestLine["Loss"])
    else:
        """
        Least squares method
        """
        ones = np.ones([len(x), 1])
        x = x.reshape(len(x), 1)
        X = np.concatenate((x, ones), axis=1)
        z = np.matmul(np.matmul(np.linalg.inv((np.matmul(X.T, X))), X.T), y)
        line_y = (z[0] * x) + z[1]
        d = {"Slope": f"{z[0]:.2f}", "Y-Intercept": f"{z[1]:.2f}", "Y": line_y, "X": x, "Loss": f"{euclidean_distance_calc(line_y, y):.3f}", }
        with open("Data.txt", "w") as f:
            f.write(str(d))
        ploting(d["X"], d["Y"], y, x, d["Loss"])

if __name__ == "__main__":
    main(grid_search = True)
    plt.show()


import numpy as np
import numpy.ma as ma
from scipy import stats as st

def nancorr(x,y):
    """
    r = nancorr(x,y)
    Calculate correlation matrix, treating NaN values as missing data
    """
    x_msk = ma.masked_invalid(x)
    y_msk = ma.masked_invalid(y)
    r = ma.corrcoef(x_msk,y_msk)
    return r

def maxcorr(x,y,**options):
    """
    (rmax,lag,ind) = maxcorr(x,y,**'maxlag'=int(len(x)/4)):
    Calculate the maximum lagged correlation between two 1D arrays
    Inputs:
    x,y are 1D arrays
    Options
    'maxlag' the maximum number of lagged correlations to calculate (default: 1/4 of array length)
    Output:
    r is the correlation coefficient with the maximum absolute value
    lag is the lag of the maximum correlation (positive: y lags x)
    """

    nrows = len(x)
    maxlag = int(np.floor(nrows/4))
    if ('maxlag' in options):
        maxlag = options['maxlag']

    # use masked arrays (mask NaNs)
    x = ma.masked_invalid(x)
    y = ma.masked_invalid(y)

    lags = np.arange(-maxlag,maxlag+1)
    rs = np.zeros(np.shape(lags))
    for ni, lag in enumerate(lags):
        lag = lags[ni]
        if lag < 0:
            rs[ni] = ma.corrcoef(x[-lag:],y[:lag])[0,1]
        elif lag > 0:
            rs[ni] = ma.corrcoef(x[:-lag],y[lag:])[0,1]
        else:
            rs[ni] = ma.corrcoef(x,y)[0,1]

    ind = ma.argmax(np.abs(rs))
    rmax = rs[ind]
    lag = lags[ind]

    return (rmax,lag,ind)

def rsig(r,nu):
    """ p-value for correlation coefficient r, and degrees of freedom nu

    INPUTS:
    r - correlation coefficient
    nu - degrees of freedom (N-2)

    OUTPUT:
    p - significance level/p-value

    significance levels of 0.05 and 0.01 correspond with Appendix E in
    Emery and Thomson (2004) Data Analysis Methods in Physical
    Oceanography
    """

    # t value
    t = abs(r)*np.sqrt(nu)/np.sqrt(1-r**2)

    # significance level, using the "survival function" (1-cdf)
    p = 2*(st.t.sf(t,nu))

    return p

def rcrit(nu,sig=0.05):
    """
    Critical r (correlation coefficient), given significance level
    and degrees of freedom.

    INPUTS:
    nu - degrees of freedom (N-2)
    sig - significance level (default 0.05)

    OUTPUT:
    rcrit - critical r value

    Values for 0.05 and 0.01 correspond with Appendix E in
    Emery and Thomson (2004) Data Analysis Methods in Physical
    Oceanography
    """

    # critical t value (this is equivalent to Matlab tinv function)
    t = st.t.ppf(1 - sig/2,nu)

    # critical r value
    rc = t/np.sqrt(t**2+nu)

    return rc

def linreggm(x,y):
    '''
    Geometric mean (Type II) linear regression.

    Returns slope and intercept where y = slope*x + intercept

    References:
    - Ricker (1984) Computation and uses of central trend lines, Can. J. Zool., 62, 1897-1905.
    - Glover, Jenkins and Doney (2011) Modeling Methods for Marine Science. Section 3.2.5, Cambridge University Press.
    '''

    # least-squares regression of y on x
    result_yx = st.linregress(x,y)

    # least-squares regression of x on y
    result_xy = st.linregress(y,x)

    slope = np.sqrt(result_yx.slope/result_xy.slope)
    slope = slope*np.sign(result_yx.slope)

    xbar = np.mean(x)
    ybar = np.mean(y)

    intercept = ybar - slope*xbar

    return slope,intercept


import numpy as np
def get_box_from_point(x,y,kernel,pad,stride):

    kernel_x = kernel[0]
    kernel_y = kernel[1]
    pad_x = pad[0]
    pad_y = pad[1]
    stride_x = stride[0]
    stride_y = stride[1]

    x_min = (x - 1) * stride_x + 1 - pad_x
    x_max = (x - 1) * stride_x - pad_x + kernel_x
    y_min = (y - 1) * stride_y + 1 - pad_y
    y_max = (y - 1) * stride_y - pad_y + kernel_y

    return x_min, y_min, x_max, y_max

def get_convd_size(W, H, kernel, pad, stride):
    kernel_x = kernel[0]
    kernel_y = kernel[1]
    pad_x = pad[0]
    pad_y = pad[1]
    stride_x = stride[0]
    stride_y = stride[1]
    H_res = int((H + 2 * pad_y - kernel_y)/stride_y) + 1
    W_res = int((W + 2 * pad_x - kernel_x)/stride_x) + 1
    return W_res, H_res

def get_original_size(W, H, kernel, pad, stride):
    kernel_x = kernel[0]
    kernel_y = kernel[1]
    pad_x = pad[0]
    pad_y = pad[1]
    stride_x = stride[0]
    stride_y = stride[1]
    H_res = (H - 1) * stride_y + kernel_y - 2 * pad_y
    W_res = (W - 1) * stride_x + kernel_x - 2 * pad_x
    return W_res, H_res

def single_map_value(value_rec, kernel, pad, stride):
    W = value_rec.shape[0]
    H = value_rec.shape[1]
    W_ori, H_ori = get_original_size(W, H, kernel, pad, stride)
    res_rec = np.full([W_ori, H_ori],0.)
    for i in range(W):
        for j in range(H):
            tmp_v = value_rec[i, j]
            x_min, y_min, x_max, y_max = get_box_from_point(i, j, kernel, pad, stride)
            give_v = (tmp_v+0.)/((x_max + 1 - x_min)*(y_max + 1 - y_min))
            for p in range(x_min, x_max+1):
                for q in range(y_min, y_max+1):
                    if p >= 0 and p < W_ori and q >=0 and q < H_ori:
                        res_rec[p, q] += give_v
    return res_rec

def multiple_map_value(value_rec, params_list):
    tmp_res = value_rec
    for params in params_list:
        kernel = params[0]
        pad = params[1]
        stride = params[2]
        tmp_res = single_map_value(tmp_res, kernel, pad, stride)
    return tmp_res

# tst_area = np.full([40,40],0.)
# tst_area[20,20] = 1.
# res_area = single_map_value(value_rec=tst_area, kernel=[5, 5], pad=[2,2], stride=[1,1])
# for i in range(res_area.shape[0]):
#     for j in range(res_area.shape[1]):
#         print i,j,res_area[i, j]


"""
    Regressions
"""
import numpy as np
import pandas as pd
from matplotlib import pyplot
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

X = np.array(
    [
        3.3,
        4.4,
        5.5,
        6.71,
        6.93,
        4.168,
        9.779,
        6.182,
        7.59,
        2.167,
        7.042,
        10.791,
        5.313,
        7.997,
        5.654,
        9.27,
        3.1,
    ]
)

Y = np.array(
    [
        1.7,
        2.76,
        2.09,
        3.19,
        1.694,
        1.573,
        3.366,
        2.596,
        2.53,
        1.221,
        2.827,
        3.465,
        1.65,
        2.904,
        2.42,
        2.94,
        1.3,
    ]
)

# Generate the line of best fit with predicted values
predicted_y_values = list(map(lambda x: 0.7 * x + 0.3, X))
given_num_error = sum([(i - j) ** 2 for i, j in zip(Y, predicted_y_values)])

# Print the given number error
print(given_num_error)

print(np.polyfit(X, Y, 1))

# Generate the line of best fit using the polyfit values
predicted_y_values = list(map(lambda x: 0.25 * x + 0.79, X))
polyfit_num_error = sum([(i - j) ** 2 for i, j in zip(Y, predicted_y_values)])

# print polyfit_num_error
print(polyfit_num_error)
print(given_num_error - polyfit_num_error)

# plot the predicted y values
pyplot.scatter(X, Y)
pyplot.plot(X, predicted_y_values)
pyplot.show()

# Use scikit learn to get the line of best fit
lr_reg = LinearRegression()
lr_reg.fit(X.reshape(-1, 1), Y.reshape(-1, 1))

# print out the coefficient and the y intercept
print(lr_reg.coef_)
print(lr_reg.intercept_)

print("Now in the sales section!")
print("Get CSV and create both the x and y columns")
dataframe = pd.read_csv("./Advertising.csv")
feature_cols = ["TV", "radio", "newspaper"]
X = dataframe[feature_cols][:150]
Y = dataframe.sales[:150]

print("Generating a linear regression on the top 150 companies (first one)")
sales_regression = LinearRegression()
sales_regression.fit(X, Y)

print("Printing the coefficient and y intercept of our first 150 sales")
print(sales_regression.coef_)
print(sales_regression.intercept_)

print("Predicting the sales of the bottom 50 companies (last ones)")
print(sales_regression.predict(dataframe[feature_cols][:-50]))

r2_score


import numpy as np

t1 = np.array([1,2])
t2 = np.array([
    [0, 3],
    [1, 10],
])

# normal * operation apply row-wise
t3 = t1 * t2
# t3 = array([
#   [0, 6],
#   [1, 20],
# ])
# NOTE: this also happens for +/np.add operation

# in numpy, vector has no meaning of T
# but matrix does
t1.T == t1

# perform math matrix operation
t4 = t1.dot(t2)
# t4 = array([ 2, 23 ])
# here, t1 as horizontal vector and t2 act as normal matrix

# so what if I want to perform and adding along
# column instead of row?
# Maybe you don't need that in Numpy


#This imports all my functions
import numpy as np
import matplotlib.pyplot as plot
x=np.arange(-5,5,.1)

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

#This is my function and area
y1 = -0.5*x + 4
actual_area_y1 = 40

#These are my values
Δx = 1
n_y1=-5

#These are my arrays
n_step_y1 = np.array([n_y1])
a_y1=np.array([(-0.5*n_y1+4)])

#This is my loop to find the area based on my chosen Δx, putting the areas into an array
while n_y1<6:
    n_y1 += Δx #add Δx to points to make rectangles up to 100
    n_step_y1 = np.append (n_step_y1, n_y1) #add nstep to an array
    area_y1 = Δx * (-0.5*(n_y1) + 4) #find area for rectangle
    a_y1 = np.append (a_y1, area_y1) #add area to an array
    if n_y1 ==5:
        break  #stops loop

#This adds my areas at each point and finds the total area and percent difference from actual area
print ("The area for the function y=-0.5x+4 is", np.sum(a_y1)) #find sum of area array and print sum as area for function
perdiff = (abs(actual_area_y1 - np.sum(a_y1))/((actual_area_y1 + np.sum(a_y1))/2))*100 #make %difference equation
print ("The actual area for y=-0.5x+4 is 40. The % difference between actual value and coded value is", perdiff, "%")

###########################################################
#This is my attempt at making a percent difference vs. different n steps plot.

#These are my values
area_graph_y1 = 0
b_y1 = -5
Δx_graph_y1 = 0

#these are my arrays
perdiff_array_y1 = ([0])
#Δx_array_y1 = (dtype=float)
a_graph_y1 = np.array([(-0.5*b_y1+4)])

#this loop goes through different Δx sizes and finds the area and percent difference of the function at each Δx, putting values into arrays
#if Δx_graph_y1 <= 5:
#    Δx_graph_y1 += 1
#    Δx_array_y1 = np.append (Δx_array_y1, Δx_graph_y1)
#    while Δx_graph_y1 < 5:
#        b_y1 += Δx_graph_y1
#        a_graph_y1 = np.append (a_graph_y1, b_y1)
#        perdiff_graph_y1 = (abs(actual_area_y1 - np.sum(a_graph_y1))/((actual_area_y1 + np.sum(a_graph_y1))/2))*100
#        perdiff_array_y1 = np.append (perdiff_array_y1, perdiff_graph_y1)
#        if b_y1 == 5:
#            break

#This shows what is not working
#print(perdiff_array_y1)
#print(Δx_array_y1)

#This is my plotting
plot.figure()
plot.title("Percent difference v. n step size (Y1)")
plot.axis([-5,5,0,30])
plot.xlabel("n step size")
plot.ylabel("percent difference")
#plot.plot(Δx_array_y1,perdiff_array_y1)
#plot.show()

################################################
#y2 math
y2 = -0.29*x**2 - x + 12.5
actual_area_y2 = 100.83
n_y2=-5
n_step_y2 = np.array([n_y2])
a_y2=np.array([-0.29*(n_y2)**2 -(n_y2) + 12.5])
perdiff_array_y2 = np.empty(11, dtype=np.int)
while n_y2<6:
    n_y2 += Δx #add Δx to points to make rectangles up to 100
    n_step_y2 = np.append (n_step_y2, n_y2) #add nstep to an array
    area_y2 = Δx * (-0.29*(n_y2)**2 - (n_y2) + 12.5) #find area for rectangle
    a_y2 = np.append (a_y2, area_y2) #add area to an array
    if n_y2 ==5:
        break  #stops loop
print ("The area for the function y=-0.29*x**2-x+12.5 is", np.sum(a_y2))
perdiff_y2 = (abs(actual_area_y2 - np.sum(a_y2))/((actual_area_y2 + np.sum(a_y2))/2))*100
print ("The actual area for y=-0.29*x**2-x+12.5 is 100.83. The % difference between actual value and coded value is", perdiff_y2,"%")
###########################################################
#This is my attempt at making a percent difference vs. different n steps plot.
#These are my values
area_graph_y2 = 0
b_y2 = -5
Δx_graph_y2 = 0
#these are my arrays
perdiff_array_y2 = ([0])
Δx_array_y2 = ([0])
a_graph_y2 = np.array([(-0.29*(b_y2)**2-(b_y2)+12.5)])
#this loop goes through different Δx sizes and finds the area and percent difference of the function at each Δx, putting values into arrays
#if Δx_graph_y2 <= 5:
#    Δx_graph_y2 += 1
#    Δx_array_y2 = np.append (Δx_array_y2, Δx_graph_y2)
#    while Δx_graph_y2 < 5:
#        b_y2 += Δx_graph_y2
#        area_graph_y2 = Δx_graph_y2 = np.append (area_graph_y2, b_y2)
#        perdiff_graph_y2 = (abs(actual_area_y2 - np.sum(a_graph_y2))/((actual_area_y2 + np.sum(a_graph_y2))/2))*100
#        perdiff_array_y2 = np.append (perdiff_array_y2, perdiff_graph_y2)
#        if b_y2 == 5:
#            break

#This shows what is not working
#print(perdiff_array_y2)
#print(Δx_array_y2)

#This is my plotting
plot.figure()
plot.title("Percent difference v. n step size (Y2)")
plot.axis([-5,5,0,30])
plot.xlabel("n step size")
plot.ylabel("percent difference")
plot.plot(Δx_array_y2,perdiff_array_y2)
plot.show()

################################################
y3 = 1+((10*(x+1))*np.exp(-1*(x**2)))
actual_area_y3 = 27.72
n_y3=-5
n_step_y3 = np.array([n_y3])
a_y3=np.array([1+((10*(n_y3+1))*np.exp(-1*(n_y3**2)))])
perdiff_array_y3 = np.empty(11, dtype=np.int)
while n_y3<6:
    n_y3 += Δx #add Δx to points to make rectangles up to 100
    n_step_y3 = np.append (n_step_y3, n_y3) #add nstep to an array
    area_y3 = Δx * (1 +((10*(n_y3+1))*np.exp(-1*(n_y3**2)))) #find area for rectangle
    a_y3 = np.append (a_y3, area_y3) #add area to an array
    if n_y3 ==5:
        break  #stops loop
print ("The area for the function y=1 + ( (10 * (x + 1) ) * np.exp(-1 * (x**2) ) ) is", np.sum(a_y3))
perdiff_y3 = (abs(actual_area_y3 - np.sum(a_y3))/((actual_area_y3 + np.sum(a_y3))/2))*100
print ("The actual area for y3 = 1 + 10*(x + 1)**(-x**2) is 27.72. The % difference between actual value and coded value is", perdiff_y3, "%")
plot.clf()
###################################################################
#This is my attempt at making a percent difference vs. different n steps plot.
#These are my values
area_graph_y3 = 0
b_y3 = -5
Δx_graph_y3 = 0
#these are my arrays
perdiff_array_y3 = ([0])
Δx_array_y3 = ([0])
a_graph_y3 = np.array([1+((10*(b_y3+1))*np.exp(-1*(b_y3**2)))])
#this loop goes through different Δx sizes and finds the area and percent difference of the function at each Δx, putting values into arrays
#if Δx_graph_y3 <= 5:
#    Δx_graph_y3 += 1
#    Δx_array_y3 = np.append (Δx_array_y3, Δx_graph_y3)
#    while Δx_graph_y3 < 5:
#        b_y3 += Δx_graph_y3
#        area_graph_y3 = Δx_graph_y3 = np.append (area_graph_y2, b_y2)
#        perdiff_graph_y2 = (abs(actual_area_y2 - np.sum(a_graph_y2))/((actual_area_y2 + np.sum(a_graph_y2))/2))*100
#        perdiff_array_y2 = np.append (perdiff_array_y2, perdiff_graph_y2)
#        if b_y2 == 5:
#            break

#This shows what is not working
#print(perdiff_array_y2)
#print(Δx_array_y2)

#This is my plotting
plot.figure()
plot.title("Percent difference v. n step size (Y2)")
plot.axis([-5,5,0,30])
plot.xlabel("n step size")
plot.ylabel("percent difference")
plot.plot(Δx_array_y2,perdiff_array_y2)
plot.show()


import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import inv

N = 25
X = np.reshape(np.linspace(0, 0.9, N), (N, 1))
Y = np.cos(10*X**2) + 0.1 * np.sin(100*X)
#K = 12  # order of the func
listTrainning = []
for i in np.linspace(0, 0.9, N):
    listTrainning.append(np.cos(10*i**2) + 0.1 * np.sin(100*i))

def PsiiFill(K):
    Psii = np.zeros((N, K + 1))
    for i in range(N):
        for j in range(0, K+1):
            Psii[i][j] = X[i][0]**j

    theta = np.dot(np.dot(inv(np.dot(Psii.T, Psii)), Psii.T), Y)
    return theta

#print(theta)

# def Psi(x):
#     for i in range(K + 1):
#         temp.append([x**i])
#     return np.array(temp)
#
# for r in range(1, N+1):
#     Psii[r].append(Psi(r).T)
#
# Psii = Psii.reshape(N, K)
# # θ∗ = (Φ⊤Φ)−1Φ⊤y
# theta = np.dot(np.dot(inv(np.dot(Psi.T, Psi)), Psi.T), Y)
# print(theta)

def f(x, order):
    fx = 0
    theta_tem = PsiiFill(order)
    #print(theta_tem)
    for k in range(order+1):
        fx = fx + np.dot((x**k), theta_tem[k][0])
    return fx

testingX = np.linspace(-0.3, 1.3, 200)

list_Y_0 = []
for i in testingX:
    # print(f(i))
    list_Y_0.append(f(i, 0))

list_Y_1 = []
for i in testingX:
    # print(f(i))
    list_Y_1.append(f(i, 1))

list_Y_2 = []
for i in testingX:
    # print(f(i))
    list_Y_2.append(f(i, 2))

list_Y_3 = []
for i in testingX:
    # print(f(i))
    list_Y_3.append(f(i, 3))

list_Y_11 = []
for i in testingX:
    # print(f(i))
    list_Y_11.append(f(i, 11))

font = {'family': 'serif',
        'color':  'black',
        'weight': 'normal',
        'size': 12,
        }

fontDot = {'family': 'serif',
        'color':  'red',
        'weight': 'normal',
        'size': 12,
        }
print(testingX)
plt.plot(np.linspace(0, 0.9, N), listTrainning, 'ro')
plt.text(0.2, 3, r'Pink Dot: tranning data', fontdict=fontDot)

plt.plot(testingX, list_Y_0, 'b')
plt.text(-0.2, 0.35, r'order 0', fontdict=font)

plt.plot(testingX, list_Y_1, 'g')
plt.text(1.1, -0.5, r'order 1', fontdict=font)

plt.plot(testingX, list_Y_2, 'r')
plt.text(-0.28, 3.0, r'order 2', fontdict=font)

plt.plot(testingX, list_Y_3, 'c')
plt.text(1.0, 3, r'order 3', fontdict=font)

plt.plot(testingX, list_Y_11, 'm')
plt.text(-0.1, 3.5, r'order 11', fontdict=font)

plt.axis([-0.3, 1.3, -1, 4])
plt.show()


import numpy as np

# 随机写的样本数据
x = np.array([[2.3, 3.5], [4.8, 7.6], [3.2, 7.7], [18.5, 32], [33.2, 17],
              [7, 9]])
# 样本点对应的输出
y = np.array([15.88, 20.69, 34.22, 25, 49.34, 20])

# 归一化，不做归一化可能会导致无法收敛或者收敛速度变慢
max_x = x.max(axis=0)
x = x / max_x

# 参数第一位是截距，后面两位分别是x的对应权重
theta = np.array([1, 1, 1])
# 更新步长
alpha = 0.01
# 停止迭代的阈值
threshold = 0.00001

# 批量梯度下降
def get_grad_BGD(theta, x, y):
  grad = [0, 0, 0]
  comm = theta[0] + theta[1] * x[:, 0] + theta[2] * x[:, 1] - y
  grad[0] = 2. * np.mean(comm)
  grad[1] = 2. * np.mean(x[:, 0] * comm)
  grad[2] = 2. * np.mean(x[:, 1] * comm)
  return np.array(grad)

# 随机梯度下降
def get_grad_SGD(theta, x, y):
  grad = [0, 0, 0]
  # 随机取一个样本和y值
  r = np.random.randint(0, len(x))
  xi = x[r]
  yi = y[r]
  comm = theta[0] + theta[1] * xi[0] + theta[2] * xi[1] - yi
  grad[0] = 2. * comm
  grad[1] = 2. * xi[0] * comm
  grad[2] = 2. * xi[1] * comm
  return np.array(grad)

# 小批量梯度下降
def get_grad_MBGD(theta, batch, x, y):
  grad = [0, 0, 0]
  # 随机取一个样本和y值
  r = np.random.choice(len(x), batch, replace=False)
  xm = x[r]
  ym = y[r]
  comm = theta[0] + theta[1] * xm[:, 0] + theta[2] * xm[:, 1] - ym
  grad[0] = 2. * np.mean(comm)
  grad[1] = 2. * np.mean(xm[:, 0] * comm)
  grad[2] = 2. * np.mean(xm[:, 1] * comm)
  return np.array(grad)

batch = 4

# 更新参数theta
def update_theta(theta, alpha, grad):
  new_theta = theta - alpha * grad
  return new_theta

# 计算RMSE,即我们当前损失值的平方根
def get_rmse(theta, x, y):
  squared_err = (theta[0] + theta[1] * x[:, 0] + theta[2] * x[:, 1] - y)**2
  rmse = np.sqrt(np.mean(squared_err))
  return rmse

# 计算梯度的模
def grad_norm(grad):
  g = np.array(grad)
  norm = np.sqrt(np.sum(g**2))
  return norm

# 进行一次计算，得到新旧梯度的模以及新的theta值
def iterate(alpha, theta, x, y):
  grad = get_grad_BGD(theta, x, y)
  # grad = get_grad_MBGD(theta, batch, x, y)
  norm = grad_norm(grad)
  theta = update_theta(theta, alpha, grad)
  # grad = get_grad_MBGD(theta, batch, x, y)
  grad = get_grad_BGD(theta, x, y)
  new_norm = grad_norm(grad)
  return norm, new_norm, theta

# 设置迭代初始值
count = 1
new_norm = 1
norm = 0
while np.abs(new_norm - norm) > threshold:
  norm, new_norm, theta = iterate(alpha, theta, x, y)
  count += 1

print('iteration count: %s' % count)
print('Coef: [%s %s] ' % (theta[1], theta[2]))
print('Intercept %s' % theta[0])
rms = get_rmse(theta, x, y)
print('RMSE: %s' % rms)

# 通过sklearn的线性回归工具来拟合并且计算rmse，和我们自己实现的梯度下降得到的rmse做对比
print('--------------------------')
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(x, y)
print('Sklearn Coef: %s' % lr.coef_)
print('Sklearn Intercept: %s' % lr.intercept_)
sktheta = [lr.intercept_, lr.coef_[0], lr.coef_[1]]
rms = get_rmse(sktheta, x, y)
print('Sklearn RMSE: %s' % rms)


from sympy import *
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def draw_circle():
    thetas = np.linspace(0., 2. * np.pi, 50)
    radius = 0.1
    xs = (radius * np.cos(thetas) + np.ones_like(thetas) * .1).reshape(-1, 1)
    ys = (radius * np.sin(thetas) + np.ones_like(thetas) * .1).reshape(-1, 1)
    zs = (np.ones_like(xs) * 0.3).reshape(-1, 1)
    return np.concatenate((xs, ys, zs), axis=1)  # ARM IN STRAIGHT CONFIG

def get_jacobian(thetas):
    t0, t1, t2, t3 = symbols("t0 t1 t2 t3")

    a = .09548
    d = 0.20603
    l1 = .20327
    l2 = .15245
    l3 = .044

    x = cos(t0)*(a+l1*cos(t1)+l2*cos(t1+t2)+l3*cos(t1+t2+t3))
    y = sin(t0)*(a+l1*cos(t1)+l2*cos(t1+t2)+l3*cos(t1+t2+t3))
    z = d+l1*sin(t1)+l2*sin(t1+t2)+l3*sin(t1+t2+t3)

    J = Matrix([[diff(x, t0), diff(x, t1), diff(x, t2), diff(x, t3)],
                [diff(y, t0), diff(y, t1), diff(y, t2), diff(y, t3)],
                [diff(z, t0), diff(z, t1), diff(z, t2), diff(z, t3)]])

    return np.array(J.evalf(subs={t0: thetas[0], t1: thetas[1], t2: thetas[2], t3: thetas[3]})).astype(np.float64)

def get_jacobian_arm():
    t0, t1, t2, t3 = symbols("t0 t1 t2 t3")

    a = .09548
    d = 0.20603
    l1 = .20327
    l2 = .15245
    l3 = .044

    # x = cos(t_0) * (a + l1 * cos(t_1) + l2 * cos(t_1 + t_2))
    # y = sin(t_0) * (a + l1 * cos(t_1) + l2 * cos(t_1 + t_2))
    # z = d + l1 * sin(t_1) + l2 * sin(t_1 + t_2)

    x = a+l1*cos(t1)+l2*cos(t1+t2)+l3*cos(t1+t2+t3)
    y = a+l1*cos(t1)+l2*cos(t1+t2)+l3*cos(t1+t2+t3)
    z = d+l1*sin(t1)+l2*sin(t1+t2)+l3*sin(t1+t2+t3)

    J = Matrix([[diff(x, t1), diff(x, t2), diff(x, t3)],
                [diff(y, t1), diff(y, t2), diff(y, t3)],
                [diff(z, t1), diff(z, t2), diff(z, t3)]])

    det = J
    sing1 = -1.94521
    sing1_ = 1.94521
    sing2 = [1.30103, 2.03241]
    sing2_ = [-1.30103, -2.03241]
    sing3 = [1.84254, 0]
    sing3_ = [-1.84254, 0]
    print(det)

def jacobian_determinant(thetas):
    jac = get_jacobian(thetas)
    det_jac = np.sqrt(np.linalg.det(np.dot(jac.T, jac)))
    return det_jac

def forward_kinematics(thetas):
    alpha = [np.pi/2., 0., 0., 0., 0.]
    a = [.09548, .20327, .15245, .044, 0.]
    d = [0.20603, 0., 0., 0., 0.]
    T = []
    for i in range(len(alpha)):
        T.append(get_transform(thetas[i], alpha[i], a[i], d[i]))

    joint_0 = np.array([[np.cos(thetas[0]), -np.sin(thetas[0]), 0., 0.],
                        [np.sin(thetas[0]), np.cos(thetas[0]), 0., 0.],
                        [ 0., 0., 1., 0.],
                        [0., 0., 0., 1.]])
    joint_1 = T[0]
    joint_2 = np.matmul(joint_1, T[1])
    joint_3 = np.matmul(joint_2, T[2])
    joint_4 = np.matmul(joint_3, T[3])
    joint_5 = np.matmul(joint_4, T[4])
    joints = [joint_0, joint_1, joint_2, joint_3, joint_4, joint_5]

    return joints

def get_transform(theta, alpha, a, d):
    return np.array([
        [np.cos(theta), -np.sin(theta) * np.cos(alpha), np.sin(theta)*np.sin(alpha), a * np.cos(theta)],
        [np.sin(theta), np.cos(theta) * np.cos(alpha), -np.cos(theta) * np.sin(alpha), a * np.sin(theta)],
        [0., np.sin(alpha), np.cos(alpha), d],
        [0., 0., 0., 1.]
    ])

def euler_to_rot(r,p,y):
    cr = np.cos(r)
    sr = np.sin(r)
    cp = np.cos(p)
    sp = np.sin(p)
    cy = np.cos(y)
    sy = np.sin(y)

    return np.array([[cp*cy, -cp*sy, sp],
                     [sr*sp*cy+cr*sy, -sr*sp*sy+cr*cy, -sr*cp],
                     [-cr*sp*cy+sr*sy, cr*sp*sy+sr*cy, cr*cp]])

def rot_to_euler(rot):
    c2 = np.sqrt(rot[0, 0]**2+rot[0, 1]**2)

    roll = np.arctan2(rot[1, 2], rot[2, 2])
    s1 = np.sin(roll)
    c1 = np.cos(roll)

    pitch = np.arctan2(-rot[0, 2], c2)
    yaw = np.arctan2(s1*rot[0, 2]-c1*rot[1, 0], c1*rot[1, 1]-s1*rot[2, 1])

    return roll, pitch, yaw

def inverse_kinematics(pose, p, r):
    #pose = X Y Z R P Y
    # print(pose)
    a = 0.09548
    l1 = 0.20327
    l2 = 0.15245
    l3 = 0.044
    d = 0.20603
    x = pose[0]#, -1]#pose[0]
    y = pose[1]#, -1]
    z = pose[2]#, -1]
    # rot = pose[0:3, 0:3]#euler_to_rot(pose[3], pose[4], pose[5])
    # roll, pitch, yaw = rot_to_euler(rot)

    #SOLVE FOR THETA 0
    theta_0 = np.nan_to_num(np.arctan2(y, x))
    x_ = ((np.cos(theta_0)*x+np.sin(theta_0)*y)-a)
    z_ = z-d
    #SOLVE FOR THETA 2
    c2 = (x_**2+z_**2-l1**2-l2**2)/(2.*l1*l2)
    s2_pos = np.nan_to_num(np.sqrt(1.-c2**2)) #ELBOW DOWN
    s2_neg = -np.nan_to_num(np.sqrt(1.-c2**2)) #ELBOW UP
    theta_2 = np.arctan2(s2_neg, c2)
    #SOLVE FOR THETA 1
    k1 = l1+l2*c2
    k2 = l2*s2_neg
    theta_1 = np.arctan2(z_, x_)-np.arctan2(k2, k1)
    #SOLVE FOR THETA 3
    theta_3 = p-(theta_1+theta_2)
    #SOLVE FOR THETA_4
    theta_4 = r
    thetas = [theta_0, theta_1, theta_2, theta_3, theta_4]
    return thetas

def plot(joints, col, ax):
    for i in range(len(joints)):
        #PLOT JOINT
        ax.scatter(joints[i][0, -1], joints[i][1, -1], joints[i][2, -1], c='k')

        #PLOT LINK
        if i < len(joints)-1:
            ax.plot([joints[i][0, -1], joints[i+1][0, -1]], [joints[i][1, -1], joints[i+1][1, -1]],
                    [joints[i][2, -1], joints[i+1][2, -1]], c = col)

        #PLOT JOINT AXIS
        # u = .1
        # xs = (joints[i][0:3, -1]+joints[i][0:3, 0]*u)
        # ys = (joints[i][0:3, -1]+joints[i][0:3, 1]*u)
        # zs = (joints[i][0:3, -1]+joints[i][0:3, 2]*u)
        # # xs = joints[i][0:3, -1] * (1. - u) + u * norm_orientation[0:3, 0]
        # # ys = joints[i][0:3, -1]*(1.-u)+u*norm_orientation[0:3, 1]
        # # zs = joints[i][0:3, -1]*(1.-u)+u*norm_orientation[0:3, 2]
        # ax.plot([joints[i][0, -1], xs[0]], [joints[i][1, -1], xs[1]], [joints[i][2, -1], xs[2]], c='r')
        # ax.plot([joints[i][0, -1], ys[0]], [joints[i][1, -1], ys[1]], [joints[i][2, -1], ys[2]], c='g')
        # ax.plot([joints[i][0, -1], zs[0]], [joints[i][1, -1], zs[1]], [joints[i][2, -1], zs[2]], c='b')

def init_plot():
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.set_xlim((-.5, .5))
    ax.set_ylim((-.5, .5))
    ax.set_zlim((-.5, .5))
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    return ax

def get_constants(initial_theta, final_theta, time_start, time_step):
    time_final = time_start + time_step
    traj_mat = np.array([[1., time_start, time_start ** 2, time_start ** 3],
                         [0., 1., time_start * 2., 3. * time_start ** 2],
                         [1., time_final, time_final ** 2, time_final ** 3],
                         [0., 1., time_final * 2., 3. * time_final ** 2]])
    b = np.array([initial_theta, 0., final_theta, 0.])
    return np.dot(np.linalg.pinv(traj_mat), b.T)

if __name__=="__main__":
    # a = 0.09548
    # l1 = 0.20327
    # l2 = 0.15245
    # l3 = 0.044
    # d = 0.20603
    # ax = init_plot()
    # initial_thetas = [0., 0., 0., 0., 0.]
    # joints = forward_kinematics(initial_thetas)
    # # print(joints[1][0:3,0:3])
    # plot(joints, 'r', ax)
    #
    # initial_thetas = [np.pi/2., np.pi/4., -np.pi/4., 0., 0.]
    # joints = forward_kinematics(initial_thetas)
    # # print(joints[1][0:3,0:3])
    # plot(joints, 'r',ax)
    # # initial_thetas = [-np.pi/2., np.pi/4., -np.pi/4., 0., 0.]
    # # joints = forward_kinematics(initial_thetas)
    # # plot(joints, 'r',ax)
    #
    #
    # # pose = [0., a+np.cos(np.pi/4.)*(l1+l2+l3), d+np.sin(np.pi/4.)*(l1+l2+l3)]
    #
    # theta = inverse_kinematics(joints[-3], 0., 0.)
    # joints_2 = forward_kinematics(theta)
    # plot(joints_2, 'b', ax)
    # plt.show()
    # # print(forward_kinematics(theta))
    get_jacobian_arm()

if __name__ == "__main__":
    print(inverse_kinematics([0.520, 0.041, 0.0927], 0, 0))


import numpy as np
from fractions import Fraction

_k = [0 for i in range(24)]
_b = [0 for i in range(24)]

_k[0] = _b[0] = 224 + Fraction(50, 60) + Fraction(22, 3600)

# raNgebAlAstrI
divisor = 233 + Fraction(32, 60)

# Nilakantha recurrence relations
for i in range(1,24):
    _k[i] = _k[i-1] - (_b[i-1] / divisor)
    _b[i] = _b[i-1] + _k[i]

def khandajya(k: int):
    """
    Return the kth khandajya computed by the nilakantha recurrence

    Inputs:
      k (int) : index from 0 to 23
    Outputs:
      int : kth khandajya
    """
    assert ((k>=0) & (k<24)), f"Input must be between 0 and 23 inclusive, got {k}"
    return float(_k[k])

def pindajya(k: int):
    """
    Return the kth pindajya computed by the nilakantha recurrence

    Inputs:
      k (int) : index from 0 to 23
    Outputs:
      int : kth pindajya
    """
    assert ((k>=0) & (k<24)), f"Input must be between 0 and 23 inclusive, got {k}"
    return float(_b[k])


import numpy as n, pylab as p
from scipy import stats as st
a=st.norm(0,1)
b=st.norm(0.1,1)
domain=n.linspace(-4,4,10000)
avals=a.cdf(domain)
bvals=b.cdf(domain)
diffN=n.abs(avals-bvals).max()

a=st.norm(0,1)
b=st.norm(0,1.2)
domain=n.linspace(-4,4,10000)
avals=a.cdf(domain)
bvals=b.cdf(domain)
diffN2=n.abs(avals-bvals).max()

a=st.uniform(0,1)
b=st.uniform(0.05,1.0)
domain=n.linspace(0,1.05,10000)
avals=a.cdf(domain)
bvals=b.cdf(domain)
diffU=n.abs(avals-bvals).max()

a=st.uniform(0,1)
b=st.uniform(-0.05,1.05)
domain=n.linspace(0,1.05,10000)
avals=a.cdf(domain)
bvals=b.cdf(domain)
diffU2=n.abs(avals-bvals).max()

#a=st.weibull(1.5)
#b=st.weibull(1.7)
#domain=n.linspace(0,1.05,10000)
#avals=a.cdf(domain)
#bvals=b.cdf(domain)
#diffW=n.abs(avals-bvals).max()

#a=st.power(1.5)
#b=st.power(1.7)
#domain=n.linspace(0,1.05,10000)
#avals=a.cdf(domain)
#bvals=b.cdf(domain)
#diffP=n.abs(avals-bvals).max()

#x = n.arange(1,100.)/50.
x=n.linspace(0,20,100000)
step=x[1]-x[0]
def weib(x,nn,a):
    return (a / nn) * (x / nn)**(a - 1) * n.exp(-(x / nn)**a)

#count, bins, ignored = p.hist(n.random.weibull(5.,1000))
#x = n.arange(1,100.)/50.
#scale = count.max()/weib(x, 1., 5.).max()
W=weib(x, 1., 1.5)
W_=W/(W*step).sum()
W__=n.cumsum(W_)
W2=weib(x, 1., 1.7)
W2_=W2/(W2*step).sum()
W2__=n.cumsum(W2_)
diffW=n.abs(W_-W2_).max()
#p.plot(x, W_)
#p.plot(x, W2_)
##p.plot(x, weib(x, 1., 5.)*scale)
#p.show()

a=st.powerlaw(1.5)
b=st.powerlaw(1.7)
domain=n.linspace(0,5.05,10000)
avals=a.cdf(domain)
bvals=b.cdf(domain)
diffP=n.abs(avals-bvals).max()

print("distancias de KS para os modelos matematicos:", diffN,diffN2,diffU,diffU2,diffW,diffP)
# distancias de KS para os modelos matematicos:
# 0.0398776116762 0.0439947104098 0.0952338090952 0.047619047619 0.128565475845 0.0460149130584

# X = (-n.ln(U))^{1/a}
lb,rb,NE,shape1,shape2=0,10,10000,1.5,1.7
x=n.linspace(lb,rb,NE)
step=x[1]-x[0]
W=weib(x, 1., shape1)
W_=W/((W*step).sum())
W__=n.cumsum(W_)
W2=weib(x, 1., shape2)
W2_=W2/((W2*step).sum())
W2__=n.cumsum(W2_)
diffW=n.abs(W__-W2__).max()

lb,rb,NE,shape1,shape2=0,10,10000,1.5,1.7
x=n.linspace(lb,rb,NE)
step=x[1]-x[0]
W=weib(x, 1., shape1)
W_=W/((W).sum())
W__=n.cumsum(W_)
W2=weib(x, 1., shape2)
W2_=W2/((W2).sum())
W2__=n.cumsum(W2_)
diffW=n.abs(W__-W2__).max()


import numpy as np

class LogisticRegression:
    def __init__(self, alpha=1, tol=1e-7, max_iter=1000):
        self.alpha = alpha
        #self.solver = solver
        self.tol = tol
        self.max_iter = max_iter
        #self.penalty = penalty

    def __sigmoid(self, X, W, b):
        z = np.dot(W.T, X) + b

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

    def __costFunction(self, W, b, X, Y):
        y_hat = self.__sigmoid(X, W, b)

        loss = (Y * np.log(y_hat) + (1-Y) * np.log(1-y_hat))

        cost = -np.mean(loss)

        return cost

    def __computeGradient(self, X, Y, W, b):
        [N_x, M] = X.shape

        y_hat = self.__sigmoid(X, W, b)

        dW = (1/M)*np.dot(X, (y_hat - Y).T)
        db = (1/M)*np.sum(y_hat - Y, axis=1, keepdims=True)

        return dW, db

    def __gradientDescent(self, X, Y):
        [N_X, M] = X.shape

        self.W = np.zeros((N_X, 1))
        self.b = 0

        J_old = self.__costFunction(self.W, self.b, X, Y)
        dW, db = self.__computeGradient(X, Y, self.W, self.b)

        self.cost_list = []
        for i in range(self.max_iter):
            self.cost_list.append(J_old)
            print('Cost after iteration %i: %f' %(i, J_old ))

            self.W -= self.alpha*dW
            self.b -= self.alpha*db

            J_new = self.__costFunction(self.W, self.b, X, Y)

            if (np.abs(J_new - J_old) < self.tol):
                break

            dW, db = self.__computeGradient(X, Y, self.W, self.b)
            J_old = J_new

    def run(self, X, Y):
        self.__gradientDescent(X, Y)

    def predict(self, new_X):
        y_hat = self.__sigmoid(new_X, self.W, self.b)

        return y_hat


import numpy as np
from numpy.linalg import norm, eig, inv

def cosine(x, y):
    return np.dot(x,y) / (norm(x) * norm(y))

def main():
    X = np.array([[1, 1, 0], [2, 2, 0], [0, 0.01, 1], [0, 0.01, 1.1]], dtype=np.float)
    print("Data Matrix")
    print(X)

    S = np.zeros((4,4), dtype=np.float)
    for i in range(4):
        for j in range(4):
            S[i,j] = cosine(X[i,:], X[j,:])

    print("\nSimilarity Matrix")
    print(S)

    D = np.zeros(4)
    for i in range(4):
        D[i] = np.sum(S[i,:])

    print("Degree matrix")
    Dm = np.diag(D)
    print(Dm)

    Ds = np.sqrt(inv(Dm))
    L = np.dot(Ds, np.dot(S, Ds))

    e, A = eig(L)

    # sort the eigenvalues and corresponding eigenvectors in the ascending order
    sortind = np.argsort(e)
    e = e[sortind]
    A = A[:, sortind]

    print("\nEigenvalues")
    print(e)

    print("\nEigenvectors")
    print(A)

    # Check whether eigenvalue decomposition is correct.
    print(norm(L @ A[:,2] - e[2] * A[:,2]))
    pass

if __name__ == '__main__':
    main()


"""Get pi with Monte Carlo simulation."""

import mpmath
import numpy as np

from calcpi import print_prettify  # noqa: F401  # pylint: disable=unused-import

def pi(accuracy: int) -> mpmath.mpf:  # pylint: disable=invalid-name
    """Return Pi gotten by Monte Carlo simulation.

    Args:
        accuracy (int): [description]

    Returns:
        mpmath.mpf: Pi
    """
    mpmath.mp.dps = accuracy
    points = np.random.uniform(size=(accuracy, 2))
    point_count = points.shape[0]
    distances = np.power(points[:, 0], 2) + np.power(points[:, 1], 2)
    inner_circle_point_count = np.count_nonzero(distances <= 1)
    return mpmath.mpf(4) * inner_circle_point_count / point_count


import numpy as np

def compress_image(image, num_values):
    """Compress an image using SVD and keeping the top `num_values` singular values.

    Args:
        image: numpy array of shape (H, W)
        num_values: number of singular values to keep

    Returns:
        compressed_image: numpy array of shape (H, W) containing the compressed image
        compressed_size: size of the compressed image
    """
    compressed_image = None
    compressed_size = 0

    # YOUR CODE HERE

    # Steps:
    #     1. Get SVD of the image
    #     2. Only keep the top `num_values` singular values, and compute `compressed_image`
    #     3. Compute the compressed size
    u, s, v = np.linalg.svd(image)
    compressed_image = np.dot(u[:, :num_values].dot(np.diag(s[:num_values])), v[:num_values, :])
    compressed_size = num_values * u.shape[0] + num_values + num_values * v.shape[1]
    pass
    # END YOUR CODE

    assert compressed_image.shape == image.shape, \
           "Compressed image and original image don't have the same shape"

    assert compressed_size > 0, "Don't forget to compute compressed_size"

    return compressed_image, compressed_size


# From http://ethen8181.github.io/machine-learning/ab_tests/frequentist_ab_test.html#Comparing-Two-Proportions

# See https://towardsdatascience.com/python-code-from-hypothesis-test-to-online-experiments-with-buiness-cases-e0597c6d1ec

import statsmodels.stats.api as sms

def two_proprotions_test(success_a, size_a, success_b, size_b):
    """
    A/B test for two proportions;
    given a success a trial size of group A and B compute
    its zscore and pvalue

    Parameters
    ----------
    success_a, success_b : int
        Number of successes in each group

    size_a, size_b : int
        Size, or number of observations in each group

    Returns
    -------
    zscore : float
        test statistic for the two proportion z-test

    pvalue : float
        p-value for the two proportion z-test
    """
    prop_a = success_a / size_a
    prop_b = success_b / size_b
    prop_pooled = (success_a + success_b) / (size_a + size_b)
    var = prop_pooled * (1 - prop_pooled) * (1 / size_a + 1 / size_b)
    zscore = np.abs(prop_b - prop_a) / np.sqrt(var)
    one_side = 1 - stats.norm(loc = 0, scale = 1).cdf(zscore)
    pvalue = one_side * 2
    return zscore, pvalue

def demo_two_proprotions_test():
    success_a = 486
    size_a = 5000
    success_b = 527
    size_b = 5000

    zscore, pvalue = two_proprotions_test(success_a, size_a, success_b, size_b)
    print('zscore = {:.3f}, pvalue = {:.3f}'.format(zscore, pvalue))

def compute_sample_size(prop1, min_diff, significance=0.05, power=0.8):
    """
    Computes the sample sized required for a two-proportion A/B test;
    result matches R's pwr.2p.test from the pwr package

    Parameters
    ----------
    prop1 : float
        The baseline proportion, e.g. conversion rate

    min_diff : float
        Minimum detectable difference

    significance : float, default 0.05
        Often denoted as alpha. Governs the chance of a false positive.
        A significance level of 0.05 means that there is a 5% chance of
        a false positive. In other words, our confidence level is
        1 - 0.05 = 0.95

    power : float, default 0.8
        Often denoted as beta. Power of 0.80 means that there is an 80%
        chance that if there was an effect, we would detect it
        (or a 20% chance that we'd miss the effect)

    Returns
    -------
    sample_size : int
        Required sample size for each group of the experiment

    References
    ----------
    R pwr package's vignette
    - https://cran.r-project.org/web/packages/pwr/vignettes/pwr-vignette.html

    Stackoverflow: Is there a python (scipy) function to determine parameters
    needed to obtain a target power?
    - https://stackoverflow.com/questions/15204070/is-there-a-python-scipy-function-to-determine-parameters-needed-to-obtain-a-ta
    """
    prop2 = prop1 + min_diff
    effect_size = sms.proportion_effectsize(prop1, prop2)
    sample_size = sms.NormalIndPower().solve_power(
        effect_size, power=power, alpha=significance, ratio=1)

    return sample_size


import numpy as np

"""

# https://github.com/smoonka/SuperResolution/blob/master/ycbcr2rgb.m

[0.256788235294118         0.504129411764706        0.0979058823529412
-0.148223529411765        -0.290992156862745        0.43921568627451
 0.43921568627451         -0.367788235294118       -0.0714274509803921] * [R;G;B] + [16;128;128]

"""

ycbcr_from_rgb = np.array([[65.481, 128.553, 24.966],
                           [-37.797, -74.203, 112.0],
                           [112.0, -93.786, -18.214]])

rgb_from_ycbcr = np.linalg.inv(ycbcr_from_rgb)

def rgb2ycbcr(image):
    _type = image.dtype
    _image = image.astype(np.float32)
    if _type != np.uint8:
        _image = _image * 255

    _image = _image @ ycbcr_from_rgb.T / 255

    _image = _image + np.array([[[16, 128, 128]]])

    _image = np.round(_image)
    if _type != np.uint8:
        _image = _image / 255

    return _image.astype(_type)

def ycbcr2rgb(image):
    _type = image.dtype
    _image = image.astype(np.float32)
    if _type != np.uint8:
        _image = _image * 255

    _image = _image - np.array([[[16, 128, 128]]])
    _image = _image @ rgb_from_ycbcr.T * 255

    if _type != np.uint8:
        _image = _image / 255

    return _image.astype(_type)

if __name__ == '__main__':
    import cv2
    import os

    project_root = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))

    _image_ = cv2.imread(os.path.join(project_root, 'experiments/exp3/obama.bmp'))
    rgb = cv2.cvtColor(_image_, cv2.COLOR_BGR2RGB)

    # rgb = rgb.astype(np.float32) / 255
    yuv = rgb2ycbcr(rgb)
    _rgb = ycbcr2rgb(yuv)

    # _rgb = _rgb.astype(np.uint8)

    bgr = cv2.cvtColor(_rgb, cv2.COLOR_RGB2BGR)

    cv2.imshow('asdf', yuv[:, :, 0])
    cv2.imshow('bgr', bgr)

    cv2.waitKey()


#
# DeepRacer Guru
#
# Version 3.0 onwards
#
# Copyright (c) 2021 dmh23
#

import numpy as np
from scipy import stats, optimize

#  TODO - fix duplications, initial check-in just gets it working with different flavours of equation ...

def get_linear_regression(plot_x: np.ndarray, plot_y: np.ndarray):
    assert len(plot_x) == len(plot_y)
    assert not np.isnan(plot_x).any()     # X axis must be complete, no gaps indicated by NaN

    # Remove non-numbers/gaps indicated by the y axis values
    nan_filter = np.isfinite(plot_y)
    analyse_x = plot_x[nan_filter]
    analyse_y = plot_y[nan_filter]

    if len(analyse_x) <= 2:
        return analyse_x, analyse_y, 1
    else:
        slope, intercept, r, p, std_err = stats.linregress(analyse_x, analyse_y)

        min_x = np.min(analyse_x)
        max_x = np.max(analyse_x)
        step_x = (max_x - min_x) / 100
        fitted_x = np.arange(min_x, max_x + step_x, step_x)

        def fitted_line(x):
            return slope * x + intercept

        fitted_y = list(map(fitted_line, fitted_x))
        return fitted_x, fitted_y, r

def f_quadratic(x, a, b, c):
    return a * x + b * x ** 2 + c

def get_quadratic_regression(plot_x: np.ndarray, plot_y: np.ndarray):
    assert len(plot_x) == len(plot_y)
    assert not np.isnan(plot_x).any()     # X axis must be complete, no gaps indicated by NaN

    # Remove non-numbers/gaps indicated by the y axis values
    nan_filter = np.isfinite(plot_y)
    analyse_x = plot_x[nan_filter]
    analyse_y = plot_y[nan_filter]

    if len(analyse_x) <= 2:
        return analyse_x, analyse_y
    else:
        params, _ = optimize.curve_fit(f_quadratic, analyse_x, analyse_y)
        (a, b, c) = params

        min_x = np.min(analyse_x)
        max_x = np.max(analyse_x)
        step_x = (max_x - min_x) / 100
        fitted_x = np.arange(min_x, max_x + step_x, step_x)

        def fitted_line(x):
            return f_quadratic(x, a, b, c)

        fitted_y = list(map(fitted_line, fitted_x))
        return fitted_x, fitted_y

def f_cubic(x, a, b, c, d):
    return a * x + b * x ** 2 + c * x ** 3 + d

def get_cubic_regression(plot_x: np.ndarray, plot_y: np.ndarray):
    assert len(plot_x) == len(plot_y)
    assert not np.isnan(plot_x).any()     # X axis must be complete, no gaps indicated by NaN

    # Remove non-numbers/gaps indicated by the y axis values
    nan_filter = np.isfinite(plot_y)
    analyse_x = plot_x[nan_filter]
    analyse_y = plot_y[nan_filter]

    if len(analyse_x) <= 2:
        return analyse_x, analyse_y
    else:
        params, _ = optimize.curve_fit(f_cubic, analyse_x, analyse_y)
        (a, b, c, d) = params

        min_x = np.min(analyse_x)
        max_x = np.max(analyse_x)
        step_x = (max_x - min_x) / 100
        fitted_x = np.arange(min_x, max_x + step_x, step_x)

        def fitted_line(x):
            return f_cubic(x, a, b, c, d)

        fitted_y = list(map(fitted_line, fitted_x))
        return fitted_x, fitted_y


# IPT11
# @autor Lukáš Plevač
# @date 8.12.2020

import numpy as np
import math

np.set_printoptions(suppress=True)

###
# LINEAR
##

## Pomocí regresní přímky popište závislost Yi na Xi
# @param Xi np.array of values
# @param Yi np.array of values
# @return beta0 and beta1
def regreseLinearBetas(Xi, Yi):
    # n * beta0 + Xi.sum() * beta1 = Yi.sum()
    # Xi.sum() * beta0 + Xi.pow(2).sum() = Xi.sum * Yi.sum()

    if (Xi.shape != Yi.shape):
        print("error Xi shape is not smae as Yi shape")
        return 0, 0

    Xi_sum      = Xi.sum()

    Xi_pow2_sum = np.power(Xi, 2)
    Xi_pow2_sum = Xi_pow2_sum.sum()

    Yi_sum      = Yi.sum()

    n           = Xi.size

    Xi_mul_Yi_sum = (Xi * Yi).sum()

    print("{}Beta0 + {}beta1 = {}".format(n, Xi_sum, Yi_sum))
    print("{}Beta0 + {}beta1 = {}".format(Xi_sum, Xi_pow2_sum, Xi_mul_Yi_sum))

    # clac betas
    xx = np.array([
        [n, Xi_sum],
        [Xi_sum, Xi_pow2_sum]
    ])

    xy = np.array([
        [Yi_sum],
        [Xi_mul_Yi_sum]
    ])

    betas = np.matmul(np.linalg.inv(xx), xy)

    print("#############################")
    print("betas = (X'X)**-1 . X'Y = ")
    print(np.linalg.inv(xx))
    print(".")
    print(xy)
    print("=")
    print(betas)
    print("Beta0 is {}, Beta1 is {}".format(betas[0][0], betas[1][0]))
    print("#############################")

    return betas[0][0], betas[1][0]

## Provede předpověď Y pro X
# @param beta0
# @param beta1
# @param X
# @retrn Predicted value
def regreseLinearPredict(beta0, beta1, x):
    y = beta0 + (beta1 * x)
    print("#############################")
    print("Y = beta0 + beta1 * x = {}".format(y))
    print("#############################")
    return y

# Get Se of regreseLinear
# @param beta0
# @param beta1
# @param Xi
# @param Yi
# @retrn Se
def regreseLinearGetSe(beta0, beta1, Xi, Yi):

    Yi_pow2_sum = np.power(Yi, 2)
    Yi_pow2_sum = Yi_pow2_sum.sum()

    Yi_sum      = Yi.sum()

    Xi_mul_Yi_sum = (Xi * Yi).sum()

    print("Yi.pow(2).sum is {}".format(Yi_pow2_sum))
    print("Yi.sum is {}".format(Yi_pow2_sum))
    print("(Xi * Yi).sum() is {}".format(Xi_mul_Yi_sum))

    Se = Yi_pow2_sum - beta0 * Yi_sum - beta1 * Xi_mul_Yi_sum

    print("#####################")
    print("Se = {} - {} * {} - {} * {} = {}".format(
         Yi_pow2_sum,
         beta0,
         Yi_sum,
         beta1,
         Xi_mul_Yi_sum,
         Se
    ))
    print("#####################")

    return Se

# Get SigmaPow2 regreseLinear
# @param beta0
# @param beta1
# @param Xi
# @param Yi
# @retrn Sigma**2
def regreseLinearGetSigmaPow2(beta0, beta1, Xi, Yi):
    Se = regreseLinearGetSe(beta0, beta1, Xi, Yi)
    n  = Xi.size

    SigmaPow2 = Se / (n-2)

    print("#####################")
    print("SigmaPow2 = s**2 = Se / (n-2) = {} / ({} - 2) = {}".format(
         Se,
         n,
         SigmaPow2
    ))
    print("#####################")

    return SigmaPow2

# Get Qvality or regreseLinear in %
# @param beta0
# @param beta1
# @param Xi
# @param Yi
# @retrn R**2
def regreseLinearGetQvality(beta0, beta1, Xi, Yi):
    prum = np.mean(Yi)

    Sypow2 = (1 / (Yi.size - 1)) * np.power(Yi - prum, 2).sum()

    print("#####################")
    print("Sy**2 = (1 / ( n - 1)) * suma((Yi - prum(Y)) ** 2) = {}".format(
         Sypow2
    ))
    print("#####################")

    St = Sypow2 * (Yi.size - 1)

    print("#####################")
    print("St = ( n - 1) * Sy**2 = {}".format(
         St
    ))
    print("#####################")

    Se = regreseLinearGetSe(beta0, beta1, Xi, Yi)

    Rpow2 = 1 - Se / St

    print("#####################")
    print("R**2 = 1 - Se / St = 1 - {} / {} = {}".format(
         Se,
         St,
         Rpow2
    ))
    print("#####################")

    return Rpow2

###
# HYPERBOLA
##

## Pomocí regresní hyperboly popište závislost Yi na Xi
# @param Xi np.array of values
# @param Yi np.array of values
# @return beta0, beta1 and beta2
def regreseHyperbolaBetas(Xi, Yi):
    # n * beta0 + Xi.sum() * beta1 + Xi.pow2.sum() * beta2 = Yi.sum()
    # Xi.sum() * beta0 + Xi.pow(2).sum() + Xi.pow(3).sum()* beta2 = Xi.sum * Yi.sum()
    # Xi.pow(2).sum() * beta0 + Xi.pow(3).sum() + Xi.pow(4).sum() * beta2 = Xi.pow(2).sum * Yi.sum()

    if (Xi.shape != Yi.shape):
        print("error Xi shape is not smae as Yi shape")
        return 0, 0

    Xi_sum      = Xi.sum()
    Xi_pow2_sum = np.power(Xi, 2).sum()
    Xi_pow3_sum = np.power(Xi, 3).sum()
    Xi_pow4_sum = np.power(Xi, 4).sum()

    Yi_sum      = Yi.sum()

    Xi_mul_Yi_sum      = (Xi * Yi).sum()
    Xi_pow2_mul_Yi_sum = (np.power(Xi, 2) * Yi).sum()

    n                  = Xi.size

    print("{}Beta0 + {}beta1 + {}beta2 = {}".format(n, Xi_sum, Xi_pow2_sum, Yi_sum))
    print("{}Beta0 + {}beta1 + {}beta2 = {}".format(Xi_sum, Xi_pow2_sum, Xi_pow3_sum, Xi_mul_Yi_sum))
    print("{}Beta0 + {}beta1 + {}beta2 = {}".format(Xi_pow2_sum, Xi_pow3_sum, Xi_pow4_sum, Xi_pow2_mul_Yi_sum))

    # clac betas
    xx = np.array([
        [n, Xi_sum, Xi_pow2_sum],
        [Xi_sum, Xi_pow2_sum, Xi_pow3_sum],
        [Xi_pow2_sum, Xi_pow3_sum, Xi_pow4_sum]
    ])

    xy = np.array([
        [Yi_sum],
        [Xi_mul_Yi_sum],
        [Xi_pow2_mul_Yi_sum]
    ])

    betas = np.matmul(np.linalg.inv(xx), xy)

    print("#############################")
    print("betas = (X'X)**-1 . X'Y = ")
    print(np.linalg.inv(xx))
    print(".")
    print(xy)
    print("=")
    print(betas)
    print("Beta0 is {}, Beta1 is {}, Beta2 is {}".format(betas[0][0], betas[1][0], betas[2][0]))
    print("#############################")

    return betas[0][0], betas[1][0], betas[2][0]

## Provede předpověď Y pro X
# @param beta0
# @param beta1
# @param beta2
# @param X
# @retrn Predicted value
def regreseHyperbolaPredict(beta0, beta1, beta2, x):
    y = beta0 + (beta1 * x) + (beta2 * x ** 2)
    print("#############################")
    print("Y = beta0 + beta1 * x + beta2 * x ** 2 = {}".format(y))
    print("#############################")
    return y

# get Se for regreseHyperbola
# @param beta0
# @param beta1
# @param beta2
# @param Xi
# @param Yi
# @retrn Se
def regreseHyperbolaGetSe(beta0, beta1, beta2, Xi, Yi):
    Yi_pow2_sum = np.power(Yi, 2).sum()
    Yi_sum      = Yi.sum()

    Xi_mul_Yi_sum = (Xi * Yi).sum()
    Xi_pow2_mul_Yi_sum = (np.power(Xi, 2) * Yi).sum()

    Se = Yi_pow2_sum - beta0 * Yi_sum - beta1 * Xi_mul_Yi_sum - beta2 * Xi_pow2_mul_Yi_sum

    print("#####################")
    print("Se = {} - {} * {} - {} * {} - {} * {} = {}".format(
         Yi_pow2_sum,
         beta0,
         Yi_sum,
         beta1,
         Xi_mul_Yi_sum,
         beta2,
         Xi_pow2_mul_Yi_sum,
         Se
    ))
    print("#####################")

    return Se

# Get SigmaPow2 regreseHyperbola
# @param beta0
# @param beta1
# @param beta3
# @param Xi
# @param Yi
# @retrn Sigma**2
def regreseHyperbolaGetSigmaPow2(beta0, beta1, beta2, Xi, Yi):
    Se = regreseHyperbolaGetSe(beta0, beta1, beta2, Xi, Yi)
    n  = Xi.size

    SigmaPow2 = Se / (n-3)

    print("#####################")
    print("SigmaPow2 = s**2 = Se / (n-3) = {} / ({} - 3) = {}".format(
         Se,
         n,
         SigmaPow2
    ))
    print("#####################")

    return SigmaPow2

# Get Qvality or regreseHyperbola in %
# @param beta0
# @param beta1
# @param beta2
# @param Xi
# @param Yi
# @retrn R**2
def regreseHyperolaGetQvality(beta0, beta1, beta2, Xi, Yi):
    prum = np.mean(Yi)

    Sypow2 = (1 / (Yi.size - 1)) * np.power(Yi - prum, 2).sum()

    print("#####################")
    print("Sy**2 = (1 / ( n - 1)) * suma((Yi - prum(Y)) ** 2) = {}".format(
         Sypow2
    ))
    print("#####################")

    St = Sypow2 * (Yi.size - 1)

    print("#####################")
    print("St = ( n - 1) * Sy**2 = {}".format(
         St
    ))
    print("#####################")

    Se = regreseHyperbolaGetSe(beta0, beta1, beta2, Xi, Yi)

    Rpow2 = 1 - Se / St

    print("#####################")
    print("R**2 = 1 - Se / St = 1 - {} / {} = {}".format(
         Se,
         St,
         Rpow2
    ))
    print("#####################")

    return Rpow2

###
# PLANE
##

## Pomocí regresní roviny popište závislost Yi na Xi a Zi
# @param Xi np.array of values
# @param Yi np.array of values
# @param Zi np.array of values
# @return beta0, beta1 and beta2
def regresePlaneBetas(Xi, Yi, Zi):
    # n * beta0 + Xi.sum() * beta1 + Zi.sum() * beta2 = Yi.sum()
    # Xi.sum() * beta0 + Xi.pow(2).sum() * beta1 + (Zi * Xi).sum() * beta2 = (Xi * Yi).sum()
    # Zi.sum() * beta0 + (Zi * Xi).sum() * beta1 + Zi.pow(2).sum() * beta2 = (Zi * Yi).sum()

    if ((Xi.shape != Yi.shape) and (Xi.shape != Zi.shape)):
        print("error Xi shape is not same as Yi shape or Zi shape")
        return 0, 0

    Xi_sum      = Xi.sum()
    Xi_pow2_sum = np.power(Xi, 2).sum()

    Zi_sum = Zi.sum()
    Zi_pow2_sum = np.power(Zi, 2).sum()

    Xi_mul_Zi_sum = (Zi * Xi).sum()

    Yi_sum        = Yi.sum()

    Xi_mul_Yi_sum = (Xi * Yi).sum()
    Zi_mul_Yi_sum = (Zi * Yi).sum()

    n             = Xi.size

    print("{}Beta0 + {}beta1 + {}beta2 = {}".format(n, Xi_sum, Zi_sum, Yi_sum))
    print("{}Beta0 + {}beta1 + {}beta2 = {}".format(Xi_sum, Xi_pow2_sum, Xi_mul_Zi_sum, Xi_mul_Yi_sum))
    print("{}Beta0 + {}beta1 + {}beta2 = {}".format(Zi_sum, Xi_mul_Zi_sum, Zi_pow2_sum, Zi_mul_Yi_sum))

    # clac betas
    xx = np.array([
        [n, Xi_sum, Zi_sum],
        [Xi_sum, Xi_pow2_sum, Xi_mul_Zi_sum],
        [Zi_sum, Xi_mul_Zi_sum, Zi_pow2_sum]
    ])

    xy = np.array([
        [Yi_sum],
        [Xi_mul_Yi_sum],
        [Zi_mul_Yi_sum]
    ])

    betas = np.matmul(np.linalg.inv(xx), xy)

    print("#############################")
    print("betas = (X'X)**-1 . X'Y = ")
    print(np.linalg.inv(xx))
    print(".")
    print(xy)
    print("=")
    print(betas)
    print("Beta0 is {}, Beta1 is {}, Beta2 is {}".format(betas[0][0], betas[1][0], betas[2][0]))
    print("#############################")

    return betas[0][0], betas[1][0], betas[2][0]

## do predict Y from X and Z
# @param Xi np.array of values
# @param Yi np.array of values
# @param Zi np.array of values
# @return Y value
def regresePlanePredict(beta0, beta1, beta2, x, z):
    y = beta0 + (beta1 * x) + (beta2 * z)
    print("#############################")
    print("Y = beta0 + beta1 * x + beta2 * z = {}".format(y))
    print("#############################")
    return y

# get Se for regresePlane
# @param beta0
# @param beta1
# @param beta2
# @param Xi
# @param Yi
# @param Zi
# @retrn Se
def regresePlaneGetSe(beta0, beta1, beta2, Xi, Yi, Zi):
    Yi_pow2_sum = np.power(Yi, 2).sum()
    Yi_sum      = Yi.sum()

    Xi_mul_Yi_sum = (Xi * Yi).sum()
    Zi_mul_Yi_sum = (Zi * Yi).sum()

    Se = Yi_pow2_sum - beta0 * Yi_sum - beta1 * Xi_mul_Yi_sum - beta2 * Zi_mul_Yi_sum

    print("#####################")
    print("Se = {} - {} * {} - {} * {} - {} * {} = {}".format(
         Yi_pow2_sum,
         beta0,
         Yi_sum,
         beta1,
         Xi_mul_Yi_sum,
         beta2,
         Zi_mul_Yi_sum,
         Se
    ))
    print("#####################")

    return Se

# Get SigmaPow2 regresePlane
# @param beta0
# @param beta1
# @param beta3
# @param Xi
# @param Yi
# @retrn Sigma**2
def regresePlaneGetSigmaPow2(beta0, beta1, beta2, Xi, Yi, Zi):
    Se = regresePlaneGetSe(beta0, beta1, beta2, Xi, Yi, Zi)
    n  = Xi.size

    SigmaPow2 = Se / (n-3)

    print("#####################")
    print("SigmaPow2 = s**2 = Se / (n-3) = {} / ({} - 3) = {}".format(
         Se,
         n,
         SigmaPow2
    ))
    print("#####################")

    return SigmaPow2

# Get Qvality or regreseHyperbola in %
# @param beta0
# @param beta1
# @param beta2
# @param Xi
# @param Yi
# @param Zi
# @retrn R**2
def regresePlaneGetQvality(beta0, beta1, beta2, Xi, Yi, Zi):
    prum = np.mean(Yi)

    Sypow2 = (1 / (Yi.size - 1)) * np.power(Yi - prum, 2).sum()

    print("#####################")
    print("Sy**2 = (1 / ( n - 1)) * suma((Yi - prum(Y)) ** 2) = {}".format(
         Sypow2
    ))
    print("#####################")

    St = Sypow2 * (Yi.size - 1)

    print("#####################")
    print("St = ( n - 1) * Sy**2 = {}".format(
         St
    ))
    print("#####################")

    Se = regresePlaneGetSe(beta0, beta1, beta2, Xi, Yi, Zi)

    Rpow2 = 1 - Se / St

    print("#####################")
    print("R**2 = 1 - Se / St = 1 - {} / {} = {}".format(
         Se,
         St,
         Rpow2
    ))
    print("#####################")

    return Rpow2

def PearsonKorelKoef(Xi, Yi):
    PrumX  = np.mean(Xi)
    PrumY  = np.mean(Yi)
    n      = Xi.size

    # Vzorec https://portal.matematickabiologie.cz/index.php?pg=aplikovana-analyza-klinickych-a-biologickych-dat--biostatistika-pro-matematickou-biologii--zaklady-korelacni-analyzy--pearsonuv-korelacni-koeficient--vypocet-pearsonova-korelacniho-koeficientu
    p = ((Xi - PrumX) * (Yi - PrumY)).sum() / math.sqrt(
        np.power(Xi - PrumX, 2).sum() * np.power(Yi - PrumY, 2).sum()
    )

    return p

##
## Non-correct
##
def XiYidependenceNormal(Xi, Yi):
    p = PearsonKorelKoef(Xi, Yi)
    print("#####################")
    print("p = {}".format(
         p
    ))

    n = Xi.size

    print("Pearsonův korelační koeficient")
    print("#####################")

    T = (p / (math.sqrt(1 - (p ** 2)))) * math.sqrt(n - 2)

    print("#####################")
    print("T = p / sqrt(1 - p **2) * sqrt(n - 2) = {}".format(
        T
    ))
    print("n = {}".format(
        n
    ))
    print("#####################")

    print("#####################")
    print("Dopočítej!!!!")
    print("H0: Xi a Yi jsou nezávislé")
    print("H1: Xi a Yi nejsou nezávislé")
    print("W = { T: |T| >= t(1 - apha / 2)(n-2)} <= zamítne H0 (Pokud bude plati jsou závislé)")
    print("#####################")

def SpearmanKorelKoef(Xi, Yi):
    #je nutné seřadit podle velikosti
    XiSort = np.sort(Xi)
    YiSort = np.sort(Yi)

    #ted je nutné indexi oproti původnímu
    ri = np.array([])
    qi = np.array([])
    for x in Xi:
        indexes = np.where(XiSort == x)
        index   = np.mean(indexes)
        ri      = np.append(ri, np.array(index + 1))

    for y in Yi:
        indexes = np.where(YiSort == y)
        index   = np.mean(indexes)
        qi      = np.append(qi, np.array(index + 1))

    print("#####################")
    print("ri = {}".format(
        ri
    ))
    print("qi = {}".format(
        qi
    ))
    print("#####################")

    n  = Xi.size
    ps = 1 - (6 / (n * (n ** 2 - 1))) * np.power(ri - qi, 2).sum()

    print("#####################")
    print("n = {}".format(
        n
    ))
    print("ps = 1 - 6 / (n(n**2 - 1)) * suma((ri - qi)**2) = {}".format(
        ps
    ))
    print("#####################")

    return ps

##
## Non-correct
##
def XiYidependenceSpojit(Xi, Yi):
    ps = SpearmanKorelKoef(Xi, Yi)

    n = Xi.size
    T = (ps / math.sqrt(1 - (ps ** 2))) * math.sqrt(n - 2)

    print("#####################")
    print("T = ps / sqrt(1 - (ps ** 2)) * sqrt(n - 2) = {}".format(
        T
    ))
    print("#####################")

    print("#####################")
    print("Dopočítej!!!!")
    print("H0: Xi a Yi jsou nezávislé")
    print("H1: Xi a Yi nejsou nezávislé")
    print("W = { T: |T| >= t(1 - apha / 2)(n-2)} <= zamítne H0 (Pokud bude plati jsou závislé)")
    print("#####################")

##
# Linear
##
Xi = np.array([
    25, 31, 40, 64, 34, 15, 57, 45
])

Yi = np.array([
    21, 22, 33, 46, 23, 12, 55, 40
])

#beta0, beta1 = regreseLinearBetas(Xi, Yi)

#Y = regreseLinearPredict(beta0, beta1, 20)
#print("Y is {}".format(Y))

#Se = regreseLinearGetSigmaPow2(beta0, beta1, Xi, Yi)
##SigmaPow2 = regreseLinearGetSigmaPow2(beta0, beta1, Xi, Yi)

#Rpow2 = regreseLinearGetQvality(beta0, beta1, Xi, Yi)

##
# Hyperbola
#  dtype=np.float64
##
Xi = np.array([
    138, 140, 144, 146, 148, 152, 153, 157
])

Yi = np.array([
    5.3, 5.5, 5.8, 5.6, 5.1, 4.4, 4.1, 3.9
])

#beta0, beta1, beta2 = regreseHyperbolaBetas(Xi, Yi)
#regreseHyperbolaPredict(beta0, beta1, beta2, 150)
#regreseHyperbolaGetSigmaPow2(beta0, beta1, beta2, Xi, Yi)
#regreseHyperolaGetQvality(beta0, beta1, beta2, Xi, Yi)

##
# Rovina
##
Xi = np.array([
    25, 26, 25, 27, 28, 27
])

Yi = np.array([
    1.34, 1.16, 1.25, 1.32, 1.45, 1.37
]) # (Predikované)!!!!!!

Zi = np.array([
    7.5, 4.3, 6.4, 5.2, 7.9, 6.8
])

#beta0, beta1, beta2 = regresePlaneBetas(Xi, Yi, Zi)
#regresePlanePredict(beta0, beta1, beta2, 26, 7)
#regresePlaneGetSigmaPow2(beta0, beta1, beta2, Xi, Yi, Zi)
#regresePlaneGetQvality(beta0, beta1, beta2, Xi, Yi, Zi)

##
# Korelační analíza
##

Xi = np.array([
    3.9, 4.2, 5.6, 5.7, 6.6, 7.2, 10.8, 10.7, 12.3, 15.7, 24.7
])

Yi = np.array([
    3.6, 4.3, 3.4, 3.7, 7.2, 3.0, 12.3, 7.0, 23.7, 23.6, 46.1
])

# pro normální rozdělení
#XiYidependenceNormal(Xi, Yi)

# pro spojité rozdělení
#XiYidependenceSpojit(Xi, Yi)


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

# The reaction rate to a new drug is given by the following function where t is time (in hours) after the drug is administered.

t = symbols( 't', positive = True )
S = exp( -t**2 ) + 3 / ( t + 3 )
a, b, n = 1, 9, 8

def trapezoidal_rule( f, a, b, n ):
	area = 0

	steps = np.linspace( a, b, n + 1, endpoint = True )

	for i in range( 0, n + 1 ):

		v = round( f.subs( { t: steps[ i ] } ), 4 )

		if i == 0 or i == n:
			area += .5 * v
		else:
			area += v

	return area * ( b - a ) / n

def simpsons_rule( f, a, b, n ):
	area = 0

	steps = np.linspace( a, b, n + 1, endpoint = True )

	for i in range( 0, n + 1 ):

		v = round( f.subs( { t: steps[ i ] } ), 4 )

		if i == 0 or i == n:
			area += v
		elif i % 2 == 0:
			area += 2 * v
		else:
			area += 4 * v

	return area * ( b - a ) / ( 3*n )

area = simpsons_rule( S, a, b, n )

g_xlim = [ 0, 10 ]

lam_s = lambdify( t, S, np )
x_vals = np.linspace( g_xlim[0], g_xlim[1], 1000, endpoint = True )
y_vals = lam_s( x_vals )

plt.vlines( x = a, ymin = 0, ymax = S.subs( { t: a } ), color = 'Black', zorder = 1, alpha = .4 )
plt.vlines( x = b, ymin = 0, ymax = S.subs( { t: b } ), color = 'Black', zorder = 1, alpha = .4 )

bounds = np.arange( a, b, 1/25., dtype=float)

for n in bounds:
	y = S.subs( { t: n } )
	plt.vlines( x = n, ymin = 0, ymax = y, color = 'Teal', zorder = 1, alpha = .2 )

plt.title( 'Simpson''s Rule Area: {0}'.format( round( area, 3 ) ) )
plt.plot( x_vals, y_vals )
plt.show()


import numpy as np
#Differential Drive Robot Model
#Input:
#Input Vehicle parameters:
#r_l = radius of the left wheel
#r_r = radius of the right wheel
#L = distance between the two wheels
#Control Input parameters:
#u_l = left wheel angular velocity
#u_r = right wheel angular velocity
#Robot State Input parameters
#(x,y) = initial robot position in 2D, measured at the center between the two wheels
#theta = initial robot orientation, angle counterclockwise from the x-axis

#Output: New robot state
#(x,y) = position in 2D
#theta = angle with respect to the x-axis

#The following input parameters should be reflected in the visualization of the robot model:
#r_l, r_r, L

#this method is the same for all robot models
def forwardKinematics(R, omega, ICC, x, y, theta, t):
    x_new = (np.cos(omega * t) * (x - ICC[0])) + (-np.sin(omega * t) * (y - ICC[1])) + ICC[0]
    y_new = (np.sin(omega * t) * (x - ICC[0])) + (np.cos(omega * t) * (y - ICC[1])) + ICC[1]
    theta_new = theta + (omega * t)
    return [x_new, y_new, theta_new]

#this method is the same for all robot models
def straightMotion(v, x, y, theta, t):
    x_new = x + (v * t * np.cos(theta))
    y_new = y + (v * t * np.sin(theta))
    theta_new = theta
    return [x_new, y_new, theta_new]

#one step of the robot's motion
def robotStep(r_l, r_r, L, u_l, u_r, x, y, theta, t):
    v_l = u_l * r_l                                  #linear velocity of the left wheel
    v_r = u_r * r_r                                  #linear velocity of the right wheel

    if v_l == v_r:                                   #driving straight
        [x,y,theta] = straightMotion(v_l, x, y, theta, t)

    else:
        R = (L/2) * (v_l + v_r)/(v_r - v_l)
        omega = (v_r - v_l)/L
        ICC = [x - R * np.sin(theta), y + R * np.cos(theta)] #Instantaneous Center of Curvature

        [x,y,theta] = forwardKinematics(R, omega, ICC, x,y, theta, t)

    return [x,y,theta]

def main(r_l, r_r, L, u_l, u_r, x, y, theta):

    robot_path = []

    t = 0
    t_step = 0.1                                       #update rate for the visualization

    #read all the input parameters described above from the user interface

    robot_path.append((x,y))

    #main loop
    loopy = 0

    while(loopy < 100):
        t = t+t_step
        [x, y , theta] = robotStep(r_l, r_r, L, u_l, u_r, x, y, theta, t_step)
        robot_path.append((x,y))
        loopy += 1;

    print(robot_path)


from sympy import *
from rodrigues_R_utils import *

px_1, py_1, pz_1 = symbols('px_1 py_1 pz_1')
sx_1, sy_1, sz_1 = symbols('sx_1 sy_1 sz_1')
px_2, py_2, pz_2 = symbols('px_2 py_2 pz_2')
sx_2, sy_2, sz_2 = symbols('sx_2 sy_2 sz_2')
px_m, py_m, pz_m = symbols('px_m py_m pz_m')
sx_m, sy_m, sz_m = symbols('sx_m sy_m sz_m')

position_symbols_1 = [px_1, py_1, pz_1]
rodrigues_symbols_1 = [sx_1, sy_1, sz_1]
position_symbols_2 = [px_2, py_2, pz_2]
rodrigues_symbols_2 = [sx_2, sy_2, sz_2]
all_symbols = position_symbols_1 + rodrigues_symbols_1 + position_symbols_2 + rodrigues_symbols_2

RT_wc_1 = matrix44FromRodrigues(px_1, py_1, pz_1, sx_1, sy_1, sz_1)
RT_wc_2 = matrix44FromRodrigues(px_2, py_2, pz_2, sx_2, sy_2, sz_2)

R_cw_1=RT_wc_1[:-1,:-1].transpose()
T_wc_1=Matrix([px_1, py_1, pz_1]).vec()
T_cw_1=-R_cw_1*T_wc_1
RT_cw_1=Matrix.hstack(R_cw_1, T_cw_1)
RT_cw_1=Matrix.vstack(RT_cw_1, Matrix([[0,0,0,1]]))

relative_pose = RT_cw_1 * RT_wc_2

rodrigues = rodriguesFromMatrix44(relative_pose)
t = relative_pose[0 : 3, 3]

observation = t.col_join(rodrigues)
measurement = Matrix([px_m, py_m, pz_m, sx_m, sy_m, sz_m])
delta = (measurement-observation)
delta_jacobian = delta.jacobian(all_symbols)

with open("relative_pose_rodrigues_wc_jacobian.h",'w') as f_cpp:
    f_cpp.write("inline void relative_pose_obs_eq_rodrigues_wc(Eigen::Matrix<double, 6, 1> &delta, double px_1, double py_1, double pz_1, double sx_1, double sy_1, double sz_1, double px_2, double py_2, double pz_2, double sx_2, double sy_2, double sz_2, double px_m, double py_m, double pz_m, double sx_m, double sy_m, double sz_m)\n")
    f_cpp.write("{")
    for i in range (6):
        f_cpp.write("delta.coeffRef(%d,%d) = %s;\n"%(i, 0, ccode(delta[i])))
    f_cpp.write("}")
    f_cpp.write("\n")
    f_cpp.write("inline void relative_pose_obs_eq_rodrigues_wc_jacobian(Eigen::Matrix<double, 6, 12, Eigen::RowMajor> &j, double px_1, double py_1, double pz_1, double sx_1, double sy_1, double sz_1, double px_2, double py_2, double pz_2, double sx_2, double sy_2, double sz_2)\n")
    f_cpp.write("{")
    for i in range (6):
        for j in range (12):
            f_cpp.write("j.coeffRef(%d,%d) = %s;\n"%(i,j, ccode(delta_jacobian[i,j])))
    f_cpp.write("}")
    f_cpp.write("inline void relative_pose_rodrigues_wc(Eigen::Matrix<double, 6, 1> &relative_pose, double px_1, double py_1, double pz_1, double sx_1, double sy_1, double sz_1, double px_2, double py_2, double pz_2, double sx_2, double sy_2, double sz_2)\n")
    f_cpp.write("{")
    for i in range (6):
        f_cpp.write("relative_pose.coeffRef(%d,%d) = %s;\n"%(i, 0, ccode(observation[i])))
    f_cpp.write("}")
    f_cpp.write("\n")


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

import numpy as np
import math

#################################
#  Interpolating spline helpers #
#################################

def knots_average(u, k):
    m = len(u) + k + 1
    if ((m - (2*(k+1))) > 0):
        v = np.zeros(m - (2*(k+1)))
        for i in range(0, m - (2*(k+1))):
            v[i] = (1/k) * sum([u[j] for j in range(i+1, i+k+1)])
        t = np.concatenate(((k+1)*[0], v, (k+1)*[1]), axis=None)
        return t
    else:
        return np.concatenate(((k+1)*[0], (k+1)*[1]), axis=None)

def knots_uniform(u, k):
    m = len(u) + k + 1
    if ((m - (2*(k+1))) > 0):
        v = np.zeros(m - (2*(k+1)))
        for i in range(1, m - (2*(k+1))+1):
            v[i-1] = i / (m - (2*(k+1))+1)
        t = np.concatenate(((k+1)*[0], v, (k+1)*[1]), axis=None)
        return t
    else:
        return np.concatenate(((k+1)*[0], (k+1)*[1]), axis=None)

_switcher = {
    0: knots_average,
    1: knots_uniform
}

def calc_knots(u, k, k_type):
    # Get the function from switcher dictionary
    func = _switcher.get(k_type)
    if(not func):
        raise NameError('Invalid Type for Generation of Knots')
    # Execute the function
    return func(u, k)


# JM (19 Jan 2022): collection of models

import numpy as np

def mod_nicolson_bailey(k, r, n=200, a=1.0):
    """
    (Modified) Nicolson-Bailey model, with non-dimensional inputs

    k    the carrying capacity
    r    some positive constant
    n    number of generations to run (optional)
    a    measure of some sort of death/survival rate (optional)

    Outputs the arrays "host" and "para" as a time-series in generation

    """

    host_init, para_init = k / (k-1) * np.log(k) / a, np.log(k) / a + 1e-1

    host, para = np.zeros(n), np.zeros(n)
    host[0], para[0] = host_init, para_init

    for i in range(n-1):
        host[i+1] = host[i] * np.exp(r * (1.0 - host[i] / k)) * np.exp(-a * para[i])
        para[i+1] = host[i] * (1.0 - np.exp(-a * para[i]))

    return host, para

def noisy_lotka_volterra(n=200, noise=1e-16, a=2/3, b=4/3, c=1.0, d=1.0, prey_ini=2.0, pred_ini=2.0):
    """
    (Stochastic) Lotka-Volterra equation, with (optional) non-dimensional inputs

    n         number of generations to run
    noise     stochastic noise level (default is basically off)
    a         growth rate of prey
    b         death rate of prey by predation
    c         death rate of predator
    d         growth rate of predator by predation
    prey_ini  initial value for prey
    pred_ini  initial value for predator

    Outputs the arrays "prey" and "predator" as a time-series in non-dimensional time

    """

    prey, predator = np.zeros(n), np.zeros(n)

    prey[0], predator[0] = prey_ini, pred_ini
    dt = 0.2

    i = 0 # Euler step
    prey[i+1]     = prey[i]     + dt * (a * prey[i]               - b * prey[i] * predator[i])
    predator[i+1] = predator[i] + dt * (d * prey[i] * predator[i] - c           * predator[i])

    # Adams-Bashforth 2 scheme
    for i in range(0, n-2):
        prey[i+2]     = prey[i+1]     + dt * ( 3/2 * (a * prey[i+1]                 - b * prey[i+1] * predator[i+1])
                                              -1/2 * (a * prey[i  ]                 - b * prey[i  ] * predator[i  ])
                                             ) + noise * np.random.rand()
        predator[i+2] = predator[i+1] + dt * ( 3/2 * (d * prey[i+1] * predator[i+1] - c             * predator[i+1])
                                              -1/2 * (d * prey[i  ] * predator[i  ] - c             * predator[i  ])
                                             )

    return prey, predator


# -*- coding: utf-8 -*-
" Sometimes we need to fit a function for perdiction or other usage from several given data. In order to achieve the objective, we use technique called interpolation or fitting. This pyfile can help us calculate the function required."

import numpy as np
import sympy as sp

""" Data Input: We input data in an array which has the form of (x,y)

data = np.array([[1,-1],
                 [2,-1],
                 [3,1]
                 ])
"""

" Polynomial Interpolation f(x) = c0 + c1x + c2x^2 + ... + cnx^n "

# In fact, this is a problem solving system of linear equation. Therefore, we have to meet the case that there are multiple solutions or probably no solution. To simplify our analysis, we only consider the case that the number of equation is equal to the number of variable. For example, if our data contains three (x,y), we can just solve f(x)=c0+c1x+c2x^2.

def Polynomial(data):
    dim = data.shape[0]
    A = np.zeros((dim,dim))
    for c in range(dim):
        g = lambda x:x**c
        A[:,c] = g(data[:,0])
    soln = np.linalg.solve(A,data[:,1])
    #for index in range(dim):
    #    print("c%d = %r"%(index,soln[index]))
    return soln

def Polynomial_predict(data,x):
    coefficient = Polynomial(data)
    result = 0
    for index in range(len(coefficient)):
        g = lambda x: x**index
        result = result + g(x)*coefficient[index]
    return result

# Polynomial_predict(data,-1)
data = np.array([[1,0],
                 [2,4],
                 [3,8]])
Polynomial(data)
Polynomial_predict(data,1.5)
" Lagrangian Interpolation "

def li_calc(data,i):
    dim = data.shape[0]
    x = sp.Symbol('x')
    li = 1
    for index in range(dim):
        if index != i:
            li = li*(x-data[index,0])/(data[i,0]-data[index,0])
        else:
            li = li
    return li

def Lagrangian(data):
    dim = data.shape[0]
    L = 0
    for index in range(dim):
        L = L +li_calc(data,index)*data[index,1]
    return L.expand()

def Lagrangian_predict(data,y):
    result = Lagrangian(data)
    x = sp.Symbol('x')
    return result.evalf(subs = {x:y})

data = np.array([[1,-1],
                 [2,-1],
                 [3,1]])
Lagrangian(data)
Lagrangian_predict(data,1.5)

" Newton Interpolation "

def Divided_difference(data):
    dim = data.shape[0]
    D = np.zeros((dim,dim+1))
    D[:,0] = data[:,0]
    D[:,1] = data[:,1]
    diff = 1
    for column in range(2,dim+1):
        for row in range(diff,dim):
            D[row,column] = (D[row,column-1]-D[row-1,column-1])/(D[row,0]-D[row-diff,0])
        diff = diff+1
    return D

# Divided_difference(data)

def Newton(data):
    Coefficient = Divided_difference(data)
    x = sp.Symbol('x')
    Newton = 0
    X = 1
    dim = data.shape[0]
    for index in range(dim):
        Newton = Newton + Coefficient[index,index+1]*X
        X = X*(x-Coefficient[index,0])
    return Newton.expand()

"""
data = np.array([[0,2],
                [1,-3],
                [2,-6],
                [3,11]])
Newton(data)
"""

def Newton_predict(data,y):
    result = Newton(data)
    x = sp.Symbol('x')
    return result.evalf(subs = {x:y})

Divided_difference(data)
Newton(data)
Newton_predict(data,1.5)


# -*- coding: utf-8 -*-
import warnings
import math
import numpy as np
from numba import njit

warnings.filterwarnings('error')

@njit
def f_eval(t, tc, m, w, a, b, c1, c2):
    """Evaluates LPPLS function for a given time point."""

    fp = a + math.pow(tc - t, m) * (b + ((c1 * math.cos(w * math.log(tc - t))) + \
        (c2 * math.sin(w * math.log(tc - t)))))

    return fp

@njit
def get_c(c1, c2):
    """Evaluates C parameter given C1 and C2."""

    c = c1 / math.cos(math.atan(c2 / c1))

    return c

@njit
def solve_matrix_equation(obs, tc, m, w):
    """Optimization problem for linear parameters: a, b, c1, c2.

    For details see:
        Filimonov & Sornette, A stable and robust calibration scheme of the
        log-periodic power law model, 2013.
    """

    n_points = obs.shape[1]

    time = obs[0]
    price = obs[1]

    # @TODO make taking tc - t or |tc - t| configurable
    dT = np.abs(tc - time)
    phase = np.log(dT)

    fi = np.power(dT, m)
    gi = fi * np.cos(w * phase)
    hi = fi * np.sin(w * phase)

    fi_pow_2 = np.power(fi, 2)
    gi_pow_2 = np.power(gi, 2)
    hi_pow_2 = np.power(hi, 2)

    figi = np.multiply(fi, gi)
    fihi = np.multiply(fi, hi)
    gihi = np.multiply(gi, hi)

    yi = price
    yifi = np.multiply(yi, fi)
    yigi = np.multiply(yi, gi)
    yihi = np.multiply(yi, hi)

    matrix_1 = np.array([
        [n_points,      np.sum(fi),       np.sum(gi),       np.sum(hi)],
        [np.sum(fi),    np.sum(fi_pow_2), np.sum(figi),     np.sum(fihi)],
        [np.sum(gi),    np.sum(figi),     np.sum(gi_pow_2), np.sum(gihi)],
        [np.sum(hi),    np.sum(fihi),     np.sum(gihi),     np.sum(hi_pow_2)]
    ])

    matrix_2 = np.array([
        [np.sum(yi)],
        [np.sum(yifi)],
        [np.sum(yigi)],
        [np.sum(yihi)]
    ])

    # Compute the linear solution.
    sol = np.linalg.solve(matrix_1, matrix_2)
    a, b, c1, c2 = sol[:, 0]

    return a, b, c1, c2

@njit
def get_oscillations(w, tc, t1, t2):
    return w / (2.0 * math.pi) * math.log((tc - t1) / (tc - t2))

@njit
def get_damping(m, w, b, c):
    return m * abs(b) / (w * abs(c))