"""
Example 1 - Single Variable Linear Regression

NOTE: The example and sample data is being taken from the "Machine Learning course by Andrew Ng" in Coursera.

Problem:
  Suppose you are selling your house and you
want to know what a good market price would be. One way to do this is to
first collect information on recent houses sold and make a model of housing
prices.
"""

import matplotlib.pyplot as plt
# initial imports
import numpy as np

plt.ion()

from models.linear_regression import compute_cost, gradient_descent

# ----------------Loading X and y matrix ---------------
print('Loading data ...')

data = np.loadtxt('data/ex1data1.txt', delimiter=',')
X = data[:, 0:-1]
y = data[:, -1:]
m = y.shape[0]

# printing first 5 elements
print(X[0:5])

# ----------------Plotting Data-----------------
fig = plt.figure("data")
axes1 = fig.add_subplot()
axes1.scatter(X, y, marker="x", c='r')

# ---------------Cost and Gradient descent------------
# adding bias units to X

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

# Some gradient descent settings
iterations = 1500
alpha = 0.01
theta = np.zeros([X.shape[1], 1])

print('\nTesting the cost function ...')
# compute and display initial cost
J = compute_cost(X, y, theta);
print('With theta = [0 ; 0]\nCost computed = {}'.format(J))
print('Expected cost value (approx) 32.07')

# further testing of the cost function
J = compute_cost(X, y, np.array([[-1], [2]]))
print('\nWith theta = [-1 ; 2]\nCost computed = {}'.format(J))
print('Expected cost value (approx) 54.24')

print('\nRunning Gradient Descent ...')
# run gradient descent
theta, _ = gradient_descent(X, y, theta, alpha, iterations)

# print theta to screen
print('Theta found by gradient descent:')
print(theta)
print('Expected theta values (approx)')
print(' [-3.6303\n  1.1664]')

# ---------------- plotting the linear model---------------------------
plt.plot(X[:, 1:], np.dot(X, theta), lw=1)
plt.show()

# ------------------ plotting the J(theta0,theta1)---------------------
print('Visualizing J(theta_0, theta_1) ...\n')

# Grid over which we will calculate J
theta0_vals = np.linspace(-10, 10, 100)
theta1_vals = np.linspace(-1, 4, 100)

# initialize J_vals to a matrix of 0's
J_vals = np.zeros([theta0_vals.size, theta1_vals.size])

# Fill out J_vals
for i in range(theta0_vals.size):
    for j in range(theta1_vals.size):
        t = np.array([theta0_vals[i], theta1_vals[j]]).reshape(2, 1)
        J_vals[i, j] = compute_cost(X, y, t)

# Because of the way meshgrids work in the surf command, we need to
# transpose J_vals before calling surf, or else the axes will be flipped
J_vals = J_vals.T
theta0_vals, theta1_vals = np.meshgrid(theta0_vals, theta1_vals)

# --------------- Surface plot------------------
from mpl_toolkits.mplot3d.axes3d import Axes3D
from matplotlib import cm

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')
ax.plot_surface(theta0_vals, theta1_vals, J_vals, rstride=2, cstride=2, lw=0, cmap=cm.jet)
ax.set_xlabel('theta_0')
ax.set_ylabel('theta_1')

# ----------------- Contour plot------------------

fig1 = plt.figure()
ax1 = fig1.add_subplot()
# Plot J_vals as 15 contours spaced logarithmically between 0.01 and 100
ax1.contour(theta0_vals, theta1_vals, J_vals, levels=np.logspace(-2, 3, 20))
ax1.set_xlabel('theta_0')
ax1.set_ylabel('theta_1')

# matplotlib interactive off to view the graph at the end of program
plt.ioff()
plt.show()


import numpy as np

def inc_index(vec,index,h):
    '''
    Auxiliary function for gradient and Hessian computation.
    Args:
        vec (array): numpy array.
        index (int): index.
        h (float):   quantity that vec[index] will be increased.
    Returns:
        vec (array): numpy array vec with vec[index] increased by h.
    '''
    vec[index] +=h
    return vec

def dec_index(vec,index,h=1):
    '''
    Auxiliary function for gradient and Hessian computation.
    Args:
        vec (array): numpy array.
        index (int): index.
        h (float):   quantity that vec[index] will be decreased.
    Returns:
        vec (array): numpy array vec with vec[index] decreased by h.
    '''
    vec[index] -=h
    return vec
def compute_error(x_obj,x_approx):
    '''
    Relative or absolute error between x_obj and x_approx.
    '''
    if np.linalg.norm(x_obj) > np.nextafter(0,1):
        Err=np.linalg.norm(x_obj-x_approx)/np.linalg.norm(x_obj)
    else:
        Err=np.linalg.norm(x_obj-x_approx)
    return Err
def norm_residual(feas_primal, feas_dual):
    '''
    Computes norm of residual for Newtons infeasible initial point method
    '''
    return np.sqrt(np.linalg.norm(feas_primal)**2 +\
                   np.linalg.norm(feas_dual)**2
                   )
def log_barrier_aux_eval_constraints(eval_f_const_inequality):
    '''
    Auxiliary function for evaluation of constraint inequalities in logarithmic barrier
    '''
    #get values that are nonnegative through indexes
    idx_zeros = np.logical_and(eval_f_const_inequality < np.nextafter(0,1),
                               eval_f_const_inequality > -np.nextafter(0,1))
    idx_positive = eval_f_const_inequality > 0
    idx  = np.logical_or(idx_zeros, idx_positive)
    #eval constraint inequality functions
    #next line produces warning if a value of constraint is nonnegative
    eval_f_const_inequality = np.log(-eval_f_const_inequality)
    #assign large value for values positive or equal to 0
    eval_f_const_inequality[idx] = 1e10
    return eval_f_const_inequality
def constraint_inequalities_funcs_eval(x, constraint_inequalities):
    '''
    Auxiliary function for the evaluation of constraint inequalities in logarithmic barrier function
    '''
    const_ineq_funcs_eval = np.array([const(x) for const in \
                                      constraint_inequalities_funcs_generator(constraint_inequalities)])
    return const_ineq_funcs_eval
def logarithmic_barrier(f,x, t_path, constraint_inequalities):
    '''
    Implementation of Logarithmic barrier function.
    '''
    constraint_ineq_funcs_eval = constraint_inequalities_funcs_eval(x,constraint_inequalities)
    log_barrier_const_eval = log_barrier_aux_eval_constraints(constraint_ineq_funcs_eval)
    return t_path*f(x) + np.sum(log_barrier_const_eval)
def constraint_inequalities_funcs_generator(constraint_inequalities):
    '''
    Generator for functional form of inequalities.
    For every example this function produces different fuctions.
    '''
    for k, v in constraint_inequalities.items():
        yield v


# coding: utf-8

# In[1]:

import sympy

# In[2]:

sympy.init_printing()

# In[3]:

from sympy import I,pi,oo

# In[4]:

x = sympy.Symbol("x")

# In[5]:

y = sympy.Symbol("y", real=True)

# In[6]:

y.is_real


import numpy as np

DIMENSIONS = 2

# Function to implement bayes classifier for Gaussian, Exponential class density
# Prior probability is assumed to be equal unless specified
def bayes_gaussian_exponential(theta_0, theta_1, X_test, p0=0.5, p1=0.5):
    # Density Class 0 parameters - mean and covariance matrix
    mu_0 = theta_0[0]
    sigma_0 = theta_0[1]
    det_sigma_0 = np.linalg.det(sigma_0)
    inv_sigma_0 = np.linalg.inv(sigma_0)

    # Density Class 1 parameters - lambda 1 and lambda 2
    # The features are assumed to be independent for exponential
    lambda_1 = theta_1[0]
    lambda_2 = theta_1[1]

    # Placeholder for output
    Y_pred = np.zeros(len(X_test))

    # Estimate the posterior density and label the output properly
    for idx in range(len(X_test)):
        X = X_test[idx]
        q0 = 1 / (((2 * np.pi) ** DIMENSIONS / 2) * (det_sigma_0 ** 0.5)) * np.exp(
            -0.5 * (X - mu_0) @ inv_sigma_0 @ np.transpose(X - mu_0)) * p0
        X = np.abs(X)
        q1 = lambda_1 * np.exp(-lambda_1 * X[0]) * lambda_2 * np.exp(-lambda_2 * X[1]) * p1

        if q0 >= q1:
            Y_pred[idx] = 0
        else:
            Y_pred[idx] = 1

    return Y_pred


#Takes a field-centric x-y position at height, and converts that into a pixel
#Allows a small outline of the AOE to be created
#Only correct for equiangular fisheye of 180 degree coverage!
#Change if camera changes

#Standard Imports
import math
import numpy as np

def pointPixelEA(tgt,tgt_h,robot,robot_h,robot_heading): #m,m,m,m,m,m,radians; target position, target height, robot position, robot height, robot heading
    focal_length = 214.1528 #pixels #Change this if camera profile changes, will fuck things if not done, keep hardcoded

    #Gives height for later math, eliminate for performace, keep for elevated accuracy
    delta_height = tgt_h - robot_h

    POI_loc = (tgt[0],-1*tgt[1])
    robot_loc = robot

    heading = robot_heading

   #Define Local Functions
    def getPictureRadius(focal_length_z,robot_heading_z,robot_loc_z,POI_loc_z,delta_height_z): #Gives radius in pixels of desired point
        radius = math.sqrt((POI_loc_z[0] - robot_loc_z[0])**2 + (POI_loc_z[1] - robot_loc_z[1])**2 )

        #Find Zenith Angle
        zenith_angle = math.pi/2 - math.atan2(delta_height_z,radius)

        #Corner overlap testing
            #Defines radius on sensor based on focal length and zenith angle, equisolid testing, 180 FOV
        r = 2 * focal_length_z * math.sin(zenith_angle * 0.5)

        return r

    #Finds angle between tgt vector and optical axis
    def findTheta(POI_loc_z,robot_loc_z,robot_heading_z):
        theta = (math.atan2(POI_loc_z[1] - robot_loc_z[1],POI_loc_z[0] - robot_loc_z[0]) + robot_heading_z)%(2*math.pi)
        return theta

    #Converts from polar to cartesian coordinates, outputs x-coordinate
    def polarCartesianX(theta_z,point_radius_z):
        x = point_radius_z * math.cos(theta_z)
        return x

    #Converts from polar to cartesian coordinates, outputs y-coordinate
    def polarCartesianY(theta_z,point_radius_z):
        y = point_radius_z * math.sin(theta_z)
        return y

    #Determines how far out the target pixel is, in pixels.
    point_radius = getPictureRadius(focal_length,heading,robot_loc,POI_loc,delta_height)
    #Outputs theta
    zulu = findTheta(POI_loc,robot_loc,heading)

    #Final Calculation
    pixel_x = polarCartesianX(zulu,point_radius)
    pixel_y = polarCartesianY(zulu,point_radius)

    return np.array([pixel_x,pixel_y]) #Returns revised pixel position

#NOTES:
    '''
    Field is measured with y axis in starting direction of robot from red, with x 90 degrees clockwise
    from that. Robot Angle is measured with y towards front of robot, x 90 degrees clockwise.
    Heading is the differental between each y axis
    '''


import numpy as np
import random as ra

def f(x, y):
    r1 = np.sqrt(x**2 + (y-4)**2)
    return r1

def g(x, y):
    r2 = np.sqrt((x-4)**2 + y**2)
    return r2

def getProbability(n):
    counter = 0
    darkYellow = 0
    squareArea = 4*4

    while n > counter:
        x = ra.uniform(0, 4)
        y = ra.uniform(0, 4)

        if (f(x, y) <= 4 and g(x, y) <= 4):
            darkYellow += 1
        counter += 1

    probabilityDarkYellow = (darkYellow / n)
    circlesArea = squareArea * probabilityDarkYellow
    probabilityDarkYellow_percentage = round((darkYellow / n)*100,2)

    print(f'Estimated area is: {circlesArea} cm2. Out of {n} times, {darkYellow} coordinates were inside the dark yellow area.')

getProbability(10000)


import numpy as np

# Activation Functions
def identity(input):
    """Compute identity neuron activation """

    return input

def sigmoid(input):
    """Compute sigmoid neuron activation """

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

def tanh(input):
    """ Compute Tanh neuron activation """

    return np.tanh(input)

def relu(input):
    """ Compute ReLu neuron activation """

    return np.maximum(0, input)

def softmax(input):
    """ Compute softmax neuron activation with numerical stability protection"""

    exps = np.exp(input - np.amax(input, axis=0))
    return exps/np.sum(exps, axis=0)

ACTIVATIONS = {'identity': identity,
               'sigmoid': sigmoid,
               'tanh': tanh,
               'relu': relu,
               'softmax': softmax}

# Activation function derivatives
def derivative_identity(identity_output):
    """Compute derivative of identity function """

    return np.ones(identity_output.shape)

def derivative_sigmoid(sigmoid_output):
    """ Compute derivative of sigmoid function """

    return sigmoid_output*(1 - sigmoid_output)

def derivative_tanh(tanh_output):
    """ Compute derivative of Tanh function """

    return 1 - tanh_output**2

def derivative_relu(relu_output):
    """ Compute derivative of ReLu function """

    relu_output[relu_output <= 0] = 0
    relu_output[relu_output > 0] = 1

    return  relu_output

def derivative_softmax(softmax_output):
    """ Compute softmax neuron activation """
    pass

ACTIVATIONS_DERIVATIVES = {'identity': derivative_identity,
                           'sigmoid': derivative_sigmoid,
                           'tanh': derivative_tanh,
                           'relu': derivative_relu,
                           'softmax': derivative_softmax}

# Cost functions
def mean_square_error(model_output, target):
    """ Compute mean square error """

    if model_output.shape != target.shape:
        raise ValueError('Dimensions of model output and target do not match')

    return np.sum(np.square(target - model_output))/model_output.size/2

def binary_cross_entropy(model_output, target):
    """ Compute binary cross-entropy cost """

    if model_output.shape != target.shape:
        raise ValueError('Dimensions of model output and target do not match')

    # Limit the model output to the interval (0,1) to prevent divide by zero
    eps = np.finfo(model_output.dtype).eps
    model_output = np.clip(model_output, eps, 1- eps)

    return -np.sum(target * np.log(model_output) + (1 - target)*np.log(1 - model_output))/model_output.shape[0]

def cross_entropy(model_output, target):
    """ Compute cross-entropy cost """

    if model_output.shape != target.shape:
        raise ValueError('Dimensions of model output and target do not match')

    # Limit the model output to the interval (0,1) to prevent divide by zero
    eps = np.finfo(model_output.dtype).eps
    model_output = np.clip(model_output, eps, 1- eps)

    return -np.sum(target * np.log(model_output))/model_output.shape[0]

COST_FUNCTIONS = {'mse': mean_square_error, 'binary_cross_entropy': binary_cross_entropy, 'cross_entropy':cross_entropy}
COST_FUNCTION_SELECTION = {'identity': mean_square_error, 'sigmoid': 'binary_cross_entropy', 'softmax': 'cross_entropy'}

# Cost function derivatives
def derivative_mean_square_error(model_output, target):
    """ Compute derivative of mean square error cost function"""

def derivative_cross_entropy(model_output, target):
    """ Compute derivative of cross-entropy cost function"""

    return model_output - target

COST_FUNCTION_DERIVATIVES = {'mse': derivative_mean_square_error, 'cross_entropy': derivative_cross_entropy}

# Regularisation Cost functions
def l2_cost(network, l2_param, targets):

    # get weights
    weights = network.get_weights()[0]

    l2_cost = 0
    for layer_weights in weights:
        l2_cost += 0.5 * l2_param * np.sum(layer_weights**2)/targets.shape[0]

    return l2_cost

# Regularisation Cost function derivatives
def l2_cost_derivative(network, l2_param, targets):

    # get weights
    weights = network.get_weights()[0]

    l2_cost_derivative = 0
    for layer_weights in weights:
        l2_cost_derivative += l2_param * np.sum(layer_weights)/targets.size

    return l2_cost_derivative

REGULARISATION_COST_FUNCTIONS = {'l2': l2_cost}
REGULARISATION_COST_FUNCTION_DERIVATIVES = {'l2': l2_cost_derivative}


import numpy as np
import matplotlib.pyplot as plt
from scipy.special import sph_harm
from scipy.special import assoc_laguerre

def get_wave_r1(n,l,m,Zm,r):
        x = r
        y = 0
        z = 0
        X, Z = np.meshgrid(x, z)

        rho = np.linalg.norm((X,y,Z), axis=0) *Zm / n
        Lag = assoc_laguerre(2 * rho, n - l - 1, 2 * l + 1)
        Ylm  = sph_harm(m, l, np.arctan2(y,X), np.arctan2(np.linalg.norm((X,y), axis=0), Z))
        Psi = np.exp(-rho) * np.power((2*rho),l) * Lag * Ylm

        density = np.conjugate(Psi) * Psi
        density = density.real
        return density[0]

def get_wave_r2(n,l,m,r,Zm):
        x = 0
        y = 0
        z = r
        X, Z = np.meshgrid(x, z)

        rho = np.linalg.norm((X,y,Z), axis=0)*Zm  / n
        Lag = assoc_laguerre(2 * rho, n - l - 1, 2 * l + 1)
        Ylm  = sph_harm(m, l, np.arctan2(y,X), np.arctan2(np.linalg.norm((X,y), axis=0), Z))
        Psi = np.exp(-rho) * np.power((2*rho),l) * Lag * Ylm

        density = np.conjugate(Psi) * Psi
        density = density.real
        return density[0]

def get_wave_r3(n,l,m,r,Zm):
        x = 0
        y = r
        z = 0
        X, Z = np.meshgrid(x, z)

        rho = np.linalg.norm((X,y,Z), axis=0)*Zm  / n
        Lag = assoc_laguerre(2 * rho, n - l - 1, 2 * l + 1)
        Ylm  = sph_harm(m, l, np.arctan2(y,X), np.arctan2(np.linalg.norm((X,y), axis=0), Z))
        Psi = np.exp(-rho) * np.power((2*rho),l) * Lag * Ylm

        density = np.conjugate(Psi) * Psi
        density = density.real
        return density[0]

def get_wave_mean(n,l,m,r,Zm):
    n = n
    l = l
    m = m
    Zm = Zm
    wave1 =get_wave_r1(n,l,m,r,Zm)[0]
    wave2 =get_wave_r2(n,l,m,r,Zm)[0]
    wave3 =get_wave_r3(n,l,m,r,Zm)[0]
    mean_wave = (wave1+ wave2 + wave3)/3
    #return mean_wave+wave1+wave2+wave3
    return np.array([mean_wave, wave1, wave2, wave3])

if __name__ == '__main__':


# coding: utf-8

# In[254]:

import pandas as pd
import numpy as np
import os
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# In[255]:

#checking the path directory
print("Previous directory",os.getcwd())
#Now changing the path directory
path=r"C:\Users\Pavan\Desktop\Machine Learning Github\Home Works\HW1"
os.chdir(path)
print("Current directory",os.getcwd())

# Hosuing data set ----Question 1
#
# Run linear regression using Normal Equations and Mean Square Error without using the libraries

# In[256]:

#Loading the DataSet
col_names=["CRIM","ZN","INDUS","CHAS","NOX","RM","AGE","DIS","RAD","TAX","PTRATIO","B","LSTAT","MEDV"]
train_housing=pd.read_table("housing_train.txt",sep="\s+",names=col_names)
train_housing

# In[257]:

y_train=train_housing["MEDV"]
y_train

# In[258]:

del train_housing["MEDV"]
train_housing

# In[259]:

#Using the Normal Equations I am calculating the coefficients of the paremets(w1,w2,w3-----w13)
#Now we have the Data matrix(X) and the labels(Y) now we need to find the coefficients
w_normal_equations=np.linalg.inv(train_housing.T.dot(train_housing)).dot(train_housing.T).dot(y_train)
w_normal_equations

# In[260]:

w=np.reshape(w_normal_equations,(1,13))
w

# In[261]:

##Function for calculating mean squared error using the Normal Equations for the training set
def mean_square_error(y,w,x,n_iterations):
    squared_error=0
    mean_squared_error=0
    for i in range(n_iterations):#For all the data points considerong the (Y-h(x))i.e(y-WX)
        squared_error=squared_error+((y_train[i]-(w.dot(x.iloc[i])))*(y[i]-(w.dot(x.iloc[i]))))
    mean_squared_error=squared_error/n_iterations

    print("Mean Squared Error for the training is:",mean_squared_error)

mean_square_error(y_train,w,train_housing,433)

# In[262]:

#Now we are conisdering the testing data set
test_data=pd.read_table("housing_test.txt",sep="\s+",header=None,names=col_names)
test_data

# In[263]:

y_test=test_data["MEDV"]
y_test

# In[264]:

del test_data["MEDV"]

# In[265]:

x_test=test_data
x_test

# In[266]:

##The mean squared error function is already defined before and I just called that function using the function name
mean_square_error(y_test,w,x_test,74)

#
train error: 24.47
#
test error: 24.29
#
using the Normal Equations

#
Part 2 : Perform everything using the ScikitLearn package

# In[270]:

##Mean squared error using Scikit Learn for the training data
lin_reg = LinearRegression()
lin_reg.fit(train_housing, y_train)# Finding the parameters
lin_reg.intercept_, lin_reg.coef_
train_predictions=lin_reg.predict(train_housing)
print("\n The MSE Error for testing is:",mean_squared_error(y_train,train_predictions))

# In[272]:

##Now calculating the mean sqaured error for the testing dataset
test_predictions=lin_reg.predict(test_data)
print("\n The MSE Error for the testing is:",mean_squared_error(y_test,test_predictions))

#
Training error: 22.08
#
Testing error: 22.63
#
using the scikitlearn package

#
NOW PERFORMING EVERYTHING BY NORMALIZING the Data

# In[273]:

train_housing

# In[274]:

#This gives the total Number of time syou need to learn the inner loop
x=len(train_housing)
x

# In[275]:

#This give sthe total number of times you need to run the for loop
y=len(train_housing.columns)
y

# In[276]:

#Function for Normalization
#X-Number of Rows
#Y- Number of columns
def Normalization(train_housing,x,y):
    for i in range(y):
        z=train_housing.columns[i]
        for j in range(x):
            train_housing[z].iloc[j]=(((train_housing[z].iloc[j]-(min(train_housing[z])))/(max(train_housing[z])-min(train_housing[z]))))

# In[277]:

#This is the Normalized data(Training Data)
Normalization(train_housing,x,y)

# In[278]:

#This is Normalizing the test data
x=len(test_data)
y=len(test_data.columns)
Normalization(x_test,x,y)

# In[279]:

x_test

# In[280]:

train_housing.shape

# In[281]:

y_train.shape

# In[282]:

w_equations=np.linalg.inv(train_housing.T.dot(train_housing)).dot(train_housing.T).dot(y_train)
w_equations

# In[283]:

w_new=w_equations.reshape(1,13)
w_new

# In[284]:

#This is forthe training data
mean_square_error(y_train,w_new,train_housing,433)

# In[285]:

#Now calculating the error for the test data
mean_square_error(y_test,w_new,x_test,74)

#
 Results:
#
 Training Error: 26.33
#
 Testing Error:  32.104

# In[286]:

#by using the scikit learn library
lin_reg = LinearRegression()
lin_reg.fit(train_housing, y_train)# Finding the parameters
lin_reg.intercept_, lin_reg.coef_
train_predictions=lin_reg.predict(train_housing)
print("\n The MSE Error for testing is:",mean_squared_error(y_train,train_predictions))

# In[287]:

##Now calculating the mean sqaured error for the testing dataset
test_predictions=lin_reg.predict(x_test)
print("\n The MSE Error for the testing is:",mean_squared_error(y_test,test_predictions))

#
 By using library:
#
 Training Error: 25.1277
#
 Testing Error:  30.2312


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation
import functions

plt.style.use('seaborn-pastel')

def animateDoublePendulum(file, fps, animate = True, verbose = False, save = False):
	# load data and assign them
	if verbose: print("Load data from file", file)
	settings, data = functions.loadDataFromFile(file)
	m1, m2, l1, l2, g, t_max, dt, sim_mode = settings["m1"], settings["m2"], settings["l1"], settings["l2"], settings["g"], settings["tmax"], settings["dt"], settings["sim"]
	t, q1, q2, p1, p2 = data["t"], data["q1"], data["q2"], data["p1"], data["p2"]
	n = len(t)
	if verbose: print("Loading complete.\nStarting calculation.")
	# calculating the x, y, e_kin, e_pot, e_tot values
	x1 = l1*np.sin(q1)
	x2 = x1 + l2*np.sin(q2)
	y1 = -l1*np.cos(q1)
	y2 = y1 - l2*np.cos(q2)
	E_kin = .5*m1*l1**2*p1**2 + .5*m2*(l1**2*p1**2 + l2**2*p2**2 + 2*p1*p2*l1*l2*np.cos(q1 - q2))
	E_pot = -g*(m1*l1*np.cos(q1) + m2*(l1*np.cos(q1) + l2*np.cos(q2)))
	E_tot = E_kin + E_pot
	if verbose: print("Calculation complete.\nStart plotting.")
	if animate:
		# plot the pendulum
		fig = plt.figure(figsize=(8,8))
		gs = fig.add_gridspec(ncols=2, nrows=2)
		time_template = 'time = %.2fs'

		# prepare realspace plot
		ax = fig.add_subplot(gs[0,0])
		ax.set_xlim(-(l1+l2), l1+l2)
		ax.set_ylim(-(l1+l2), l1+l2)
		ax.set_aspect('equal')
		ax.set_xlabel("X")
		ax.set_ylabel("Y")
		time_text = ax.text(0.05, 0.9, '0 s', transform=ax.transAxes)

		# prepare Energy-time plot
		ax1 = fig.add_subplot(gs[1,0])
		ax1.set_xlim(min(t), max(t))
		ax1.set_ylim(min(min(E_tot), min(E_kin), min(E_pot)), max(max(E_tot), max(E_kin), max(E_pot)))
		ax1.grid()
		ax1.set_xlabel("Time / s")
		ax1.set_ylabel("Energy / arb. units")

		# prepare phasespace plot 1
		ax2 = fig.add_subplot(gs[0,1])
		ax2.set_xlim(min(q1), max(q1))
		ax2.set_ylim(min(p1), max(p1))
		ax2.set_xlabel(r"$\vartheta_1$")
		ax2.set_ylabel(r"$p_1$")

		# prepare phasespace plot 2
		ax3 = fig.add_subplot(gs[1,1])
		ax3.set_xlim(min(q2), max(q2))
		ax3.set_ylim(min(p2), max(p2))
		#ax3.set_xlim(min(min(q1), min(q2)), max(max(q1), max(q2)))
		#ax3.set_ylim(min(min(p1), min(p2)), max(max(p1), max(p2)))
		ax3.set_xlabel(r"$\vartheta_2$")
		ax3.set_ylabel(r"$p_2$")

		# init plots
		## realspace
		line, = ax.plot([0, x1[0], x2[0]], [0, y1[0], y2[0]], 'o-',lw=2)
		## energy time
		E_tot_graph, = ax1.plot([],[])
		E_kin_graph, = ax1.plot([],[])
		E_pot_graph, = ax1.plot([],[])
		## phase space
		point1, = ax2.plot([q1[0]], [p1[0]], '')
		point2, = ax3.plot([q2[0]], [p2[0]], '')

		def animate(i):
			x = [0, x1[i], x2[i]]
			y = [0, y1[i], y2[i]]
			t_list = t[:i]
			E_tot_list = E_tot[:i]
			E_kin_list = E_kin[:i]
			E_pot_list = E_pot[:i]

			q1_list = q1[:i]
			q2_list = q2[:i]
			p1_list = p1[:i]
			p2_list = p2[:i]

			line.set_data(x, y)
			E_tot_graph.set_data(t_list, E_tot_list)
			E_kin_graph.set_data(t_list, E_kin_list)
			E_pot_graph.set_data(t_list, E_pot_list)
			point1.set_data(q1_list, p1_list)
			point2.set_data(q2_list, p2_list)
			time_text.set_text(time_template % (t[i]))
			return line, E_tot_graph, E_kin_graph, E_pot_graph, point1, point2, time_text

		anim = FuncAnimation(fig, animate, frames=np.arange(0, n, max(int(1/fps/dt),1)), interval=1000/fps, blit = True)
		if save:
			if verbose: print("Video saving...")
			anim.save(file + ".mp4", fps=fps)
			if verbose: print("Video saving done.")
		else:
			plt.show()
	else:
		# plot the energies
		fig = plt.figure()

		plt.plot(t, E_kin, label="Kinetic")
		plt.plot(t, E_pot, label="Potentail")
		plt.plot(t, E_tot, label="Total")

		plt.ylim([-50,200])
		plt.legend()
		plt.show()
"""
### >>> BEGIN SETUP <<<
file = "default.txt"
fps = 30
animate_pendulum = True
plot_energies = False
### >>> END SETUP <<<

animateDoublePendulum(file, fps)
"""


#!/usr/bin/nv python
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------
# Filename: wavelets.py
#  Purpose: Signal Analysis
#   Author: Vidal Gonzalez P
#    Email: vidalgonz8@gmail.com
# --------------------------------------------------------------------
"""

        Some useful functions.

"""
import numpy as np

def ormsby(freqs, tvec):
    '''
    Computes ormsby amplitude wavelet.
    '''
    f1, f2, f3, f4 = freqs
    a1 = ((np.pi * f4)**2 / (np.pi * f4 - np.pi * f3)) * np.sinc(f4 * tvec)**2
    a2 = ((np.pi * f3)**2 / (np.pi * f4 - np.pi * f3)) * np.sinc(f3 * tvec)**2
    b1 = ((np.pi * f2)**2 / (np.pi * f2 - np.pi * f1)) * np.sinc(f2 * tvec)**2
    b2 = ((np.pi * f1)**2 / (np.pi * f2 - np.pi * f1)) * np.sinc(f1 * tvec)**2
    return((a1 - a2) - (b1 - b2))

def ricker(fc, tvec):
    '''
    Computes ricker amplitude wavelet
    '''
    return ((1.0 - 2.0 * np.pi**2 * fc**2 * tvec**2) * \
        np.exp(-np.pi**2 * fc**2 * tvec**2))

def main():
    pass

if (__name__ == '__main__'):
    main()


import math
import numpy as np
from scipy.spatial.distance import cdist

__all__ = ("naive_gaussian_kernel", "naive_sigmoid_kernel", "naive_laplacian_kernel",
           "naive_linear_kernel", "naive_polynomial_kernel", "naive_matern_kernel",)

def naive_gaussian_kernel(X1, X2, sigma):
    pairwise_dists = cdist(X1, X2, 'sqeuclidean')
    return np.exp(-pairwise_dists / (2 * sigma ** 2))

def naive_laplacian_kernel(X1, X2, sigma):
    pairwise_dists = cdist(X1, X2, 'euclidean')
    return np.exp(-pairwise_dists / sigma)

def naive_linear_kernel(X1, X2, beta, sigma):
    return beta + (1 / sigma ** 2) * X1 @ X2.T

def naive_sigmoid_kernel(X1, X2, alpha, beta):
    out = X1 @ X2.T
    return np.tanh(out * alpha + beta)

def naive_polynomial_kernel(X1, X2, alpha, beta, degree):
    out = X1 @ X2.T
    return np.power(out * alpha + beta, degree)

def naive_matern_kernel(X1, X2, sigma, nu):
    pairwise_dists = cdist(X1 / sigma, X2 / sigma, 'euclidean')

    if nu == 0.5:
        K = np.exp(-pairwise_dists)
    elif nu == 1.5:
        K = pairwise_dists * math.sqrt(3)
        K = (1. + K) * np.exp(-K)
    elif nu == 2.5:
        K = pairwise_dists * math.sqrt(5)
        K = (1. + K + K ** 2 / 3.0) * np.exp(-K)
    elif nu == np.inf:
        K = np.exp(-pairwise_dists ** 2 / 2.0)
    return K


"""
This module illustrates how to solve a system of equations using solve routine
and the linalg module.

Suppose we have the following system of equations:

    3x1 - 2x2 + x3 = 7
    x1 + x2 -2x3 = -4
    -3x1 -2x2 + x3 = 1

We can solve it by the single matrix equation:

    Ax = b
"""
import numpy as np
from numpy import linalg

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

b = np.array([7, -4, 1])

linalg.solve(A, b) # array([ 1., -1., 2.])


import numpy as np

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

print(sigmoid(5))
print(sigmoid(0.8))
a = np.full(5, 0.5)
print(a)
print(round(0.99999999, 3))

# b = [1, 1, 1] - 3
# print(b)
print(sigmoid(5.008))
print(sigmoid(0.843))

x1 = np.array([[1, 1, 1],
               [0, 0, 1],
               [0, 0, 1]])

x2 = np.array([[1, 0, 0],
               [1, 0, 0],
               [1, 1, 1]])

x3 = np.array([[1, 1, 1],
               [1, 0, 0],
               [1, 1, 1]])

d1 = np.array([1, 0, 0])
d2 = np.array([0, 1, 0])
d3 = np.array([0, 0, 1])

X = [x1, x2, x3]
D = [d1, d2, d3]
A = [0.0 for i in range(2)]
Z = [0.0 for i in range(2)]
O = np.full((3, 3), 0.0)
W1 = np.full((9, 2), 1.0)
W2 = np.full((2, 3), 1.0)

print(W1)
print(W1[:, 0])

for i in range(3):
    for k in range(3):
        A[k] = np.dot(X[i], W1[:, k])
        Z[k] = sigmoid(A[k])


import numpy as np
import scipy.stats as scp

def d(S_, K_, r_,sigma_ ,tau_):
    d1_ = 1 / (sigma_ * np.sqrt(tau_)) * ( np.log(S_/K_) + (r_ + sigma_**2/2) * tau_)
    d2_ = d1_ - sigma_ * np.sqrt(tau_)
    return d1_, d2_

def call_option(S_, K_, r_,sigma_ ,tau_ ,d1_,d2_):
    return scp.norm.cdf(d1_) * S_ - scp.norm.cdf(d2_) * K_ * np.exp(-r_ *tau_)

def call_vega(S_, tau_ , d1_):
    return S_ * scp.norm.pdf(d1_) * np.sqrt(tau_)

def Newton_Raphson(S_,K_,r_,tau_, sigma0_ ,price_, epsilon_):
    d1_,d2_ = d(S_, K_, r_,sigma0_ ,tau_)
    g = call_option(S_, K_, r_,sigma0_ ,tau_,d1_,d2_)-price_
    sigma_ = sigma0_ - g/call_vega(S_,tau_, d1_)
    while np.abs(sigma_-sigma0_)/sigma0_ > epsilon_:
        sigma0_ = sigma_
        d1_,d2_ = d(S_, K_, r_,sigma0_ ,tau_)
        g = call_option(S_, K_, r_,sigma0_ ,tau_,d1_,d2_)-price_
        sigma_ = sigma0_ - g/call_vega(S_,tau_, d1_)
    return sigma_


import numpy as np

# core functions
totalreturn = lambda x: (x[-1]/x[0])-1
finalreturn = lambda x: x[-1]
sharpe = lambda x: np.sqrt(12) * (np.mean(x) / np.std(x))
ann_vol = lambda x: np.sqrt(12) * np.std(x)
cagr = lambda x: ((((x[-1]) / x[0])) ** (12.0/(x.count()-1))) - 1
cagr2 = lambda x: ((np.mean(x)+1) ** 12) -1

def max_drawdown(X):
    mdd = 0
    peak = X[0]
    for x in X:
        if x > peak:
            peak = x
        dd = (peak - x)
        if dd > mdd:
            mdd = dd
    return mdd

def avg_max_drawdown(X):
    ldd = []
    mdd = 0
    peak = X[0]
    for x in X:
        if x > peak:
            peak = x
        dd = (peak - x)
        if dd > mdd:
            mdd = dd
            ldd.append(mdd)
    return 0 if len(ldd) == 0 else np.mean(ldd)

def bca_max_drawdown(X):
    mdd = 0
    peak = X[0]
    for x in X:
        if x > peak:
            peak = x
        if peak != 0:
            dd = 1-x/peak
        if dd > mdd:
            mdd = dd
    return mdd


import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

country = "id"
fdir = "../data/"
if country == "it":
    data = np.loadtxt(fdir+"itdata.csv", skiprows=1, delimiter=",", usecols=(1,2,3))[16:,:]
    day_since_ldown = data[:,0] - 16
elif country == "id":
    data = np.loadtxt(fdir+"data.csv", skiprows=1, delimiter=",", usecols=(1,2,4))[32:,:]
    day_since_ldown = data[:,0] - 31

new_case = data[:,1]
new_death = data[:,2]

def fcase(xdays, logyoffset, logygrad1, xchange, logygrad2):
    idxbefore = xdays < xchange
    idxafter = xdays >= xchange
    xbefore = xdays[idxbefore]
    xafter = xdays[idxafter]
    logybefore = logyoffset + logygrad1 * xbefore
    logyoffset2 = logyoffset + (logygrad1 - logygrad2) * xchange
    logyafter = logyoffset2 + logygrad2 * xafter
    y = xdays * 0
    y[idxbefore] = logybefore
    y[idxafter] = logyafter
    return y

p0case = (7.6, 0.19, 8.0, 0.01)
p0death = (4.7, 0.19, 8.0, 0.01)
pcase, pcasevar = curve_fit(fcase, day_since_ldown, np.log(new_case), p0=p0case)
pdeath, pdeathvar = curve_fit(fcase, day_since_ldown, np.log(new_death), p0=p0death)

pcasestd = np.sqrt(np.diag(pcasevar))
pdeathstd = np.sqrt(np.diag(pdeathvar))

dgcase = pcase[1] - pcase[3]
dgdeath = pdeath[1] - pdeath[3]
stddgcase = (pcasestd[1]**2 + pcasestd[3]**2)**.5
stddgdeath = (pdeathstd[1]**2 + pdeathstd[3]**2)**.5

print(pcase, pcasestd)
print(pdeath, pdeathstd)
print(dgcase / stddgcase)
print(dgdeath / stddgdeath)

country_name = {
    "it": "Italia",
    "id": "Indonesia"
}[country]
plt.title("Studi kasus: %s" % country_name)
plt.plot(day_since_ldown, new_case, 'C0o-', alpha=0.3, label="Kasus baru")
plt.plot(day_since_ldown, np.exp(fcase(day_since_ldown, *pcase)), 'C0-')
plt.plot(day_since_ldown, new_death, 'C1o-', alpha=0.3, label="Kematian / hari")
plt.plot(day_since_ldown, np.exp(fcase(day_since_ldown, *pdeath)), 'C1-')
plt.xlabel("Hari setelah social distancing")
plt.ylabel("Jumlah kasus")
plt.gca().set_yscale("log")
plt.legend()
plt.show()


from scipy import integrate
def integrand(z, y, x):
    return x * y**2 + z
x_lower_lim, x_upper_lim = 0.0, 0.5
y_lower_lim, y_upper_lim = lambda x:0.0, lambda x:1.0-2.0*x
z_lower_lim, z_upper_lim = lambda x,y:-1.0, lambda x,y:1.0+2.0*x-y
# int_{x=0}^{0.5} int_{y=0}^{1-2x} int_{z=-1}^{1+2x-y} (x y**2 + z) dz dy dx
integral,error = integrate.tplquad(integrand,
                                   x_lower_lim, x_upper_lim,
                                   y_lower_lim, y_upper_lim,
                                   z_lower_lim, z_upper_lim)
print(integral, error)

example_snippets/multimenus_snippets/Snippets/SciPy/Integration and ODE solvers/Integrate given function object/General purpose triple integration.py


#  BACKPROP MATH UNDERSTANDING
# DW/DX = DW/DY*DY/DX

# USING BASIC CHAIN RULE TO USE BACKPROP

import torch

x = torch.tensor(1.0)
y=torch.tensor(2.0)

w= torch.tensor(1.0,requires_grad=True)

y_hat = w*x
loss = (y_hat-y)**2

loss.backward()

print(w.grad)

# GRAD_DESC WITH AUTOGRAD MANUALLY
import numpy as np
# f = w*x
# f = 2*x

x = np.array([1,2,3,4],dtype='float')
y = np.array([2,4,6,8],dtype='float')

w=0.0 #weights init

# model pred
def forward(x):
    return w*x

# loss = MSE
def loss(y,y_pred):
    return ((y_pred-y)**2).mean()

# then we cal gradients manually using loss
# MSE = 1/n * (w*x-y)**2
# d(mse)/dw = 1/n 2x(w*x - y)

def gradients(x,y,y_pred):
    return np.dot(2*x,y_pred-y).mean()

print(f'prediction before for f(5):{forward(5):.3f}')

n_iters = 20
lr = 1e-2
for epoch in range(n_iters):
    # forward pass
    y_pred = forward(x)
    # loss cal
    l = loss(y,y_pred)
    # gradients update with weights
    dw = gradients(x,y,y_pred)

    # update weights
    w -= lr*dw

    if epoch%3 ==0:
        print(f'after {epoch} epoch\'s weight\'s are {w:.6f} and  loss : {l:.5f}')

print(f'our final prediction\'s is f(5) == {forward(5)}')

# so we saw that with lr==1e-3 it learnt pretty slow but now with lr==1e-2 its almost got it correct
# the same we will do now using autograd of pytorch

print('using AUTOGRAD','-'*20)

import torch
# f = w*x
# f = 2*x

x = torch.tensor([1,2,3,4],dtype=torch.float32)
y = torch.tensor([2,4,6,8],dtype=torch.float32)

w=torch.tensor(0.0,requires_grad=True) #weights init req. grad will calc. gradients automatically

# model pred
def forward(x):
    return w*x

# loss = MSE
def loss(y,y_pred):
    return ((y_pred-y)**2).mean()

# then we cal gradients manually using loss
# MSE = 1/n * (w*x-y)**2
# d(mse)/dw = 1/n 2x(w*x - y)

# def gradients(x,y,y_pred):
#     return np.dot(2*x,y_pred-y).mean()

print(f'prediction before for f(5):{forward(5):.3f}')

n_iters = 30
lr = 1e-2
for epoch in range(n_iters):
    # forward pass
    y_pred = forward(x)
    # loss cal
    l = loss(y,y_pred)
    # gradients update with weights
    # dw = gradients(x,y,y_pred) # instead of this we just propagate it backwards using back. prop

    l.backward()

    # update weights
    with torch.no_grad():
        w -= lr*w.grad

    # we zero the gradients otherwise it adds up and messes things up

    w.grad.zero_()

    if epoch%3 ==0:
        print(f'after {epoch} epoch\'s weight\'s are {w:.6f} and  loss : {l:.5f}')

print(f'our final prediction\'s is f(5) == {forward(5)}')


import numpy as np
import pandas as pd

def median_absolute_deviation(x):
    """
    Returns the median absolute deviation from the window's median
    :param x: Values in the window
    :return: MAD
    """
    return np.median(np.abs(x - np.median(x)))

def hampel(ts, window_size=5, n=3, imputation=False):

    """
    Median absolute deviation (MAD) outlier in Time Series
    :param ts: a pandas Series object representing the timeseries
    :param window_size: total window size will be computed as 2*window_size + 1
    :param n: threshold, default is 3 (Pearson's rule)
    :param imputation: If set to False, then the algorithm will be used for outlier detection.
        If set to True, then the algorithm will also imput the outliers with the rolling median.
    :return: Returns the outlier indices if imputation=False and the corrected timeseries if imputation=True
    """

    if type(ts) != pd.Series:
        raise ValueError("Timeserie object must be of tyme pandas.Series.")

    if type(window_size) != int:
        raise ValueError("Window size must be of type integer.")
    else:
        if window_size <= 0:
            raise ValueError("Window size must be more than 0.")

    if type(n) != int:
        raise ValueError("Window size must be of type integer.")
    else:
        if n < 0:
            raise ValueError("Window size must be equal or more than 0.")

    # Copy the Series object. This will be the cleaned timeserie
    ts_cleaned = ts.copy()

    # Constant scale factor, which depends on the distribution
    # In this case, we assume normal distribution
    k = 1.4826

    rolling_ts = ts_cleaned.rolling(window_size*2, center=True)
    rolling_median = rolling_ts.median().fillna(method='bfill').fillna(method='ffill')
    rolling_sigma = k*(rolling_ts.apply(median_absolute_deviation).fillna(method='bfill').fillna(method='ffill'))

    outlier_indices = list(
        np.array(np.where(np.abs(ts_cleaned - rolling_median) >= (n * rolling_sigma))).flatten())

    if imputation:
        ts_cleaned[outlier_indices] = rolling_median[outlier_indices]
        return ts_cleaned

    return outlier_indices


import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from scipy.optimize import curve_fit

def moving_average(ydata,point=5):
    """
    moving average

    ydata: original np.array data
    point: average points

    return: moving average data
    data length of calculated data is as same as original.

    ref:畳み込み積分や移動平均を求めるnumpy.convolve関数の使い方
    https://deepage.net/features/numpy-convolve.html

    numpyで移動平均
    https://qiita.com/wrblue_mica34/items/51adf0059b61887075d9
    """

    b =np.ones(point)/point
    y_ma = np.convolve(ydata,b, mode='same')
    #  Mode ‘same’ returns output of length max(M, N). Boundary effects are still visible.

    return y_ma

def cent_of_gravity(x,y,bg=0,printf=False):
    """
    center of gravity method
    fwhm is calculated from variance.
    This method is greatly affected by the background,
    so it is necessary to remove the background appropriately.
    Especially the variance is affected.

    """
    y_rembg = y-bg
    cg = np.sum(x*(y_rembg))/np.sum(y_rembg)

    vpd = y_rembg*(x-cg)*(x-cg)
    # vp2: variance sigma^2
    vp2= np.sum(vpd)/np.sum(y_rembg)
    # vp: standard deviation
    vp = np.sqrt(vp2)

    if printf==True:
        print(f'mu: {cg}, var: {vp2}, var1/2: {vp}')

    return cg, vp2

def fwhm(x,y,bg=0,printf=False):
    """
    full width at half maximum
    fwhm = 2.35*sigma (gauss distribution)
    The data needs to be smoothed.
    """
    # find max index
    ymax_ind = np.argmax(y)
    center_x= x[ymax_ind]
    ymax = y.max()

    yhalf = (ymax-bg)/2
    yhalf_ind = np.where( y-bg > yhalf)[0]
    yhalf_ind_min = yhalf_ind.min()
    yhalf_ind_max = yhalf_ind.max()

    fwhm_s = x[yhalf_ind_min]
    fwhm_l = x[yhalf_ind_max]
    fwhm = np.abs(fwhm_s-fwhm_l)
    # if the difference between the center and small edge is over 2, fwhm value set 'nan'.
    if np.abs(fwhm_l-center_x) > 2*np.abs(center_x-fwhm_s) :
         center_x, fwhm = np.nan, np.nan

    if printf==True:
        print(f'center_x: {center_x}, fwhm: {fwhm}, center_y: {ymax}, half_y: {yhalf}')

    return center_x, fwhm, ymax, yhalf

def r2_cal(ydata, fitdata):
    """
    Coefficient of determination
    """

    residuals =  ydata - fitdata
    rss = np.sum(residuals**2)
    tss = np.sum((ydata-np.mean(ydata))**2)
    r2 = 1 - (rss / tss)

    return r2

def gauss_fit(xdata,ydata, para4_list, printf=False):
    # para4_list = [a,mu,sigma,c]
    try:
        popt, pcov = curve_fit(gauss, xdata,ydata,
        p0=np.array(para4_list), maxfev=10000)

    except RuntimeError as Rte:
#             print('RuntimeError')
        popt = (0, 0, 0, 0)

    if printf==True:
        print(f"initial parameter -> {para4_list}")
        print(f"estimated parameter -> {popt}" )

    return popt

# Gauss distribution
def gauss(x, a = 1, mu = 0, sigma = 1, bg = 0):
    return a *(1/(sigma*np.sqrt(2*np.pi))) *np.exp(-(x - mu)**2 / (2*sigma**2)) + bg

def gauss_pdf(x, a = 1, mu = 0, sigma = 1, bg = 0):
    """using scipy module function
    """
    return a*norm.pdf(x, mu, sigma) + bg

# make simulation data with gauss noise
def simu_data(original_data,sigma):
    data_with_noise=[]
    for iy in original_data:
        data_temp = np.random.normal(loc=iy, scale=sigma, size=1)
        data_with_noise.append(float(data_temp))

    return np.array(data_with_noise)

if __name__ == '__main__':
    # make x data
    # -10～10まで0.05刻みの数値配列作成
    x = np.arange(-10, 10, 0.01)

    # N = 100
    # x = np.linspace(-10.0,10.0,N)

    a = 1
    mu = 0
    sigma = 1
    bg = 0

    y = gauss_pdf(x,a,mu,sigma,bg)
    # plt.plot(x,y)

    yn = simu_data(original_data=y,sigma=0.2)
    ys = moving_average(yn,point=10)

    plt.plot(x,yn,'g')
    plt.plot(x,ys,'b')
    plt.plot(x,y,'r')
    plt.show()

    cent_of_gravity(x,y,bg=0,printf=True)
    cent_of_gravity(x,yn,bg=0,printf=True)
    cent_of_gravity(x,ys,bg=0,printf=True)

    fwhm(x,y,bg=0,printf=True)
    fwhm(x,yn,bg=0,printf=True)
    fwhm(x,ys,bg=0,printf=True)

    para4_list=[1,0,1,0]
    gauss_fit(x,y, para4_list, printf=True)
    gauss_fit(x,yn, para4_list, printf=True)
    gauss_fit(x,ys, para4_list, printf=True)


"""Problem 1.

(a) Plot the distributions of samples from both classes.

Author: Lucas David -- <ld492@drexel.edu>
License: MIT (C) 2011

"""
from scipy.integrate import simps

def a_plot_distributions():
    INTERVALS = 100
    dx = (6 + 3.0) / INTERVALS

    P = [0.4, 0.6]
    CLASS_1_GAUSSIAN = (2, 1)
    CLASS_2_UNIFORM = (0, 1)

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

    print('MAP (considering priori probabilities):')

    plt.ylim([0, 1.2])
    x = np.linspace(-3, 6, INTERVALS)
    y = P[0] * mlab.normpdf(x, CLASS_1_GAUSSIAN[0],
                            math.sqrt(CLASS_1_GAUSSIAN[1]))
    lg1, = plt.plot(x, y, label='Class +1', linewidth=2, c='orange')

    start = int(round((0 + 3) / dx))
    end = int(round((1 + 3) / dx))
    c_0_area = simps(y, x)
    c_1_area = simps(y[start:end], x[start:end])
    print('density of gaussian:', c_0_area - c_1_area)

    x = np.linspace(-3, 6, INTERVALS)
    y = np.array([1.0 if CLASS_2_UNIFORM[0] <= e <= CLASS_2_UNIFORM[1]
                  else 0.0 for e in x])
    y = P[1] * y / abs(CLASS_2_UNIFORM[0] - CLASS_2_UNIFORM[1])
    lg2, = plt.plot(x, y, label='Class -1', linewidth=2, c='b')

    # clipping not required, as the uniform dist. is above
    # the gaussian at all times (verified through inspection).
    print('density of uniform:', simps(y, x))

    plt.legend([lg1, lg2], ['Class +1', 'Class -1'])
    plt.grid()
    plt.tight_layout(0)
    plt.savefig('results/map.png')

    plt.clf()

    print('MV (considering equal prob.):')

    plt.ylim([0, 1.2])
    x = np.linspace(-3, 6, INTERVALS)
    y = mlab.normpdf(x, CLASS_1_GAUSSIAN[0],
                     math.sqrt(CLASS_1_GAUSSIAN[1]))
    lg1, = plt.plot(x, y, label='Class +1', linewidth=2, c='orange')

    start = int((0 + 3) / dx)
    end = int((1 + 3) / dx)
    c_0_area = simps(y / 2, x)
    c_1_area = simps(y[start:end] / 2, x[start:end])
    print('density of gaussian:', c_0_area - c_1_area)

    y = np.array([1.0 if CLASS_2_UNIFORM[0] <= e <= CLASS_2_UNIFORM[1]
                  else 0.0 for e in x])
    y = y / abs(CLASS_2_UNIFORM[0] - CLASS_2_UNIFORM[1])
    lg2, = plt.plot(x, y, label='Class -1', linewidth=2, c='b')

    print('density of uniform:', simps(y / 2, x))

    plt.legend([lg1, lg2], ['Class +1', 'Class -1'])
    plt.grid()
    plt.tight_layout(0)
    plt.savefig('results/mv.png')

def main():
    print(__doc__)

    a_plot_distributions()

if __name__ == '__main__':
    main()


import numpy as np

def cart2polar(x, y, center=np.array([0, 0])):
    """
    transforms cartesian coords [x,y] into polar coords [r,phi] in the frame of the lense center

    :param coord: set of coordinates
    :type coord: array of size (n,2)
    :param center: rotation point
    :type center: array of size (2)
    :returns:  array of same size with coords [r,phi]
    :raises: AttributeError, KeyError
    """
    coordShift_x = x - center[0]
    coordShift_y = y - center[1]
    r = np.sqrt(coordShift_x**2+coordShift_y**2)
    phi = np.arctan2(coordShift_y, coordShift_x)
    return r, phi

def polar2cart(r, phi, center):
    """
    transforms polar coords [r,phi] into cartesian coords [x,y] in the frame of the lense center

    :param coord: set of coordinates
    :type coord: array of size (n,2)
    :param center: rotation point
    :type center: array of size (2)
    :returns:  array of same size with coords [x,y]
    :raises: AttributeError, KeyError
    """
    x = r*np.cos(phi)
    y = r*np.sin(phi)
    return x - center[0], y - center[1]

def phi_gamma_ellipticity(phi, gamma):
    """

    :param phi: angel
    :param gamma: ellipticity
    :return:
    """
    e1 = gamma*np.cos(2*phi)
    e2 = gamma*np.sin(2*phi)
    return e1, e2

def ellipticity2phi_gamma(e1, e2):
    """
    :param e1: ellipticity component
    :param e2: ellipticity component
    :return: angle and abs value of ellipticity
    """
    phi = np.arctan2(e2, e1)/2
    gamma = np.sqrt(e1**2+e2**2)
    return phi, gamma

def phi_q2_ellipticity(phi, q):
    """

    :param phi:
    :param q:
    :return:
    """
    e1 = (1.-q)/(1.+q)*np.cos(2*phi)
    e2 = (1.-q)/(1.+q)*np.sin(2*phi)
    return e1, e2

def transform_e1e2(x, y, e1, e2, center_x=0, center_y=0):
    """
    maps the coordinates x, y with eccentricities e1 e2 into a new elliptical coordiante system

    :param x:
    :param y:
    :param e1:
    :param e2:
    :param center_x:
    :param center_y:
    :return:
    """
    x_shift = x - center_x
    y_shift = y - center_y
    x_ = (1-e1) * x_shift - e2 * y_shift
    y_ = -e2 * x_shift + (1 + e1) * y_shift
    det = np.sqrt((1-e1)*(1+e1) + e2**2)
    return x_ / det, y_ / det

def ellipticity2phi_q(e1, e2):
    """
    :param e1:
    :param e2:
    :return:
    """
    phi = np.arctan2(e2, e1)/2
    c = np.sqrt(e1**2+e2**2)
    if c > 0.999:
        c = 0.999
    q = (1-c)/(1+c)
    return phi, q

def phi_q2_ellipticity_bounds(phi, q, bounds=None):
    """

    :param phi:
    :param q:
    :param bounds:
    :return:
    """
    e1, e2 = phi_q2_ellipticity(phi, q)
    if bounds in ['lower', 'upper']:
        e = max(abs(e1), abs(e2))
        if bounds == 'lower':
            e1, e2 = -e, -e
        elif bounds == 'upper':
            e1, e2 = e, e
        else:
            raise ValueError("bounds %s keyword not valid" %bounds)
    return e1, e2


"""
Source:
https://www.dorukhanserg.in/post/implementing-rpca/
https://www.dorukhanserg.in/post/pca-to-rpca/
"""

import numpy as np
import numpy.linalg as la

def soft_thresholding(y: np.ndarray, mu: float):
    """
    Soft thresholding operator as explained in Section 6.5.2 of https://web.stanford.edu/~boyd/papers/pdf/prox_algs.pdf
    Solves the following problem:
    argmin_x (1/2)*||x-y||_F^2 + lmb*||x||_1

    Parameters
    ----------
        y : np.ndarray
            Target vector/matrix
        lmb : float
            Penalty parameter
    Returns
    -------
        x : np.ndarray
            argmin solution
    """
    return np.sign(y) * np.clip(np.abs(y) - mu, a_min=0, a_max=None)

def svd_shrinkage(y: np.ndarray, tau: float):
    """
    SVD shrinakge operator as explained in Theorem 2.1 of https://statweb.stanford.edu/~candes/papers/SVT.pdf
    Solves the following problem:
    argmin_x (1/2)*||x-y||_F^2 + tau*||x||_*

    Parameters
    ----------
        y : np.ndarray
            Target vector/matrix
        tau : float
            Penalty parameter
    Returns
    -------
        x : np.ndarray
            argmin solution

    """
    U, s, Vh = np.linalg.svd(y, full_matrices=False)
    s_t = soft_thresholding(s, tau)
    return U.dot(np.diag(s_t)).dot(Vh)

class RobustPCA:
    """
    Solves robust PCA using Inexact ALM as explained in Algorithm 5 of https://arxiv.org/pdf/1009.5055.pdf
    Parameters
    ----------
        lmb:
            penalty on sparse errors
        mu_0:
            initial lagrangian penalty
        rho:
            learning rate
        tau:
            mu update criterion parameter
        max_iter:
            max number of iterations for the algorithm to run
        tol_rel:
            relative tolerance

    """
    def __init__(self, lmb: float, mu_0: float=1e-5, rho: float=2, tau: float=10,
                max_iter: int=10, tol_rel: float=1e-3):
        assert mu_0 > 0
        assert lmb > 0
        assert rho > 1
        assert tau > 1
        assert max_iter > 0
        assert tol_rel > 0
        self.mu_0_ = mu_0
        self.lmb_ = lmb
        self.rho_ = rho
        self.tau_ = tau
        self.max_iter_ = max_iter
        self.tol_rel_ = tol_rel

    def fit(self, X: np.ndarray):
        """
        Fits robust PCA to X and returns the low-rank and sparse components
        Parameters
        ----------
            X:
                Original data matrix

        Returns
        -------
            L:
                Low rank component of X
            S:
                Sparse error component of X
        """
        assert X.ndim == 2
        mu = self.mu_0_
        Y = X / self._J(X, mu)
        S = np.zeros_like(X)
        S_last = np.empty_like(S)
        for k in range(self.max_iter_):
            # Solve argmin_L ||X - (L + S) + Y/mu||_F^2 + (lmb/mu)*||L||_*
            L = svd_shrinkage(X - S + Y/mu, 1/mu)

            # Solve argmin_S ||X - (L + S) + Y/mu||_F^2 + (lmb/mu)*||S||_1
            S_last = S.copy()
            S = soft_thresholding(X - L + Y/mu, self.lmb_/mu)

            # Update dual variables Y <- Y + mu * (X - S - L)
            Y += mu*(X - S - L)
            r, h = self._get_residuals(X, S, L, S_last, mu)

            # Check stopping cirteria
            tol_r, tol_h = self._update_tols(X, L, S, Y)
            if r < tol_r and h < tol_h:
                break

            # Update mu
            mu = self._update_mu(mu, r, h)

        return L, S

    def _J(self, X: np.ndarray, lmb: float):
        """
        The function J() required for initialization of dual variables as advised in Section 3.1 of
        https://people.eecs.berkeley.edu/~yima/matrix-rank/Files/rpca_algorithms.pdf
        """
        return max(np.linalg.norm(X), np.max(np.abs(X))/lmb)

    @staticmethod
    def _get_residuals(X: np.ndarray, S: np.ndarray, L: np.ndarray, S_last: np.ndarray, mu: float):
        primal_residual = la.norm(X - S - L, ord="fro")
        dual_residual = mu*la.norm(S - S_last, ord="fro")
        return primal_residual, dual_residual

    def _update_mu(self, mu: float, r: float, h: float):
        if r > self.tau_ * h:
            return mu * self.rho_
        elif h > self.tau_ * r:
            return mu / self.rho_
        else:
            return mu

    def _update_tols(self, X, S, L, Y):
        tol_primal = self.tol_rel_ * max(la.norm(X), la.norm(S), la.norm(L))
        tol_dual = self.tol_rel_ * la.norm(Y)
        return tol_primal, tol_dual


##### FIRST ORDER TRANSFER FUNCTION CONTROL SIMULATION WITH MULTISTEP #####

import numpy as np
from sklearn.metrics import mean_squared_error
import pandas as pd
from scipy import signal
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from control import *
from multi_step import *

# Simulate taup * dy/dt = -y + K*u
Kp = 1.0
taup = 1.0

# (1) Transfer Function
num = [Kp]
den = [taup,1]
sys1 = signal.TransferFunction(num,den)
t1,y1 = signal.step(sys1)

# Time definition
ts = 0.1	#sampling time [s]
tf = 20	#simulation time [min]
tf = 60.0*tf      #-----> samples per minute = 60.0/ts
t = np.arange(0.0, tf, ts)
tt = t/60 # set minutes
# tt = t # set seconds

# ODE Integrator
def model3(y,t,u):
    return (-y + Kp * u)/taup

t3 = np.linspace(0,100,100)

tc = np.array([2, 3, 7])
a = np.array([2, 3, 5])

# ctrl = pid(ts, 0.08863, 0.5455, 0.0036)   # control 1_1
ctrl = pid(ts, 1.415, 1.415, 0.0)   # control 1_2c
sp = step_multiple(t, tc, a, ts)
# sp = 1
u = 1
y3_0 = 0

# print("LEN P: ", len(sp))
Y = np.zeros(t.shape)

for k in range(t.size):

    y3 = odeint(model3,y3_0,np.array([0.0, ts]),args=(u,))
    # print("Y3: ",y3)

    yk = y3[1]
    # print("yk: ",yk)
    # print("k: ",k)
    Y[k] = yk
    # print("U BEFORE es: ",u)
    # u = ctrl.solve(sp[k]+0.5*np.random.rand(1),yk) # with noise
    u = ctrl.solve(sp[k],yk)
    # u = ctrl.solve(sp,yk)
    # print("sp: ",sp)
    y3_0 = yk

plt.figure(1)
# plt.plot(t1,y1,'b--',linewidth=3,label='Transfer Fcn')
# plt.plot(t2,y2,'g:',linewidth=2,label='State Space')
plt.plot(tt,Y,'r-',linewidth=1,label='ODE Integrator')
plt.xlabel('Time [s]')
plt.ylabel('Response (y)')
plt.grid()
plt.legend(loc='best')
plt.show()

# # MATLAB response plotting

# df = pd.read_csv (r'control_data\control1_1.csv', header = None)
# y_matlab = df.to_numpy()
# # print(data[0][1]+1)
# print("LEN MATLAB: ",len(y_matlab[0]))
# t_plot_matlab = np.arange(0.0, len(y_matlab[0]), 1)
# # print(t_plot_matlab)

# plt.figure(1)
# # plt.plot(t1,y1,'b--',linewidth=3,label='Transfer Fcn')
# # plt.plot(t2,y2,'g:',linewidth=2,label='State Space')
# plt.plot(tt,Y,'r-',linewidth=1,label='ODE Integrator')
# plt.xlabel('Time [s]')
# plt.ylabel('Response (y)')
# plt.grid()
# plt.legend(loc='best')
# plt.show()
# plt.plot(t_plot_matlab,y_matlab[0],'b-',linewidth=1,label='MATLAB data')
# plt.xlabel('Samples')
# plt.ylabel('Response (y)')
# plt.grid()
# plt.legend(loc='best')
# plt.show()

# RMS_ERROR = np.sqrt(((y_matlab[0]-Y)**2).mean())
# RMS_ERROR_SKLEARN = mean_squared_error(y_matlab[0],Y, squared=False)
# print("My error [%]: ",RMS_ERROR*100)
# print("SKLEARN error [%]: ",RMS_ERROR_SKLEARN*100)


# ---
# jupyter:
#   jupytext:
#     formats: ipynb,py:percent
#     text_representation:
#       extension: .py
#       format_name: percent
#       format_version: '1.3'
#       jupytext_version: 1.6.0
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# %%
from pathlib import Path
from functools import partial

from utils import load_polar

import pybem as pb
import numpy as np
import pandas as pd
import proplot as plot
import sympy as sy

# %% [markdown]
# Inputs

# %% [markdown]
# How to compute the Aspect Ratio of the blade.
#
# $$
# AR = R^2 / S
# $$
# where $S$ is the blade area, computed like:
# $$
# S = \int_{R_{min}}^{R} c(r)dr
# $$
#
# We are now going to use `sympy` to compute the area numerically for some special cases to validate our simulator. We assume the chord to vary linearly with `r`.

# %%
r, R, R0 = sy.symbols("r, R, R0")
a, b = sy.symbols("a, b")
c, c0 = sy.symbols("c, c0")

# %% [markdown]
# Set up a generic linear variation

# %%
expr = a + b * r
expr

# %% [markdown]
# Create system of equations to determine the coefficients such that they match initial and final values.

# %%
eq1 = sy.Eq(lhs = expr.subs(r, R), rhs = c) # Tip
eq2 = sy.Eq(lhs = expr.subs(r, R0), rhs = c0) # Hub

# %% [markdown]
# Solve the system and obtain the coefficients

# %%
sol = sy.linsolve([eq1, eq2], (a, b))

a_sol , b_sol = sol.args[0]
print("a =", a_sol)
print("b =", b_sol)

# %% [markdown]
# Create chord variation equation and integrate to obtain blade area.

# %%
chord = a_sol + b_sol * r

area = sy.factor(sy.integrate(chord, (r, R0, R)))
area

# %%
print(sy.pycode(area))

print(sy.pycode(chord))

# %%
PATH_POLARS = Path("../polars")
file_lift = "lift.csv"
file_drag = "drag.csv"
file_propeller = PATH_POLARS / "propeller1_inches.txt"

PITCH_RATIO = 0.9
PITCH = 32.4  # inches for diameter of 36 inches

# %%
INCH_METER = 0.0254
PITCH = INCH_METER * PITCH  # meters

# %%
csv_reader = partial(pd.read_csv, sep=";", index_col=None)
load_polar = partial(
    load_polar,
    path=PATH_POLARS,
    file_lift=file_lift,
    file_drag=file_drag,
    reader=csv_reader,
)

# %%
dimensions_original_df = pd.read_csv(filepath_or_buffer=file_propeller, sep=",")

# Enforce stripped columns
dimensions_original_df.columns = [col.strip() for col in dimensions_original_df.columns]
dimensions_original_df = dimensions_original_df[["radius", "chord"]]

# Convert to international units
dimensions_original_df = dimensions_original_df.mul(INCH_METER)

# Name
dimensions_original_df.index = ["Hub", "S1", "S2", "S3", "S4", "Tip"]

# %% [markdown]
# Create the blade by defining the sections at each stage.

# %%
def generate_sections(coefficient, dimensions_original):

    dimensions_df = dimensions_original.copy()

    # Scale the propeller size and compute theta
    dimensions_df["chord"] *= coefficient

    R = dimensions_df["radius"].max()

    # Compute pitch angle distribution
    for idx, row in dimensions_df.iterrows():

        r = row["radius"]

        # Constant pitch law
        tan_theta = (2.0 * PITCH_RATIO * R) / (2.0 * np.pi * r)
        theta = np.arctan(tan_theta)  # radians
        theta = np.rad2deg(theta)  # degrees

        dimensions_df.loc[idx, "theta"] = theta

    # Define sections
    sections = [
        pb.Section(
            name="Hub",
            r=dimensions_df.loc["Hub", "radius"],
            beta=dimensions_df.loc["Hub", "theta"],
            chord=dimensions_df.loc["Hub", "chord"],
            airfoil=pb.Airfoil(
                polar_cl=load_polar(airfoil_type="765", which="cl"),
                polar_cd=load_polar(airfoil_type="765", which="cd"),
            ),
        ),
        pb.Section(
            name="S1",
            r=dimensions_df.loc["S1", "radius"],
            beta=dimensions_df.loc["S1", "theta"],
            chord=dimensions_df.loc["S1", "chord"],
            airfoil=pb.Airfoil(
                polar_cl=load_polar(airfoil_type="765", which="cl"),
                polar_cd=load_polar(airfoil_type="765", which="cd"),
            ),
        ),
        pb.Section(
            name="S2",
            r=dimensions_df.loc["S2", "radius"],
            beta=dimensions_df.loc["S2", "theta"],
            chord=dimensions_df.loc["S2", "chord"],
            airfoil=pb.Airfoil(
                polar_cl=load_polar(airfoil_type="764", which="cl"),
                polar_cd=load_polar(airfoil_type="764", which="cd"),
            ),
        ),
        pb.Section(
            name="S3",
            r=dimensions_df.loc["S3", "radius"],
            beta=dimensions_df.loc["S3", "theta"],
            chord=dimensions_df.loc["S3", "chord"],
            airfoil=pb.Airfoil(
                polar_cl=load_polar(airfoil_type="763", which="cl"),
                polar_cd=load_polar(airfoil_type="763", which="cd"),
            ),
        ),
        pb.Section(
            name="S4",
            r=dimensions_df.loc["S4", "radius"],
            beta=dimensions_df.loc["S4", "theta"],
            chord=dimensions_df.loc["S4", "chord"],
            airfoil=pb.Airfoil(
                polar_cl=load_polar(airfoil_type="762", which="cl"),
                polar_cd=load_polar(airfoil_type="762", which="cd"),
            ),
        ),
        pb.Section(
            name="Tip",
            r=dimensions_df.loc["Tip", "radius"],
            beta=dimensions_df.loc["Tip", "theta"],
            chord=dimensions_df.loc["Tip", "chord"],
            airfoil=pb.Airfoil(
                polar_cl=load_polar(airfoil_type="761", which="cl"),
                polar_cd=load_polar(airfoil_type="761", which="cd"),
            ),
        ),
    ]

    return sections

# %%
# Define propeller
COEFF_0 = 0.5
COEFF_N = 3
N = 5

results = []
for coeff in np.linspace(start=COEFF_0, stop=COEFF_N, num=N):

    sections = generate_sections(
        coefficient=coeff, dimensions_original=dimensions_original_df
    )

    propeller = pb.Propeller(B=2, sections=sections)

    # Define flow conditions and BEM method

    for J in np.linspace(1e-1, 1.5):

        pi = np.pi

        _lambda = J / pi

        bem = pb.BladeElementMethod(
            _lambda=_lambda, propeller=propeller, tip_loss=True, hub_loss=False
        )

        try:
            # Solve
            bem.solve()
            CT, CQ = bem.integrate_forces()
        except:
            CT = np.nan
            CQ = np.nan

        AR = propeller.aspect_ratio

        # Create experiments non-dimensionless coefficients
        results.append(
            (
                AR,
                J,
                CT * (pi ** 3.0) / 4 / J ** 2.0,
                CQ * (pi ** 4.0) / 4 / J ** 2.0,
                _lambda * CT / CQ,  # efficiency
            )
        )

        del bem

    del propeller

results_df = pd.DataFrame(results, columns=["AR", "J", "CT", "CP", "eta"]).dropna()

# %%
results_df

# %%
_array = [[1, 2], [3, 3]]
fig, axes = plot.subplots(array=_array, share=0)

Rs = results_df["AR"].unique()
for R in Rs:

    mask = results_df["AR"] == AR
    _results_df = results_df.loc[mask].set_index("J").drop("AR", axis=1)

    name = np.round(AR, 2)
    name = str(name)
    ############
    # Thrust
    ############
    ax = axes[0]
    thrust = _results_df["CT"]
    thrust.name = name
    lines = ax.plot(
        thrust,
        cycle="plum",
    )
    ax.format(
        title="Thrust",
        ylabel="$C_T$",
    )

    ############
    # Torque
    ############
    ax = axes[1]
    torque = _results_df["CP"]
    torque.name = name

    ax.plot(
        torque,
        cycle="plum",
    )
    ax.format(
        title="Torque / Power",
        ylabel="$C_P$",
    )

    ############
    # Efficiency
    ############
    ax = axes[-1]
    eta = _results_df["eta"]
    eta.name = name
    ax.plot(eta, cycle="plum")
    ax.format(title="Efficiency", ylabel="$\eta$")

axes[-1].legend(title="Aspect Ratio")

fig.save("Aspect_Ratio.pdf")

# %%

notebooks/Geometry influence - Aspect Ratio.py


"""
Defines a complex polynomial object from coefficients:
f(z) = a_0 + a_1 * z + a_2 * z^2 + ... + a_n * z^n

where for each i, a_i is a complex interval

Author:
Yuan Wang
Princeton University
"""
from interval import interval, inf, imath
from complexinterval import ComplexInterval, _one, _zero, _real
import operator
import numpy as np
import math

class ComplexPolynomial:
	def __init__(self, coeffs = [ComplexInterval()]):
		self.coeffs = coeffs

	def coeffs_copy(self):
		"""
		Return a copy of this complex polynomia's coefficients
		"""
		return self.coeffs[:]

	def derive(self):
		"""
		Returns a polynomial that is the first derivative of
		the current polynomial
		"""
		mycoeffs = self.coeffs
		coeffs = [0] * (len(mycoeffs) - 1)
		for i in range(len(mycoeffs) - 1):
			factor = _real(i + 1)
			coeffs[i] = mycoeffs[i + 1] * factor
		return ComplexPolynomial(coeffs)

	def evaluate(self, z):
		"""
		Evaluates a complex polynomial at z
		"""
		total = _zero()
		coeffs = self.coeffs
		for i in range(len(coeffs)):
			total = total + coeffs[i] * z**i
		return total

	def coeffString(self):
		out = ""
		for i in range(len(self.coeffs)):
			out += '(' + str(min(min(self.coeffs[i].a))) + ' + ' \
			+ str(min(min(self.coeffs[i].b))) + 'i)' + 'z^' + str(i) + ' + '
		return out[:-2]

	def isZero(self):
		"""
		Returns whether or not this polynomial is zero
		"""
		for i in range(len(self.coeffs)):
			if self.coeffs[i].isZero() == False:
				return False
		return True

	def __str__(self):
		"""
		Returns a string representation of the polynomial
		"""

		if (len(self.coeffs) == 0):
			return "f(z) =  0"

		return "f(z) =  " + self.coeffString()

	def __call__(self, z):
		return self.evaluate(z)

	def __add__(self, other):
		coeffs = self.coeffs[:]
		# add coefficientspairwise
		for i in range(min(len(self.coeffs), len(other.coeffs))):
			coeffs[i] = coeffs[i] + other.coeffs[i]

		if (len(other.coeffs) > len(self.coeffs)):
			return ComplexPolynomial(coeffs + other.coeffs[len(other.coeffs):])
		else:
			return ComplexPolynomial(coeffs)

	def __neg__(self):
		coeffs = [-coeff for coeff in self.coeffs]
		return ComplexPolynomial(coeffs)

	def __sub__(self, other):
		return self.__add__(-other)

	def __mul__(self, poly):
		"""
		Multiplies two polynomials.
		"""
		coeffs = []
		if (self.isZero() | poly.isZero()):
			return ComplexPolynomial([_zero()])

		for i in range(len(self.coeffs) + len(poly.coeffs) - 1):
			coeffs.append(_zero())
		P = self.coeffs
		Q = poly.coeffs
		for k in range(len(P)):
			summand = [q_i * P[k] for q_i in Q]
			for j in range(len(Q)):
				coeffs[k + j] = coeffs[k + j] + summand[j]

		return ComplexPolynomial(coeffs)

def main():
	print("Testing Complex Polynomials")
	print("----------------------------")
	xa = interval([1, 2])
	xb = interval([5, 6])
	x = ComplexInterval(xa, xb)

	ya = interval([4, 7])
	yb = interval([2, 3])
	y = ComplexInterval(ya, yb)

	wa = interval([2, 2])
	wb = interval([3, 3])
	w = ComplexInterval(wa, wb)

	za = interval([4, 4])
	zb = interval([5, 5])
	z = ComplexInterval(za, zb)

	a_0_a = interval([1, 1])
	a_0_b = interval([5, 5])
	a_0 = ComplexInterval(a_0_a, a_0_b)

	a_1_a = interval([1, 1])
	a_1_b = interval([5, 5])
	a_1 = ComplexInterval(a_1_a, a_1_b)

	a_2_a = interval([3, 3])
	a_2_b = interval([2, 2])
	a_2 = ComplexInterval(a_2_a, a_2_b)

	a_3_a = interval([7, 7])
	a_3_b = interval([-4, -4])
	a_3 = ComplexInterval(a_3_a, a_3_b)

	a_4_a = interval([-6, -6])
	a_4_b = interval([1, 1])
	a_4 = ComplexInterval(a_4_a, a_4_b)

	a_5 = ComplexInterval(interval([4]), interval([0]))
	a_6 = ComplexInterval(interval([5]), interval([0]))
	a_7 = ComplexInterval(interval([5]), interval([0]))

	coeffs = [a_1, a_2, a_3, a_4]

	print("Testing Complex Constructor")
	print("----------------------------")
	poly_1 = ComplexPolynomial(coeffs)
	print(poly_1)
	poly_2 = ComplexPolynomial([_zero(), a_4])
	print(poly_2)
	print("============================")

	print("Testing Evaluation")
	print("----------------------------")
	print(poly_1.evaluate(w))
	print(poly_1.evaluate(_one()))
	print(poly_1.evaluate(_zero()))

	print("")

	print(poly_2.evaluate(w))
	print(poly_2.evaluate(_one()))
	print(poly_2.evaluate(_zero()))
	print("============================")

	print("Derivation")
	print("----------------------------")
	print(poly_1.derive())

	print("")

	print(poly_2.derive())
	print("============================")

	print("Multiplication")
	print("----------------------------")
	poly_4 = ComplexPolynomial([a_5, a_6])
	poly_5 = ComplexPolynomial([a_7, a_5])

	print(poly_4)
	print(poly_5)
	print(poly_4 * poly_5)
	print(poly_4 * poly_4)

	print("============================")

	print("Addition")
	print("----------------------------")
	print(poly_4 + poly_2)
	print(poly_1 + poly_5)

	print("============================")

	print("Subtraction")
	print("----------------------------")
	print(poly_4 - poly_5)
	print(poly_4 - poly_2)
	print(poly_1 - poly_5)

	print("============================")

if __name__=="__main__":
	main()


import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize
from scipy import stats
from utils import sigmoid , cost_function_logistic_regression_J

# pass
Y = np.array([0	,0	,0	,0	,0	,0	,1	,0	,1	,0	,1	,0	,1	,0	,1	,1	,1	,1	,1	,1])
# hours
X1 = np.array([0.50	,0.75	,1.00	,1.25	,1.50	,1.75	,1.75	,2.00	,2.25	,2.50	,2.75	,3.00	,3.25	,3.50	,4.00	,4.25	,4.50	,4.75	,5.00	,5.50])
m = X1.size
X0 = np.ones(m)
X= np.vstack((X0,X1)).T

res = optimize.minimize(cost_function_logistic_regression_J, x0=[0,0] , args=(X,Y))
print(res)
teta0 = res.x[0]
teta1 = res.x[1]

teta_x = teta0 + teta1 *X1
h = sigmoid(teta_x)

plt.scatter(X1, Y)
plt.plot(X1, h)
plt.title('data set and logistic regression using optimize.minimize')
plt.ylabel('pass')
plt.xlabel('hours')
plt.grid()
plt.show()


import numpy as np
from numpy import linalg as la

def rotation_matrix_by_2_vec(a, b):
    unit_vector_a = a / np.linalg.norm(a)
    unit_vector_b = b / np.linalg.norm(b)
    cos_t = np.dot(unit_vector_a, unit_vector_b)
    sin_t = np.sqrt(1-cos_t**2)*np.sign(np.cross(unit_vector_a, unit_vector_b))
    return np.array([[cos_t, -sin_t], [sin_t, cos_t]])

def rotation_matrix_by_angle(t):
    cos_t = np.cos(t)
    sin_t = np.sin(t)
    return np.array([[cos_t, -sin_t], [sin_t, cos_t]])


import numpy as np

def linear_kernel(x, y):
    return np.dot(x, y)

def polynomial_kernel(x, y, d=5):
    return (np.dot(x, y) + 1) ** d

def RBF_kernel(x, y, sigma=1.0):
    return np.exp(-np.linalg.norm((x - y)) ** 2 / (2 * (sigma ** 2)))


import numpy as np
from scipy.optimize import linprog

c1 = np.array([0.3, 0.2]) * -1
c2 = np.array([4.5, 1.5])
A_ub = [
    [-1, 1],
    [1, 1],
    [-1, -1]
]
b_ub = [0, 150, -50]

bounds = ((0, 100), (0, None))

def callback(xk, **kwargs):
    np.set_printoptions(precision=3)
    np.set_printoptions(suppress=True)
    print(kwargs)

res = linprog(c1, A_ub=A_ub, b_ub=b_ub, bounds=bounds, callback=callback)
print(res)
res = linprog(c2, A_ub=A_ub, b_ub=b_ub, bounds=bounds, callback=callback)
print(res)


import numpy as np
import networkx as nx

G = nx.dense_gnm_random_graph(5, 5, seed=12345)

matrix = nx.adjacency_matrix(G).todense()
print(matrix)
# [[0 0 1 0 0]
#  [0 0 1 1 0]
#  [1 1 0 0 1]
#  [0 1 0 0 1]
#  [0 0 1 1 0]]

paths_len_4 = np.linalg.matrix_power(matrix, 4)
print(paths_len_4)
# [[ 3 5  0  0 5]
#  [ 5 9  0  0 9]
#  [ 0 0 13 10 0]
#  [ 0 0 10  8 0]
#  [ 5 9  0  0 9]]


import numpy as np
from scipy import constants

def spectral_radiance(wavelength_nm, temperature: float):
    """
    Estimates the blackbody radiation as a function of wavelength and temperature
    .. math::
        B_{\nu}(T) = \frac{2 h c^2 / \lambda^5}{e^{h c/\lambda kT} - 1}
    where :math:`\nu = c/\lambda`

    Parameters
    ----------
    wavelength_nm: float
        The wavelength in nanometers
    temperature: float
        The temperature in Kelvin

    Returns
    -------
    float:
        The spectral radiance in J * s / (cm^2 nm sr)
    """

    hc = 6.62607015 * 2.99792458  # x 1E -34 (J s) x 1E8 (m/s) = 1E-26 (J m)
    hc2 = hc * 2.99792458  # x 1E -34 (J s) x 1E16 (m/s)^2 = 1E-18 (J m^2 s^{-1})
    hc_by_kt_lambda = 1E6 * hc / 1.380649 / temperature / wavelength_nm
    radiance = 2.0 * hc2 * np.power(wavelength_nm, -5.0)  # 1E-18 (J m^2 s^{-1}) / 1E-45 (m^5) = 1E27 J / (m^3 s)
    radiance *= 1E18 / (np.exp(hc_by_kt_lambda) - 1.0)  # 1E27 J/m^3 s = 1E18 J / (m^2 nm s)
    return radiance

def temperature_at_radiacnce(radiance: float, wavelength_nm: float):
    """
    Estimates the blackbody temperature in Kelvin for a source at a given wavelength in nm and a known spectral radiance
    ..math::
        T(B, \lambda) = \frac{\lambda k}{h c} \{ \ln\left[\frac{hc^2}{\lambda^5 B} + 1\right]\}

    Parameters
    ----------
    radiance: float
        The spectral radiance in W / cm^2 / nm / s / sr
    wavelength_nm: float
        The wavelength in nm

    Returns
    -------
    float:
        The estimated temperature in K
    """
    hc = 6.62607015 * 2.99792458  # x 1E -34 (J s) x 1E8 (m/s) = 1E-26 (J m)
    hc2 = hc * 2.99792458  # x 1E -34 (J s) x 1E16 (m/s)^2 = 1E-18 (J m^2 s^{-1})
    arg = 2.0 * hc2 * np.power(wavelength_nm, -5.0)  # 1E-18 (J m^2 s^{-1}) / 1E-45 (m^5) = 1E27 J / (m^3 s)
    arg /= 1E-14 * radiance  # / 1E27 [J / (m^3 s)] / [J / s cm^2 nm ] = 1E27 / 1E13 = 1E14
    arg += 1.0
    temperature = 1E6 * hc / wavelength_nm / 1.380649  # 1E-26 (J m) / 1E-9 m / 1E-23 J/K
    temperature /= np.log(arg)
    return temperature


import numpy as np

def dist_pll_lines_2d(m, b1, b2):
    """Finding the distance between two parallel lines.
    The distance between two parallel lines is the distance between the points where a perpendicular line intersects.
    This function will find that distance (d). The parameters of the function can be obtained from the equation of a parallel
    line y = mx + b.
    Parameters
    ----------
    m  : float, int
        slope of two parallel lines which are the same, i.e., slope of
        line 1, m1 = -(1/m2)
    b1 : float, int
        intercept of line 1 where y = mx + b1
    b2 : float
        intercept of line 2 where y = mx + b2
    Returns
    -------
    float
        The distance d between two parallel lines.
    Examples
    --------
    >>> dist_pll_lines_2d(3.0, 4.5, 2.5)
    0.6324
    >>> dist_pll_lines_2d(-4, 11, 23)
    2.9104
    """
    # apply corresponding values from the two parallel line equations to
    # the equation below
    if not isinstance(m, (int, float)):
        raise TypeError("m must be an integer or float")

    if not isinstance(b1, (int, float)):
        raise TypeError("b1 must be an integer or float")

    if not isinstance(b2, (int, float)):
        raise TypeError("b2 must be an integer or float")

    d = abs(b2 - b1) / np.sqrt(m ** 2 + 1)
    return d

def get_distance(x1, x2, metric="Euclidean", p=None):
    """Calculates the distance between two n dimensional vectors.
    Possible metrics include: Euclidean, Manhattan, Chebyshev, or Minkowski.
    Parameters
    ----------
    x1 : list of int or float
        The first n dimensional vector.
    x2 : list of int or float
        The second n dimensional vector.
    metric : str, default="Euclidean"
        The distance metric, must be one of "Euclidean", "Manhattan", Chebyshev,
        or "Minkowski"
    p : int, default=None
        The order of Minkowski distance to calculate.  Only required if `metric` is
        set to "Minkowski".
    Returns
    -------
    float
        The relevant distance between the two vectors.
    Examples
    --------
    >>> x1 = [1, 2, 3, 4]
    >>> x2 = [5, 6, 7, 8]
    >>> get_distance(x1, x2, metric="Euclidean")
    8
    >>> get_distance(x1, x2, metric="Manhattan")
    16
    >>> get_distance(x1, x2, metric="Chebyshev")
    4
    >>> get_distance(x1, x2, metric="Minkowski", 3)
    6.3496
    """

    # cast to lower for flexibility
    metric = metric.lower()

    # verify distance metric
    if metric not in ["euclidean", "manhattan", "chebyshev", "minkowski"]:
        raise ValueError(f"Invalid distance metric: {metric}")

    # verify that vectors are passed as python lists
    if not isinstance(x1, list) or not isinstance(x2, list):
        raise TypeError("x1 and x2 must be Python lists")

    # verify dimensions of vectors match
    if len(x1) != len(x2):
        raise TypeError("x1 and x2 must be the same length")

    # verify p if minkowski distance is metric
    if metric.lower() == "minkowski":
        if not isinstance(p, (int, float)):
            raise TypeError("p must be int or float")

    # convert to numpy arrays
    x1 = np.array(x1)
    x2 = np.array(x2)

    # check if arrays are equal if so distance is 0
    if np.array_equal(x1, x2):
        return 0
    elif metric == "euclidean":
        return np.sqrt(np.sum((np.square(x1 - x2))))
    elif metric == "manhattan":
        return np.sum(np.abs(x1 - x2))
    elif metric == "chebyshev":
        return np.max(np.abs(x1 - x2))
    elif metric == "minkowski":
        return np.power(np.sum(np.power(np.abs(x1 - x2), p)), 1 / p)

def is_intersection_3d(m1, b1, m2, b2):
    """Determines whether two infinite lines intersect in 3-dimensional space.
    Note that if two parallel lines are provided, they will be considered as NOT intersecting.
    Also note that this function expects integer values for x, y, z coordinates. Values will be rounded
    if integer values are not provided.
    This algorithm uses the following idea to test for intersection: Two (non parallel) lines intersect
    in 3d space if and only if they are coplanar.
    Parameters
    ----------
    m1 : list or tuple of floats
        This list corresponds to a 3-dimensional vector ⟨𝑚𝑥1,𝑚𝑦1,𝑚𝑧1⟩ describing the
        direction vector (or slope) of line 2. List or tuple must be of length 3.
    b1 : list or tuple of floats
        Any point on line 1. This list corresponds to a point (x1, y1, z1) that lies on line 1.
        This point must lie on line 2.
    m2 : list or tuple of floats
        This list corresponds to a 3-dimensional vector ⟨𝑚𝑥2,𝑚𝑦2,𝑚𝑧2⟩ describing the
        direction vector (or slope) of line 2.
    b2 : list or tuple of floats
        Any point on line 2. This list corresponds to a point (x2, y2, z2) that lies on line 2.
        This point must lie on line 2.
    Returns
    -------
    bool
        True if there is intersection, False if not.
    Examples
    --------
    >>> m1 = (1, 0, 0)
    >>> m2 = (0, 1, 0)
    >>> b1 = (0, 0, 0)
    >>> b2 = (0, 0, 0)
    >>> is_intersection_3d(m1, b1, m2, b2)
    True
    >>> m3 = (1, 3, -1)
    >>> m4 = (2, 1, 4)
    >>> b3 = (0, -2, 4)
    >>> b4 = (0, 3, -3)
    >>> is_intersection_3d(m3, m4, b3, b4)
    False
    """

    # Validate input
    if not isinstance(m1, (list, tuple) or not isinstance(m2, (list, tuple))):
        raise TypeError(
            "Only lists or tuples are supported. Please provide m1 & m2 as lists or tuples"
        )

    if not isinstance(b1, (list, tuple)) or not isinstance(b1, (list, tuple)):
        raise TypeError(
            "Only lists or tuples are supported. Please provide b1 & b2 as lists or tuples."
        )

    if len(m1) != 3 or len(m2) != 3 or len(b1) != 3 or len(b2) != 3:
        raise ValueError("All tuples should of length 3. Please check your inputs")

    # Ensure all values are integers
    m1 = (round(m1[0]), round(m1[1]), round(m1[2]))
    m2 = (round(m2[0]), round(m2[1]), round(m2[2]))
    b1 = (round(b1[0]), round(b1[1]), round(b1[2]))
    b2 = (round(b2[0]), round(b2[1]), round(b2[2]))

    m1 = np.array(m1)
    m2 = np.array(m2)
    b1 = np.array(b1)
    b2 = np.array(b2)

    # Check if lines are parallel
    if (m1 == m2).all():
        return False

    # Lines intersect if and only if they lie on the same plane (and are not parallel).
    x = np.cross(m1, m2)
    disp = np.array(b2) - np.array(b1)
    if np.dot(x, disp) == 0:
        return True
    else:
        return False

def is_orthogonal(m1, m2):
    """Determines whether two infinite lines are perpendicular in n-dimensional space.
    Parameters
    ----------
    m1 : list or tuple of floats
        This list corresponds to a n-dimensional vector ⟨mx1, my1, mz1, ...⟩ describing the
        direction vector of line 1.
    m2 : list or tuple of floats
        This list corresponds to a n-dimensional vector ⟨mx2, my2, mz2, ...⟩ describing the
        direction vector of line 2. Demensions of line 1 and line 2 must be equal.
    Returns
    -------
    bool
        True if there is orthogonal, False if not.
    Examples
    --------
    >>> m1 = (1, 0)
    >>> m2 = (0, 1)
    >>> is_orthogonal(m1, m2)
    True
    >>> m3 = (0, 0, 1)
    >>> m4 = (1, 1, 1)
    >>> is_orthogonal(m3, m4)
    False
    """
    # Validate input
    if not isinstance(m1, (list, tuple) or not isinstance(m2, (list, tuple))):
        raise TypeError("m1 and m2 must be lists or tuples")

    if len(m1) < 1 or len(m2) < 1:
        raise ValueError("The dimension of inputs must be at least 2")

    # Checking if m1 and m2 have the same dimension
    if len(m1) != len(m2):
        raise ValueError("m1 and m2 must be the same length")

    line1 = np.array(m1)
    line2 = np.array(m2)
    if round(np.dot(line1, line2), 10) == 0:
        return True
    else:
        return False


'''
Functions for getting input and performing
main operations.
'''
from sys import exit as leave
from math import cos, radians
import numpy as np

def read_input():
    '''
    Returns user's input.
    '''
    #Getting user's year.
    year = int(input('Enter a year you are interested in (must be integer number): '))

    try:
        year = int(year)

    #Excepting an event when users gives wrong year number.
    except ValueError:
        print('     THE YEAR VALUE MUST BE INTEGER NUMBER    ')
        leave()

    try:
        #Getting coordinates of the place.
        lattitude, longtitude = input('Enter lattitude and longtitude separated with a coma \
(example: 50.456322,98.23423423): ').split(',')

    #Excepting an event when users gives only one number.
    except ValueError:
        print('         THERE MUST BE TWO VALUES IN INPUT FIELD!!!        ')
        leave()
    try:
        lattitude, longtitude = float(lattitude), float(longtitude)

    #Excepting an event when users gives wrong numbers.
    except ValueError:
        print(' THE COORDINATES VALUES MUST BE FLOAT NUMBERS ')
        leave()

    return (year, lattitude, longtitude)

def find_distances(locations_dataframe, point: tuple):
    '''
    Returns a dataframe of distances between the given point
and locations from dataframe.
    '''

    lattitude, longtitude = point
    lattitude, longtitude = radians(lattitude), radians(longtitude)
    locations_dataframe['lattitude_radians'] = np.radians(locations_dataframe['lattitude'])
    locations_dataframe['longtitude_radians'] = np.radians(locations_dataframe['longtitude'])
    locations_dataframe['delta_longtitude'] = locations_dataframe['longtitude_radians'] - longtitude
    locations_dataframe['delta_lattitude'] = locations_dataframe['lattitude_radians'] - lattitude
    locations_dataframe['half_chord'] = np.sin(locations_dataframe['delta_lattitude']/2)**2 + \
                                        cos(lattitude) * \
                                        np.cos(locations_dataframe['lattitude_radians']) * \
                                        np.sin(locations_dataframe['delta_longtitude']/2)**2
    locations_dataframe['distances'] = 6367 * 2 * np.arctan2(
                                                  np.sqrt(locations_dataframe['half_chord']),
                                                  np.sqrt(1 - locations_dataframe['half_chord']))

    return locations_dataframe

def find_closes_locations(locations_dataframe):
    '''
    Returns 10 closest locations.

    >>> import pandas as pd
    >>> closest_locations_dataframe = pd.DataFrame(columns = { \
                                                  'distances' \
                                                  })
    >>> closest_locations_dataframe['distances'] = [100, 90, 80, 30, \
                                                    20, 10, 5, 5, 4, \
                                                    3, 2, 4, 54, 33]
    >>> find_closes_locations(closest_locations_dataframe)
        distances
    10          2
    9           3
    8           4
    11          4
    6           5
    7           5
    5          10
    4          20
    3          30
    13         33
    '''
    top_closest_points = locations_dataframe.nsmallest(10, 'distances',  keep = 'all')
    return top_closest_points[:10]

if __name__ == '__main__':
    import doctest
    doctest.testmod()


import numpy as np
import pandas as pd

class ROUGH_SETS:

  def __init__(self, filename, A):
    self.filename = filename
    self.A = A

  def get_table(self):
    df = pd.read_csv(self.filename, delimiter = " ")
    return df

  #1. To provide partition of the tuples of the table for a given attribute
  def get_partition(self, attribute):
    df = self.get_table()
    attribute_values = df[['ID', attribute]].values.tolist()
    #print(attribute_values)

    attribute_types = np.unique(df[attribute].values.tolist())
    #print(attribute_types)

    partition = []
    temp = []

    for t in attribute_types:
      for i in attribute_values:
        if ( t == i[1] ):
          temp.append(i[0])
      partition.append(temp)
      temp = []

    del attribute_values
    del attribute_types
    del temp
    del t
    del i

    return partition

  #2. Using the function of task 1, compute partitions for all the attributes of the table
  def all_partitions(self):
    df = self.get_table()
    for attribute in df.columns:
      print("partition w.r.t " + attribute, get_partition(df, attribute))

  #3. To produce a simple set of given set A
  def simple_set(self, setA):
    return set(setA)

  #4. To produce frequency table of elements of given set A
  def freq_table(self, setA):
    f_table = []
    for s in setA:
      f_table.append( [ s, list(setA).count(s) ] )

    f_df = pd.DataFrame(f_table)

    del f_table
    del s

    return f_df

  #5. To get the cardinality of a given set A
  def get_cardinality(self, setA):
    return len(setA)

  #6. To get the cardinality of the corresponding simple set of a given set A.
  def cardinality_simple_set(self, setA):
    return len(set(setA))

  #7. To get the complement of a given set A.
  def complement(self, setA, U):
    return U - setA

  #8. To produce (a) intersection, (b) Union, (c) set difference of given two sets A and B
  def intersection(self, setA, setB):
    return setA & setB

  def union(self, setA, setB):
    return setA | setB

  def set_difference(self, setA, setB):
    return setA - setB

  #9. To develop boolean functions for testing whether (a) is A a subset of B  (b) is A equals to B
  def is_subset(self, setA, setB):
    return setA.issubset(setB)

  def is_equal(self, setA, setB):
    return setA == setB

  '''
  10. To develop a boolean flag vector corresponding to elements of a given partition P,
  (a) is A  a super set of element of P
  (b) is A has a non-trivial intersection with the element of P.
  '''
  def is_superset(self, partitionP):
    vector = []
    for element in partitionP:
      if ((self.A.issuperset(element)) == True):
        vector.append(1)
      else:
        vector.append(0)
    del element

    return vector

  def nt_intersection(self, partitionP):
    vector = []
    for element in partitionP:
      if ( len(self.A & set(element)) == 0 ):
        vector.append(0)
      else:
        vector.append(1)
    del element

    return vector

  '''
  11. To obtain the union of elements of the given partition P for which the flags are one (true) based on
  (a) super set flags
  (b) non-trivial intersection flags for a given set A
  The resultant sets will be referred as Lower Approximation of A and Upper Approximation of A respectively with respective to the partition P.
  '''
  def get_LSA(self, partitionP):
    vector = self.is_superset(partitionP)

    LSA = set()
    for index, v in enumerate(vector):
      if (v == 1):
        LSA = self.union(LSA, set(partitionP[index]))

    return LSA

  def get_USA(self, partitionP):
    vector = self.nt_intersection(partitionP)

    USA = set()
    for index, v in enumerate(vector):
      if (v == 1):
        USA = self.union(USA, set(partitionP[index]))

    return USA

  '''
  12. Develop an algorithm which returns Lower and Upper Approximations of given set A
  with respective to given Partition P.  Name this function as f_LUSA(A,P)
  let us denote the return values of the algorithm as LSA and USA
  '''
  def f_LUSA(self, A, P):
    self.A = A
    LSA = self.get_LSA(P)
    USA = self.get_USA(P)

    return LSA, USA

  #13. To obtain the set difference of USA and LSA. Say this resultant set as the Boundary set of A denoted as BNA.
  def get_BNA(self, P):
    LSA, USA = self.f_LUSA(self.A, P)
    BNA = self.set_difference(USA, LSA)

    return BNA

  #14.  To obtain the complement set of USA. Say this resultant set as a Negative set of A denoted as NGA.
  def get_NGA(self, P, U):
    USA = self.get_USA(P)
    return self.complement(USA, U)

  '''
  15. Develop an algorithm to get the Cardinality of sets A, U, LSA, USA,  BNA and NGA
  with respective to a Partition P obtained from  an attribute
  of a given Information System or Decision System. Say the output of this algorithm
  as n_A, N_U, n_LSA, n_USA, n_BNA and n_NGA  respectively.
  '''
  def cardinality_sets(self, attribute, U):

    P = self.get_partition(attribute)

    LSA, USA = self.f_LUSA(self.A, P)

    n_A = self.get_cardinality(A)
    n_U = self.get_cardinality(U)
    n_LSA = self.get_cardinality(LSA)
    n_USA = self.get_cardinality(USA)
    n_BNA = self.get_cardinality(self.get_BNA(P))
    n_NGA = self.get_cardinality(self.get_NGA(P, U))

    return n_A, n_U, n_LSA, n_USA, n_BNA, n_NGA

  #16. To verify that LSA, BNA and NGA of given set A with respect to a given Partition P is a partition of U, the Universal set.
  def verify_partition(self, A, P, U):
    self.A = A

    LSA = self.get_LSA(P)

    BNA = self.get_BNA(P)

    NGA = self.get_NGA(P, U)

    if ( ( len( LSA & BNA ) == 0 ) and ( len( BNA & NGA ) == 0 ) and ( len( NGA & LSA ) == 0 ) and ( LSA | BNA | NGA == U )):
      return True
    else:
      return False

###

filename = 'info_table.txt'
A = {1, 2, 3}
U = {1, 2, 3, 4, 5, 6}

rough_set = ROUGH_SETS(filename, A)

P = rough_set.get_partition("AOI")
rough_set.cardinality_sets("AOI", U)
print(rough_set.verify_partition(A, P, U))


# implementation of numerical gradient optimization, trying to choose the best
# inputs (x0, x1) that will minimize the function f. This is done by starting
# with two random inputs, and then probing the function to find the slope around
# these random inputs. In other words, we compute the derivatives (dx0, dx1)
# which are numbers that indicates how the function f changes in response to a
# tiny change in x0, x1. Then, we walk against that slope in the direction of
# steepest descent - we add some amount to our initial inputs such that the f
# function is expected to be lower. Repeat for a 1000 iterations and stop. The
# final inputs will be the local minima of the function, if one exists.
import numpy as np
np.random.seed(1) # constant seed for reproducible results

# f(x0,x1) - the function we want to minimize. It can be anything you want! Note
# however, that if this function doesn't have a minima, it can get inifinitely
# negative, and thus no minima will be found even after infinite iterations. So,
# for this demonstration, we'll remove negatives by squaring it. It can be
# assumed that this function is unknown, and resides as a compiled black-box and
# may contain arbitrary and complicated logic
def f(x0, x1):
    return (x0 - x1) ** 2

# constants - these can be learned as well! Maybe we'll cover it later.
E = 0.0001 # epsilon; infinitisimal size of probes to find derivatives
ALPHA = 0.01 # size of the steps to take in the gradient direction
ITERATIONS = 150 # number of probes/step to take

# initial values in [-10 .. +10]
x0 = np.random.rand()
x1 = np.random.rand()

for i in xrange(ITERATIONS):
    y = f(x0, x1)
    print "%s: f(%f, %f) = %f" % (i, x0, x1, y)

    # two samples, inifinitsimal points around x0 and x1
    yx0 = f(x0 + E, x1)
    yx1 = f(x0, x1 + E)

    # derivatives of x0 and x1 - or how the output of f changes w.r.t x0, x1
    dx0 = (yx0 - y) / E
    dx1 = (yx1 - y) / E

    # update to the new x, y in the gradient direction
    x0 += ALPHA * dx0 * -1 # -1 because we're after the minima, we want to walk
    x1 += ALPHA * dx1 * -1 # downwards against the slope


import numpy as np

def threshold_array(X, threshold):
    """Soft thresholding or shrinkage operator"""
    X_thresh = np.sign(X) * np.maximum(np.abs(X) - threshold, 0)
    return X_thresh

def l1_norm(X):
    return np.abs(X).sum()

def soft_threshold(X, gamma=None, eps=1e-11):
    if not gamma:
        gamma = np.sqrt(X.shape[0] * X.shape[1])

    if l1_norm(X) < gamma:
        return X

    lower = 0
    upper = np.max(np.abs(X))
    while (upper - lower) > eps:
        mid = (lower + upper) / 2
        mid_norm = l1_norm(threshold_array(X, mid))
        if mid_norm > gamma:
            lower = mid
        else:
            upper = mid
    X_thresh = threshold_array(X, mid)
    return X_thresh

def proportion_variance_explained(X, Y, center=False):
    if center:
        X = X.copy()
        X -= X.mean(axis=0)[None, :]
    return (np.linalg.norm(X @ Y @ np.linalg.inv(Y.T @ Y) @ Y.T, ord="fro") ** 2) / (
        np.linalg.norm(X, ord="fro") ** 2
    )

def calculate_explained_variance_ratio(X, Y, center=False):
    n_components = Y.shape[1]
    explained_variance_ratio = []
    for i in range(1, n_components + 1):
        pve = proportion_variance_explained(X, Y[:, :i])
        explained_variance_ratio.append(pve)
    return np.array(explained_variance_ratio)


import numpy as np
import time as tm
import sys

def PrettyPrintComplexMatrix(matrix,prec=3,linewidth1=150,suppressOn=True):
  np.set_printoptions(precision=prec,linewidth=linewidth1,suppress=suppressOn)
  print('RE=\n', np.real(matrix))
  print('Im=\n', np.imag(matrix))

def matrixMatrixMultiplication_good(A,B):
  return np.dot(A,B)

def matrixMatrixMultiplication_dummy(A,B):
  N = len(A)
  C = np.zeros((N,N),dtype=complex)
  for ii in range(0,N):
    for jj in range(0,N):
      for kk in range(0,N):
        C[ii,jj] += A[ii,kk]*B[kk,jj]
  return C

N = int(sys.argv[1])
print(N)

A = np.zeros((N,N),dtype=complex)
B = np.zeros((N,N),dtype=complex)

omega = np.exp(2.j*np.pi/N)
omega_i  = 1.
omega_ij = 1.

# A is the Discrete Fourier Transform (DFT) matrix.
for ii in range(0,N):
  for jj in range(0,N):
    A[ii,jj] = omega_ij
    B[jj,ii] = np.conj(A[ii,jj])/N
    omega_ij *= omega_i
  omega_i *= omega

print('\nA=\n')
PrettyPrintComplexMatrix(A)
print('\nB=\n')
PrettyPrintComplexMatrix(B)

t1 = tm.time()
C = matrixMatrixMultiplication_good(A,B)

print('\nC=\n')
PrettyPrintComplexMatrix(C)

print('\n\ntime for matrix multiplication: ', tm.time() - t1)