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

# Training data
X = np.array([1.2,1.5,2.6,3.4,5.4,6.1,7.8,9.1,10.3,11.1,12.3])
Y = np.array([5.2,6.4,7.1,8.2,9.1,10.3,11.2,13.7,14.7,15.2,16.7])
n_samples = X.shape[0]

# Declare variables
W = tf.Variable(np.random.randn())
b = tf.Variable(np.random.randn())

# Define hyperparameters
learningRate = 0.01
numEpochs = 1000
displayStep = 50

def linearReg(x):
	# Define the model
	y = W*x + b
	return y

def meanSquareErr(yPred,yTrue):
	mse = tf.reduce_sum(tf.pow((yPred-yTrue),2))/(2*n_samples)
	return mse

# define optimizer
optimizer = tf.optimizers.SGD(learningRate)

def runOptimization():
	with tf.GradientTape() as g:
		pred = linearReg(X)
		loss = meanSquareErr(pred,Y)

	# Compute gradients
	gradients = g.gradient(loss,[W,b])

	# Update W and b following gradients
	optimizer.apply_gradients(zip(gradients,[W,b]))

for step in range(1,numEpochs+1):
	runOptimization()
	if step % displayStep == 0:
		pred = linearReg(X)
		loss = meanSquareErr(pred,Y)
		print("Step: %i, loss: %f, W: %f, b: %f" %(step, loss, W.numpy(), b.numpy()))

plt.plot(X,Y,'ro',label = 'Original data')
plt.plot(X,np.array(W*X+b),label = 'Fit data')
plt.legend()
plt.show()


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

def error(b,m,x,y):
    finalError=0
    for i in range(len(x)):
        finalError +=(y [i]-(m*x[i]+b))**2
    return finalError/len(x)

def gradient_descent(init_m,init_b,x,y):
    learning_rate=0.001
    num_iterations=1000
    b=init_b
    m=init_m
    for i in range(num_iterations):
        b,m=step(init_b,init_m,x,y)
        init_b=init_b-(learning_rate*b)
        init_m=init_m-(learning_rate*m)
    return [init_b, init_m]

def step(b,m,x,y):
    m_gradient=0
    b_gradient=0
    for i in range(len(x)):
        b_gradient += -(2/len(x))*(y[i]-((m*x[i])+b))
        m_gradient += -x[i]*(2/len(x))*(y[i]-((m*x[i])+b))

    return [b_gradient,m_gradient]

def linearRegression():
#collecting the data
    dataset = pd.read_csv('lactic.csv')
    X = dataset.iloc[:,1].values
    Y = dataset.iloc[:,-1].values
    print(X)

    in_b=0
    in_m=0
    print('Starting at b={0},m={1},error = {2} '.format(in_b,in_m,error(in_b,in_m,X,Y)))
    [b,m]=gradient_descent(in_m,in_b,X,Y)
    print('Finally at b={0},m={1},error = {2} '.format(b,m,error(b,m,X,Y)))

    #plotting the graph
    y_vals=[m*x+b for x in range(20)]
    x_vals = range(20)

    plt.scatter(X,Y)
    plt.plot(x_vals,y_vals,linewidth=3)
    plt.show()

if __name__=='__main__':
    linearRegression()


import numpy as np
from scipy.stats import beta
import matplotlib.pyplot as plt
import seaborn as sns

if __name__ == '__main__':
    sns.set_palette('deep', desat=.6)
    sns.set_context(rc={'figure.figsize': (8, 4)})
    x = np.linspace(0, 1, 100)
    params = [
        (0.5, 0.5),
        (1, 1),
        (4, 3),
        (2, 5),
        (6, 6)
    ]
    for p in params:
        y = beta.pdf(x, p[0], p[1])
        plt.plot(x, y, label='$\\alpha={}$, $\\beta={}$'.format(p[0], p[1]))

    plt.xlabel('$\\theta$, Fairness')
    plt.ylabel('Density')
    plt.legend(title='Parameters')
    plt.show()


import numpy as np

def mean_square_error(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate MSE loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    MSE of given predictions
    """
    return (1/y_true.size) * sum(np.subtract(y_true, y_pred) ** 2)

def misclassification_error(y_true: np.ndarray, y_pred: np.ndarray, normalize: bool = True) -> float:
    """
    Calculate misclassification loss

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values
    normalize: bool, default = True
        Normalize by number of samples or not

    Returns
    -------
    Misclassification of given predictions
    """
    misclassification_amount = 0
    for i in range(y_true.size):
        if y_true[i] != y_pred[i]:
            misclassification_amount += 1
    if normalize:
        misclassification_amount /= y_true.size
    return misclassification_amount

def accuracy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate accuracy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Accuracy of given predictions
    """
    return 1 - misclassification_error(y_true, y_pred, True)

def cross_entropy(y_true: np.ndarray, y_pred: np.ndarray) -> float:
    """
    Calculate the cross entropy of given predictions

    Parameters
    ----------
    y_true: ndarray of shape (n_samples, )
        True response values
    y_pred: ndarray of shape (n_samples, )
        Predicted response values

    Returns
    -------
    Cross entropy of given predictions
    """
    raise NotImplementedError()

if __name__ == '__main__':
    y_true = np.array([279000, 432000, 326000, 333000, 437400, 555950])
    y_pred = np.array(
        [199000.37562541, 452589.25533196, 345267.48129011, 345856.57131275, 563867.1347574, 395102.94362135])
    print(mean_square_error(y_true, y_pred))


import numpy as np
import math

# gradient_descent_logistic_regresion
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
def gradient_descent_logistic_regresion (Teta,X,Y,alfa):
  m = Y.size
  H_linear_regression =  np.dot(X,Teta)
  H = sigmoid(H_linear_regression)
  E = H - Y
  dJ_to_dTeta = np.dot(E, X)
  Teta = Teta - alfa * dJ_to_dTeta
  j_vec = Y * np.log(H) + (1-Y)*np.log(1-H)
  J = (-1/m)*np.sum(j_vec)
  return {"Teta" : Teta , "J" : J}

# gradient_descent_linear_regresion
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
def gradient_descent_linear_regresion (Teta,X,Y,alfa):
  m = Y.size
  H_linear_regression =  np.dot(X,Teta)
  E = H_linear_regression - Y
  dJ_to_dTeta = (1/m)*np.dot(E, X)
  Teta = Teta - alfa * dJ_to_dTeta
  J = np.dot(E,E)/(2*m)
  return {"Teta" :  Teta , "J" : J}

# cost_function_logistic_regression_J
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
def cost_function_logistic_regression_J(Teta,X,Y):
    m = Y.size
    H_linear_regression =  np.dot(X,Teta)
    H = sigmoid(H_linear_regression)
    j_vec = Y * np.log(H) + (1-Y)*np.log(1-H)
    J = (-1/m)*np.sum(j_vec)
    return J

# cost_function_linear_regression_J
# Teta :
#   - is features vector : teta_0,teta_1,....,teta_n .
#   - Teta is column vector (n+1)x1 (n+1 is the number of features)
# X :
#   - a matrix [X0,X1,X2,....,Xn].
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1).
#   - Notice that X0 is always 1
# X*Teta :
#   - is : teta0*X0 + teta1*X1 + ….. +teta_n*Xn
#   - X*Teta is a column vector mx1
# lamda :
#   - is a scalar which is regularization parameter used for over fitting
#   - by default there is no regularization thus lambda is zero
def cost_function_linear_regression_J(Teta,X,Y,lamda=0):
    m = Y.size
    H_linear_regression =  np.dot(X,Teta)
    E = Y - H_linear_regression
    J = np.dot(E,E)/(2*m)
    if (lamda > 0):
      # regulrization does not affect Teta[0]
      J += lamda*np.dot(Teta[1:],Teta[1:])/(2*m)

    return J

def sum_square_residuals(y,h):
    """compute sum of square residuals

    Args:
        y ([number]): actual , m x 1
        h ([number]): hypothesis , m x 1

    Returns:
        number: sum over all m points (y[i] - h[i])^2
    """
    residual = y - h
    # this sum (y[i]-h[i])^2 over all items or using vector notation (y-h)^2
    ssr = np.dot(residual,residual)
    return ssr

def softplus(val):
    return np.log(1+np.exp(val))

# it turns out that the derivative to softplus is exactly sigmoid
# check here(https://medium.com/@abhinavr8/activation-functions-neural-networks-66220238e1ff#:~:text=Softplus%20function%3A%20f(x),also%20called%20the%20logistic%20function.)
def dsoftplus_to_dval(val):
    return sigmoid(val)

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

def dsigmoid_to_dval(val):
    sig = sigmoid(val)
    return sig * (1 - sig)

# return 0 or 1
def sigmoid_binari(val):
    sig = 1/(1+np.exp(-val))
    return 1 if sig >= 0.5 else 0

# return 0 or 1
def neuron(Teta,X):
  val = np.dot(Teta,X)
  return sigmoid_binari(val)

# a, b : 0,1
def logical_and(a,b):
  Teta = np.array([-30 , 20 , 20 ])
  X = np.array([1 , a , b ])
  return neuron(Teta,X)

NUMERICAL_DERIVATIVE_EPS = 0.001

def compute_numerical_derivative(func_value_plus_eps,func_value_minus_eps,eps = NUMERICAL_DERIVATIVE_EPS):
  return (func_value_plus_eps - func_value_minus_eps) / (2*eps)

# compute_X_with_normalization_for_polynom
# e.g. for order 2 X before normalization is [X0,X1,np.power(X1,2)]
# normalization is done for all Xi (i != 0)
#
# X1    :
#   - column vector mx1
# order :
#   - order of the polynom
#   - order must be > 1
# X     :
#   - a matrix [X0,X1,X2,....,Xn]
#   - each X0,X1,X2,....,Xn is a column vector mx1
#   - m is number of data set points.
#   - X is mx(n+1)
#   - Notice that X0 is always 1
def compute_X_with_normalization_for_polynom(X1,order):
  if(order < 1):
    raise Exception("order must be > 1")

  m = X1.size
  X0 = np.ones(m)
  X= np.vstack((X0,normalize(X1)))

  temp_pow = 2
  while (temp_pow <= order):
    Xi = np.power(X1,temp_pow)
    Xi = normalize(Xi)
    X= np.vstack((X,Xi))
    temp_pow += 1

  return X.T

# normalize a 1d array in general to -0.5 : 0.5
def normalize(v1d):
  v1d_range = np.amax(v1d) - np.amin(v1d)
  v1d_mean = np.mean(v1d)
  return (v1d-v1d_mean)/v1d_range if v1d_range > 0 else v1d

def normal_dist(sample_x,x):
    mean_x = np.mean(x)
    variance_x = np.var(x)
    return normal_dist_short(sample_x,mean_x,variance_x)

def normal_dist_short(sample_x,mean_x,variance_x):
    delta = sample_x - mean_x
    p = (1/math.sqrt(2*math.pi*variance_x))*math.exp(-math.pow(delta,2)/(2*variance_x))
    return p

# actual and estimated are 1
def true_positive(actual,estimated):
  mul = actual * estimated
  return np.sum(mul) # sum 1

# actual is 0 but estimated is 1
def false_positive(actual,estimated):
  ar_index_estimated_1 = np.where(estimated == 1)[0]
  actual_slice = actual[ar_index_estimated_1]
  actual_slice_0 = np.where(actual_slice == 0)[0]
  num_actual_slice_0 = len(actual_slice_0)
  return num_actual_slice_0

# actual is 1 but estimated is 0
def false_negative(actual,estimated):
  ar_index_actual_1 = np.where(actual == 1)[0]
  estimated_slice = estimated[ar_index_actual_1]
  estimated_slice_0 = np.where(estimated_slice == 0)[0]
  num_estimated_slice_0 = len(estimated_slice_0)
  return num_estimated_slice_0

def precision(actual,estimated):
    tp = true_positive(actual,estimated)
    fp = false_positive(actual,estimated)
    return tp/(tp+fp)

def recall(actual,estimated):
    tp = true_positive(actual,estimated)
    fn = false_negative(actual,estimated)
    return tp /(tp + fn)

def F1score(actual,estimated):
    prec = precision(actual,estimated)
    rec = recall(actual,estimated)
    return 2*prec*rec/(prec+rec)

def symetric_random(val_max):
  """[summary]
  get a random number [-val_max , val_max]

  Args:
      val_max (number): [description]

  Returns:
      [type]: [description]
  """
  return np.random.rand()*2*val_max - val_max

def random_normal_distribution():
    return np.random.normal()

def linear_line(x,w,b):
    return w * x + b


"""

https://apmonitor.com/pdc/index.php/Main/TransferFunctions

"""

import sympy as sym
from sympy.abc import s,t,x,y,z
import numpy as np
from sympy.integrals import inverse_laplace_transform
import matplotlib.pyplot as plt

# Define inputs
# First step (up) starts at 1 sec
U1 = 2/s*sym.exp(-s)
# Ramp (down) starts at 3 sec
U2 = -1/s**2*sym.exp(-3*s)
# Ramp completes at 5 sec
U3 = 1/s**2*sym.exp(-5*s)

# Transfer function
G = 5*(s+1)/(s+3)**2

# Calculate responses
Y1 = G * U1
Y2 = G * U2
Y3 = G * U3

# Inverse Laplace Transform
u1 = inverse_laplace_transform(U1,s,t)
u2 = inverse_laplace_transform(U2,s,t)
u3 = inverse_laplace_transform(U3,s,t)
y1 = inverse_laplace_transform(Y1,s,t)
y2 = inverse_laplace_transform(Y2,s,t)
y3 = inverse_laplace_transform(Y3,s,t)
print(u1)
print(u2)
print(u3)
print(y1)
print(y2)
print(y3)

# generate data for plot
tm = np.linspace(0,8,100)
us = np.zeros(len(tm))
ys = np.zeros(len(tm))

# substitute numeric values for u and y
for u in [u1,u2,u3]:
    for i in range(len(tm)):
        us[i] += u.subs(t,tm[i])
for y in [y1,y2,y3]:
    for i in range(len(tm)):
        ys[i] += y.subs(t,tm[i])

# plot results
plt.figure()
plt.plot(tm,us,label='u(t)')
plt.plot(tm,ys,label='y(t)')
plt.legend()
plt.xlabel('Time')
plt.show()


from __future__ import division
from builtins import range
from past.utils import old_div
import numpy as np

def solver(I, V, m, b, s, F, t, damping='linear'):
    """
    Solve m*u'' + f(u') + s(u) = F for time points in t.
    u(0)=I and u'(0)=V,
    by a central finite difference method with time step dt.
    If damping is 'linear', f(u')=b*u, while if damping is
    'quadratic', we have f(u')=b*u'*abs(u').
    s(u) is a Python function, while F may be a function
    or an array (then F[i] corresponds to F at t[i]).
    """
    N = t.size - 1              # No of time intervals
    dt = t[1] - t[0]            # Time step
    u = np.zeros(N+1)           # Result array
    b = float(b)                # Avoid integer division
    m = float(m)                # Avoid integer division

    # Convert F to array
    if callable(F):
        F = F(t)
    elif isinstance(F, (list, tuple, np.ndarray)):
        F = np.asarray(F)
    else:
        raise TypeError(
            'F must be function or array, not %s' % type(F))

    u[0] = I
    if damping == 'linear':
        u[1] = u[0] + dt*V + dt**2/(2*m)*(-b*V - s(u[0]) + F[0])
    elif damping == 'quadratic':
        u[1] = u[0] + dt*V + \
               dt**2/(2*m)*(-b*V*abs(V) - s(u[0]) + F[0])
    else:
        raise ValueError('Wrong value: damping="%s"' % damping)

    for n in range(1, N):
        if damping == 'linear':
            u[n+1] = old_div((2*m*u[n] + (b*dt/2 - m)*u[n-1] +
                              dt**2*(F[n] - s(u[n]))), (m + b*dt/2))
        elif damping == 'quadratic':
            u[n+1] = old_div((2*m*u[n] - m*u[n-1] + b*u[n]*abs(u[n] - u[n-1])
                              - dt**2*(s(u[n]) - F[n])),
                             (m + b*abs(u[n] - u[n-1])))
    return u, t

# Simplified implementation
from numpy import *

def solver_linear_damping(I, V, m, b, s, F, t):
    N = t.size - 1              # No of time intervals
    dt = t[1] - t[0]            # Time step
    u = zeros(N+1)              # Result array
    u[0] = I
    u[1] = u[0] + dt*V + dt**2/(2*m)*(-b*V - s(u[0]) + F[0])

    for n in range(1, N):
        u[n+1] = 1./(m + b*dt/2)*(2*m*u[n] +
                                  (b*dt/2 - m)*u[n-1] + dt**2*(F[n] - s(u[n])))
    return u


'''
Implementation of the nDCG metric for ranking evaluation.

Balazs Kovacs, 2017
'''

import numpy as np

def dcg(rel_scores, k=None, use_exp=False):
    '''
    Computes the DCG metric as defined in https://en.wikipedia.org/wiki/Discounted_cumulative_gain

    :param rel_scores: List of relevance scores.
    :param k: We will compute DCG@k. If k is None, we will set it to
    len(rel_scores).
    :param use_exp: If True, we use 2 ** (relevance score) - 1 in the numerator
    instead of (relevance score).

    :returns: The DCG score of the input
    '''

    if k is None:
        k = len(rel_scores)

    rel_scores = np.array(rel_scores, dtype=float)[:k]
    if use_exp:
        num = 2 ** rel_scores - 1
    else:
        num = rel_scores

    den = np.log2(np.arange(k) + 2)
    return np.sum(num / den)

def ndcg(rel_scores, k=None, use_exp=False):
    '''
    Computes the nDCG metric as defined in https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG

    :param rel_scores: List of relevance scores.
    :param k: We will compute nDCG@k. If k is None, we will set it to
    len(rel_scores).
    :param use_exp: If True, we use 2 ** (relevance score) - 1 in the numerator
    instead of (relevance score).

    :returns: The nDCG score of the input
    '''

    if k is None:
        k = len(rel_scores)

    dcg_val = dcg(rel_scores=rel_scores, k=k, use_exp=use_exp)
    idcg_val = dcg(rel_scores=sorted(rel_scores, reverse=True), k=k, use_exp=use_exp)

    return dcg_val / idcg_val

#if __name__ == '__main__':
    #r = [3, 2, 3, 0, 1, 2]
    #for use_exp in [False, True]:
        #print dcg(rel_scores=r, use_exp=use_exp)
        #print ndcg(rel_scores=r, use_exp=use_exp)


import numpy as np

def solve(A):
	u = np.random.random(A.shape[0])
	lmd, lmd_old = 1e10, 0
	cnt = 0
	while abs(lmd - lmd_old) >= 1e-5:
		lmd_old = lmd
		v = A.dot(u)
		lmd = abs(v).max()
		u = v / lmd
		cnt += 1
	x = u
	return x, lmd, cnt

def gen51():
	print('t51 result'.center(30, '-'))
	A = np.array([
		[5, -4, 1],
		[-4, 6, -4],
		[1, -4, 7]
		])
	B = np.array([
		[25, -41, 10, -6],
		[-41, 68, -17, 10],
		[10, -17, 5, -3],
		[-6, 10, -3, 2]
		])
	xa, la, ca = solve(A)
	print('x_A:', xa, '\nlambda_A:', la, ', cnt_A:', ca)
	xb, lb, cb = solve(B)
	print('x_B:', xb, '\nlambda_B:', lb, ', cnt_B:', cb)
	print('end t51'.center(30, '-')+'\n')

if __name__ == '__main__':
	gen51()


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 18 08:31:26 2017

@author: ASUS
"""

import tensorflow as tf;
import numpy as np;

# In[]
a = np.array([[1.0, 2.0], [3.0, 4.0]])

with tf.Session() as sess:
    print('total mean:',  sess.run(tf.reduce_mean(a)) ) #  (1+2+3+4)/4 = 2.5
    print('mean by column:', sess.run(tf.reduce_mean(a, axis=0))  ) # [(1+3)/2, (2+4)/2] = [2, 3]
    print('mean by row:', sess.run(tf.reduce_mean(a, axis=1))  ) # [(1+2)/2, (3+4)/2] = [1.5, 3.5]

    print('total sum:',  sess.run(tf.reduce_sum(a)) ) #  (1+2+3+4) = 10
    print('sum by column:', sess.run(tf.reduce_sum(a, axis=0))  ) # [1+3, 2+4] = [4, 6]
    print('sum by row:', sess.run(tf.reduce_sum(a, axis=1))  ) # [1+2, 3+4)] = [3, 7]

# In[]
# tf.equal(x, y, name=None) - Returns the truth value of (x == y) element-wise.
a = tf.constant([1, 2], tf.int32)
b = tf.constant([2, 2], tf.int32)
with tf.Session() as sess:
    print(sess.run(tf.equal(a, b))) # [False  True]

# In[]

x = tf.constant(["hehe", "haha", "hoho", "kaka"], tf.string)
y = tf.constant("hoho", tf.string)
with tf.Session() as sess:
    print(sess.run(tf.equal(x, y))) # [False False  True False]

# In[]
#  tf.argmax(input, axis=None, name=None, dimension=None): find index of the max value in input by axis
a = [[1,3,4,5,6]]
b = [[1,3,4], [2,4,1]]

with tf.Session() as sess:
    print(sess.run(tf.argmax(a, 1))) # 4
    print(sess.run(tf.argmax(b, 1))) # [2,1]

# In[]
#  tf.cast(x, dtype, name=None): transfer x to dtype
a = tf.convert_to_tensor(np.array([[1, 1, 2, 4], [3, 4, 5, 6]]))

with tf.Session() as sess:
    print(a.dtype)
    b = tf.cast(a, tf.float32)
    print(b.dtype)

# In[]
   # tf.truncated_normal(shape, mean, stddev): mean - 2*std <= normal(mean, std) <= mean + 2*std
shape = ([2, 2, 3, 1]) #
a = tf.truncated_normal(shape=shape, mean=0,  stddev=0.1)

with tf.Session() as sess:
    print (sess.run(a))


'''
softmax
'''

import sys
import numpy as np

def softmax(a):
    '''
    softmax function
    '''
    c = np.max(a)
    exp_a = np.exp(a - c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y

def main():
    '''
    main function
    '''
    a = np.array([0.3, 2.9, 4.0])
    print(softmax(a))
    return

if __name__ == '__main__':
    sys.exit(main())


# Simulate a Poisson point process on the surface of a n-dimensional
# ball (that is, a (n-1)-dimensional sphere).
# Author: H. Paul Keeler, 2020.
# Website: hpaulkeeler.com
# Repository: github.com/hpaulkeeler/posts
# For more details, see the post:
# hpaulkeeler.com/simulating-a-poisson-point-process-on-a-n-dimensional-sphere/

import numpy as np;  # NumPy package for arrays, random number generation, etc
from scipy.special import gamma, factorial #gamma function
from numpy import linalg as la #linear algebra pack
import matplotlib.pyplot as plt  # for plotting
from mpl_toolkits import mplot3d

plt.close('all');  # close all figures

numbDim=2; #number of dimensions of embedding (regular sphere numbDim=3)

r=1.7; #radius of sphere

#Point process parameters
lambda0=5; #intensity (ie mean density) of the Poisson process

#surface area of d-dimensional ball
areaTotal=2*np.pi**(numbDim/2)*r**(numbDim-1)/gamma(numbDim/2);

measureTotal=areaTotal*lambda0; #total measure

#Simulate Poisson point process
numbPoints=np.random.poisson(measureTotal);#Poisson number of points

xxRand=np.random.normal(0,1,size=(numbPoints,numbDim));
normRand=la.norm(xxRand,2,1); #Euclidean norms
xxRandBall=xxRand/normRand[:,None]; #rescale by Euclidean norms
xxRandBall=r*xxRandBall; #rescale for non-unit sphere

##Plotting
if numbDim==2:
    #disk
    xx= xxRandBall[:,0];
    yy= xxRandBall[:,1];
    plt.scatter(xx, yy, edgecolor='b', facecolor='b');
    plt.xlabel('x');
    plt.ylabel('y');
    plt.axis('equal');

if numbDim==3:
    #sphere
    xx= xxRandBall[:,0];
    yy= xxRandBall[:,1];
    zz= xxRandBall[:,2];
    fig = plt.figure()
    ax = plt.axes(projection='3d')
    ax.scatter3D(xx, yy,zz,color='b');
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')

    #control ticks on x,y,z axes
    plt.locator_params(axis='x', nbins=5);
    plt.locator_params(axis='y', nbins=5);
    plt.locator_params(axis='z', nbins=5);

    #create mesh to plot the outline of a sphere
    numbMesh=20;
    thetaMesh, phiMesh = np.meshgrid(np.linspace(0,np.pi,numbMesh), np.linspace(0,2*np.pi,numbMesh))
    #convert to Cartesian coordinates
    xMesh = r * np.cos(thetaMesh)*np.sin(phiMesh)
    yMesh  = r * np.sin(thetaMesh)*np.sin(phiMesh)
    zMesh  = r * np.cos(phiMesh)

    #do a surface plot with a clear faces (ie alpha=0)
    ax.plot_surface(xMesh, yMesh, zMesh, edgecolor='k',alpha=0)


'''
Resilience
Problem 243
'''

from fractions import Fraction
from itertools import combinations
from time import time

import numpy as np
from numba import jit

f0 = Fraction(15499, 94744)

@jit
def get_primes(n):
    arr = np.ones(n + 1, "?")
    arr[0], arr[1] = False, False
    for i in range(2, n + 1):
        if arr[i] == 1:
            arr[i * i:n + 1:i] = False
    return arr.nonzero()[0]

@jit
def get_prime_factors(d):
    factors = []
    a = d
    for p in primes:
        if (p * p) > a:
            if a > 1:
                factors.append(a)
            break
        elif a % p == 0:
            factors.append(p)
            while (a % p == 0):
                a = a // p

    return factors

def non_coprime_cnt(d, factors):
    '''
        Using Euler's Totient Function
    '''
    cnt = d
    for p in factors:
        cnt = (cnt // p) * (p - 1)

    return cnt

def non_coprime_cnt_1(d, factors):
    '''
        Using set inclusion exclusion principle
    '''
    cnt = 0
    nf = len(factors)
    action = -1
    for size in range(1, nf + 1):
        action = action * (-1)
        for f_set in combinations(factors, size):
            mul = 1
            for f in f_set:
                mul *= f
            s_cnt = (d // mul) - 1

            cnt += action * s_cnt

    return cnt

def compute_resilance(d):
    factors = get_prime_factors(d)

    if factors[0] == d:
        return Fraction(1)

    return Fraction(non_coprime_cnt(d, factors), d - 1)

if __name__ == "__main__":

    primes = get_primes(10**4)
    print("Primes computed")

    # Test
    # print(compute_resilance(10))
    # print(compute_resilance(11))
    # print(compute_resilance(12))
    # print(compute_resilance(20))

    x = 2 * 3 * 5 * 7 * 11 * 13 * 17
    print("x {:,}".format(x))
    step = 10 ** 8
    next_stop = step
    min_i, min_f = 0, Fraction(1, 1)

    for i in range(x, 10**10, x):
        f = compute_resilance(i)

        if f < min_f:
            min_f = f
            min_i = i

        if f < f0:
            print("\n" + "=" * 80)
            print("solution found !!! ", i)
            print("Found : {:,} !!!. Ressilance factor {:.15f}".format(
                i, float(f)))
            print("=" * 80 + "\n")
            break

        if i >= next_stop:
            print("Current i: {:,} ,required factor: {:.15f} min_i: {:,} min_f : {:.15f} ".format(
                i, float(f0), min_i, float(min_f)))
            next_stop = i + step

    print("Done")


from scipy.misc import comb

class LatticePaths:
    # Lattice paths
    # Problem 15
    # Starting in the top left corner of a 2x2 grid, and only being able to move to the right and down,
    # there are exactly 6 routes to the bottom right corner.
    # How many such routes are there through a 20x20 grid?

    def __init__(self):
        pass

    @staticmethod
    def find(n):
        return comb(2 * n, n)

if __name__ == '__main__':
    p = LatticePaths.find(20)
    print "The number of paths through a 20x20 grid is %.0f" % p


from sympy.solvers import solve
from sympy.abc import x
from sympy import *

def getDeepDotQuality(func, arg, val, n = 3):
  dy = func.diff(arg)
  dyn = dy.subs(arg, val).evalf()
  if (dyn == 0):
    return getDeepDotQuality(dy, arg, val, n+1)
  elif (n % 2 == 1):
    return 'has an inflection point'
  elif (dyn > 0):
    return 'is min'
  else:
    return 'is max'
  return 'aaaaaa'

def getDotQuality(func, arg, val):
  dy = func.subs(arg, val).evalf()
  if (dy > 0):
    return 'is min'
  elif (dy < 0):
    return 'is max'
  else:
    return getDeepDotQuality(func, arg, val)

def findExtremums(func, arg):
  dy = func.diff(arg)
  ddy = dy.diff(arg)
  extremums = solve(dy, arg)

  maxValues = []
  minValues = []
  wat = []

  for val in extremums:
    if getDotQuality(ddy, arg, val) == "is max":
      val = float(simplify(sympify(val)).evalf())
      maxValues.append(val)
    elif getDotQuality(ddy, arg, val) == "is min":
      val = float(simplify(sympify(val)).evalf())
      minValues.append(val)
    elif getDotQuality(ddy, arg, val) == "has an inflection point":
      val = float(simplify(sympify(val)).evalf())
      wat.append(val)

  return maxValues, minValues, wat

if __name__ == "__main__":
  # findExtremums(x**2, x)
  # findExtremums(x**3 - 2*x**2 + x + 1, x)
  # findExtremums(2*x**4, x)
  # findExtremums(2*x**3, x)
  max1, min1 = findExtremums(E**x**2-4*x,x)
  print(max1)
  #print(type(max1[0]))
  print(min1)
  print(type(min1[0]))


#codes are seperated by """ as multiline comments

"""
import numpy as np
defsample_z_score(mean_old_sample, mean_sample,std, size):
tmp = (mean_old_sample-mean_sample)/(std/np.sqrt(size))
    return tmp
answer = sample_z_score(120,110,20,25)
"""

"""
import numpy as np
defstandard_error(std, size):
tmp = std/np.sqrt(size)
    return tmp
answer = standard_error(0.284,10)
"""

"""
import numpy as np
import scipy.stats as stats
import random

#Generating Sample Population Ages have to mean like35 and 150000 data points. Package scipy is used for dummy data generation. We have passed the mean, the size, and the shift provided to the distribution.
population_ages1 = stats.poisson.rvs(loc=18, mu=35, size=150000)

#Generating Sample Population Ages having mean as 10 and 100000 data points
population_ages2 = stats.poisson.rvs(loc=18, mu=10, size=100000)

# Concatenating the two samples to generate one combined sample
population_ages = np.concatenate((population_ages1, population_ages2))

#Let’s take 500 sample ages from the above population decided
sample_ages = np.random.choice(a= population_ages, size=500)

print("The Sample Mean is", sample_ages.mean())
print("The Population Mean is", population_ages.mean())
print("The Difference between both the means is: ", population_ages.mean() - sample_ages.mean())

std = np.std(sample_ages)
se = standard_error(std, len(sample_ages))
print("Standard Error for the Sample is", se)
print("************************")
print("%f percentage of the mean is the Standard Error, therefore it is quite precise" %((se)/sample_ages.mean()))
"""


"""
  Question 2: Rossler attractor
"""
# Library import
import numpy as np # Data structures, vector, matrices, etc
import matplotlib.pyplot as plt # Plots
from mpl_toolkits.mplot3d import Axes3D
import pathlib
#%%
# RHS definition
def F(t, u, **kwargs):
  a, b, c = kwargs['a'], kwargs['b'], kwargs['c']
  return np.array([-u[1] - u[2], u[0] + a * u[1], b + u[2] * (u[0] - c)])

# Fourth-order Runge Kutta method
def RK4(t, u0, **kwargs):
  L = len(t)
  U = np.zeros((L, len(u0)))
  U[0] = u0
  dt = t[1] - t[0]
  for k in range(L-1):
    k1 = F(t[k], U[k], **kwargs)
    k2 = F(t[k] + 0.5 * dt, U[k] + 0.5 * dt * k1, **kwargs)
    k3 = F(t[k] + 0.5 * dt, U[k] + 0.5 * dt * k2, **kwargs)
    k4 = F(t[k] + dt, U[k] + dt * k3, **kwargs)
    U[k + 1] = U[k] + (1/6) * dt * (k1 + 2 * k2 + 2 * k3 + k4)

  return U

# Euler method for testing...
def Euler(t, u0, **kwargs):
  L = len(t)
  U = np.zeros((L, len(u0)))
  U[0] = u0
  dt = t[1] - t[0]
  for k in range(L - 1):
    U[k + 1] = U[k] + dt * F(t[k], U[k], **kwargs)

  return U

# Plot x(t)
def plot(t, x):
  plt.plot(t, x)
  plt.grid(True)
  plt.show()

# Plot solution
def plot3D(x, y, z):
  fig = plt.figure(figsize=(12, 12))
  ax = fig.add_subplot(111, projection='3d')
  ax.plot(x, y, z)
  ax.set_xlabel('x')
  ax.set_ylabel('y')
  ax.set_zlabel('z')
  plt.show()
#%% Reproducing Rossler Paper Experiment
L_r = 5000 # 340000
T_max_r = 339.249 #813.312#339.249
t_r = np.linspace(0, T_max_r, L_r + 1)
a_r, b_r, c_r = 0.2, 0.2, 5.7
u0_r = np.array([0, -6.78, 0.02])
Ur = RK4(t_r, u0_r, a=a_r, b=b_r, c=c_r)

#%% Plot Rossler experiment
plot3D(Ur[:,0], Ur[:,1], Ur[:,2])
print("Rossler experiment - (x, y, z) at t_end: ", Ur[-1])

#%% Question 4
L_1 = 5000
T_max_1 = 300
t_1 = np.linspace(0, T_max_1, L_1 + 1)
u0_1 = np.array([4, 0, 0])

#%% Experiment 1
a_, b_, c_1 = 0.1, 0.1, 4
U1 = RK4(t_1, u0_1, a=a_, b=b_, c=c_1)

#%% Experiment 2
c_2 = 6
U2 = RK4(t_1, u0_1, a=a_, b=b_, c=c_2)

#%% Experiment 3
c_3 = 8.5
U3 = RK4(t_1, u0_1, a=a_, b=b_, c=c_3)

#%% Experiment 4
c_4 = 11
U4 = RK4(t_1, u0_1, a=a_, b=b_, c=c_4)

#%% Experiment 5
c_5 = 12.5
U5 = RK4(t_1, u0_1, a=a_, b=b_, c=c_5)

#%% Experiment 6
c_6 = 14
U6 = RK4(t_1, u0_1, a=a_, b=b_, c=c_6)

#%% Plots question 4
plot3D(U1[:,0], U1[:,1], U1[:,2])
plot3D(U2[:,0], U2[:,1], U2[:,2])
plot3D(U3[:,0], U3[:,1], U3[:,2])
plot3D(U4[:,0], U4[:,1], U4[:,2])
plot3D(U5[:,0], U5[:,1], U5[:,2])
plot3D(U6[:,0], U6[:,1], U6[:,2])

#%% Question 5
L_2 = 5000
T_max_2 = 300
t_2 = np.linspace(0, T_max_1, L_1 + 1)
a_, b_, c_ = 0.2, 0.2, 5.7
u0_2a = np.array([1, 0, 0])
u0_2b = np.array([1.01, 0, 0])

#%% Solve
U7a = RK4(t_2, u0_2a, a=a_, b=b_, c=c_)
U7b = RK4(t_2, u0_2b, a=a_, b=b_, c=c_)

#%% Plots
plot3D(U7a[:,0], U7a[:,1], U7a[:,2])
plot3D(U7b[:,0], U7b[:,1], U7b[:,2])

#%% Plot only x_1(t), x_2(t) and difference
plot(t_2, U7a[:,0])
plot(t_2, U7b[:,0])
plot(t_2, U7a[:,0] - U7b[:,0])

#%% Data structure to save
X1 = np.zeros((len(U7a), 2)); X1[:,0] = t_2; X1[:,1] = U7a[:,0]
X2 = np.zeros((len(U7b), 2)); X2[:,0] = t_2; X2[:,1] = U7b[:,0]
X1X2 = np.zeros((len(U7b), 2)); X1X2[:,0] = t_2; X1X2[:,1] = U7a[:,0] - U7b[:,0]

#%% Save data
DIR = 'data/2/' # Directory name
pathlib.Path(DIR).mkdir(parents=True, exist_ok=True) # Create Folder
# Write files
np.savetxt(DIR + 'Ur.csv', Ur, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U1.csv', U1, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U2.csv', U2, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U3.csv', U3, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U4.csv', U4, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U5.csv', U5, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U6.csv', U6, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U7a.csv', U7a, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'U7b.csv', U7b, fmt='%.8f', delimiter=',', header='x,y,z', comments="")
np.savetxt(DIR + 'X1.csv', X1, fmt='%.8f', delimiter=',', header='t,x', comments="")
np.savetxt(DIR + 'X2.csv', X2, fmt='%.8f', delimiter=',', header='t,x', comments="")
np.savetxt(DIR + 'X1X2.csv', X1X2, fmt='%.8f', delimiter=',', header='t,x', comments="")


import unittest

import numpy as np
import scipy.stats as stats

def my_entropy(px):
    return -np.sum(px * np.log2(px), axis=0)

def my_cross_entropy(p_true, p_predict):
    return -np.sum(p_true * np.log2(p_predict), axis=0)

# Also known as residual entropy.
def my_kullback_leibler(px, py):
    return np.sum(px * np.log2(px / py), axis=0)

def my_kullback_leibler2(px, py):
    return my_cross_entropy(px, py) - my_entropy(px)

def my_encoding_entropy(px, eb):
    return np.sum(px * eb)

#
# Unit Tests.
#

pk0 = np.asarray([.5, .5])
pk0_1 = np.asarray([.75, .25])
pk1 = np.asarray([.3, .4, .1, .2])
pk2 = np.asarray([.3, .4, .1, .2])
pk3 = np.asarray([.31, .39, .09, .21])

# Weather : Sun, Overcast, Sun+Cloud, Sun+HeavyCloud, LightRain, Rain, HeavyRain, Storm
w1 = np.asarray([1 / 8, 1 / 8, 1 / 8, 1 / 8, 1 / 8, 1 / 8, 1 / 8, 1 / 8])
w2 = np.asarray([.35, .35, .1, .1, 0.04, 0.04, 0.01, 0.01])
w3 = np.asarray([.01, .01, .04, .04, 0.1, 0.1, 0.35, 0.35])

# but used to encode each weather state
eb1 = np.asarray([3, 3, 3, 3, 3, 3, 3, 3])
eb2 = np.asarray([2, 2, 3, 3, 4, 4, 5, 5])

class TestEntropy(unittest.TestCase):

    def test_0(self):
        # two equally probable events = 1 bit of information
        self.assertAlmostEqual(my_entropy(pk0), 1)

        # Information is reduced if probabilities not equal, as in this case information is reduced
        # when we learn it is sunny as it sunny 75% of the time.
        self.assertAlmostEqual(my_entropy(pk0_1), 0.81, places=2)

        return

    def test_1(self):
        self.assertAlmostEqual(my_entropy(pk1), stats.entropy(pk=pk1, base=2))
        return

    # Divergence from self = 0
    def test_2(self):
        self.assertAlmostEqual(my_kullback_leibler(pk1, pk1), 0)
        return

    def test_3(self):
        self.assertAlmostEqual(my_kullback_leibler(pk1, pk2), stats.entropy(pk=pk1, qk=pk2, base=2))
        return

    def test_4(self):
        self.assertAlmostEqual(my_kullback_leibler(pk1, pk3), stats.entropy(pk=pk1, qk=pk3, base=2))
        return

    # Eight equally probable weather events = 3 bits
    def test_w0(self):
        self.assertAlmostEqual(my_entropy(w1), 3)
        return

    # Cross entropy is a function of bits used on average to encode a state. If less bits can be used
    # for most common states then cross entropy is closer to the entropy of the probability distribution
    # our ideal state is for cross entropy to be = entropy (lower limit)
    def test_w1(self):
        self.assertAlmostEqual(my_encoding_entropy(w2, eb2), 2.42, places=2)
        self.assertGreater(my_encoding_entropy(w2, eb2), my_entropy(w2))
        self.assertAlmostEqual(my_encoding_entropy(w3, eb2), 4.58, places=2)
        self.assertGreater(my_encoding_entropy(w3, eb2), my_entropy(w2))
        self.assertGreater(my_encoding_entropy(w3, eb2), my_encoding_entropy(w2, eb2))
        return

    # KL Divergence = Cross Entropy - Entropy.
    # So we test the difference between our expected distribution of weather events based on the
    # number of bits we chose to encode with vs. the actual distribution
    #
    def test_w2(self):
        p_true = w3
        p_predict = 1 / np.power(2, eb2)
        self.assertAlmostEqual(my_kullback_leibler2(p_true, p_predict), 2.35, places=2)
        return

    # Cross entropy loss function for NN classification.
    def test_cross_entropy_loss(self):
        p_one_hot = np.asarray([0.0, 0.0, 1.0, 0.0, 0.0])
        p_nn_pred = np.asarray([0.1, 0.2, 0.4, 0.1, 0.2])
        self.assertAlmostEqual(my_cross_entropy(p_one_hot, p_nn_pred), -np.log2(.4))
        return

# Execute the UnitTests.
#

if __name__ == "__main__":
    tests = TestEntropy()
    suite = unittest.TestLoader().loadTestsFromModule(tests)
    unittest.TextTestRunner().run(suite)


import numpy as np
from matplotlib import pyplot as plt
from optimizer import simplex_problem, verbose_print

import seaborn as sns

sns.set_palette('Set1')

paths = []

def feasible_region(A, b):
    """
    calculate the feasible region of LP prblem
    :param A: coef of constrains
    :param b: upper bound of constrains
    :return: 2D coordinate of point in feasible region
    """
    b = np.expand_dims(b, axis=1)
    x0 = np.linspace(0, 100, 500)
    x = np.array(np.meshgrid(x0, x0))
    # Construct grid
    x = x.reshape(2, -1)
    checked_cons = np.matmul(A, x) <= np.repeat(b, x.shape[1], axis=1)
    # and logic product in column
    mask = checked_cons.all(axis=0).reshape((x0.shape[0], x0.shape[0]))
    x = x.reshape((2, x0.shape[0], x0.shape[0]))
    x = (x.T[mask.T]).T
    return x

def visual_problem(c, A, b, optimal=None):
    """
    visualize for 2 variable constrains and feasible region for LP problem

    Given A.T * x <= b,that mean
    A[0]*x0 + A[1]*x1 <= b[0]
    Minimize
    c.T * x
    :param optimal: optimal solution
    :param A: constrain coefs
    :param b: constrain value
    :return: plt figure
    """

    if c.shape[0] != 2:
        raise Exception('function must be 2 dimension')

    epsilon = 0.000000001

    if A.shape[0] != b.shape[0]:
        raise Exception('A and b must be the same shape')

    fig, ax = plt.subplots(figsize=(8, 8))
    x1 = np.linspace(0, 100)

    for i in range(A.shape[0]):
        plt.plot(x1, (b[i] - A[i][0] * x1) / (A[i][1] + epsilon), lw=3,
                 label=r'{} : ${}x_1 + {}x_2 \leq{}$'.format(i, A[i][0], A[i][1], b[i]))
        plt.fill_between(x1, 0, (b[i] - A[i][0] * x1) / (A[i][1] + epsilon), alpha=0.1)

    plt.plot(np.zeros_like(x1), x1, lw=3, label=r'$x_1 : non-negative$')
    plt.plot(x1, np.zeros_like(x1), lw=3, label=r'$x_2 : non-negative$')
    # calculate the feasible
    fx, fy = feasible_region(A, b)
    z = np.dot(c.T, [fx, fy])
    plt.scatter(fx, fy, c=z, cmap='jet', zorder=-1)
    if optimal is not None:
        plt.plot(optimal[0], optimal[1], 'ro', label='optimal point')
    # labels and stuff
    cb = plt.colorbar()
    cb.set_label('objective value', fontsize=14)
    plt.xlabel('x1', fontsize=16)
    plt.ylabel('x2', fontsize=16)
    plt.xlim(-0.5, 100)
    plt.ylim(-0.5, 100)
    plt.legend(fontsize=14)
    plt.show()

if __name__ == '__main__':
    c = np.array([-8, -2])
    A = np.array([[1, 1],
                  [2, 1],
                  [1, 0]])
    b = np.array([80, 100, 40])
    res = simplex_problem(c, A, b, print_func=verbose_print)
    visual_problem(c, A, b, res['x'])


from numpy import *

# matrix function is deprecated check this link -> https://stackoverflow.com/questions/53254738/deprecation-status-of-the-numpy-matrix-class
#m1 = matrix(arr1) # using 2D array
#m2 = matrix('1 2 ; 3 4;5 6;') (2 x 3) using string as arg
#print("diagonal matrix : ",diagonal(m))
'''m1= matrix('1 2 ; 3 4;5 6;')
m2 =matrix('1 2 ; 3 4;5 6;')
m3 = m1 + m2
m4 = m1 * m2'''

'''# matrix multiplication
arr1 = array([[1,2,3,4],[5,6,7,8]])
arr2 = array([[1,2],[3,4],[5,6],[7,8]])

row1 , col1 = arr1.shape
row2 , col2 = arr2.shape
if col1 == row2:
    print("Matrix Multiplication is possible because (%d x %d[row1,col1]) X (%d x %d[row2,col2])"%(row1 , col1,row2,col2),"where %d == %d(col1==row2)"%(col1,row2),"So that it is not possible (%d x %d[row1,col1]) X (%d x %d[row2,col2]) -> (%d x %d[row1,col2])"%(row1 , col1,row2,col2,row1,col2))
    print("Multiplication is : ",arr1.dot(arr2))
else:
    print("Matrix Multiplication is not possible because  (%d x %d[row1,col1]) X (%d x %d[row2,col2])"%(row1 , col1,row2,col2),"where %d != %d(col1!=row2)"%(col1,row2),"So that it is not possible %d x %d X %d x %d -> %d x %d"%(row1 , col1,row2,col2,col1,row2))

# addition
arr3 = array([[1,2],[3,4]])
arr4 = array([[1,2],[3,4]])
row1 , col1 = arr3.shape
row2 , col2 = arr4.shape
if arr3.shape == arr4.shape:
    print("Matrix addition is possible because","shape is (%d,%d) == (%d,%d)"%(row1 , col1,row2,col2))
    print("addition is : ",arr3+arr4) # also use this add(arr3,arr4)
else:
    print("Matrix addition is not possible because","shape is (%d,%d) != (%d,%d)"%(row1 , col1,row2,col2))

# subtraction
arr5 = array([[1,2],[3,4]])
arr6 = array([[2,3],[1,2]])
row1 , col1 = arr5.shape
row2 , col2 = arr6.shape
if arr5.shape == arr6.shape:
    print("Matrix subtraction is possible because","shape is (%d,%d) == (%d,%d)"%(row1 , col1,row2,col2))
    print("Subtraction is : ",arr5-arr6) # subtract(arr3,arr4)
else:
    print("Matrix subtraction is not possible because","shape is (%d,%d) != (%d,%d)"%(row1 , col1,row2,col2))

# element vise multiplication
arr7 = array([[1,2],[3,4]])
arr8 = array([[1,2],[3,4]])
row1 , col1 = arr7.shape
row2 , col2 = arr8.shape
if arr7.shape == arr8.shape:
    print("Matrix element wise multiplication is possible because","shape is (%d,%d) == (%d,%d)"%(row1 , col1,row2,col2))
    print("Multiplication is : ",multiply(arr7,arr8)) # also use arr7*arr8 same for divide
else:
    print("Matrix element wise multiplication is not possible because","shape is (%d,%d) != (%d,%d)"%(row1 , col1,row2,col2))

# Transpose of matrix
arr9 = array([[1, 1], [2, 1], [3, -3]])
print("Transpose of matrix : ",arr9.transpose())'''

# Slicing of Matrix

# 1D array slicing
'''arr10 = array([1, 3, 5, 7, 9, 11, 13])
print("full : ",arr10[:])
print("first 4 elements : ",arr10[:4])
# slicing include upper limit and lower exclude and range exclude upper limit
print("4th elements : ",arr10[3:4])
# when we use - indexing upper limit is excluded
print("last 2 elements not consider : ",arr10[:-2])
print("from last 2nd plus 3 elements : ",arr10[-5:-2])
print("last 3rd element : ",arr10[-3:-2])
# reverse
print("reveres array : ",arr10[::-1])'''

# 2D array slicing
'''arr11 = array([[1, 4, 5, 12, 14],
    [-5, 8, 9, 10, 17],
    [-6, 7, 11, 19, 21]])

print("Full : ",arr11[:,:]) # arr11[row slice,col slice]
# lower limit is excluded
print("arr11[2,4] : ",arr11[1:2,3:4])
print("first 2 rows and 3 columns",arr11[:2,:3])
print("third row with all columns: ",arr11[2:3,])
# in - indexing upper limit is excluded
print("arr11[1,2] : ",arr11[-3:-2,-4:-3])'''

arr12 = array([[1, 4, 5, 12,21,22],
    [-5, 8, 9, 10,23,24],
    [-6, 7, 11, 19,25,26]])

arr13 = arr12.reshape(2,3,3)
print("full : ",arr13)
''' output of above
[[[ 1  4  5]
  [12 21 22]
  [-5  8  9]]

 [[10 23 24]
  [-6  7 11]
  [19 25 26]]]

from above first 3*3 matrix is
  [ 1  4  5]
  [12 21 22]
  [-5  8  9]
  second 3*3 matrix is
  [10 23 24]
  [-6  7 11]
  [19 25 26] '''
# check below description for understand all parameters
print("all matrices only, first column : ",arr13[:,:,:1])
'''B[:,:,1] we are passing : , : and 1. First : indicates that we are selecting both the 3X3 matrices.
The second : indicates that we are selecting all the rows from both the 3X3 matrices. The third parameter
1 indicates that we are selecting only the second column values of all the rows from both the 3X3 matrices'''

print("all matrices ,second row , second and third column : ",arr13[:,1:2,1:3])
print("2 matrix ,second and third row , second and third column : ",arr13[1:2,1:3,1:3])


 #!/usr/bin/env python

import numpy as np
import random

from q1_softmax import softmax
from q2_sigmoid import sigmoid, sigmoid_grad
from q2_gradcheck import gradcheck_naive

def forward_backward_prop(data, labels, params, dimensions):
    """
    Forward and backward propagation for a two-layer sigmoidal network

    Compute the forward propagation and for the cross entropy cost,
    and backward propagation for the gradients for all parameters.

    Arguments:
    data -- M x Dx matrix, where each row is a training example.
    labels -- M x Dy matrix, where each row is a one-hot vector.
    params -- Model parameters, these are unpacked for you.
    dimensions -- A tuple of input dimension, number of hidden units
                  and output dimension
    """

    ### Unpack network parameters (do not modify)
    ofs = 0
    Dx, H, Dy = (dimensions[0], dimensions[1], dimensions[2])

    W1 = np.reshape(params[ofs:ofs+ Dx * H], (Dx, H))
    ofs += Dx * H
    b1 = np.reshape(params[ofs:ofs + H], (1, H))
    ofs += H
    W2 = np.reshape(params[ofs:ofs + H * Dy], (H, Dy))
    ofs += H * Dy
    b2 = np.reshape(params[ofs:ofs + Dy], (1, Dy))

    ### YOUR CODE HERE: forward propagation

    #This is for the Input of the hidden layer H
    # h = sigmoid(np.dot(data,W1)+b1)
    z1 = np.dot(data,W1) + b1
    a1 = sigmoid(z1)

    #This is the output Layer
    z2 = np.dot(a1,W2) +b2
    y_pred = softmax(z2)

    cost = - np.sum(labels * np.log(y_pred))

    ### END YOUR CODE

    ### YOUR CODE HERE: backward propagation

    d3 = y_pred - labels
    gradW2 = np.dot(a1.T,d3)
    gradb2 = np.sum(d3,axis=0)

    da1 = np.dot(d3,W2.T)
    dz1 = sigmoid_grad(a1)*da1

    gradW1 = np.dot(data.T,dz1)
    gradb1 = np.sum(dz1,axis=0)
    ### END YOUR CODE

    ### Stack gradients (do not modify)
    grad = np.concatenate((gradW1.flatten(), gradb1.flatten(),
        gradW2.flatten(), gradb2.flatten()))

    return cost, grad

def sanity_check():
    """
    Set up fake data and parameters for the neural network, and test using
    gradcheck.
    """
    print("Running sanity check...")

    N = 20 #Number of Training examples
    dimensions = [10, 5, 10]
    data = np.random.randn(N, dimensions[0])   # each row will be a datum
    #print("Data :: ",data.shape)
    labels = np.zeros((N, dimensions[2]))
    print("Labels Shape:: ",labels.shape)
    for i in list(range(N)):
        #Making it a one-hot vector from All Zeros
        labels[i, random.randint(0,dimensions[2]-1)] = 1

    #print("Labels Value :: ",labels)

    ## Unfolding All the Parameters
    params = np.random.randn((dimensions[0] + 1) * dimensions[1] + (
        dimensions[1] + 1) * dimensions[2], )

    print("Param Shape:: " , params.shape)
    gradcheck_naive(lambda params:
        forward_backward_prop(data, labels, params, dimensions), params)

def your_sanity_checks():
    """
    Use this space add any additional sanity checks by running:
        python q2_neural.py
    This function will not be called by the autograder, nor will
    your additional tests be graded.
    """
    print("Running your sanity checks...")
    ### YOUR CODE HERE
    #raise NotImplementedError
    ### END YOUR CODE

if __name__ == "__main__":
    sanity_check()
    your_sanity_checks()


from trapezoidal import trapezoidal

def test_trapezoidal_one_exact_result():
    """Compare one hand-computed result."""
    from math import exp
    v = lambda t: 3*(t**2)*exp(t**3)
    n = 2
    computed = trapezoidal(v, 0, 1, n)
    expected = 2.463642041244344
    error = abs(expected - computed)
    tol = 1E-14
    success = error < tol
    msg = 'error={:g} > tol={:g}'.format(error, tol)
    assert success, msg

def test_trapezoidal_linear():
    """Check that linear functions are integrated exactly."""
    f = lambda x: 6*x - 4
    F = lambda x: 3*x**2 - 4*x # Anti-derivative
    a = 1.2; b = 4.4
    expected = F(b) - F(a)
    tol = 1E-14
    for n in 2, 20, 21:
        computed = trapezoidal(f, a, b, n)
        error = abs(expected - computed)
        success = error < tol
        msg = 'n={:d}, err={:g}'.format(n, error)
        assert success, msg

def convergence_rates(f, F, a, b, num_experiments=14):
    from math import log
    from numpy import zeros
    expected = F(b) - F(a)
    n = zeros(num_experiments, dtype=int)
    E = zeros(num_experiments)
    r = zeros(num_experiments-1)
    for i in range(num_experiments):
        n[i] = 2**(i+1)
        computed = trapezoidal(f, a, b, n[i])
        E[i] = abs(expected - computed)
        if i > 0:
            r_im1 = -log(E[i]/E[i-1])/log(n[i]/n[i-1])
            # Truncate to two decimals:
            r[i-1] = float('{:.2f}'.format(r_im1))
    return r

def test_trapezoidal_conv_rate():
    """Check empirical convergence rates against the expected value 2."""
    from math import exp
    v = lambda t: 3*(t**2)*exp(t**3)
    V = lambda t: exp(t**3)
    a = 1.1; b = 1.9
    r = convergence_rates(v, V, a, b, 14)
    print(r)
    tol = 0.01
    msg = str(r[-4:])  # show last 4 estimated rates
    assert (abs(r[-1]) - 2) < tol, msg


# coding: utf-8
import numpy as np
from cv2 import cv2
import matplotlib.pyplot as plt

# Consider an image whose pixel values are confined to some specific range of values only. For example, brighter image will have all pixels confined to high values. But a good image will have pixels from all regions of the image. So you need to stretch this histogram to either ends and that is what Histogram Equalization does (in simple words). This normally improves the contrast of the image.

img = cv2.imread(r'pictures\equalization_opencv.jpg', 0)

hist, bins = np.histogram(img.flatten(), 256, [0, 256])

cdf = hist.cumsum()
cdf_normalized = cdf * hist.max() / cdf.max()

# You can see histogram lies in brighter region. We need the full spectrum. For that, we need a transformation function which maps the input pixels in brighter region to output pixels in full region. That is what histogram equalization does.
# Now we find the minimum histogram value (excluding 0) and apply the histogram equalization equation as given in wiki page. But I have used here, the masked array concept array from Numpy. For masked array, all operations are performed on non-masked elements. You can read more about it from Numpy docs on masked arrays.
cdf_m = np.ma.masked_equal(cdf, 0)
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())
cdf = np.ma.filled(cdf_m, 0).astype('uint8')

img2 = cdf[img]
# Now calculate its histogram and cdf as before
hist2, bins = np.histogram(img2.flatten(), 256, [0, 256])

cdf2 = hist2.cumsum()
cdf_normalized2 = cdf2 * hist2.max() / cdf2.max()

plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.plot(cdf_normalized, color='b'), plt.hist(img.flatten(), 256, [
    0, 256], color='r'), plt.xlim([0, 256]), plt.legend(('cdf', 'histogram'), loc='upper left')
plt.subplot(223), plt.imshow(img2, 'gray')
plt.subplot(224), plt.plot(cdf_normalized2, color='b'), plt.hist(img2.flatten(), 256, [
    0, 256], color='r'), plt.xlim([0, 256]), plt.legend(('cdf', 'histogram'), loc='upper left')

plt.show()

# Another important feature is that, even if the image was a darker image (instead of a brighter one we used), after equalization we will get almost the same image as we got. As a result, this is used as a “reference tool” to make all images with same lighting conditions. This is useful in many cases. For example, in face recognition, before training the face data, the images of faces are histogram equalized to make them all with same lighting conditions.

# About numpy.ma : https://blog.csdn.net/wzy628810/article/details/103833856
# Numpy Doc : https://numpy.org/doc/stable/reference/maskedarray.html
# OR : https://docs.scipy.org/doc/numpy-1.13.0/reference/maskedarray.generic.html#maskedarray-generic-constructing


import sympy

A = sympy.Matrix([[1, 2], [2, -1]])
B = sympy.Matrix([[1, 0, 3], [2, 1, 1]])
C = sympy.Matrix([[1, 2], [3, 1], [2, -1]])
D = sympy.Matrix([[1, 0, 3], [1, 1, -2], [2, -1, 1]])
E = sympy.Matrix([[1], [2], [-1]])
F = sympy.Matrix([[1, 2, 3]])

print(A*B)
print(D**2)
print(D*C)
print(C*B)
print(B*C)
print(F*E)
print(E*F)
print()

C = sympy.Matrix([[2, 3], [1, 2]])
D = sympy.Matrix([[1, 1, 0], [0, 1, 1], [1, 0, 1]])
E = sympy.Matrix([[3, 0, 2], [2, -1, -2], [-1, 2, 6]])

print(A**-1)
print(C**-1)
print(D**-1)
print()
print((A**-1)*sympy.Matrix([[1], [-2]]))
print((D**-1)*E)


import numpy as np

# stretched exponential decay function
def stretched_exp(x, x0, a, beta):
    return x0*np.exp(-a*(x**beta))

# 'exp exp' decay function
def expexp(x, a0, a1, lam, beta):
    return a0*np.exp(-a1*(1-np.exp(-lam*x**beta)))


# Based on http://d2l.ai/chapter_computer-vision/transposed-conv.html

import superimport

import jax
import jax.numpy as jnp

def trans_conv(X, K):
    h, w = K.shape
    Y = jnp.zeros((X.shape[0] + h - 1, X.shape[1] + w - 1))
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            Y = Y.at[i : i + h, j : j + w].add(X[i, j] * K)
    return Y

# Example from D2L fig 13.10.1
X = jnp.array([[0.0, 1], [2, 3]])
K = jnp.array([[0.0, 1], [2, 3]])
Y = trans_conv(X, K)
print(Y)

X_ = X.reshape(1, 1, 2, 2)
K_ = jnp.rot90(K, 2).reshape(1, 1, 2, 2)
Y2 = jax.lax.conv_general_dilated(X_, K_, window_strides=(1, 1), padding=((1, 1), (1, 1)), lhs_dilation=(1, 1))
# print(Y2)
assert jnp.allclose(Y, Y2)

"""
X_ = X.reshape(1, 1, 2, 2)
K_ = jnp.rot90(K, 2).reshape(1, 1, 2, 2)
Y2 = jax.lax.conv_general_dilated(X_, K_, window_strides=(1, 1), padding=((0, 0), (0, 0)), lhs_dilation=(1, 1))
print('Y2', Y2)
"""

# Transposed Matrix multiplication

K = jnp.array([[1, 2], [3, 4]])

def kernel2matrix(K):
    k, W = jnp.zeros(5), jnp.zeros((4, 9))
    k = k.at[:2].set(K[0, :])
    k = k.at[3:5].set(K[1, :])
    W = W.at[0, :5].set(k)
    W = W.at[1, 1:6].set(k)
    W = W.at[2, 3:8].set(k)
    W = W.at[3, 4:].set(k)
    return W

W = kernel2matrix(K)

X = jnp.array([[0.0, 1], [2, 3]])
Y = trans_conv(X, K)
Y2 = jnp.dot(W.T, X.reshape(-1)).reshape(3, 3)
assert jnp.allclose(Y, Y2)

# Example from Geron fig 14.27

X = jnp.ones((2, 3))
K = jnp.ones((3, 3))
X_, K_ = X.reshape(1, 1, 2, 3), jnp.rot90(K, 2).reshape(1, 1, 3, 3)
Y2 = jax.lax.conv_general_dilated(X_, K_, window_strides=(1, 1), padding=((2, 2), (2, 2)), lhs_dilation=(2, 2))
print(Y2)
print(Y2.shape)


import numpy as np
import pandas as pd

def meanX(dataX):
    return np.mean(dataX, axis=0)

def variance(X):
    m, n = np.shape(X)
    mu = meanX(X)
    muAll = np.tile(mu, (m, 1))
    X1 = X - muAll
    variance = 1. / m * np.diag(X1.T * X1)
    return variance

def normalize(X):
    m, n = np.shape(X)
    mu = meanX(X)
    muAll = np.tile(mu, (m, 1))
    X1 = X - muAll
    X2 = np.tile(np.diag(X.T * X), (m, 1))
    XNorm = X1 / X2
    return XNorm

def pca(XMat, k):
    average = meanX(XMat)
    m, n = np.shape(XMat)
    avgs = np.tile(average, (m, 1))
    data_adjust = XMat - avgs
    covX = np.cov(data_adjust.T)
    featValue, featVec = np.linalg.eig(covX)
    index = np.argsort(-featValue)
    if k > n:
        print("k must lower than feature number")
        return
    else:
        selectVec = featVec.T[index[:k]]
        finalData = np.matmul(data_adjust, selectVec.T)
        reconData = np.matmul(finalData, selectVec) + average
        real_finalData = finalData.real
        real_reconData = reconData.real
    return real_finalData, real_reconData

def loaddata(datafile):
    return np.array(pd.read_csv(datafile, sep="\t", header=None)).astype(np.float)

def reduction(CS, DS, FLAGS):
    k_CS = int(CS.shape[1] * 0.8)
    k_DS = int(DS.shape[1] * 0.8)
    CS, reconMat = pca(CS, k_CS)
    DS, reconMat = pca(DS, k_DS)
    return CS, DS


# coding: utf-8
import numpy as np
import matplotlib.pylab as plt

def softmax(a):
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    return exp_a / sum_exp_a

def soft_max_improved(a):
    c = np.max(a)
    exp_a = np.exp(a - c)
    return exp_a / np.sum(exp_a)

# X = np.arange(-5.0, 5.0, 0.1)
# Y = softmax(X)
# plt.plot(X, Y)
# # plt.ylim(-0.1, 1.1)
# plt.show()

# Test:
a = np.array([0.3, 2.9, 4.0])
# a1 = np.array([1010, 1000, 990]) # overflow

exp_a = np.exp(a)
print(exp_a)

sum_exp_a = np.sum(exp_a)
print(sum_exp_a)

print(exp_a / sum_exp_a)


import numpy as np

def unit_step(v):
	if v >= 0:
		return 1
	else:
		return 0

def perceptron(x, w, b):
    v = np.dot(w, x)+b
    y =unit_step(v)
    return y

def NOR_percep(x):
    w = np.array([-1, -1])
    b = 0.5
    result = perceptron(x, w, b)
    return result

example1 = np.array([1, 1])
example2 = np.array([1, 0])
example3 = np.array([0, 1])
example4 = np.array([0, 0])

print("1 NOR 1: ",NOR_percep(example1))
print("1 NOR 0: ",NOR_percep(example2))
print("0 NOR 1: ",NOR_percep(example3))
print("0 NOR 0: ",NOR_percep(example4 ))


import numpy as np

def calc_v(mu, r, a):
    ''' Calculate velocity at a point in an orbit given
    the gravitational parameter of the primary body, radius
    at the point of interest, and the semi-major axis of
    the orbit. '''
    return np.sqrt(2*(mu/r - mu/2/a))  # (km/s)

def calc_a(h, mu, e):
    ''' Calculate semi-major axis given specific angular momentum,
    gravitational parameter of primary body, and eccentricity. '''
    return (h**2/mu)*(1/(1 - e**2))

def calc_T(mu, a):
    ''' Calculate orbital period given gravitational parameter
    and semi-major axis. '''
    return 2*np.pi*a**1.5/np.sqrt(mu)

def calc_RA_dot(mu, J2, R, e, a, i):
    ''' Calculate time rate of change of Right Ascension (RA)
    of an orbit given gravitational parameter, J2, equatorial
    radius of primary body, eccentricity, semi-major axis,
    and inclination. '''
    return -1.5*(np.sqrt(mu)*J2*R**2)/((1 - e**2)**2*a**3.5)*np.cos(i)

def calc_AP_dot_1(mu, J2, R, e, a, i):
    ''' Calculate time rate of change of Argument of Periapsis (AP)
    given gravitational parameter, J2, equatorial radius of primary
    body, eccentricity, semi-major axis, and inclination. '''
    return -1.5*(np.sqrt(mu)*J2*R**2)/((1 - e**2)**2*a**3.5)*(2.5*(np.sin(i))**2 - 2)

def calc_AP_dot_2(RAdot, i):
    ''' Calculate time rate of change of Argument of Periapsis (AP)
    given time rate of change of Right Ascension (RAdot) and
    inclination. '''
    return RAdot*(2.5*(np.sin(i))**2 - 2)/(np.cos(i))

def find_orbital_elements(r_, v_, mu):
    ''' Calculate all six orbital elements given a position and
    velocity vector at some point in the orbit, and the gravitational
    parameter of the primary body. A variable with a trailing
    underscore denotes a vector: x_ is a vector, x is the magnitude
    of x_. Applies Algorithm 4.2 from Orbital Mechanics for Engineering
    Students, 4 ed, Curtis. Returns angles in radians. '''
    r = np.linalg.norm(r_)
    v = np.linalg.norm(v_)
    vr = np.dot(r, v)/r

    # Specific Angular Momentum
    h_ = np.cross(r_, v_)
    h = np.linalg.norm(h_)

    # Inclination
    i = np.arccos(h_[2]/h)

    # Right Ascension
    Khat_ = np.array([0.0, 0.0, 1.0])
    N_ = np.cross(Khat_, h_)
    N = np.linalg.norm(N_)

    if N != 0:
        RA = np.arccos(N_[0]/N)
        RA = RA if N_[1] >= 0 else 2*np.pi - RA
    else:
        RA = 0.0

    # Eccentricity
    e_ = (1/mu)*(np.cross(v_, h_) - mu*r_/r)
    e = np.linalg.norm(e_)

    # Argument of Periapsis
    if N != 0:
        if e > 1e-7:
            AP = np.arccos(np.dot(N_/N, e_/e))
            AP = AP if e_[2] >= 0 else 2*np.pi - AP
        else:
            AP = 0.0
    else:
        AP = 0.0

    # True Anomaly
    if e > 1e-7:
        TA = np.arccos(np.dot(e_/e, r_/r))
        TA = TA if vr >= 0 else 2*np.pi - TA
    else:
        cp = np.cross(N_, r_)
        TA = np.arccos(np.dot(N_, r_)/N/r)
        TA = TA if cp[2] >= 0 else 2*np.pi - TA

    return h, i, e, RA, AP, TA

def calc_v_infinity(mu, R1, R2):
    ''' Calculate the hyperbolic excess speed for an escape trajectory
    from planet 1 with circular orbit radius R1 about the primary with
    gravitational parameter mu headed toward planet 2 with radius R2
    about the primary.
    :param R1: `float` (km) circular orbital radius, planet 1
    :param R2: `float` (km) circular orbital radius, planet 2
    :return: `float` (km/s) hyperbolic excess speed of escape trajectory
    '''
    return np.sqrt((mu/R1)*(np.sqrt((2*R2)/(R1 + R2)) - 1))

def calc_dv_hohmann_coplanar_common_apseline(mu, ra1, rp1, ra2, rp2):
    ''' Calculate total delta-V (m/s) required for a Hohmann transfer between
    two coplanar orbits with a common apse line.
    :param mu: `float` (km**3/s**2) gravitational parameter of primary body
    :param ra1: `float` (km) apoapsis radius, initial orbit
    :param rp1: `float` (km) periapsis radius, initial orbit
    :param ra2: `float` (km) apoapsis radius, final orbit
    :param rp2: `float` (km) periapsis radius, final orbit
    :return: `float` (m/s) total delta-V required for maneuver
    '''
    a1 = 0.5*(ra1 + rp1)
    ai = 0.5*(ra2 + rp1)
    a2 = 0.5*(ra2 + rp2)

    vp1 = calc_v(mu, rp1, a1)
    vpi = calc_v(mu, rp1, ai)
    vai = calc_v(mu, ra2, ai)
    va2 = calc_v(mu, ra2, a2)

    dv1 = vpi - vp1  # (km/s) delta-V of first burn
    dv2 = va2 - vai  # (km/s) delta-V of second burn

    return (np.abs(dv1) + np.abs(dv2))  # (km/s) total maneuver delta-V


# =========================================================
# @purpose: principal components analysis
# @date：   2019/12
# @version: v1.0
# @author： Xu Huasheng
# @github： https://github.com/xuhuasheng/pca
# =========================================================

from sklearn.externals import joblib
import numpy as np
import glob
import os
import time

def pca(dataMat, r, autoset_r=False, autoset_rate=0.9):
    """
    purpose: principal components analysis
    """
    print("Start to do PCA...")
    t1 = time.time()
    meanVal = np.mean(dataMat, axis=0) # 竖着求平均值，数据格式是m×n
    meanRemoved = dataMat - meanVal
    # normData = meanRemoved / np.std(dataMat) #标准差归一化
    covMat = np.cov(meanRemoved, rowvar=0)   # 求协方差矩阵 n×n维
    eigVals, eigVects = np.linalg.eig(np.mat(covMat)) # 求特征值和特征向量  eigVals: 1xn维, eigVects: n×n维
    eigValIndex = np.argsort(-eigVals) # 特征值由大到小排序，eigValIndex是特征值索引的重排列 1×n维

    # 自动设置r的取值
    if autoset_r:
        r = autoset_eigNum(eigVals, autoset_rate)
        print("autoset: take top {} of {} features".format(r, meanRemoved.shape[1]))

    r_eigValIndex = eigValIndex[:r] # 选取前r个特征值的索引  1×r维
    r_eigVect = eigVects[:, r_eigValIndex] # 把前r个特征值对应的特征向量组成投影变换矩阵P  n×r维
    lowDDataMat = meanRemoved * r_eigVect # 矩阵点乘投影变换矩阵, 得降维后的矩阵: m×r维 公式Y=X*P
    reconMat = (lowDDataMat * r_eigVect.T) + meanVal   # 转换新空间的数据  m×n维
    t2 = time.time()
    print("PCA takes %f seconds" %(t2-t1))
    joblib.dump(r_eigVect, './pca_args_save/r_eigVect.eig')
    joblib.dump(meanVal, './pca_args_save/meanVal.mean') # save mean value
    return lowDDataMat, reconMat

def autoset_eigNum(eigValues, rate=0.99):
    """
    purpose: Automatically set the optimal number of eigen vectors
    """
    eigValues_sorted = sorted(eigValues, reverse=True)
    eigVals_total = eigValues.sum()
    for i in range(1, len(eigValues_sorted)+1):
        eigVals_sum = sum(eigValues_sorted[:i])    # 前i个特征向量求和
        if eigVals_sum / eigVals_total >= rate:
            break
    return i


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

df = pd.read_csv("china_gdp.csv", sep=",")
print(df.head(8))
print(df.columns)
print(df.dtypes)

#we can see it is similar to Logistic Function.
plt.figure(figsize=(8,5))
x_data, y_data = (df["Year"].values, df["Value"].values) #your X and Y
plt.plot(x_data, y_data, 'ro')
plt.ylabel('GDP')
plt.xlabel('Year')
plt.show()

"""Sigmoid Function"""
def sigmoid(x, Beta_1, Beta_2):
     y = 1 / (1 + np.exp(-Beta_1*(x-Beta_2)))
     return y

"""Model"""
beta_1 = 0.10
beta_2 = 1990.0

#logistic function
Y_pred = sigmoid(x_data, beta_1 , beta_2) #call function

#plot initial prediction against datapoints
plt.plot(x_data, Y_pred*15000000000000., 'b')
plt.plot(x_data, y_data, 'ro')
plt.show()

# Lets normalize our data
xdata =x_data/max(x_data)
ydata =y_data/max(y_data)
#print(len(xdata),max(x_data))

from scipy.optimize import curve_fit
popt, pcov = curve_fit(sigmoid, xdata, ydata)
#print the final parameters
print(" beta_1 = %f, beta_2 = %f" % (popt[0], popt[1]))

x = np.linspace(1960, 2015, 55)
x = x/max(x)
plt.figure(figsize=(8,5))
y = sigmoid(x, *popt)
plt.plot(xdata, ydata, 'ro', label='data')
plt.plot(x,y, linewidth=3.0, label='fit')
plt.legend(loc='best')
plt.ylabel('GDP')
plt.xlabel('Year')
plt.show()

###################################Model data using sklearn #################################
# split data into train/test
msk = np.random.rand(len(df)) < 0.8
train_x = xdata[msk]
test_x = xdata[~msk]
train_y = ydata[msk]
test_y = ydata[~msk]

# build the model using train set
popt, pcov = curve_fit(sigmoid, train_x, train_y)

# predict using test set
y_hat = sigmoid(test_x, *popt)

# evaluation
print("Mean absolute error: %.2f" % np.mean(np.absolute(y_hat - test_y)))
print("Residual sum of squares (MSE): %.2f" % np.mean((y_hat - test_y) ** 2))
from sklearn.metrics import r2_score
print("R2-score: %.2f" % r2_score(y_hat , test_y) )


import numpy as np
from scipy import integrate

f1 = lambda x, y: 1 / (np.sqrt(x+y) * (1+x+y))
f2 = lambda x, y: x**2 + y ** 2

def trapezoidal_rule_2D(f, xmin, xmax, xnum, ymin, ymax, ynum):
    integral = 0
    hx = (xmax - xmin) / xnum

    for i in range(0, xnum + 1):
        x = xmin + i * hx
        hy = (ymax(x) - ymin(x)) / ynum

        part_int = 0
        for j in range(0, ynum + 1):
            y = ymax(x) + j * hy

            if j in {0, ynum}:
                part_int += 0.5 * f(x, y)
            else:
                part_int += f(x, y)

        part_int *= hy
        if i in {0, xnum}:
            integral += 0.5 * part_int
        else:
            integral += part_int

    integral *= hx
    return integral

f = f1
xmin = 0
xmax = 1
ymin = lambda x: 0
ymax = lambda x: 1 - x
xnum = 1000
ynum = 1000
custom_int = trapezoidal_rule_2D(f, xmin, xmax, xnum, ymin, ymax, ynum) * 10
lib_int = integrate.dblquad(f, xmin, xmax, ymin, ynum)[0]

print("Custom: " + str(custom_int))
print("Library: " + str(lib_int))

f = f2
xmin = -3
xmax = 3
ymin = lambda x: -5
ymax = lambda x: 5
xnum = 1000
ynum = 1000
custom_int = trapezoidal_rule_2D(f, xmin, xmax, xnum, ymin, ymax, ynum) / 10
lib_int = integrate.dblquad(f, xmin, xmax, ymin, ynum)[0]

print("Custom: " + str(custom_int))
print("Library: " + str(lib_int))


import matplotlib.pyplot as graph
import numpy as np
import pandas as pd
import scipy.optimize as opt

# --------------------------------------------------------------------
# Logistic growth model to predict COVID-19 prevalence and
# incidence rate using existing data from John Hopkins University and
# New York Times Github (https://github.com/nytimes/covid-19-data)
#
# Written Arnel Aguinaldo, PhD (Point Loma Nazarene University)
# Applicable rights for free reproduction of this program are defined in
# MIT License
# --------------------------------------------------------------------

# growth rates (vary by region)
b0 = 0.20   #full exposure
b1 = 0.12   #60% exposure due to mitigation measures (i.e., social distancing)
b2 = 0.08   #40% exposure due to mitigation measures (i.e., social distancing)

# population max
Nmin=1
Nmax=10000
a=(Nmax-Nmin)/Nmin
dt=1

# time interval
t=np.arange(1,120,2)

# infection prevalence (total infected per day)
def n0(t):
    return Nmax/(1+a*np.exp(-b0*t))
def n1(t):
    return Nmax/(1+a*np.exp(-b1*t))
def n2(t):
    return Nmax/(1+a*np.exp(-b2*t))

# infection incidence rates (number of new cases per day)
def r0(t):
    return (n0(t)-n0(t-1))/dt
def r1(t):
    return (n1(t)-n1(t-1))/dt
def r2(t):
    return (n2(t)-n2(t-1))/dt

# graph style
graph.style.use('seaborn-talk')

# Prevalence plot
graph.figure(1)
graph.plot(t, n0(t),'b', t, n1(t), 'r', t, n2(t), 'g')
graph.xlabel('Days')
graph.ylabel('Prevalence (Total Cases)')
graph.legend([ 'Full Exposure','60% Exposure', '40% Exposure'])
graph.title('COVID19')
graph.grid('true')

# Incidence rate plot
graph.figure(2)
graph.plot(t, r0(t),'b', t, r1(t), 'r', t, r2(t), 'g')
graph.xlabel('Days')
graph.ylabel('Incidence Rate')
graph.legend([ 'Full Exposure','60% Exposure', '40% Exposure'])
graph.title('COVID19')
graph.grid('true')

graph.show()

#Day 5 and 30 prevalence by exposure
#Full exposure
print(n0(5), n0(30))
#60% exposure
print(n1(5), n1(30))
#40% exposure
print(n2(5), n2(30))

# ----------------------------------------------------------
# Fit logistic model to real data (USA or state)
# ----------------------------------------------------------

#import case data (update with the local path of the csv file)
sPath='total-cases-covid=19-04052020.csv'
alldata=pd.read_csv(
        sPath,
        sep=',',
        usecols=['Days', 'California']
        )
alldata.head()
alldata=alldata.dropna()

#logistic function to be fitted
def r(t,a,b,c):
    return c/(1+a*np.exp(-b0*t))

# initialize coefficients using known or random values
#init_guess = [1, 1.5, Nmax]
init_guess = np.random.exponential(size=3)

# set array bounds (adjust according to region or target population)
bounds = (0, [1000., 0.5, 100000.])

t = np.array(alldata['Days']) + 1
y = np.array(alldata['California'])

# real infection rate
rate = (y[1:]-y[:-1])        #daily incidence (growth)
t_max = t.size

# ----------------------------------------------------------
# Logistic model to predict prevalence (total cases)
# ----------------------------------------------------------

#non-linear optimization to estimate best fit model on case data
#uncomment next line to find best fit with new regional data
#(a,b,c),covar = opt.curve_fit(r, t, y, bounds=bounds, p0=init_guess)

#BEST FIT FOR CALIFORNIA PREVALENCE (r^2=0.992):
(a,b,c)=(234.7722, 0.2414, 19362.9526)

# time intervals
tn=np.arange(1,40,2)
tr=np.arange(1,t_max)

# fitted infection prevalence (total infected per day)
def n_lg(tn):
    return c/(1+a*np.exp(-b*tn))

# prevalence plot
graph.figure(1)
graph.scatter(t,y)
graph.plot(tn, n_lg(tn), 'r')
graph.xlabel('Days')
graph.ylabel('Prevalence (Total Cases)')
graph.legend([ 'Model','California'])
graph.title('COVID19')
graph.grid('true')

# ----------------------------------------------------------
# Logistic model to predict incidence (daily growth) rate
# ----------------------------------------------------------

y=rate

#non-linear optimization to estimate best fit model on daily rate
#uncomment next line to find best fit with new regional data
#(a,b,c),covar = opt.curve_fit(r, tr, y, bounds=bounds, p0=init_guess)

#BEST FIT FOR CALIFORNIA INCIDENCE (r^2=0.812):
(a,b,c)=(204.7359, 0.2551, 3021.3831)

def rate_lg(tr):
    return c/(1+a*np.exp(-b*tr))

# Incidence rate (%) plot
graph.figure(2)
graph.scatter(tr,rate)
graph.plot(tr, rate_lg(tr), 'r')
graph.xlabel('Days')
graph.ylabel('Incidence Rate')
graph.legend([ 'Model','California'])
graph.title('COVID19')
graph.grid('true')


## module gaussSeidel
''' x,numIter,omega = gaussSeidel(iterEqs,x,tol = 1.0e-9)
    Gauss-Seidel method for solving [A]{x} = {b}.
    The matrix [A] should be sparse. User must supply the
    function iterEqs(x,omega) that returns the improved {x},
    given the current {x} ('omega' is the relaxation factor).
'''
import numpy as np
import math

def gaussSeidel(iterEqs,x,tol = 1.0e-9):
    omega = 1.0
    k = 10
    p = 1
    for i in range(1,501):
        xOld = x.copy()
        x = iterEqs(x,omega)
        dx = math.sqrt(np.dot(x-xOld,x-xOld))
        if dx < tol: return x,i,omega
      # Compute relaxation factor after k+p iterations
        if i == k: dx1 = dx
        if i == k + p:
            dx2 = dx
            omega = 2.0/(1.0 + math.sqrt(1.0 - (dx2/dx1)**(1.0/p)))
    print('Gauss-Seidel failed to converge')


# What happens to quantization error when you fourier transform?
# before figuring out analytically we experiment computationally to find out what to expect.
import numpy as np
from numpy.fft import fft,rfft,irfft,ifft

def quantize_uniform_noise(signal,delta):
    # input signal simulated getting 'quantized' by adding noise
    noise = np.random.uniform(-delta/2,delta/2,len(signal))
    return signal + noise

def mse(signal,noisy_signal):
    return np.mean(abs(signal - noisy_signal)**2)

if __name__=="__main__":
    mse_signals = []
    mse_rft_signals = []
    sqrt = np.sqrt
    delta = sqrt(12) # 1.0
    n = 100000
    print("Simulating the effects of quantization on signals and their fourier transforms...\n\n")
    for i in range(1000):
        signal = np.random.normal(0,1,n)
        noisy_signal = quantize_uniform_noise(signal,delta)
        mse_signal = mse(signal,noisy_signal)
        mse_signals.append(mse_signal)

        rft_s = rfft(signal)/sqrt(n)
        rft_ns = rfft(noisy_signal)/sqrt(n)
        mse_rft_signal = mse(rft_s,rft_ns)
        mse_rft_signals.append(mse_rft_signal)
    print("mean squared error for the singal is {}\nmean squared error for the rftsig is {}".format(np.mean(mse_signals),np.mean(mse_rft_signals)))
    print("")
    print("the respective stds are {} and {}".format(np.std(mse_signals),np.std(mse_rft_signals)))


import numpy as np
import matplotlib.pyplot as plt

def f(x):
    return 2*x**2

# np.arange(start, stop, step) to give us smoother line
x = np.arange(0, 5, 1e-3)
y = f(x)

plt.figure()
plt.plot(x, y)

# the point and the 'close enough' point
p2_delta = 1e-4
x1 = 2
x2 = x1 + p2_delta
y1 = f(x1)
y2 = f(x2)

print((x1,y1), (x2,y2))

# derivative approximation and y-intercept for the tangent line
approximate_derivative = (y2-y1)/(x2-x1)
b = y2 -  approximate_derivative*x2

# we put the tangent line calculation into a function so we can call
# it multiple times for different values of x
# approximate_derivative and b are constant for given function
# thus calculated once above this function
def tangent_line(x):
    return approximate_derivative*x + b

# plotting the tangent line
# +- 1 to draw the tangent line on our graph
# then we calculate the y for given x using the tangent line function
# Matplotlib will draw a line for us through these points
to_plot = [x1-1, x1, x1+1]
plt.plot(to_plot, [tangent_line(i) for i in to_plot])
plt.savefig('graph1.png')

print('approximate derivative for f(x)',
    f'where x = {x1} is {approximate_derivative}')


# Use Runge-Kutta 45 to numerically solve the differential equation of the voltage discharge from a simple RC circuit
# by gunnar pope
# 01/24/19
# Usage: $ python RK4.py

# references: https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html

from scipy.integrate import solve_ivp

R = 1e6 #Ohms
C = 1e-6 #Farads

# dV/dt = -1/(R*C)*Vc
def f(t,y):
    dydt = -1.0/(R*C)*y
    return dydt

# solve_ivp(fun, t_span, y0, method='RK45', t_eval=None, dense_output=False, events=None, vectorized=False, **options)
t_start = 0
t_end   = 10

# initial conditions (this could be a vector too [a, b, c, etc]
ics = [2] #volts

# apply RK45 to numerically solve the differential equation, given the initial conditions and time span.
sol = solve_ivp(f, [t_start,t_end],ics, method='RK45')
print(sol.t)
print()
print(sol.y)

import matplotlib.pyplot as plt
import numpy as np

# compare the numerical solution to the solution in the time-domain.
t = np.linspace(t_start,t_end,100)
vout = ics*np.exp(-1/(R*C)*t)

plt.plot(t,vout, label='Exact Solution')
plt.plot(sol.t, sol.y[0], label='RK4 Solution')
plt.title("A Numerical Methods Example Using RK4 In Python")
plt.xlabel("Time (s)")
plt.ylabel("Voltage (v)")
plt.grid(True)
plt.legend()
plt.show()


import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import math
import sys
import os

data_dir = sys.argv[1]
out_dir = sys.argv[2]
out = os.path.join(sys.argv[2], 'Q2b.txt')
outfile = open(out, "w")

# 2. Sampling and Stochastic Gradient
print("\n################ 2. Sampling and Stochastic Gradient ################", file=outfile)

# (a) Sampling

w = np.array([[3],[1],[2]])
X1 = np.random.normal(3, 2, (int)(1e6))
X2 = np.random.normal(-1, 2, (int)(1e6))
noise = np.random.normal(0, np.sqrt(2), int(1e6)).reshape(-1,1)

X = np.column_stack((X1, X2))
X = np.column_stack((np.ones(X.shape[0]), X))
Y = np.dot(X, w) + noise
m = len(Y)

# (b) Stochastic Gradient

def hw(theta, i, r):
	x = X[i*r:(i+1)*r,]
	return np.dot(x, theta)

def Jw(h, i, r):
	y = Y[i*r:(i+1)*r,]
	return (0.5/r)*np.sum((y - h)**2)

def dJw(h, i, r):
	x = X[i*r:(i+1)*r,]
	y = Y[i*r:(i+1)*r,]
	return (1.0/r)*np.dot(x.T, (y - h))

def stochasticGradientDescent(x, y, r):
	print('\nBatch Size (r) = {}'.format(r), file=outfile)
	b = (int)(m/r)
	eta = 0.001
	theta = np.zeros((x.shape[1], 1))
	thetaL = [theta]
	prevCost = 0
	converged = False
	itr = 0
	while not converged:
		for i in range(b):
			h = hw(theta, i, r)
			cost = Jw(h, i, r)
			theta = theta + eta*dJw(h, i, r)
			thetaL.append(theta)
		itr += 1
		error = abs(cost - prevCost)
		prevCost = cost
		if error < 1e-7 or itr > 25000:
			converged = True

		if r == m and itr % 1000 == 0:
			print('iteration {}: error = {} '.format(itr, error), end = '', file=outfile)
			print('w = {0},{1},{2}'.format(theta[0], theta[1], theta[2]), file=outfile)
		elif r != m:
			print('iteration {}: error = {} '.format(itr, error), end = '', file=outfile)
			print('w = {0},{1},{2}'.format(theta[0], theta[1], theta[2]), file=outfile)
	print("Stopping Criteria: Epoch > 7 and Error < 1e-7", file=outfile)
	print("Max Iterations = ", itr, file=outfile)
	print("Error =", error, file=outfile)
	print("Final Parameters = {0},{1},{2}\n".format(theta[0], theta[1], theta[2]), file=outfile)
	return thetaL, itr

thetaL1, maxit1 = stochasticGradientDescent(X, Y, 1)
thetaL2, maxit2 = stochasticGradientDescent(X, Y, 100)
thetaL3, maxit3 = stochasticGradientDescent(X, Y, 10000)
thetaL4, maxit4 = stochasticGradientDescent(X, Y, 1000000)


import networkx as nx
import random

# Read data from the dataset, and create graph G_fb
G_fb = nx.read_edgelist("facebook_combined.txt", create_using=nx.Graph(), nodetype=int)

# Show the number of edges in G_fb
print("edges = " + str(G_fb.number_of_edges()))

# Show number of nodes in G_fb
print("nodes = " + str(G_fb.number_of_nodes()))

# TASK1. Now your task is to compute the probability whether there is an edge between two vertices.
edge_probab = G_fb.number_of_edges() / (
    ((G_fb.number_of_nodes() - 1) * G_fb.number_of_nodes()) / 2
)

# TASK2. Compute the ACC (average clustering coefficient) of G_fb
# (consult the NetworkX manual or the video lecture for the correct function which does it)
av_clust_coeff = nx.average_clustering(G_fb)
print("acc = " + str(av_clust_coeff))

# Now we have to generate a random graph. First we initialize it
G_rand = nx.Graph()
k = G_fb.number_of_nodes()
# TASK3. generate edges in G_rand at random:
for i in range(0, k):
    for j in range(0, i):
        # Add an edge between vertices i and j, with probability edge_probab (as in G_fb)
        if random.random() < edge_probab:
            G_rand.add_edge(i, j)

# Now we print out the number of edges and the ACC of the new graph
print("rgraph_edges = " + str(G_rand.number_of_edges()))

av_clust_coeff = nx.average_clustering(G_rand)

print("rgraph_acc = " + str(av_clust_coeff))

# The results which should be submitted to the grader include the ACC of G_fb and of G_rand. Good luck!

Courses/Trash/MathForDS[abandoned]/Discrete Math And Analyzing Social Graphs/final_task/final.py


'''
  File: lorenz.py

  Author: Thomas Kost

  Date: 08 August 2021

  @breif function for lorenz chaotic system, and plotting script
 '''
import numpy as np
import matplotlib.pyplot as plt
def lorenz(x :np.array, beta: np.array)->np.array:
    '''
    x: position state vector of lorenz system

    beta: vector of lorenz parameters

    return: derivative of state vector

    '''

    dx = np.array([ beta[0]*(x[1]-x[0]),
                    x[0]*(beta[1]-x[2])-x[1],
                    x[0]*x[1]-beta[2]*x[2]])
    return dx

def step_lorenz(x:np.array, beta:np.array, dt:float)->np.array:
    next_x = x + lorenz(x,beta)*dt
    return next_x

if __name__ == "__main__":
    dt = 0.001
    t = np.arange(0,50,dt)
    x = np.zeros((3,len(t)))
    x_0 = np.array((0,1,20))
    b = np.array((10,28,8/3.0))

    for i in range(len(t)):
      if(i == 0):
        x[:,i] = x_0
      else:
        x[:,i] = step_lorenz(x[:,i-1],b,dt)

    ax = plt.figure().add_subplot(projection='3d')
    ax.plot(x[0,:], x[1,:], x[2,:], lw=0.5)
    ax.set_xlabel("X Axis")
    ax.set_ylabel("Y Axis")
    ax.set_zlabel("Z Axis")
    ax.set_title("Lorenz Attractor")
    plt.show()


import numpy as np

def getSSM(X):
    """
    Compute a Euclidean self-similarity image between a set of points
    :param X: An Nxd matrix holding the d coordinates of N points
    :return: An NxN self-similarity matrix
    """
    D = np.sum(X**2, 1)[:, None]
    D = D + D.T - 2*X.dot(X.T)
    D[D < 0] = 0
    D = 0.5*(D + D.T)
    D = np.sqrt(D)
    return D

def getW(D, K, Mu = 0.5):
    """
    Return affinity matrix
    [1] Wang, Bo, et al. "Similarity network fusion for aggregating data types on a genomic scale."
        Nature methods 11.3 (2014): 333-337.
    :param D: Self-similarity matrix
    :param K: Number of nearest neighbors
    """
    #W(i, j) = exp(-Dij^2/(mu*epsij))
    DSym = 0.5*(D + D.T)
    np.fill_diagonal(DSym, 0)

    Neighbs = np.partition(DSym, K+1, 1)[:, 0:K+1]
    MeanDist = np.mean(Neighbs, 1)*float(K+1)/float(K) #Need this scaling
    #to exclude diagonal element in mean
    #Equation 1 in SNF paper [1] for estimating local neighborhood radii
    #by looking at k nearest neighbors, not including point itself
    Eps = MeanDist[:, None] + MeanDist[None, :] + DSym
    Eps = Eps/3
    W = np.exp(-DSym**2/(2*(Mu*Eps)**2))
    return W

def getCSM(X, Y):
    """
    Return the Euclidean cross-similarity matrix between the M points
    in the Mxd matrix X and the N points in the Nxd matrix Y.
    :param X: An Mxd matrix holding the coordinates of M points
    :param Y: An Nxd matrix holding the coordinates of N points
    :return D: An MxN Euclidean cross-similarity matrix
    """
    C = np.sum(X**2, 1)[:, None] + np.sum(Y**2, 1)[None, :] - 2*X.dot(Y.T)
    C[C < 0] = 0
    return np.sqrt(C)

def getGreedyPerm(X, M, Verbose = False):
    """
    Purpose: Naive O(NM) algorithm to do the greedy permutation
    :param X: Nxd array of Euclidean points
    :param M: Number of points in returned permutation
    :returns: (permutation (N-length array of indices), \
            lambdas (N-length array of insertion radii))
    """
    #By default, takes the first point in the list to be the
    #first point in the permutation, but could be random
    perm = np.zeros(M, dtype=np.int64)
    lambdas = np.zeros(M)
    ds = getCSM(X[0, :][None, :], X).flatten()
    for i in range(1, M):
        idx = np.argmax(ds)
        perm[i] = idx
        lambdas[i] = ds[idx]
        ds = np.minimum(ds, getCSM(X[idx, :][None, :], X).flatten())
        if Verbose:
            interval = int(0.05*M)
            if i%interval == 0:
                print("Greedy perm %i%s done..."%(int(100.0*i/float(M)), "%"))
    Y = X[perm, :]
    return {'Y':Y, 'perm':perm, 'lambdas':lambdas}


import numpy as np
from scipy.stats import boxcox,boxcox_normmax

def BoxCox(x,lamda,shift=None):
	if shift is None:
		xs,shift = ShiftX(x)
	else:
		xs = x + shift
	if lamda == 0:
		xt = np.log(xs)
	else:
		xt = (xs**lamda - 1)/lamda
	return xt

def BoxCoxLogLikelihood(x,lamda):
	n = np.size(x)
	xl = BoxCox(x,lamda)
	xlbar = np.mean(xl)

	fxl = -(n/2)*np.log(np.sum((xl - xlbar)**2)/n) + (lamda-1)*np.sum(np.log(x))

	return fxl

def MaximizeBoxCoxLikelihood(x,LamdaRange=[-4.0,4.0],Tol=0.001):
	#import matplotlib.pyplot as plt

	LR = np.array(LamdaRange)
	dL = 1.0
	Repeat = True
	out = 1.0
	while Repeat:
		nL = np.int32((LR[1]-LR[0])/dL)
		L = np.arange(nL)*dL + LR[0]
		ll = np.zeros(nL,dtype='float64')
		for j in range(0,nL):
			ll[j] = BoxCoxLogLikelihood(x,L[j])
		#print(ll)
		bad = np.where(np.isfinite(ll) == False)[0]
		ll[bad] = np.nan
		good = np.where(np.isfinite(ll))[0]
		if good.size == 0:
			return np.nan
		best = np.where(ll == np.nanmax(ll))[0]
		#print(best,ll[best[0]])
		if best[0] == 0:
			best[0] = 1
		if best[0] == nL-1:
			best[0] -= 1
		if dL < Tol:
			out = L[best[0]]
			Repeat = False
		#plt.plot(L,ll)
		LR = np.array([L[best[0]-1],L[best[0]+1]])
		dL = (LR[1]-LR[0])/nL
	return out

def ShiftX(xin):
	x = xin[np.isfinite(xin)]
	shift = 0.0
	if (x < 0).any():
		newx = x - np.min(x)
		shift += -np.min(x)
	else:
		newx = x
	if (newx == 0).any():
		gt0 = np.where(newx > 0)[0]
		if gt0.size == 0:
			return x,np.nan
		minx = np.min(newx[newx > 0])/2.0
		newx += minx
		shift += minx
	return newx,shift

def FitBoxCox(x):

	#first of all - shift the data so that there are no negatives!
	xs,shift = ShiftX(x)
	if np.isnan(shift):
		return x,1.0,1.0
	#now use scipy.stats.boxcox to fit function
	#lamda = boxcox_normmax(xs,brack=(-2.0,1.9),method='all').min()
	lamda = MaximizeBoxCoxLikelihood(xs)
	xt = boxcox(xs,lamda)

	return xt,lamda,shift

def ReverseBoxCox(xt,lamda,shift):
	if lamda == 0:
		xs = np.exp(xt)
	else:
		xs = (xt*lamda + 1)**(1/lamda)

	x = xs-shift
	return x

def BoxCoxNormalize(x,nSigma=1.0,NotFin='ignore'):
	#copy input array
	X = np.copy(x.astype('float64'))

	#deal with bad data - NotFin to value to replace infs and NaNs with
	if NotFin is 'ignore':
		good = np.where(np.isfinite(X))[0]
		Xg = X[good]
	else:
		bad = np.where(np.isfinite(X) == False)[0]
		X[bad] = NotFin
		Xg = X

	if Xg.size == 0:
		return X,0.0,1.0,1.0,1.0

	#perform BC transform
	Xbc,lamda,shift = FitBoxCox(Xg)

	Xbc[np.isfinite(Xbc) == False] = np.nan

	#calculate mean and std
	mu = np.nanmean(Xbc)
	nsig = np.nanstd(Xbc)*nSigma

	#rescale data
	Xs = (Xbc - mu)/(nsig)

	#Add bad data back in if necessary
	if NotFin is 'ignore':
		Xout = np.zeros(X.size,dtype='float64')+np.nan
		Xout[good] = Xs
	else:
		Xout = Xs
	return Xout,mu,nsig,lamda,shift

def BoxCoxUnNormalize(x,mu,nsig,lamda,shift):
	Xs = np.copy(x)
	Xbc = Xs*nsig + mu
	Xout = ReverseBoxCox(Xbc,lamda,shift)

	return Xout


import numpy as np

X = np.array([1, 2, 3, 4, 5, 6, 7])
Y = np.array([2, 3, 4, 5, 6, 7, 8])
w_gradient = 0
b_gradient = 0
w, b = 0.5, 0.5

learning_rate = .01
loss = 0
EPOCHS = 2000
N = len(Y)

for i in range(EPOCHS):

    # Predict
    Y_pred = (w * X) + b

    # Loss
    loss = np.square(Y_pred - Y).sum() / (2.0 * N)
    if i % 100 == 0:
        print(loss)

    # Backprop
    grad_y_pred = (2 / N) * (Y_pred - Y)
    w_gradient = (grad_y_pred * X).sum()
    b_gradient = (grad_y_pred).sum()

    # Optimize
    w -= (w_gradient * learning_rate)
    b -= (b_gradient * learning_rate)

print("\n\n")
print("LEARNED:")
print(w, b)
print("\n")
print("TEST:")
print(np.round(b + w * (-2)))
print(np.round(b + w * 0))
print(np.round(b + w * 1))
print(np.round(b + w * 6))
print(np.round(b + w * 3000))

# Expected: 30001, but gives 30002.
# Training for 3000 epochs will give expected result.
# For simple demo with less training data and small input range 2000 in enough
print(np.round(b + w * 30000))


import pandas as pd
import numpy as np
import math
import pdb

def average(series):
    """
    implements the average of a pandas series from scratch
    suggested functions:
    len(list)
    sum(list)
    you should get the same result as calling .mean() on your series
    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.mean.html
    See numpy documenation for implementation details:
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.mean.html
    """
    pass
    avgnum = sum(series) / len(series)
    return avgnum

def standard_deviation(series):
    """
    implements the sample standard deviation of a series from scratch
    you may need a for loop and your average function
    also the function math.sqrt
    you should get the same result as calling .std() on your data
    https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.std.html
    See numpy documenation for implementation details:
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.std.html
    """
    pass
    avgnum = sum(series) / len(series)
    sumsq = 0
    for each in series:
        t = each - avgnum
        sumsq = sumsq + pow(t,2)
    stdnum = math.sqrt(sumsq/(len(series)-1))
    return stdnum

def median(series):
    """
    finds the median of the series from scratch
    you may need to sort your values and use
    modular division
    this number should be the same as calling .median() on your data
    See numpy documenation for implementation details:
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.median.html
    https://pandas.pydata.org/pandas-docs/version/0.23.0/generated/pandas.Series.median.html
    """
    pass
    n = len(series)
    for j in range(n - 1):
        count = 0
        for i in range(0, n - 1 - j):
            if series[i] > series[i + 1]:
                series[i], series[i + 1] = series[i + 1], series[i]
                count = count + 1
        if 0 == count:
            break

    if int(n/2) == n/2:
        mednum = (series[n//2-1]+series[n//2])/2
    else:
        mednum = series[n//2]

    return mednum


import numpy as np
import pandas as pd

def accuracy_score(y_true, y_pred):
    '''Class performance metric that computes the accuracy and y_pred'''
    correct = 0
    for true, pred in zip(y_true, y_pred):
        if true == pred:
            correct += 1                                  # count the correct predictions
    accuracy = correct/len(y_true)
    return accuracy

def mse(y_true, y_pred):
    """
    Mean squared error regression loss function.
    Parameters
    :param numpy.array y_true: array-like of shape (n_samples,)
        Ground truth (correct) target values.
    :param numpy.array y_pred: array-like of shape (n_samples,)
        Estimated target values.
    :returns: loss (float) A non-negative floating point value (the best value is 0.0).
    """
    return np.mean(np.power(y_true-y_pred, 2))

def mse_prime(y_true, y_pred):
    return 2*(y_pred-y_true)/y_true.size

def cross_entropy(y_true, y_pred):
    return -(y_true * np.log(y_pred)).sum()

def cross_entropy_prime(y_true, y_pred):
    return y_pred-y_true

def r2_score(y_true, y_pred):
    """
    R^2 regression score function.
        R^2 = 1 - SS_res / SS_tot
    where SS_res is the residual sum of squares and SS_tot is the total
    sum of squares.
    :param numpy.array y_true : array-like of shape (n_samples,) Ground truth (correct) target values.
    :param numpy.array y_pred : array-like of shape (n_samples,) Estimated target values.
    :returns: score (float) R^2 score.
    """
    # Residual sum of squares.
    numerator = ((y_true - y_pred) ** 2).sum(axis=0)
    # Total sum of squares.
    denominator = ((y_true - np.average(y_true, axis=0)) ** 2).sum(axis=0)
    # R^2.
    score = 1 - numerator / denominator
    return score

class ConfusionMatrix:

    def __init__(self, true_y, predict_y):
        '''Confusion Matrix implementation for the
        evaluation of the performance model by comparing the true vs the predicted values.'''
        self.true_y = np.array(true_y)
        self.predict_y = np.array(predict_y)

    def build_matrix(self):
        import pandas as pd
        #computing a cross tabulation - frequency table of the factors
        cm = pd.crosstab(self.true_y,self.predict_y, rownames = ["True values"], colnames = ["Predicted values"])
        return cm

    def toDataframe(self):
        import pandas as pd
        return pd.DataFrame(self.build_matrix())


import numpy as np
import util

def main(train_path, valid_path, save_path, plot_path):
    """Problem: Logistic regression with Newton's Method.

    Args:
        train_path: Path to CSV file containing dataset for training.
        valid_path: Path to CSV file containing dataset for validation.
        save_path: Path to save predicted probabilities using np.savetxt().
        plot_path: Path to save plots.
    """
    x_train, y_train = util.load_dataset(train_path, add_intercept=True)
    x_valid, y_valid = util.load_dataset(valid_path, add_intercept=True)
    clf = LogisticRegression()
    clf.fit(x_train, y_train)
    util.plot(x_valid, y_valid, clf.theta, plot_path)
    np.savetxt(save_path, clf.predict(x_valid))

class LogisticRegression:
    """Logistic regression with Newton's Method as the solver.

    Example usage:
        > clf = LogisticRegression()
        > clf.fit(x_train, y_train)
        > clf.predict(x_eval)
    """
    def __init__(self, step_size=0.01, max_iter=1000000, eps=1e-5,
                 theta_0=None, verbose=True):
        """
        Args:
            step_size: Step size for iterative solvers only.
            max_iter: Maximum number of iterations for the solver.
            eps: Threshold for determining convergence.
            theta_0: Initial guess for theta. If None, use the zero vector.
            verbose: Print loss values during training.
        """
        self.theta = theta_0
        self.step_size = step_size
        self.max_iter = max_iter
        self.eps = eps
        self.verbose = verbose

    def fit(self, x, y):
        """Run Newton's Method to minimize J(theta) for logistic regression.

        Args:
            x: Training example inputs. Shape (n_examples, dim).
            y: Training example labels. Shape (n_examples,).
        """
        self.theta = np.zeros(x.shape[1])
        while True:
            y_pred = self.predict(x)
            grad = ((y_pred - y) * x.T).mean(axis=1)
            hess = ((y_pred * (1 - y_pred)) * x.T) @ x / x.shape[1]
            diff = grad @ np.linalg.inv(hess.T)
            self.theta = self.theta - diff
            if np.abs(diff).sum() < self.eps:
                return self

    def predict(self, x):
        """Return predicted probabilities given new inputs x.

        Args:
            x: Inputs of shape (n_examples, dim).

        Returns:
            Outputs of shape (n_examples,).
        """
        z = self.theta @ x.T
        return 1 / (1 + np.exp(-z))

if __name__ == '__main__':
    main(train_path='ds1_train.csv',
         valid_path='ds1_valid.csv',
         save_path='logreg_pred_1.txt',
         plot_path='logreg_1.jpg')

    main(train_path='ds2_train.csv',
         valid_path='ds2_valid.csv',
         save_path='logreg_pred_2.txt',
         plot_path='logreg_2.jpg')