# Simple mathematical SIR model
#Imports
import math
import numpy as np
import time
import random as rand

#Simulation methods
class Population:
	def __init__(self, S, I, R = 0, N = None):
		self.S = S #Susceptible population
		self.I = I #Infected population
		self.R = R
		if (R == 0) and (N != None):
			self.R = N - I - S
		else:
			self.R = R #Removed population
		self.N = S + I + R #Total population size

class Infection:
	def __init__(self, beta, gamma):
		self.beta = beta #Effective contact rate
		self.gamma = gamma #Recovery rate
		self.R0 = beta / gamma #Basic reproduction number

class MetaData:
	def __init__(self, dt, dtype, duration, iteration_count, sample_count):
		self.dt = dt #Timestep
		self.dtype = dtype #Data type of stored values
		self.duration = duration #Virtual duration of simulation
		self.iteration_count = 0 #Number of iterations performed
		self.sample_count = 0 #Length of series (= iteration_count + 1)

class TimeSeriesData:
	def __init__(self, t_series, S_series, I_series, R_series):
		self.t_series = t_series #Time samples
		self.S_series = S_series #Susceptible population over time
		self.I_series = I_series #Infected population over time
		self.R_series = R_series #Removed population over time

class Model:
	def __init__(self, initial_population, infection, time_series_data, meta_data):
		self.initial_population = initial_population
		self.infection = infection
		self.time_series_data = time_series_data
		self.meta_data = meta_data

def simulate(initial_population, infection, dt, max_duration, transfer_rate_tolerance = 0):
	#Cache parameters
	N = initial_population.N
	S = initial_population.S
	I = initial_population.I
	R = initial_population.R
	beta = infection.beta
	gamma = infection.gamma
	#Determine internal simulation parameters
	#Data type
	dtype = None
	if (N < 6.55040e+04):
		dtype = np.float16
	elif (N < 3.4028235e+38):
		dtype = np.float32
	elif (N < 1.7976931348623157e+308):
		dtype = np.float64
	else:
		raise Exception("Population too large for floating-point datatype.")
	#Iteration limit
	max_iterations = math.ceil(max_duration / dt)
	max_samples = max_iterations + 1
	transfer_increment_tolerance = transfer_rate_tolerance * dt * N
	#Initialise storage
	S_series = np.zeros(max_samples, dtype = dtype) #Susceptible population time series
	I_series = np.zeros(max_samples, dtype = dtype) #Infected population time series
	R_series = np.zeros(max_samples, dtype = dtype) #Removed population time series
	t_series = np.zeros(max_samples, dtype = dtype) #Time data
	#Store initial values
	S_series[0] = S
	I_series[0] = I
	R_series[0] = R
	#t_series[0] = 0 #Redundant
	#Run simulation
	t = 0
	i = 0
	while i < max_iterations:
		#Increment iteration
		t += dt
		i += 1
		#Compute increments
		dS = - beta * I * S / N
		dR = gamma * I
		dI = - dS - dR
		#Update compartments
		S += dS * dt
		I += dI * dt
		R += dR * dt
		#Store current values
		S_series[i] = S
		I_series[i] = I
		R_series[i] = R
		t_series[i] = t
		#Check for equilibrium
		if (abs(dS) + abs(dR) < transfer_increment_tolerance):
			break
	#Remove excess storage
	t_series = t_series[:i]
	S_series = S_series[:i]
	I_series = I_series[:i]
	R_series = R_series[:i]
	#Return data
	time_series_data = TimeSeriesData(t_series, S_series, I_series, R_series)
	meta_data = MetaData(dt, dtype, t, i, i + 1)
	return Model(initial_population, infection, time_series_data, meta_data)

#Interactive demo
if __name__ == "__main__":
	import matplotlib.pyplot as plt
	from matplotlib.widgets import Slider, Button, RadioButtons, CheckButtons

	#Default parameters
	default_population = Population(S = 990, I = 10, R = 0)
	default_infection = Infection(beta = 0.7, gamma = 0.2)
	default_max_duration = 100
	default_tolerance = 0.01
	default_dt = 0.05
	default_model = simulate(default_population, default_infection, default_dt, default_max_duration, default_tolerance)
	#Active model
	active_model = default_model #Current model
	active_population = default_population
	active_N = active_population.N
	active_infection = default_infection

	#Initialise matplotlib
	#Figure
	fig = plt.figure(figsize = (10, 6), dpi = 120) #Figure
	fig.suptitle("Simple mathematical SIR model") #Figure title
	fig.canvas.set_window_title("SIR model demo")
	fig.set_tight_layout({"rect": [0.05, 0.05, 0.95, 0.95]})

	#Gridspec layout
	gs_fig = fig.add_gridspec(ncols = 2, nrows = 2, height_ratios = [2, 1]) #Figure gridspec
	gs_widgets = gs_fig[1, 0:2].subgridspec(4, 2) #Widgets gridspec

	#Colours
	rgb_widget_ax = (0.5, 0.5, 0.5)
	rgb_S = (0.0, 0.0, 1.0)
	rgb_I = (1.0, 0.0, 0.0)
	rgb_R = (0.0, 0.0, 0.0)

	#Plots
	ax_time = fig.add_subplot(gs_fig[0, 0]); #Time series axes
	ax_phase = fig.add_subplot(gs_fig[0, 1]); #Phase plane axes

	#Phase plane
	ax_phase.set_xlabel('Susceptible (persons)')
	ax_phase.set_ylabel('Infected (persons)')
	ax_phase.set_title("Phase plane")
	line_phase, = ax_phase.plot([], [], "blue") #Current model as phase line
	quiv_phase = ax_phase.quiver([], [], [], [], [], pivot = 'mid', scale_units = 'xy') #Quiver arrows
	#fig.colorbar(quiv_phase, extend='max')

	#Time series plot
	ax_time.set_xlabel('Time (days)')
	ax_time.set_ylabel('Persons')
	ax_time.set_title("Time series")
	#Initialise lines
	line_S, = ax_time.plot([], [], color = rgb_S, label = 'S')
	line_I, = ax_time.plot([], [], color = rgb_I, label = 'I')
	line_R, = ax_time.plot([], [], color = rgb_R, label = 'R')
	#Legend
	ax_time.legend( (line_S, line_I, line_R), ("Susceptible", "Infected", "Removed") )

	#Widgets
	#Widget axes
	ax_beta = fig.add_subplot(gs_widgets[0, 0], facecolor = rgb_widget_ax)
	ax_gamma = fig.add_subplot(gs_widgets[1, 0], facecolor = rgb_widget_ax)
	ax_population = fig.add_subplot(gs_widgets[2, 0], facecolor = rgb_widget_ax)
	ax_update = fig.add_subplot(gs_widgets[3, 0], facecolor = rgb_widget_ax)
	ax_saveFig = fig.add_subplot(gs_widgets[0, 1], facecolor = rgb_widget_ax)
	ax_saveTimeAx = fig.add_subplot(gs_widgets[1, 1], facecolor = rgb_widget_ax)
	ax_savePhaseAx = fig.add_subplot(gs_widgets[2, 1], facecolor = rgb_widget_ax)
	#Sliders
	sld_beta= Slider(ax_beta, r'$\beta$', 0.1, 10.0, valinit = default_infection.beta)
	sld_gamma = Slider(ax_gamma, r'$\gamma$', 0.1, 10.0, valinit = default_infection.gamma)
	sld_population = Slider(ax_population, 'N', 10.0, 20000.0, valinit = active_N)
	#Buttons
	btn_update = Button(ax_update, 'Apply changes', color = rgb_widget_ax, hovercolor = '0.975')
	btn_saveFig = Button(ax_saveFig, 'Save figure', color = rgb_widget_ax, hovercolor = '0.975')
	btn_saveTimeAx = Button(ax_saveTimeAx, 'Save time series', color = rgb_widget_ax, hovercolor = '0.975')
	btn_savePhaseAx = Button(ax_savePhaseAx, 'Save phase plane', color = rgb_widget_ax, hovercolor = '0.975')
	#Instructions
	txt_instructions = fig.text(0.1, 0.9,
	"""Click a point from the arrow region on the $\it{Phase \: plane}$ to select a starting population.\nThe simulation graph will appear on the left.""")

	#Functions
	def updateQuiver(N, infection):
		global quiv_phase
		#Generate new flow field quiver
		samplesS = np.linspace(0, N, 15)
		samplesI = np.linspace(0, N, 15)
		fieldS, fieldI = np.meshgrid(samplesS, samplesI)
		flowFieldS = -(infection.beta / N) * fieldS * fieldI
		flowFieldR = infection.gamma * fieldI
		flowFieldI = - flowFieldS - flowFieldR
		#Set invalid states (S + I > N) to zero
		flowFieldS = np.flip(np.tril(np.flip(flowFieldS, axis = 0), k = 0), axis = 0)
		flowFieldI = np.flip(np.tril(np.flip(flowFieldI, axis = 0), k = 0), axis = 0)
		#Generate transfer rate field (for colour mapping)
		rateField = np.abs(flowFieldS) + np.abs(flowFieldR)
		#Rescale flow fields to improve arrow sizing
		magnitudeField = np.hypot(flowFieldS, flowFieldI)
		targetMagnitudeField = np.log(magnitudeField + 1)
		scaleFactorField = np.divide(targetMagnitudeField, magnitudeField, out=np.zeros_like(targetMagnitudeField), where=(magnitudeField!=0))
		flowFieldS *= scaleFactorField
		flowFieldI *= scaleFactorField
		#Plot quiver
		quiv_phase.remove()
		quiv_phase = ax_phase.quiver(fieldS, fieldI, flowFieldS, flowFieldI, rateField, pivot = 'tail', scale_units = 'xy')

	def updateTimeSeries(model): #Update time series data
		global line_S, line_I, line_R, line_phase
		#Get data
		tsd = model.time_series_data
		t = tsd.t_series
		S = tsd.S_series
		I = tsd.I_series
		R = tsd.R_series
		#Plot data
		line_S.set_data(t, S)
		line_I.set_data(t, I)
		line_R.set_data(t, R)
		#Set time domain
		ax_time.set_xlim(0, model.meta_data.duration)
		#Line solution in phase space
		line_phase.set_data(S, I)

	def updateParams(val = None):
		global active_N, active_infection
		global line_phase, line_S, line_I, line_R
		#Update parameters
		active_N = sld_population.val
		active_infection = Infection(beta = sld_beta.val, gamma = sld_gamma.val)
		#Format time series vertical axis
		ax_time.set_ylim(0, active_N)
		#Format phase plane
		ax_phase.set_ylim(0, active_N)
		ax_phase.set_xlim(0, active_N)
		#Remove current quiver & lines
		line_phase.set_data([], [])
		line_S.set_data([], [])
		line_I.set_data([], [])
		line_R.set_data([], [])
		#Update quiver
		updateQuiver(active_N, active_infection)
		#Redraw
		fig.canvas.draw_idle()

	def updateModel(S, I):
		global active_N, active_population, active_infection
		active_population = Population(S = S, I = I, N = active_N)
		active_model = simulate(active_population, active_infection, default_dt, default_max_duration, default_tolerance)
		updateTimeSeries(active_model)
		fig.canvas.draw_idle()

	def onmouserelease(event):
		global active_model
		ex = event.xdata
		ey = event.ydata
		if (event.inaxes == ax_phase):
			if (ex > 0) and (ey > 0) and (0 <= ex + ey <= active_N):
				updateModel(ex, ey)

	def saveFig(event = None):
		t = time.localtime()
		fig.savefig(time.strftime('%Y-%m-%d %H.%M %Z.png', t))

	def saveTimeAx(event = None):
		t = time.localtime()
		extent = ax_time.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
		fig.savefig(time.strftime('%Y-%m-%d %H.%M %Z.png', t), bbox_inches = extent.expanded(1.1, 1.2))

	def savePhaseAx(event = None):
		t = time.localtime()
		extent = ax_phase.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
		fig.savefig(time.strftime('%Y-%m-%d %H.%M %Z.png', t), bbox_inches = extent.expanded(1.1, 1.2))

	#Connect interactivity
	#sld_beta.on_changed(updateParams)
	btn_update.on_clicked(updateParams)
	btn_saveFig.on_clicked(saveFig)
	btn_saveTimeAx.on_clicked(saveTimeAx)
	btn_savePhaseAx.on_clicked(savePhaseAx)
	cid_mouserelease = fig.canvas.mpl_connect('button_release_event', onmouserelease)

	#Initialise model
	updateParams()
	plt.show()


"""
Implementation of Modern Portfolio Theory
Author: Rajan Subramanian
Created May 15 2020
"""

import numpy as np
from typing import List

class ModernPortfolioTheory:
    """Implements Harry Markowitz's Model of mean variance optimization
    Args:
    mu_vec:     represents forecasted means of constituents in portfolio
    sigma_vec:  represents forecasted volatility of constituents in portfolio
    cov_mat:    covariance matrix of constituents in portfolio

    Attributes:
    weights:    proportion of capital allocated to security i
    size:       total number of securities in portfolio
    """
    def __init__(self, mu_vec: List[float], sigma_vec: List[float], cov_mat: List[list[float]]):
        self.mu_vec = np.array(mu_vec)
        self.sigma_vec = np.array(sigma_vec)
        self.cov_mat = cov_mat
        self.weights = np.zeros_like(mu_vec)
        self.size = len(mu_vec)

    def compute_portfolio_mean(self) -> float:
        """Returns the portfolio mean: mup = w'mu"""
        return self.weights.T @ self.mu_vec

    def compute_portfolio_variance(self) -> float:
        """Returns the portfolio variance: w'cov_mat w"""
        return self.weights.T @ self.cov_mat @ self.weights

    def is_spd(self, x) -> bool:
        """Return True if matrix is spd, else False"""
        return all(np.linalg.eigvals(x) > 0)

    def global_minimum_variance(self, mean_constraint: bool = False, target: None) -> np.array:
        """computes weights associated with global minimum variance
           subject to constraint w'I = 1
           if mean constraint is true, then another constraint is added
           w'mu = target
        """
        n = self.size + 1 if mean_constraint is False else self.size + 2
        A = np.zeros((n,n))
        ones = np.ones(self.size)
        b = np.zeros(n)
        A[:self.size,:self.size] = self.covmat*2
        A[-1,:self.size],A[:self.size,-1] = ones, ones
        if mean_constraint is True:
            A[-2,:self.size],A[:self.size,-2] = self.mu_vec.T,self.mu_vec
            b[-2] = target
        b[-1] = 1


import numpy as np

def GaussianElimination(A, B, d=True):
    #forward elimination in (n-1) steps
    '''
      Step like switching rows when pivot becomes
      0 has been ignored and a simple implementation
      has been done :)
    '''
    col = 0
    for i in range(len(A[0])-1):
        for j in range(i, len(A[0])-1):
            div = A[j+1][col]/A[i][col]
            temp = []
            for idx in range(len(A[j+1])):
                temp.append(A[j+1][idx]-A[i][idx]*div)
            A[j+1] = temp
            B[j+1][0] -= (B[i][0]*div)

            if d:
                print('\n---------------')
                print('Matrix A: ')
                print(np.matrix(A))
                print('\nMatrix B: ')
                print(np.matrix(B))
                print('---------------\n')
        col += 1

    ans = []
    loop = len(A[0])-1
    while loop >= 0:
        val = 0
        for i in range(loop+1, len(A[0])):
            val += (A[loop][i]*ans[len(A[0])-1-i])
        ans.append((B[loop][0] - val)/A[loop][loop])
        loop -= 1

    ans.reverse()
    col_mat = np.matrix(ans)
    col_mat = col_mat.T

    return col_mat

var = int(input())

A = []
B = []

for i in range(var):
    val = input().split(' ')
    A.append([float(i) for i in val])

for i in range(var):
    val = float(input())
    B.append([val])

ans = GaussianElimination(A, B)
print('\nThe required answer is: ')
for i in range(var):
    print("%.4f"%ans[i][0])


import numpy as np
import matplotlib.pyplot as plt

# from mpl_toolkits.mplot3d import Axes3D
from matplotlib import rc

# from matplotlib.ticker import AutoMinorLocator
from matplotlib.ticker import MultipleLocator

# import bspline_polynomial as bp
# import ptg.bspline_polynomial as bp
import ptg.bspline_basis_manual as bp

# (siblenv) [~/sibl/geo/doc] python plot_bspline_basis_manual.py

DEGREE = 2  # e.g., p=0 constant, p=1 linear, p=2 quadratic (max degree currently 2)
DISPLAY = 1
DPI = 100  # dots per inch
LATEX = 0
SERIALIZE = 0
VERBOSE = 0

if LATEX:
    rc("font", **{"family": "serif", "serif": ["Computer Modern Roman"]})
    rc("text", usetex=True)

# number of time intervals per knot
# nti = 2 ** 1  # for minimal interpolation
# nti = 2 ** 2  # for quarter-unit interpolation
nti = 2 ** 5  # for LaTeX figures

# knot_vector = [0, 1, 2]
knot_vector = [0, 1, 2, 3, 4, 5, 6]

print(f"Computing B-spline bases with degree p={DEGREE}")
print(f"with knot vector {knot_vector} and ")
print(f"with number of time intervals (per knot span) nti={nti}")

num_knots = len(knot_vector)
for k in np.arange(num_knots - 1 - DEGREE):

    t, y = bp.bspline_basis_manual(knot_vector, k, DEGREE, nti, VERBOSE)

    if VERBOSE:
        print(f"t={t}")
        print(f"y = {y}")

    # fig = plt.figure(figsize=plt.figaspect(1.0), dpi=DPI)
    # fig = plt.figure(dpi=DPI)
    fig = plt.figure(figsize=plt.figaspect(1.0 / (len(knot_vector) - 1)), dpi=DPI)
    ax = fig.gca()
    # ax.grid()
    ax.grid(True, which="major", linestyle="-")
    ax.grid(True, which="minor", linestyle=":")
    # ax.scatter(t, y)
    ax.plot(t, y, linestyle="None", marker=".")

    # # if k == len(knot_vector) - 2:
    # if k in [2, 5]:  # plot three per page, over two pages
    #     # stack all figures in documentation, x-axis only on
    #     # last figure, which will be on the bottom of the stack
    #     ax.set_xlabel(r"$t$")
    # else:
    #     # suppress x-ticks except for on the bottom plot
    #     plt.setp(ax.get_xticklabels(), visible=False)

    ax.set_xlabel(r"$t$")
    ax.set_ylabel(r"$N^{" + str(DEGREE) + "}_{" + str(k) + "}(t)$")

    eps = 0.1
    ax.set_xlim([knot_vector[0] - 2 * eps, knot_vector[-1] + 2 * eps])
    ax.set_ylim([0 - 2 * eps, 1 + 2 * eps])
    ax.set_aspect("equal")
    ax.xaxis.set_major_locator(MultipleLocator(1.0))
    ax.xaxis.set_minor_locator(MultipleLocator(0.25))
    ax.yaxis.set_major_locator(MultipleLocator(1.0))
    ax.yaxis.set_minor_locator(MultipleLocator(0.25))

    if DISPLAY:
        plt.show()

    if SERIALIZE:
        extension = ".pdf"  # or '.svg'
        bstring = "N(p=" + str(DEGREE) + ")_" + str(k) + extension
        # fig.savefig(bstring, bbox_inches="tight")
        fig.savefig(bstring, bbox_inches="tight", pad_inches=0)


import numpy as np
import matplotlib.pyplot as plt

# input
u = 40 # initial velocity in m/s
g = 9.81 # gravitational acceleration m/s^2

theta1 = 45 # angle of projectile
theta2 = 60 # angle of projectile

ux1 = u*np.cos(theta1*np.pi/180) # velocity in x direction
uy1 = u*np.sin(theta1*np.pi/180) # velocity in y direction

ux2  = u*np.cos(theta2*np.pi/180) # velocity in x direction
uy2 = u*np.sin(theta2*np.pi/180) # velocity in y direction

t_total_1 = 2*uy1/g
t_total_2 = 2*uy2/g

t1 = np.linspace(0,t_total_1,100)
t2 = np.linspace(0,t_total_2,100)

x1 = ux1*t1
y1 = (uy1*t1)-(0.5*g*t1**2)

x2 = ux2*t2
y2= (uy2*t2)-(0.5*g*t2**2)

plt.figure(figsize=(10,7)) # set graph size
plt.margins(x=0) # set x axis margin
plt.title('Projectile motion')
plt.plot(x1,y1,label = r'$\theta$ = 45$\degree$')
plt.plot(x2,y2,label = r'$\theta$ = 60$\degree$',color='red')
plt.legend()
plt.show()

# https://www.udemy.com/user/shriram-s-kakade/


# _*_coding:utf-8-*_
import numpy as np
# 定义矩阵变量并输出变量的一些属性
# 用np.array()生成矩阵
arr=np.array([[1,2,3],
              [4,5,6]])

print(arr)
print('number of arr dimensions: ',arr.ndim)
print('~    ~    ~   shape: ',arr.shape)
print('~    ~    ~   size: ', arr.size)

# 输出结果：
[[1 2 3]
 [4 5 6]]
number of arr dimensions:  2
~    ~    ~   shape:  (2, 3)
~    ~    ~   size:  6

# 定义一些特殊矩阵
# 指定矩阵数据类型
arr=np.array([[1,2,3],
              [4,5,6]],
              dtype=np.float64) # 我的电脑np.int是int32，还可以使用np.int32/np.int64/np.float32/np.float64
print(arr.dtype)

# 用np.zeros()生成全零矩阵
arr_zeros=np.zeros( (2,3) )
print(arr_zeros)

# 用np.ones()生成全一矩阵
arr_ones=np.ones( (2,3) )
print(arr_ones)

# 生成随机矩阵np.random.random()
arr_random=np.random.random((2,3))
print(arr_random)

# 用np.arange()生成数列
arr=np.arange(6,12)
print(arr)

# 用np.arange().reshape()将数列转成矩阵
arr=np.arange(6,12).reshape( (2,3) )
print(arr)

# 用np.linspace(开始，结束，多少点划分线段)，同样也可以用reshape()
arr=np.linspace(1,5,3)
print(arr)

# 矩阵运算
arr1=np.array([1,2,3,6])
arr2=np.arange(4)

# 矩阵减法，加法同理
arr_sub=arr1-arr2
print(arr1)
print(arr2)
print(arr_sub)

# 矩阵乘法
arr_multi=arr1**3 # 求每个元素的立方，在python中幂运算用**来表示
print(arr_multi)

arr_multi=arr1*arr2 # 元素逐个相乘
print(arr_multi)

arr_multi=np.dot(arr1, arr2.reshape((4,1))) # 维度1*4和4*1矩阵相乘
print(arr_multi)

arr_multi=np.dot(arr1.reshape((4,1)), arr2.reshape((1,4))) # 维度4*1和1*4矩阵相乘
print(arr_multi)

arr_multi=arr1.dot(arr2.reshape((4,1))) # 也可以使用矩阵名.doc(矩阵名)
print(arr_multi)

# 三角运算：np.sin()/np.cos()/np.tan()
arr_sin=np.sin(arr1)
print(arr_sin)

# 逻辑运算
print(arr1<3) # 查看arr1矩阵中哪些元素小于3，返回[ True  True False False]

# 矩阵求和，求矩阵最大最小值
arr1=np.array([[1,2,3],
               [4,5,6]])
print(arr1)
print(np.sum(arr1)) # 矩阵求和
print(np.sum(arr1,axis=0)) # 矩阵每列求和
print(np.sum(arr1,axis=1).reshape(2,1)) # 矩阵每行求和

print(np.min(arr1)) # 求矩阵最小值
print(np.min(arr1,axis=0))
print(np.min(arr1,axis=1))

print(np.max(arr1)) # 求矩阵最大值

print(np.mean(arr1)) # 输出矩阵平均值，也可以用arr1.mean()
print(np.median(arr1)) # 输出矩阵中位数

# 输出矩阵某些值的位置
arr1=np.arange(2,14).reshape((3,4))
print(arr1)

print(np.argmin(arr1)) # 输出矩阵最小值的位置，0
print(np.argmax(arr1)) # 输出矩阵最大值的位置，11

print(np.cumsum(arr1)) # 输出前一个数的和，前两个数的和，等等
print(np.diff(arr1)) # 输出相邻两个数的差值

arr_zeros=np.zeros((3,4))
print(np.nonzero(arr_zeros)) #输出矩阵非零元素位置，返回多个行向量，第i个行向量表示第i个维度
print(np.nonzero(arr1))

print(np.sort(arr1)) # 矩阵逐行排序
print(np.transpose(arr1)) # 矩阵转置，也可以用arr1.T

print(np.clip(arr1,5,9)) #将矩阵中小于5的数置5，大于9的数置9

# numpy索引
arr1=np.array([1,2,3,6])
arr2=np.arange(2,8).reshape(2,3)

print(arr1)
print(arr1[0]) # 索引从0开始计数

print(arr2)
print(arr2[0][2]) # arr[行][列]，也可以用arr[行,列]
print(arr2[0,:]) # 用:来代表所有元素的意思
print(arr2[0,0:3]) # 表示输出第0行，从第0列到第2列所有元素
                   # 注意python索引一般是左闭右开

# 通过for循环每次输出矩阵的一行
for row in arr2:
    print(row)

# 如果要每次输出矩阵的一列，就先将矩阵转置
arr2_T=arr2.T
print(arr2_T)
for row in arr2_T:
    print(row)

# 将矩阵压成一行逐个输出元素
arr2_flat=arr2.flatten()
print(arr2_flat)

for i in arr2.flat: # 也可以用arr2.flatten()
    print(i)

# 矩阵合并与分割
# 矩阵合并
arr1=np.array([1,2,3,6])
arr2=np.arange(4)
arr3=np.arange(2,16+1,2).reshape(2,4)
print(arr1)
print(arr2)
print(arr3)

arr_hor=np.hstack((arr1,arr2)) # 水平合并，horizontal
arr_ver=np.vstack((arr1,arr3)) # 垂直合并，vertical
print(arr_hor)
print(arr_ver)

# 矩阵分割
print('arr3: ',arr3)
print(np.split(arr3,4,axis=1)) # 将矩阵按列均分成4块
print(np.split(arr3,2,axis=0)) # 将矩阵按行均分成2块
print(np.hsplit(arr3,4)) # 将矩阵按列均分成4块
print(np.vsplit(arr3,2)) # 将矩阵按行均分成2块
print(np.array_split(arr3,3,axis=1)) # 将矩阵进行不均等划分

# numpy复制：浅复制，深复制
# 浅复制
arr1=np.array([3,1,2,3])
print(arr1)
a1=arr1
b1=a1
# 通过上述赋值运算，arr1,a1,b1都指向了同一个地址（浅复制）
print(a1 is arr1)
print(b1 is arr1)
print(id(a1))
print(id(b1))
print(id(arr1))

# 会发现通过b1[0]改变内容，arr1,a1,b1的内容都改变了
b1[0]=6
print(b1)
print(a1)
print(arr1)

# 深复制
arr2=np.array([3,1,2,3])
print('\n')
print(arr2)
b2=arr2.copy() # 深复制，此时b2拥有不同于arr2的空间
a2=b2.copy()
# 通过上述赋值运算，arr1,a1,b1都指向了不同的地址（深复制）
print(id(arr2))
print(id(a2))
print(id(b2))
# 此时改变b2,a2的值，互不影响
b2[0]=1
a2[0]=2
print(b2)
print(a2)
print(arr2)

# 线性代数模块（linalg）
# 求范数
a=np.array([5,12])
print(a)
b=np.linalg.norm(a) # norm表示范数，默认求2范数，ord=1求1范数，ord=np.inf求无穷范数
print(b)

# 求矩阵的迹、行列式、秩、特征值、特征向量
b = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(np.trace(b))      # 15，求矩阵的迹（主对角线上各个元素的总和）

c=np.linalg.det(b)
print(c)                # 输出一个很小的值6.66133814775e-16，求矩阵的行列式值
                        # 如果希望输出为0，使用round(c, 2)，四舍五入保留小数点后两位
                        # 不过对精度要求高可以使用decimal模块

c=np.linalg.matrix_rank(b)
print(c)                # 2，求矩阵的秩

u,v=np.linalg.eig(b) # u为特征值
print(u)
print(v)

# 矩阵分解
# Cholesky分解并重建
d = np.array([
    [2, 1],
    [1, 2]
])

l = np.linalg.cholesky(d)
print(l) # 得到下三角矩阵
e=np.dot(l, l.T)
print(e) # 重建得到矩阵d

# 对不正定矩阵，进行SVD分解并重建
U, s, V = np.linalg.svd(d)

S = np.array([
    [s[0], 0],
    [0, s[1]]
])

print(np.dot(U, np.dot(S, V))) # 重建得到矩阵d

# 矩阵乘法
# https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html#numpy.dot
print(np.dot(3, 4)) # 12，0-D矩阵相乘（也就是标量相乘）

print(np.dot([2j, 3j], [2j, 3j])) # (-13+0j)，1-D矩阵相乘（实际上是向量做点积）

a=[[1, 0], [0, 1]]
b=[[4, 1, 0], [2, 2, 0]]
print(np.dot(a, b))
'''
array([[4, 1],
    [2, 2]])
2-D矩阵相乘
这里是2*2矩阵和2*3矩阵相乘，结果为2*3矩阵
'''

a=[[1, 0], [1, 2]]
b=[2,2]
c=np.dot(a,b)
print(c)
'''
[2 6]
注意这里b是向量
numpy处理时并不是按照矩阵乘法规则计算
而是向量点积
也就是np.dot([1, 0],[1, 2])和np.dot([1, 2],[2,2])
'''

# 再做个实验来区别向量乘法和矩阵乘法
b=np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

# 这里插播一下，np.array([1,0,1])是3维向量，而不是1*3的矩阵
c1=np.array([[1,0,2]])
print(c1.shape) # (1, 3)，这是一个1*3的矩阵
c2=np.array([1,0,2])
print(c2.shape) # (3,)，这是一个3维向量

# print(np.dot(b,c1)) # 报错，不符合矩阵乘法规则
print(np.dot(b,c2)) # [ 7 16 25]，点积运算

print(np.dot(c1,b)) # [[15 18 21]]，矩阵乘法运算规则
print(np.dot(c2,b)) # [15 18 21]，点积运算

# 还要补充一下，如果是用python自带的*运算符计算则是广播机制
print(b*c1) # print(b*c2)结果一样
'''
[[ 1  0  6]
 [ 4  0 12]
 [ 7  0 18]]
'''
print(b+c1) # print(b*c2)结果一样
'''
[[ 2  2  5]
 [ 5  5  8]
 [ 8  8 11]]
'''


"""
File: MCint_class.py
Exercise 9.14
Copyright (c) 2016 Andrew Malfavon
License: MIT
Description:
"""

import numpy as np
import random

class Integrator(object):
    def __init__(self, a, b, n):
        self.a, self.b, self.n = a, b, n
        self.points, self.weights = self.construct_method()

    def construct_method(self):
        raise NotImplementedError('no rule in class %s' %
                                  self.__class__.__name__)

    def integrate(self, f):
        s = 0
        for i in range(len(self.weights)):
            s += self.weights[i]*f(self.points[i])
        return s

    def vectorized_integrate(self, f):
        return dot(self.weights, f(self.points))

class Midpoint(Integrator):
    def construct_method(self):
        a, b, n = self.a, self.b, self.n # quick forms
        h = (b-a)/float(n)
        x = linspace(a + 0.5*h, b - 0.5*h, n)
        w = zeros(len(x)) + h
        return x, w

class Trapezoidal(Integrator):
    def construct_method(self):
        x = linspace(self.a, self.b, self.n)
        h = (self.b - self.a)/float(self.n - 1)
        w = zeros(len(x)) + h
        w[0] /= 2
        w[-1] /= 2
        return x, w

class Simpson(Integrator):
    def construct_method(self):
        if self.n % 2 != 1:
            print 'n=%d must be odd, 1 is added' % self.n
            self.n += 1
        x = linspace(self.a, self.b, self.n)
        h = (self.b - self.a)/float(self.n - 1)*2
        w = zeros(len(x))
        w[0:self.n:2] = h*1.0/3
        w[1:self.n-1:2] = h*2.0/3
        w[0] /= 2
        w[-1] /= 2
        return x, w

class GaussLegendre2(Integrator):
    def construct_method(self):
        if self.n % 2 != 0:
            print 'n=%d must be even, 1 is subtracted' % self.n
            self.n -= 1
        nintervals = int(self.n/2.0)
        h = (self.b - self.a)/float(nintervals)
        x = zeros(self.n)
        sqrt3 = 1.0/sqrt(3)
        for i in range(nintervals):
            x[2*i] = self.a + (i+0.5)*h - 0.5*sqrt3*h
            x[2*i+1] = self.a + (i+0.5)*h + 0.5*sqrt3*h
        w = zeros(len(x)) + h/2.0
        return x, w

class MCint_vec(Integrator):
    def construct_method(self):
        h = float(self.b - self.a) / self.n
        x = np.random.uniform(self.a, self.b, self.n)
        w = np.zeros(len(x)) + h
        return x, w

def example_func(x):
    return (8 * x**3) + (3 * x**2) +(4 * x)

def func_integrate(x):
    return (2 * x**4) + (x**3) +(2 * x**2)

def test_Mcint_vec():
    #the exact error is dependent on values selected during np.random
    example_exact = (func_integrate(3) - func_integrate(2))
    assert abs(MCint_vec(2, 3, 1000000).integrate(example_func) - example_exact) < 0.1
    assert abs(MCint_vec(0, np.pi, 1000000).integrate(np.cos)) < 0.01
    assert abs(MCint_vec(0, np.pi, 1000000).integrate(np.sin) - 2.0) < 0.01


import numpy as np
import matplotlib.pyplot as plt

N = 100
X = np.linspace(0, 6*np.pi, N)
Y = np.sin(X)

plt.plot(X, Y)
plt.show()

def create_poly(X, deg):
    n = len(X)
    data = [np.ones(n)]
    for d in range(deg):
        data.append(X**(d+1))
    return np.vstack(data).T

def fit(X, Y):
    return np.linalg.solve(X.T.dot(X), X.T.dot(Y))

def fit_and_display(X, Y, sample, deg):
    N = len(X)
    train_idx = np.random.choice(N, sample)
    Xtrain = X[train_idx]
    Ytrain = Y[train_idx]

    plt.scatter(Xtrain, Ytrain)
    plt.show()

    # fit polynomial
    Xtrain_poly = create_poly(Xtrain, deg)
    w = fit(Xtrain_poly, Ytrain)

    # display polynomial
    X_poly = create_poly(X, deg)
    Y_hat = X_poly.dot(w)
    plt.plot(X, Y)
    plt.plot(X, Y_hat)
    plt.scatter(Xtrain, Ytrain)
    # plt.title("deg = %d", deg)
    plt.show()

for deg in (5, 6, 7, 8, 9):
    fit_and_display(X, Y, 50, deg)

def calc_mse(Y, Yhat):
    d = Y - Yhat
    return d.dot(d) / len(d)

def plt_train_vs_test_curves(X, Y, sample=20, max_deg=20):
    N = len(X)
    train_idx = np.random.choice(N, sample)
    Xtrain = X[train_idx]
    Ytrain = Y[train_idx]

    test_idx = [idx for idx in range(N) if idx is not train_idx]
    Xtest = X[test_idx]
    Ytest = Y[test_idx]

    mse_trains = []
    mse_tests = []
    for deg in range(max_deg + 1):
        Xtrain_poly = create_poly(Xtrain, deg)
        w = fit(Xtrain_poly, Ytrain)
        Yhat_train = Xtrain_poly.dot(w)
        mse_train = calc_mse(Ytrain, Yhat_train)

        Xtest_poly = create_poly(Xtest, deg)
        Yhat_test = Xtest_poly.dot(w)
        mse_test = calc_mse(Ytest, Yhat_test)

        mse_trains.append(mse_train)
        mse_tests.append(mse_test)

    plt.plot(mse_trains, label="train mse")
    plt.plot(mse_tests, label="test mse")
    plt.legend()
    plt.show()

    plt.plot(mse_trains, label="train mse")
    plt.legend()
    plt.show()

if __name__ == "__main__":
    # make up some data and plot it
    N = 100
    X = np.linspace(0, 6 * np.pi, N)
    Y = np.sin(X)

    plt.plot(X, Y)
    plt.show()

    for deg in (5, 6, 7, 8, 9):
        fit_and_display(X, Y, 50, deg)
    plt_train_vs_test_curves(X, Y)


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

%matplotlib inline
plt.rcParams['figure.figsize'] = (5.0, 4.0)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'

%load_ext autoreload
%autoreload 2

def zero_pad(X, pad):
    X_pad = np.pad(X, ((0,0) , (pad,pad) , (pad,pad) , (0,0)), 'constant'  )
    return X_pad

x = np.random.randn(4, 3, 3, 2)
x_pad = zero_pad(x, 2)
print ("x.shape =", x.shape)
print ("x_pad.shape =", x_pad.shape)
print ("x[1,1] =", x[1,1])
print ("x_pad[1,1] =", x_pad[1,1])

fig, axarr = plt.subplots(1, 2)
axarr[0].set_title('x')
axarr[0].imshow(x[0,:,:,0])
axarr[1].set_title('x_pad')
axarr[1].imshow(x_pad[0,:,:,0])

def conv_single_step(a_slice_prev, W, b):
    s = W * a_slice_prev
    Z = np.sum(s)
    Z = Z +b
    return Z

a_slice_prev = np.random.randn(4, 4, 3)
W = np.random.randn(4, 4, 3)
b = np.random.randn(1, 1, 1)

Z = conv_single_step(a_slice_prev, W, b)
print("Z =", Z)

def conv_forward(A_prev, W, b, hparameters):
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    (f, f, n_C_prev, n_C) = W.shape
    stride = hparameters["stride"]
    pad = hparameters["pad"]
    n_H = np.int((n_H_prev - f + (2 * pad))/stride) + 1
    n_W = np.int((n_W_prev - f + (2 * pad))/stride) + 1
    Z = np.zeros((m, n_H , n_W , n_C))
    A_prev_pad = zero_pad(A_prev, pad)
    for i in range(m):
        a_prev_pad = A_prev_pad[i , : , : , :]
        for h in range(n_H):
            for w in range(n_W):
                for c in range(n_C):
                    vert_start = h*stride
                    vert_end = h*stride+ f
                    horiz_start = w*stride
                    horiz_end = w*stride + f
                    a_slice_prev = a_prev_pad[vert_start : vert_end , horiz_start : horiz_end]
                    Z[i, h, w, c] = np.sum(np.multiply(a_slice_prev ,W[:,:,:,c])) + b[0,0,0,c]
    cache = (A_prev, W, b, hparameters)
    return Z, cache
np.random.seed(1)
A_prev = np.random.randn(10,4,4,3)
W = np.random.randn(2,2,3,8)
b = np.random.randn(1,1,1,8)
hparameters = {"pad" : 2,
               "stride": 2}

Z, cache_conv = conv_forward(A_prev, W, b, hparameters)
print("Z's mean =", np.mean(Z))
print("Z[3,2,1] =", Z[3,2,1])
print("cache_conv[0][1][2][3] =", cache_conv[0][1][2][3])
def pool_forward(A_prev, hparameters, mode = "max"):
    (m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
    f = hparameters["f"]
    stride = hparameters["stride"]
    n_H = int(1 + (n_H_prev - f) / stride)
    n_W = int(1 + (n_W_prev - f) / stride)
    n_C = n_C_prev
    A = np.zeros((m, n_H, n_W, n_C))
    for i in range(m):
        for h in range(n_H):
            for w in range(n_W):
                for c in range (n_C):
                    vert_start = h*stride
                    vert_end = h*stride + f
                    horiz_start = w*stride
                    horiz_end = w*stride + f
                    a_prev_slice = A_prev[i,vert_start : vert_end , horiz_start : horiz_end , c]
                    if mode == "max":
                        A[i, h, w, c] = np.max(a_prev_slice)
                    elif mode == "average":
                        A[i, h, w, c] = np.mean(a_prev_slice)
    cache = (A_prev, hparameters)
    return A, cache
np.random.seed(1)
A_prev = np.random.randn(2, 4, 4, 3)
hparameters = {"stride" : 2, "f": 3}

A, cache = pool_forward(A_prev, hparameters)
print("mode = max")
print("A =", A)
print()
A, cache = pool_forward(A_prev, hparameters, mode = "average")
print("mode = average")
print("A =", A)

def conv_backward(dZ, cache):
    (A_prev, W, b, hparameters) = None
    (m, n_H_prev, n_W_prev, n_C_prev) = None
    (f, f, n_C_prev, n_C) = None
    stride = None
    pad = None
    (m, n_H, n_W, n_C) = None
    dA_prev = None
    dW = None
    db = None
    A_prev_pad = None
    dA_prev_pad = None

    for i in range(None):
        a_prev_pad = None
        da_prev_pad = None
        for h in range(None):
            for w in range(None):
                for c in range(None):
                    vert_start = None
                    vert_end = None
                    horiz_start = None
                    horiz_end = None
                    a_slice = None
                    da_prev_pad[vert_start:vert_end, horiz_start:horiz_end, :] += None
                    dW[:,:,:,c] += None
                    db[:,:,:,c] += None
        dA_prev[i, :, :, :] = None
    return dA_prev, dW, db

np.random.seed(1)
dA, dW, db = conv_backward(Z, cache_conv)
print("dA_mean =", np.mean(dA))
print("dW_mean =", np.mean(dW))
print("db_mean =", np.mean(db))

def create_mask_from_window(x):
    mask = (x == np.max(x))
    return mask
np.random.seed(1)
x = np.random.randn(2,3)
mask = create_mask_from_window(x)
print('x = ', x)
print("mask = ", mask)

def distribute_value(dz, shape):
    (n_H, n_W) = None
    average = None
    a = None
    return a
a = distribute_value(2, (2,2))
print('distributed value =', a)

def pool_backward(dA, cache, mode = "max"):
    (A_prev, hparameters) = None
    stride = None
    f = None
    m, n_H_prev, n_W_prev, n_C_prev = None
    m, n_H, n_W, n_C = None
    dA_prev = None

    for i in range(None):
        a_prev = None
        for h in range(None):
            for w in range(None):
                for c in range(None):
                    vert_start = None
                    vert_end = None
                    horiz_start = None
                    horiz_end = None
                    if mode == "max":
                        a_prev_slice = None
                        mask = None
                        dA_prev[i, vert_start: vert_end, horiz_start: horiz_end, c] += None
                    elif mode == "average":
                        da = None
                        shape = None
                        dA_prev[i, vert_start: vert_end, horiz_start: horiz_end, c] += None
    return dA_prev
    np.random.seed(1)
A_prev = np.random.randn(5, 5, 3, 2)
hparameters = {"stride" : 1, "f": 2}
A, cache = pool_forward(A_prev, hparameters)
dA = np.random.randn(5, 4, 2, 2)

dA_prev = pool_backward(dA, cache, mode = "max")
print("mode = max")
print('mean of dA = ', np.mean(dA))
print('dA_prev[1,1] = ', dA_prev[1,1])
print()
dA_prev = pool_backward(dA, cache, mode = "average")
print("mode = average")
print('mean of dA = ', np.mean(dA))
print('dA_prev[1,1] = ', dA_prev[1,1])


import random
import time
import numpy as np

MAT_SIZE = 800

def multiply_matrices(mat_one, mat_two):
    if len(mat_one) == len(mat_two) and len(mat_one[0]) == len(mat_two[0]):
        new_mat = np.zeros((len(mat_one), len(mat_one[0])), dtype=float)
        new_mat = np.dot(mat_one, mat_two)
        return new_mat
    else:
        return None

def show_sub_square(matrix, start, size):
    for row in range(start, start + size):
        print('  '.join(['%.2f' % float(matrix[row, col])
                         for col in range(start, start + size)]))

def main():
    matrix = np.zeros((MAT_SIZE, MAT_SIZE), dtype=float)
    # generate small fraction of non-default values between 0 and 1
    small_fraction = round(MAT_SIZE * MAT_SIZE * .01)
    # small_fraction = 7 # This value is editable to remove more Zero values

    for i in range(small_fraction):
        row = random.randint(0, (MAT_SIZE - 1))
        col = random.randint(0, (MAT_SIZE - 1))
        value = random.uniform(0, 1)
        matrix[row, col] = value

    print("Matrix to Square: ")
    show_sub_square(matrix, 0, MAT_SIZE)

    start_time = time.perf_counter()
    new_mat = multiply_matrices(matrix, matrix)

    stop_time = time.perf_counter()
    elapsed = stop_time - start_time
    print("Product:")
    show_sub_square(new_mat, 0, MAT_SIZE)
    print("Calculation time:", elapsed, "seconds")

if __name__ == "__main__":
    main()

# MAT_SIZE | TIME
#    5     | 6.279999999997399e-05 seconds
#   10     | 5.070000000001462e-05 seconds
#   20     | 5.1499999999982116e-05 seconds
#   40     | 7.719999999999949e-05 seconds
#   80     | 0.0003721999999999892 seconds
#   100    | 0.0004270000000000107 seconds
#   140    | 0.000695100000000004 seconds
#   200    | 0.0013534000000000046 seconds
#   400    | 0.0044208000000000025 seconds
#   800    | 0.036617200000000016 seconds


# -*- coding: utf-8 -*-
"""
Linear regression using the deviated randomly linear dependency (y(x) = a*x + b)
Developed in the Spyder IDE using Kite

@author: ssklykov
"""
# %% Import section
from SampleValues import GenerateSample
import numpy as np
from ComparisonLinPlots import PlotWErrTwo
# %% Controlling / modelling values
a = 2; b = 1 # From dependency y(x) = a*x + b
n = 10  # number of sampling points (modelling measures from some awesome experiment)
nDigits = 2  # Precision of calculation / rounding
percentError = 30  # An error controlling deviations in generated values [%]
xMin = 0; xMax = 5  # Controlling minimal and maximal values from an interval [a,b]
nSamples = 11  # 10 + 1 samples, specify always in this manner, because np.linspace(a,b,n) - including "a" from the interval

# %% Generating the sample values - from a linear dependency
values = GenerateSample(a, b, xMin, xMax, nSamples, percentError, nDigits)
(x, yMean, yStD) = values.generateSampleValues()

# %% Linear Regression
def LinearRegression(x, yMean, yStD, nDigits):
    # Interim values calculation from the book (Sx, Sxx, etc)
    S = 0.0; Sx = 0.0; Sxx = 0.0; Sy = 0.0; Sxy = 0.0; sigma2 = 0.0;
    aRegressed = 0; bRegressed = 0
    for i in range(len(x)):
        sigma2 = 1 / pow(yStD[i], 2)
        S += sigma2; Sx += x[i]*sigma2; Sy += yMean[i]*sigma2
        Sxx += pow(x[i], 2)*sigma2; Sxy += (x[i]*yMean[i])*sigma2
    delta = (S*Sxx) - pow(Sx, 2)
    if (delta != 0):
        aRegressed = (S*Sxy - Sx*Sy)/delta; bRegressed = (Sy*Sxx - Sx*Sxy)/delta
        aRegressed = round(aRegressed, nDigits); bRegressed = round(bRegressed,nDigits)
    return (aRegressed, bRegressed)

# %% Regression evaluation
(aR, bR) = LinearRegression(x, yMean, yStD, nDigits)

# %% Plotting
# Generation of arrays for plotting
nRegressed = (nSamples-1)*10 + 1  # For plotting - calculation in 10 times more points between specified interval [xMin,xMax]
xRegressed = np.linspace(xMin, xMax, nRegressed)
yRegressed = np.zeros(nRegressed)
for i in range(nRegressed):
    yRegressed[i] = aR*xRegressed[i] + bR
# Plot
PlotWErrTwo(x, yMean, yStD, xRegressed, yRegressed, "Linear Regression results")


"""
Low-level multichoose
"""
#*****************************************************************************
#       Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>
#
#  Distributed under the terms of the GNU General Public License (GPL)
#
#    This code is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    General Public License for more details.
#
#  The full text of the GPL is available at:
#
#                  http://www.gnu.org/licenses/
#*****************************************************************************
from combinat import CombinatorialClass
from sage.rings.arith import binomial
import sage.misc.prandom as rnd

class MultichooseNK(CombinatorialClass):
    def __init__(self, n, k):
        """
        TESTS::

            sage: a = MultichooseNK(3,2)
            sage: a == loads(dumps(a))
            True
        """
        self._n = n
        self._k = k

    def cardinality(self):
        """
        Returns the number of multichoices of k things from a list of n
        things.

        EXAMPLES::

            sage: MultichooseNK(3,2).cardinality()
            6
        """
        n,k = self._n, self._k
        return binomial(n+k-1,k)

    def __iter__(self):
        """
        An iterator for all multichoices of k things from range(n).

        EXAMPLES::

            sage: [c for c in MultichooseNK(3,2)]
            [[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]
        """
        n,k = self._n, self._k
        dif = 0
        if k == 0:
            yield []
            return

        if n < 1+(k-1)*dif:
            return
        else:
            subword = [ i*dif for i in range(k) ]

        yield subword[:]
        finished = False

        while not finished:
            #Find the biggest element that can be increased
            if subword[-1] < n-1:
                subword[-1] += 1
                yield subword[:]
                continue

            finished = True
            for i in reversed(range(k-1)):
                if subword[i]+dif < subword[i+1]:
                    subword[i] += 1
                    #Reset the bigger elements
                    for j in range(1,k-i):
                        subword[i+j] = subword[i]+j*dif
                    yield subword[:]
                    finished = False
                    break

        return

    def random_element(self):
        """
        Returns a random multichoice of k things from range(n).

        EXAMPLES::

            sage: MultichooseNK(5,2).random_element()
            [0, 2]
            sage: MultichooseNK(5,2).random_element()
            [0, 1]
        """
        n,k = self._n, self._k
        rng = range(n)
        r = []
        for i in range(k):
            r.append( rnd.choice(rng))

        r.sort()
        return r


"""
# Multivariate Linear Regression Algorithm

### This is the file finally submitted for Assignment 3 for a multivarite linear regression algorithm. Note a few things:
    - this runs with python 3.6
    - it had to be adjusted to pandas 0.23.0 because Vocareum uses python 3.6
    - a version of this file working fine in python 3.7 and associated most up to date versions of numpy and pandas can be found at:
    [AI-PerceptronLearningAlgorithm-A3\py37\problem2.py]
    - also for running the file in Vocareum the paths to the input.csv and output.csv files was amended to match, again refer to the version of this file
    for python 3.7 for complete paths that will work with this repository.

# Execution
## $ python3 problem2.py input2.csv output2.csv
### This should generate an output file called output2.csv. The outputs file shall include ten cases in total, ten with the specified learning rates (and 100 iterations), the last learning rate being one of my own choice. After each of these ten runs, the program prints a new line to the output file, containing a comma-separated list of alpha, number_of_iterations, b_0, b_age, and b_weight in that order. These represent the regression models that the gradient descents have computed for the given dataset.
"""

# builtin modules
import os
import psutil
import requests
import sys
import math

# 3rd party modules
import pandas as pd
import numpy as np
#import plotly.graph_objects as go

# Prepare data

def get_data(source_file):

# Define input and output filepaths
    input_path = os.path.join(os.getcwd(), source_file)

    # Read input data
    df = pd.read_csv(input_path)

    for col in df.columns:
        df[col] = (df[col] - np.mean(df[col]))/np.std(df[col])
        #note: numpy.std returns the population standard deviation
    return df

def gradient_descent(df, iterations:int = 100, learning_rates = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10, 0.02]):

    """
    X:dataframe of feature columns: age and weight
    y: dataframe of label column: height
    beta:
    learning_rate:
    iterations:
    """
    df = pd.concat([pd.Series(1, index=df.index, name='b_0'), df], axis=1)

    X = df[df.columns[0:3]].values

    y = df[df.columns[3]].values

    m = y.shape[0]
    betas = np.zeros(X.shape[1]) #initialize betas as zeros, e.g. array([0., 0., 0.])
    betas_new =[]

    for alfa in learning_rates:
        i = 0
        while i < iterations:
            hypothesis = np.dot(X, betas)
            betas = betas - (1/m) * alfa *(X.T.dot((hypothesis - y)))
            i += 1
        betas_new.append(betas)

    return betas_new

def write_csv(filename, betas_new, iterations:int = 100, learning_rates = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10, 0.02]):
        # write the outputs csv file
        filepath = os.path.join(os.getcwd(), filename)
        iter_array = np.full(len(learning_rates), iterations)
        df_iter = pd.DataFrame(iter_array)
        df_lr = pd.DataFrame(learning_rates)
        df_b = pd.DataFrame(betas_new)
        df_final = pd.concat([df_lr, df_iter, df_b], axis = 1, ignore_index = True)
        dataframe = df_final.rename(columns={0:'alpha',1:'number_of_iterations',2:'b_0', 3:'b_age',4:'b_weight'})
        dataframe.to_csv(filepath, index = False, header = False)
        return print("New Outputs file saved to: <<", filename, ">>", sep='', end='\n')

def main():
    """
    ## $ python3 problem2.py input2.csv output2.csv
    """
    #take string for input data csv file
    in_data = str(sys.argv[1])
    #take string for output data csv file
    out_data = str(sys.argv[2])

    df = get_data(in_data)
    betas_new = gradient_descent(df)
    write_csv(out_data, betas_new)
    print(out_data)

if __name__ == '__main__':
    main()


import numpy as np
from numba import jit
import numpy.typing as npt
from typing import Tuple

class Vector:
    pass

@jit(nopython=True)
def hermite_splines(lambda0: float)->Tuple[float, float, float, float]:
    """Computes the cubic Hermite splines in lambda0
    Inputs: - float: lambda0
    Output: - tuple: cubic Hermite splines evaluated in lambda0"""
    h00 = 2*(lambda0**3) - 3*(lambda0**2) + 1
    h10 = (lambda0**3) - 2*(lambda0**2) + lambda0
    h01 = -2*(lambda0**3) + 3*(lambda0**2)
    h11 = (lambda0**3) - (lambda0**2)
    return (h00, h10, h01, h11)

@jit(nopython=True)
def hermite_interp(x0: float, xk: float, xkn: float, pk: float, pkn: float, mk: float, mkn: float)->float:
    """Returns the interpolated value for x0.
    Inputs: - float: x0, abscissa of the point to interpolate
            - float: xk, abscissa of the nearest lowest point to x0 on the grid
            - float: xkn, abscissa of the nearest largest point to x0 on the grid
            - float: pk, value associated to xk
            - float: pkn, value associated to xkn
            - float: mk, tangent in xk
            - float: mkn, tangent in xkn
    Output: - float: interpolated value for x0
    """
    t = (x0-xk)/(xkn-xk)
    hsplines = hermite_splines(t)
    return (pk*hsplines[0] + mk*(xkn-xk)*hsplines[1] + pkn*hsplines[2] + mkn*(xkn-xk)*hsplines[3])

@jit(nopython=True)
def HermiteInterpolation(x0: float, x, y, yp):
    """Returns the interpolated value for x0
    Inputs: - float: x0, abscissa of the point to interpolate
            - np.ndarray: x, x-axis grid
            - np.ndarray: y, values of elements in x
            - np.ndarray: yp, tangents of the x elements
    Output: - float: interpolated value"""
    ###### Extrapolation case ######
    if x0 <= np.min(x):
        return y[0]
    elif x0 >= np.max(x):
        return y[-1]

    ###### Interpolation case ######
    indx = np.searchsorted(x, x0)
    xk, xkn = x[indx-1], x[indx]
    pk, pkn = y[indx-1], y[indx]
    mk, mkn = yp[indx-1], yp[indx]
    return hermite_interp(x0, xk, xkn, pk, pkn, mk, mkn)

@jit(nopython=True)
def HermiteInterpolationVect(xvect, x: Vector, y: Vector, yp: Vector):
    """Returns the interpolated value for all elements in xvect
    Inputs: - np.ndarray: xvect, vector of abscissa of the point to interpolate
            - np.ndarray: x, x-axis grid
            - np.ndarray: y, values of elements in x
            - np.ndarray: tang, tangents of the x elements
    Output: - np.ndarray: interpolated values"""
    N = len(xvect)
    out = np.zeros(N)
    for i in range(N):
        x0 = xvect[i]
        out[i] = HermiteInterpolation(x0, x, y, yp)
    return out

from numba import njit, types
from numba.extending import overload, register_jitable
from numba import generated_jit

def _hermite(x0,x,y,yp,out=None):
    pass

@overload(_hermite)
def _hermite(x0,x,y,yp,out=None):
    def _hermite(x0,x,y,yp,out=None):
        return HermiteInterpolation(x0,x,y,yp)
    return _hermite

from numba.core.types.misc import NoneType as none

@generated_jit
def hermite(x0,x,y,yp,out=None):
    try:
        n = x0.ndim
        if n==1:
            input_type = 'vector'
        elif n==2:
            input_type = 'matrix'
        else:
            raise Exception("Invalid input type")
    except:
        # n must be a scalar
        input_type = 'scalar'

    if input_type == 'scalar':
        def _hermite(x0,x,y,yp,out=None):
            return HermiteInterpolation(x0,x,y,yp)
    elif input_type == 'vector':
        def _hermite(x0,x,y,yp,out=None):
            return HermiteInterpolationVect(x0,x,y,yp)
    elif input_type == 'matrix':
        def _hermite(x0,x,y,yp,out=None):
            return HermiteInterpolationVect(x0[:,0],x,y,yp)
    return _hermite


"""asg4.py

This assignment is based on the Linear Regression - Least Squares
theory.  The present script is associated with the text document
available from the course web page.

Do not touch the imports, and specifically, do not import matplotlib
in this file! Use the provided file draw.py for visualization. You can
run it by executing the script from command line:

python3 draw.py

The imports listed below should be enough to accomplish all tasks.

The functions /docstring/s contain some real examples and usage of the
functions. You can run these examples by executing the script from
command line:

python3 asg4.py

Note that the unit tests for the final grading may contain different
tests, and that certain requirements given below are not tested in the
testing before the final testing.
"""

import numpy as np
np.set_printoptions(precision=3)
from scipy import linalg as la

def least_squares(A, b):
    """Calculate the least squares solutions to Ax = b.
    You should do this by using the QR decomposition.

    YOUR ARE NOT ALLOWED TO USE THE FUNCTION lstsq() FROM NUMPY or SCIPY

    Parameters:
        A ((m,n) ndarray): A matrix
        b ((m, ) ndarray): A vector of length m.

    Returns:
        x ((n, ) ndarray): The solution to the normal equations.

    Examples
    --------
    >>> A = np.array([[4, 1],[1, 1],[8, 9],[6, 9],[5, 2],[7, 7],[7, 1],[5, 1]])
    >>> b = np.array([[8],[4],[1],[8],[4],[6],[7],[8]])
    >>> np.array(least_squares(A,b))
    array([[ 1.236],
           [-0.419]])
    """
    M = np.asmatrix(A);         #Stores A as a matrix in M without copying it
    return np.asarray(((M.T @ M)**-1) @ M.T @ b);   #Calculate solution to least squares, cast as ndarray

def linear_model(x,y):
    """Find the a and b coefficients of the least squares line y = ax + b.

    Parameters
    ----------
    x       : np.ndarray : a numpy array of floats for the input (predictor variables)
    y       : np.ndarray : a numpy array of floats for the output (response variable)

    Returns
    -------
    (a,b)   : a tuple containing the coefficients of the line y = ax + b.

    Examples
    --------
    >>> x = np.array([2, 3, 4, 5, 6, 7, 8, 9])
    >>> y = np.array([1.75, 1.91, 2.03, 2.13, 2.22, 2.30, 2.37, 2.43])
    >>> np.array(linear_model(x,y))
    array([0.095, 1.621])
    """
    coefm = least_squares(np.vander(x, 2), y)
    return (coefm[0,0], coefm[0,1])

def exponential_model(x,y):
    """Find the a and b coefficients of the best fitting curve y = ae^(bx).

    Parameters
    ----------
    x       : np.ndarray : a numpy array of floats for the input (predictor variables)
    y       : np.ndarray : a numpy array of floats for the output (response variable)

    Returns
    -------
    (a,b)   : a tuple containing the coefficients of the model  y = ae^(bx).

    Examples
    --------
    >>> x = np.array([2, 3, 4, 5, 6, 7, 8, 9])
    >>> y = np.array([1.75, 1.91, 2.03, 2.13, 2.22, 2.30, 2.37, 2.43])
    >>> np.array(exponential_model(x,y))
    array([1.662, 0.045])
    """
    yl = np.log(y)
    out = least_squares(np.vander(x,2),yl)
    return (np.exp(out[0,1]), out[0,0])

def power_model(x,y):
    """Find the a and b coefficients of the best fitting curve y = a x^b.

    Parameters
    ----------
    x       : np.ndarray : a numpy array of floats for the input (predictor variables)
    y       : np.ndarray : a numpy array of floats for the output (response variable)

    Returns
    -------
    (a,b)   : a tuple containing the coefficients of the model  y = a x^b.

    Examples
    --------
    >>> x = np.array([2, 3, 4, 5, 6, 7, 8, 9])
    >>> y = np.array([1.75, 1.91, 2.03, 2.13, 2.22, 2.30, 2.37, 2.43])
    >>> np.array(power_model(x,y))
    array([1.501, 0.219])
    """
    xl = np.log(x)
    yl = np.log(y)
    out = least_squares(np.vander(xl,2),yl)
    return (np.exp(out[0,1]), out[0,0])

def logarithmic_model(x,y):
    """Find the a and b coefficients of the best fitting curve y = a + b ln x.

    Parameters
    ----------
    x       : np.ndarray : a numpy array of floats for the input (predictor variables)
    y       : np.ndarray : a numpy array of floats for the output (response variable)

    Returns
    -------
    (a,b)   : a tuple containing the coefficients of the model y = a + b ln x.

    Examples
    --------
    >>> x = np.array([2, 3, 4, 5, 6, 7, 8, 9])
    >>> y = np.array([1.75, 1.91, 2.03, 2.13, 2.22, 2.30, 2.37, 2.43])
    >>> np.array(logarithmic_model(x,y))
    array([1.415, 0.455])
    """
    xl = np.log(x)
    out = least_squares(np.vander(xl,2),y)
    return (out[0,1],out[0,0]);

def training_error(f,xx,yy):
    """Find the sum of squared errors of the model f on the data xx and yy used to
    determine the parameters of f.

    Parameters
    ----------
    f        : a lambda function containing the fitted parameters
               implementing one models under study
    xx       : np.ndarray : a numpy array of floats for the input (predictor variables)
    yy       : np.ndarray : a numpy array of floats for the output (response variable)

    Returns
    -------
    err      : a float representing the training error.
    >>> x = np.array([2, 3, 4, 5, 6, 7, 8, 9])
    >>> y = np.array([1.75, 1.91, 2.03, 2.13, 2.22, 2.30, 2.37, 2.43])
    >>> a,b = power_model(x,y)
    >>> f_pow = lambda xx: a*(xx**b)
    >>> np.array(training_error(f_pow, x, y))
    array(0.008)
    """
    return np.linalg.norm(f(xx)-yy)

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


import scipy as sp

def cdiff(f, xpts, vary=[0], accur=2, degree=1, tol=1e-5):
    if accur not in [2,4,6]:
        raise ValueError("Invalid accuracy.  Must be 2, 4, or 6")
    if degree not in [1,2]:
        raise ValueError("Only degrees 1 and 2 are defined")

    #cdiff = lambda ccfs, hcfs, xval: sum([c*f(x+h*tol) for c,h,x in zip(ccfs, hcfs, [xval]*len(ccfs))])/(tol**float(degree))
    cdiff = lambda co, ho, xvals, i: sp.sum([c*f(*(sp.asarray([x+h*tol if index in i else x for (x,index) in zip(xvals, range(len(xvals)))]))) for c,h in zip(co, ho)], axis=0)/(tol**float(degree))

    if degree==1:
        if accur==2:
            return cdiff([-1.0/2,0,1.0/2], [-1,0,1],xpts,vary)
        if accur==4:
            return cdiff([1.0/12,-2.0/3,0,2.0/3,-1.0/12], [-2,-1,0,1,2],xpts,vary)
        if accur==6:
            return cdiff([-1.0/60,3.0/20,-3.0/4,0,3.0/4,-3.0/20,1.0/60],[-3,-2,-1,0,1,2,3],xpts,vary)
    if degree==2:
        if accur==2:
            return cdiff([1,-2,1],[-1,0,1],xpts,vary)
        if accur==4:
            return cdiff([-1.0/12,4.0/3,-5.0/2,4.0/3,-1.0/12],[-2,-1,0,1,2],xpts,vary)
        if accur==6:
            return cdiff([1.0/90,-3.0/20,3.0/2,-49.0/18,3.0/2,-3.0/20,1.0/90],[-3,-2,-1,0,1,2,3],xpts,vary)

def fbdiff(f, xpts, vary=0, accur=1, degree=1, direction='f',tol=1e-5):
    """Computer forward difference using coefficients from taylor series"""
    if accur not in [1,2,3]:
        raise ValueError("Invalid accuracy.  Must be 1, 2, or 3")
    if degree not in [1,2]:
        raise ValueError("Only degrees 1 and 2 are defined")
    if direction not in ['f', 'b']:
        raise ValueError("Invalid direction.  Must be 'f'orward or 'b'ackward")

    #fdiff = lambda ccfs, hcfs, xval: sum([c*f(x+h*tol) for c,h,x in zip(ccfs, hcfs, [xval]*len(ccfs))])/(tol**float(degree))
    #fdiff = lambda co, ho, xvals: sp.sum([c*f(*(sp.asarray(xvals)+h*tol)) for c,h in zip(co, ho)],axis=0)/(tol**float(degree))
    fdiff = lambda co, ho, xvals, i: sp.sum([c*f(*(sp.asarray([x+h*tol if index in i else x for (x,index) in zip(xvals, range(len(xvals)))]))) for c,h in zip(co, ho)], axis=0)/(tol**float(degree))

    if degree==1:
        if accur==1:
            if direction is 'f':
                return fdiff([-1,1],[0,1],xpts,vary)
            else:
                return fdiff([1,-1],[0,-1],xpts,vary)
        if accur==2:
            if direction is 'f':
                return fdiff([-3.0/2,2,-1.0/2],[0,1,2],xpts,vary)
            else:
                return fdiff([3.0/2,-2,1.0/2],[0,-1,-2],xpts,vary)
        if accur==3:
            if direction is 'f':
                return fdiff([-11.0/6,3,-3.0/2,1.0/3],[0,1,2,3],xpts,vary)
            else:
                return fdiff([11.0/6,-3,3.0/2,-1.0/3],[0,-1,-2,-3],xpts,vary)
    if degree==2:
        if accur==1:
            if direction is 'f':
                return fdiff([1,-2,1],[0,1,2],xpts,vary)
            else:
                return fdiff([-1,2,-1],[0,-1,-2],xpts,vary)
        if accur==2:
            if direction is 'f':
                return fdiff([2,-5,4,-1],[0,1,2,3],xpts,vary)
            else:
                return fdiff([-2,5,-4,1],[0,-1,-2,-3],xpts,vary)
        if accur==3:
            if direction is 'f':
                return fdiff([35.0/12,-26.0/3,19.0/2,-14.0/3,11.0/12],[0,1,2,3,4],xpts,vary)
            else:
                return fdiff([-35.0/12,26.0/3,-19.0/2,14.0/3,-11.0/12],[0,-1,-2,-3,-4],xpts,vary)


"""
For these functions, a trajectory has the shape [x,y,t]
"""
import numpy as np
import matplotlib.pyplot as plt
import math

# Euclidean distance
def euclidean_distance(p, q):
    dist = math.sqrt( (p[0]-q[0])**2 + (p[1]-q[1])**2 )
    return dist

def trajectory_arclength(traj):
    x, y = traj[0], traj[1]
    n    = len(x)
    arclen = np.empty(n)
    arclen[0] = 0
    for i in range(1,n):
        d = euclidean_distance( [x[i],y[i]], [x[i-1], y[i-1]] )
        arclen[i] = arclen[i-1] + d

    return arclen

def trajectory_speeds(traj):
    x, y, t = np.array(traj[0]), np.array(traj[1]), np.array(traj[2])
    return np.divide(np.sqrt(np.square(x[1:]-x[:-1])+np.square(y[1:]-y[:-1])),t[1:]-t[:-1])

# Average speed of a trajectory
def avg_speed(traj):
    x, y, t = np.array(traj[0]), np.array(traj[1]), np.array(traj[2])
    speed = np.divide(np.sqrt(np.square(x[1:]-x[:-1])+np.square(y[1:]-y[:-1])),t[1:]-t[:-1])
    return np.mean(speed)

# Median speed of a trajectory
def median_speed(traj):
    x, y, t = np.array(traj[0]), np.array(traj[1]), np.array(traj[2])
    speed = np.divide(np.sqrt(np.square(x[1:]-x[:-1])+np.square(y[1:]-y[:-1])),t[1:]-t[:-1])
    return np.median(speed)

# Trajectory duration
def trajectory_duration(traj):
    t = traj[2]
    return t[-1] - t[0]

#TODO: re-do histogram function for duration and arclength
def tr_histogram(trajectories):
    duration = []
    arclen = []

    for tr in trajectories:
        duration.append(trajectory_duration(tr))
        arclen.append(trajectory_arclength(tr))
    _ = plt.hist(duration, bins='auto')
    plt.title("Histogram of trajectory duration")
    plt.show()

# Truncates a float f to n decimals
def truncate(f, n):
    s = '{}'.format(f)
    if 'e' in s or 'E' in s:
        return '{0:.{1}f}'.format(f, n)
    i, p, d = s.partition('.')

    return '.'.join([i, (d+'0'*n)[:n]])


# --------------
# Code starts here

import numpy as np

# Code starts here

# Adjacency matrix
adj_mat = np.array([[0,0,0,0,0,0,1/3,0],
                   [1/2,0,1/2,1/3,0,0,0,0],
                   [1/2,0,0,0,0,0,0,0],
                   [0,1,0,0,0,0,0,0],
                  [0,0,1/2,1/3,0,0,1/3,0],
                   [0,0,0,1/3,1/3,0,0,1/2],
                   [0,0,0,0,1/3,0,0,1/2],
                   [0,0,0,0,1/3,1,1/3,0]])

# Compute eigenvalues and eigencevectrs
eigenvalues, eigenvectors = np.linalg.eig(adj_mat)
# Eigen vector corresponding to 1
abs(eigenvectors[:,0])
eigen_1=abs(eigenvectors[:,0])/np.linalg.norm(eigenvectors[:,0],1)
# most important page
page=np.where(np.max(eigen_1) ==eigen_1)[0][0] + 1
print("page:")
print(page)
# Code ends here

# --------------
# Code starts here

# Initialize stationary vector I
init_I = np.array([1,0,0,0,0,0,0,0])

# Perform iterations for power method
for _ in range (10):
    init_I = np.dot(adj_mat, init_I)
    init_I /= np.linalg.norm(init_I, 1)

print(init_I)
power_page = np.where(np.max(init_I) == init_I)[0][0] + 1
print(power_page)

# Code ends here

# --------------
# Code starts here

# New Adjancency matrix
# New Adjancency matrix
new_adj_mat = np.array([[0,0,0,0,0,0,0,0],
                   [1/2,0,1/2,1/3,0,0,0,0],
                  [1/2,0,0,0,0,0,0,0],
                   [0,1,0,0,0,0,0,0],
                   [0,0,1/2,1/3,0,0,1/2,0],
                   [0,0,0,1/3,1/3,0,0,1/2],
                   [0,0,0,0,1/3,0,0,1/2],
                   [0,0,0,0,1/3,1,1/2,0]])

# Initialize stationary vector I
new_init_I= np.array([1,0,0,0,0,0,0,0])

# Perform iterations for power method
for _ in range(10):
    new_init_I= np.dot(new_adj_mat, new_init_I)
    new_init_I /= np.linalg.norm(new_init_I, 1)

print(new_init_I)

# Code ends here

# --------------
# Alpha value
alpha = 0.85

# Code starts here

# Modified adjancency matrix
G= (alpha*new_adj_mat) + (1-alpha)*(1/len(new_adj_mat))*np.ones(new_adj_mat.shape)

# Initialize stationary vector I
final_init_I= np.array([1,0,0,0,0,0,0,0])

# Perform iterations for power method
for _ in range(1000):
    final_init_I= np.dot(G, final_init_I)
    final_init_I /= np.linalg.norm(final_init_I, 1)

print(final_init_I)
# Code ends here


import numpy as np

def t_score(X, y):
    """
    This function calculates t_score for each feature, where t_score is only used for binary problem
    t_score = |mean1-mean2|/sqrt(((std1^2)/n1)+((std2^2)/n2)))

    Input
    -----
    X: {numpy array}, shape (n_samples, n_features)
        input data
    y: {numpy array}, shape (n_samples,)
        input class labels

    Output
    ------
    F: {numpy array}, shape (n_features,)
        t-score for each feature
    """

    n_samples, n_features = X.shape
    F = np.zeros(n_features)
    c = np.unique(y)
    if len(c) == 2:
        for i in range(n_features):
            f = X[:, i]
            # class0 contains instances belonging to the first class
            # class1 contains instances belonging to the second class
            class0 = f[y == c[0]]
            class1 = f[y == c[1]]
            mean0 = np.mean(class0)
            mean1 = np.mean(class1)
            std0 = np.std(class0)
            std1 = np.std(class1)
            n0 = len(class0)
            n1 = len(class1)
            t = mean0 - mean1
            t0 = np.true_divide(std0**2, n0)
            t1 = np.true_divide(std1**2, n1)
            F[i] = np.true_divide(t, (t0 + t1)**0.5)
    else:
        print('y should be guaranteed to a binary class vector')
        exit(0)
    return np.abs(F)

def feature_ranking(F):
    """
    Rank features in descending order according to t-score, the higher the t-score, the more important the feature is
    """
    idx = np.argsort(F)
    return idx[::-1]


import tensorflow as tf
import numpy as np

#STUFF

def normalization(p):
    """
    :param p: list of values
    :return: return min-max normalization
    """
    r = []
    min_v = min(p)
    max_v = max(p)
    for i in p:
        r.append((i-min_v)/(max_v - min_v))

    return r

def one_hot_encode(x, num=10):
    """
        argument
            - x: a list of labels
            - num: number of classes (length of the encoded vector)
        return
            - one hot encoding matrix (number of labels, number of class)
    """
    encoded = np.zeros((len(x), num))

    for idx, val in enumerate(x):
        encoded[idx][val] = 1

    return encoded

def softmax(x, axis=-1):
    ex = tf.keras.backend.exp(x - tf.keras.backend.max(x, axis=axis, keepdims=True))
    return ex/tf.keras.backend.sum(ex, axis=axis, keepdims=True)

def ecludian_distance(p, q):
    n = len(p)
    assert n == len(q)
    return tf.sqrt(sum([pow(p[i] - q[i], 2) for i in range(n)]))

#VECTORS

def cosine_similarity(p, q):
    """
    :param p: document vector, eg = [1,2, 1, 0.6]
    :param q: query vector, eg = [0.4, 1, 0]
    :return:
    """
    n = len(p)
    assert n == len(q)
    dot = sum([a*b for a, b in zip(p, q)])
    x = tf.sqrt(sum([pow(i, 2) for i in p]))
    y = tf.sqrt(sum([pow(i, 2) for i in q]))

    return dot / (x*y)

def cos_sim(v1, v2):
    norm1 = tf.sqrt(tf.reduce_sum(tf.square(v1), axis=1))
    norm2 = tf.sqrt(tf.reduce_sum(tf.square(v2), axis=1))
    dot_products = tf.reduce_sum(v1 * v2, axis=1, name="cos_sim")

    return dot_products / (norm1 * norm2)

def euclidean_score(v1, v2):
    euclidean = tf.sqrt(tf.reduce_sum(tf.square(v1 - v2), axis=1))
    return 1 / (1 + euclidean)

#MATRIX OPERATIONS

def add(matrix_a, matrix_b):
    if _check_not_integer(matrix_a) and _check_not_integer(matrix_b):
        rows, cols = _verify_matrix_sizes(matrix_a, matrix_b)
        matrix_c = []
        for i in range(rows[0]):
            list_1 = []
            for j in range(cols[0]):
                val = matrix_a[i][j] + matrix_b[i][j]
                list_1.append(val)
            matrix_c.append(list_1)

        return matrix_c

def subtract(matrix_a, matrix_b):
    if _check_not_integer(matrix_a) and _check_not_integer(matrix_b):
        rows, cols = _verify_matrix_sizes(matrix_a, matrix_b)
        matrix_c = []
        for i in range(rows[0]):
            list_1 = []
            for j in range(cols[0]):
                val = matrix_a[i][j] - matrix_b[i][j]
                list_1.append(val)
            matrix_c.append(list_1)

        return matrix_c

def scalar_multiply(matrix, n):
    return [[x * n for x in row] for row in matrix]

def multiply(matrix_a, matrix_b):
    if _check_not_integer(matrix_a) and _check_not_integer(matrix_b):
        matrix_c = []
        rows, cols = _verify_matrix_sizes(matrix_a, matrix_b)

        if cols[0] != rows[1]:
            raise ValueError(f"Cannot multiply matrix of dimensions ({rows[0]},{cols[0]}) "
                             f"and ({rows[1]},{cols[1]})")
        for i in range(rows[0]):
            list_1 = []
            for j in range(cols[1]):
                val = 0
                for k in range(cols[1]):
                    val = val + matrix_a[i][k] * matrix_b[k][j]
                list_1.append(val)
            matrix_c.append(list_1)

        return matrix_c

def identity(n):
    """
    :param n: dimension for nxn matrix
    :type n: int
    :return: Identity matrix of shape [n, n]
    """
    n = int(n)
    return [[int(row == column) for column in range(n)] for row in range(n)]

def transpose(matrix, return_map=True):
    if _check_not_integer(matrix):
        if return_map:
            return map(list, zip(*matrix))
        else:
            # mt = []
            # for i in range(len(matrix[0])):
            #     mt.append([row[i] for row in matrix])
            # return mt
            return [[row[i] for row in matrix] for i in range(len(matrix[0]))]

def minor(matrix, row, column):
    minor = matrix[:row] + matrix[row + 1 :]
    minor = [row[:column] + row[column + 1 :] for row in minor]
    return minor

def determinant(matrix):
    if len(matrix) == 1:
        return matrix[0][0]

    res = 0
    for x in range(len(matrix)):
        res += matrix[0][x] * determinant(minor(matrix, 0, x)) * (-1) ** x

    return res

def inverse(matrix):
    det = determinant(matrix)
    if det == 0:
        return None

    matrix_minor = [[] for _ in range(len(matrix))]
    for i in range(len(matrix)):
        for j in range(len(matrix)):
            matrix_minor[i].append(determinant(minor(matrix, i, j)))

    cofactors = [[x * (-1) ** (row + col) for col, x in enumerate(matrix_minor[row])] for row in range(len(matrix))]
    adjugate = transpose(cofactors)

    return scalar_multiply(adjugate, 1 / det)

#ADVANCED OPERATIONS

def make_attention_mat(x1, x2):
    # x1, x2 = [batch, height, width, 1] = [batch, d, s, 1]
    # x2 => [batch, height, 1, width]
    # [batch, width, wdith] = [batch, s, s]
    euclidean = tf.sqrt(tf.reduce_sum(tf.square(x1 - tf.matrix_transpose(x2)), axis=1))
    return 1 / (1 + euclidean)

#MATRIX UTILS

def _check_not_integer(matrix):
    try:
        rows = len(matrix)
        cols = len(matrix[0])
        return True
    except TypeError:
        raise TypeError("Cannot input an integer value, it must be a matrix")

def _shape(matrix):
    return list((len(matrix), len(matrix[0])))

def _verify_matrix_sizes(matrix_a, matrix_b):
    shape = _shape(matrix_a)
    shape += _shape(matrix_b)
    if shape[0] != shape[2] or shape[1] != shape[3]:
        raise ValueError(f"operands could not be broadcast together with shape "
                         f"({shape[0], shape[1]}), ({shape[2], shape[3]})")
    return [shape[0], shape[2]], [shape[1], shape[3]]


# Question 02, Lab 07
# AB Satyaprakash - 180123062

# imports
from math import sqrt, log, exp
from scipy.stats import norm
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt

# functions

def calEurCallPutPrices(T, K, S, r, σ, t):
    if(T == t):
        putp = max(K-S, 0)
        callp = max(S-K, 0)
        return [callp, putp]

    d1 = (log(S/K)+(r+(σ**2/2))*(T-t))/(σ*sqrt(T-t))
    d2 = d1-σ*sqrt(T-t)

    putp = K*exp(-r*(T-t))*norm.cdf(-d2) - S*norm.cdf(-d1)
    callp = S*norm.cdf(d1)-K*norm.cdf(d2)*exp(-r*(T-t))
    return [callp, putp]

# program body
# Given data
T, K, r, sig = 1, 1, 0.05, 0.6
t = np.array([0, 0.2, 0.4, 0.6, 0.8, 1])
S = np.arange(0.05, 3.05, 0.05)

# Fill 2-D arrays will zeros for storing prices
callPrices = np.zeros(shape=(t.shape[0], S.shape[0]))
putPrices = np.zeros(shape=(t.shape[0], S.shape[0]))

for i in range(t.shape[0]):
    for j in range(S.shape[0]):
        [callPrices[i][j], putPrices[i][j]] = calEurCallPutPrices(
            T, K, S[j], r, sig, t[i])

for i in range(t.shape[0]):
    plt.plot(S, callPrices[i], label='t = {}'.format(t[i]))
plt.xlabel('Stock Prices')
plt.ylabel('Option Prices')
plt.title('Plot of C(t,s) vs s')
plt.legend()
plt.show()

for i in range(t.shape[0]):
    plt.plot(S, putPrices[i], label='t = {}'.format(t[i]))
plt.xlabel('Stock Prices')
plt.ylabel('Option Prices')
plt.title('Plot of P(t,s) vs s')
plt.legend()
plt.show()

callPricesT = np.matrix.transpose(callPrices)
putPricesT = np.matrix.transpose(putPrices)

tx, Sy = np.meshgrid(t, S)

fig = plt.figure(figsize=(8, 6))
ax = Axes3D(fig)
ax.scatter3D(tx, Sy, callPricesT, c='g')
ax.set_title('Scatter Plot of C(t,x) vs t and x')
ax.set_xlabel('Stock Prices')
ax.set_ylabel('Time')
ax.set_zlabel('Price of European Call Option')
plt.show()

fig = plt.figure(figsize=(8, 6))
ax = Axes3D(fig)
ax.scatter3D(tx, Sy, putPricesT, c='r')
ax.set_title('Scatter Plot of P(t,x) vs t and x')
ax.set_xlabel('Stock Prices')
ax.set_ylabel('Time')
ax.set_zlabel('Price of European Put Option')
plt.show()

Semester 6/MA 374 (Financial Engg. Lab)/Lab 7/180123062_AB_q2.py


from reliability.Fitters import Fit_Weibull_Mixture
from reliability.Distributions import Weibull_Distribution
from reliability.Other_functions import histogram
import numpy as np
import matplotlib.pyplot as plt

# create some failures from two distributions
group_1 = Weibull_Distribution(alpha=10, beta=3).random_samples(40, seed=2)
group_2 = Weibull_Distribution(alpha=40, beta=4).random_samples(60, seed=2)
all_data = np.hstack([group_1, group_2])  # combine the data
results = Fit_Weibull_Mixture(failures=all_data)  # fit the mixture model

# this section is to visualise the histogram with PDF and CDF
# it is not part of the default output from the Fitter
plt.figure(figsize=(9, 5))
plt.subplot(121)
histogram(all_data)
results.distribution.PDF()
plt.subplot(122)
histogram(all_data, cumulative=True)
results.distribution.CDF()

plt.show()

'''
Results from Fit_Weibull_Mixture (95% CI):
              Point Estimate  Standard Error   Lower CI   Upper CI
Parameter
Alpha 1             8.654923        0.394078   7.916006   9.462815
Beta 1              3.910594        0.509724   3.028959   5.048845
Alpha 2            38.097040        1.411773  35.428112  40.967028
Beta 2              3.818227        0.421366   3.075574   4.740207
Proportion 1        0.388206        0.050264   0.295325   0.489987
Log-Likelihood: -375.9906311550037
'''


#!/usr/bin/env python3
# Name: Riley Kendall and Nikki Schwartz
# Student ID: 2274503
# Email: kenda106@mail.chapman.edu
# Course: PHYS220/MATH220/CPSC220 Fall 2017
# Assignment: CLASSWORK 10
import randomwalk
import numpy as np

#estimating the value of e
def estimate_e(N=100000):
    '''estimate_e(N)
    Estimating the value of 'e' using np.random
        N(int) : N amount of random x and y coordinents
    Returns:
        np.exp(xs).sum()/N +1 (int) : The estimated numeric value for e'''
    xs = np.random.uniform(0,1,N)
    return np.exp(xs).sum()/N +1


import numpy as np

# Write a function that takes as input a list of numbers, and returns
# the list of values given by the softmax function.

def softmax(L):
    expL = np.exp(L)
    return np.divide(expL, expL.sum())

# e.g. [1, 2, 3, 4]
arr1 = [1, 2, 3, 4]
out = softmax(arr1)
print("\nOutput array : \n", out)


#!/usr/bin/env python3

import numpy as np

def gaussianKernel(x1, x2, sigma):
    #RBFKERNEL returns a radial basis function kernel between x1 and x2
    #   sim = gaussianKernel(x1, x2) returns a gaussian kernel between x1 and x2
    #   and returns the value in sim

    # Ensure that x1 and x2 are column vectors
    x1 = x1.ravel()
    x2 = x2.ravel()

    # You need to return the following variables correctly.
    #sim = 0;

    # ====================== YOUR CODE HERE ======================
    # Instructions: Fill in this function to return the similarity between x1
    #               and x2 computed using a Gaussian kernel with bandwidth
    #               sigma
    #
    #

    sim = np.exp(-np.sum((x1 - x2) ** 2.0) / (2.0 * (sigma ** 2.0)))

    # =============================================================

    return sim
    #end


## Generate a contour plot
# Import some other libraries that we'll need
# matplotlib and numpy packages must also be installed
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import random
import math

# define objective function
def f(x):
    x1 = x[0]
    x2 = x[1]
    obj = 0.2 + x1**2 + x2**2 - 0.1*math.cos(6.0*3.1415*x1) - 0.1*math.cos(6.0*3.1415*x2)
    return obj

# Start location
x_start = [0.8, -0.5]

# Design variables at mesh points
i1 = np.arange(-1.0, 1.0, 0.01)
i2 = np.arange(-1.0, 1.0, 0.01)
x1m, x2m = np.meshgrid(i1, i2)
fm = np.zeros(x1m.shape)
for i in range(x1m.shape[0]):
    for j in range(x1m.shape[1]):
        fm[i][j] = 0.2 + x1m[i][j]**2 + x2m[i][j]**2 \
             - 0.1*math.cos(6.0*3.1415*x1m[i][j]) \
             - 0.1*math.cos(6.0*3.1415*x2m[i][j])

# Create a contour plot
plt.figure()
# Specify contour lines
#lines = range(2,52,2)
# Plot contours
CS = plt.contour(x1m, x2m, fm)#,lines)
# Label contours
plt.clabel(CS, inline=1, fontsize=10)
# Add some text to the plot
plt.title('Non-Convex Function')
plt.xlabel('x1')
plt.ylabel('x2')

##################################################
# Simulated Annealing
##################################################
# Number of cycles
n = 50
# Number of trials per cycle
m = 50
# Number of accepted solutions
na = 0.0
# Probability of accepting worse solution at the start
p1 = 0.7
# Probability of accepting worse solution at the end
p50 = 0.001
# Initial temperature
t1 = -1.0/math.log(p1)
# Final temperature
t50 = -1.0/math.log(p50)
# Fractional reduction every cycle
frac = (t50/t1)**(1.0/(n-1.0))
# Initialize x
x = np.zeros((n+1,2))
x[0] = x_start
xi = np.zeros(2)
xi = x_start
na = na + 1.0
# Current best results so far
xc = np.zeros(2)
xc = x[0]
fc = f(xi)
fs = np.zeros(n+1)
fs[0] = fc
# Current temperature
t = t1
# DeltaE Average
DeltaE_avg = 0.0
for i in range(n):
    print 'Cycle: ' + str(i) + ' with Temperature: ' + str(t)
    for j in range(m):
        # Generate new trial points
        xi[0] = xc[0] + random.random() - 0.5
        xi[1] = xc[1] + random.random() - 0.5
        # Clip to upper and lower bounds
        xi[0] = max(min(xi[0],1.0),-1.0)
        xi[1] = max(min(xi[1],1.0),-1.0)
        DeltaE = abs(f(xi)-fc)
        if (f(xi)>fc):
            # Initialize DeltaE_avg if a worse solution was found
            #   on the first iteration
            if (i==0 and j==0): DeltaE_avg = DeltaE
            # objective function is worse
            # generate probability of acceptance
            p = math.exp(-DeltaE/(DeltaE_avg * t))
            # determine whether to accept worse point
            if (random.random()<p):
                # accept the worse solution
                accept = True
            else:
                # don't accept the worse solution
                accept = False
        else:
            # objective function is lower, automatically accept
            accept = True
        if (accept==True):
            # update currently accepted solution
            xc[0] = xi[0]
            xc[1] = xi[1]
            fc = f(xc)
            # increment number of accepted solutions
            na = na + 1.0
            # update DeltaE_avg
            DeltaE_avg = (DeltaE_avg * (na-1.0) +  DeltaE) / na
    # Record the best x values at the end of every cycle
    x[i+1][0] = xc[0]
    x[i+1][1] = xc[1]
    fs[i+1] = fc
    # Lower the temperature for next cycle
    t = frac * t

# print solution
print 'Best solution: ' + str(xc)
print 'Best objective: ' + str(fc)

plt.plot(x[:,0],x[:,1],'y-o')
plt.savefig('contour.png')

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.plot(fs,'r.-')
ax1.legend(['Objective'])
ax2 = fig.add_subplot(212)
ax2.plot(x[:,0],'b.-')
ax2.plot(x[:,1],'g--')
ax2.legend(['x1','x2'])

# Save the figure as a PNG
plt.savefig('iterations.png')

plt.show()


"""
Written by Ivan Debono
mail [at] ivandebono [dot] eu

October 2016
Modified 22 April 2017

PURPOSE Output the Champernowne constant up to desired digit
        (See http://mathworld.wolfram.com/ChampernowneConstant.html)

INPUT   last: last digit
        base: base representation for digit. Default = 10

OUTPUT  champernowne_str: string representation of Champernowne's constant
        champernowne_flt: Champernowne's constant, in Python Decimal format
        (i.e. floating point with any user-defined precision),
        to same number of digits as last digit
"""

from decimal import getcontext, Decimal
import numpy as np

def champernowne(last,base=10):

    champernowne_str = "0."
    for c in range(1,last+1):
        champernowne_str += str(np.base_repr(c,base=base))
    getcontext().prec = len(champernowne_str)
    champernowne_flt=Decimal(champernowne_str)
    return champernowne_str,champernowne_flt


"""
================
Phase Unwrapping
================

Some signals can only be observed modulo 2*pi, and this can also apply to
two- and three dimensional images. In these cases phase unwrapping is
needed to recover the underlying, unwrapped signal. In this example we will
demonstrate an algorithm [1]_ implemented in ``skimage`` at work for such a
problem. One-, two- and three dimensional images can all be unwrapped using
skimage. Here we will demonstrate phase unwrapping in the two dimensional case.
"""

import numpy as np
from matplotlib import pyplot as plt
from skimage import data, img_as_float, color, exposure
from skimage.restoration import unwrap_phase

# Load an image as a floating-point grayscale
image = color.rgb2gray(img_as_float(data.chelsea()))
# Scale the image to [0, 4*pi]
image = exposure.rescale_intensity(image, out_range=(0, 4 * np.pi))
# Create a phase-wrapped image in the interval [-pi, pi)
image_wrapped = np.angle(np.exp(1j * image))
# Perform phase unwrapping
image_unwrapped = unwrap_phase(image_wrapped)

plt.figure()
plt.subplot(221)
plt.title('Original')
plt.imshow(image, cmap='gray', vmin=0, vmax=4 * np.pi)
plt.colorbar()

plt.subplot(222)
plt.title('Wrapped phase')
plt.imshow(image_wrapped, cmap='gray', vmin=-np.pi, vmax=np.pi)
plt.colorbar()

plt.subplot(223)
plt.title('After phase unwrapping')
plt.imshow(image_unwrapped, cmap='gray')
plt.colorbar()

plt.subplot(224)
plt.title('Unwrapped minus original')
plt.imshow(image_unwrapped - image, cmap='gray')
plt.colorbar()

"""
.. image:: PLOT2RST.current_figure

The unwrapping procedure accepts masked arrays, and can also optionally
assume cyclic boundaries to connect edges of an image. In the example below,
we study a simple phase ramp which has been split in two by masking
a row of the image.
"""

# Create a simple ramp
image = np.ones((100, 100)) * np.linspace(0, 8 * np.pi, 100).reshape((-1, 1))
# Mask the image to split it in two horizontally
mask = np.zeros_like(image, dtype=np.bool)
mask[image.shape[0] // 2, :] = True

image_wrapped = np.ma.array(np.angle(np.exp(1j * image)), mask=mask)
# Unwrap image without wrap around
image_unwrapped_no_wrap_around = unwrap_phase(image_wrapped,
                                              wrap_around=(False, False))
# Unwrap with wrap around enabled for the 0th dimension
image_unwrapped_wrap_around = unwrap_phase(image_wrapped,
                                           wrap_around=(True, False))

plt.figure()
plt.subplot(221)
plt.title('Original')
plt.imshow(np.ma.array(image, mask=mask), cmap='jet')
plt.colorbar()

plt.subplot(222)
plt.title('Wrapped phase')
plt.imshow(image_wrapped, cmap='jet', vmin=-np.pi, vmax=np.pi)
plt.colorbar()

plt.subplot(223)
plt.title('Unwrapped without wrap_around')
plt.imshow(image_unwrapped_no_wrap_around, cmap='jet')
plt.colorbar()

plt.subplot(224)
plt.title('Unwrapped with wrap_around')
plt.imshow(image_unwrapped_wrap_around, cmap='jet')
plt.colorbar()

plt.show()

"""
.. image:: PLOT2RST.current_figure

In the figures above, the masked row can be seen as a white line across
the image. The difference between the two unwrapped images in the bottom row
is clear: Without unwrapping (lower left), the regions above and below the
masked boundary do not interact at all, resulting in an offset between the
two regions of an arbitrary integer times two pi. We could just as well have
unwrapped the regions as two separate images. With wrap around enabled for the
vertical direction (lower rigth), the situation changes: Unwrapping paths are
now allowed to pass from the bottom to the top of the image and vice versa, in
effect providing a way to determine the offset between the two regions.

References
----------

.. [1] Miguel Arevallilo Herraez, David R. Burton, Michael J. Lalor,
       and Munther A. Gdeisat, "Fast two-dimensional phase-unwrapping
       algorithm based on sorting by reliability following a noncontinuous
       path", Journal Applied Optics, Vol. 41, No. 35, pp. 7437, 2002
"""


import math
import numpy

def gaussian(x, mu, sig):
    '''
    Gaussian function.
    '''
    return (1 / math.sqrt(2 * math.pi * sig ** 2)) * \
        numpy.exp(-(x - mu) ** 2 / (2 * sig ** 2))

def logistic(x, x0, L, M, k):
    '''
    Logistic function.
    '''
    return M + (L / (1 + numpy.exp(-k * (x - x0))))


import numpy as np
import pandas as pd

from .validators import data_validations

def _normalize(df: pd.DataFrame):
    for col in df.columns:
        squared_sum = (df[col]**2).sum()
        sqrt_squared_sum = squared_sum ** (1/2)
        df[col] = df[col] / sqrt_squared_sum

def _add_weights(df, weights):
    sm = sum(weights)
    weights = [w / sm for w in weights]
    for i in range(len(weights)):
        df.iloc[:, i] = df.iloc[:, i]*weights[i]

def _get_best_and_worst(df, impacts):
    best = []
    worst = []

    for i in range(len(impacts)):
        mn = df.iloc[:,i].min()
        mx = df.iloc[:,i].max()

        if impacts[i] == '+':
            best.append(mx)
            worst.append(mn)
        else:
            best.append(mn)
            worst.append(mx)

    return np.array(best), np.array(worst)

def _euclidean(row1, row2):
    return (((row1 - row2)**2).sum())**(1/2)

# Main Function
def _topsis(original_df, weights, impacts):
    df = original_df.iloc[:, 1:]

    _normalize(df)
    _add_weights(df, weights)
    best, worst = _get_best_and_worst(df, impacts)

    s1 = []
    s2 = []
    for i in range(df.shape[0]):
        s1.append(_euclidean(np.array(df.iloc[i, :]), best))
        s2.append(_euclidean(np.array(df.iloc[i, :]), worst))

    df['s+'] = s1
    df['s-'] = s2
    df['p+'] = df['s-'] / (df['s-'] + df['s+'])

    df['rank'] = np.nan
    indices = np.argsort(df['p+'].values)[::-1]
    k = 1
    for i in indices:
        df.iloc[i, -1] = k
        k+=1

    original_df['Topsis Score'] = (df['p+']*100).round(2)
    original_df['Rank'] = df['rank'].astype(int)

def topsis(input_file, weights, impacts, output_file, want_roll=True):
    """
    Expects :-
    input_file -> "Excel/Csv" file path
    weights -> Comma seperated integers
    impacts -> Comma seperated +/- impacts
    output_file -> output csv file path"

    want_roll -> Set False if you don't want to create copy of input data.
    Preffered is False but set to true coz college assignment xD

    Outputs:-
    Creates a csv file on "output_file" path containing score and Ranks

    NOTE: No Validation is done in this function
    """
    # PreProcessing
    weights = [int(w) for w in weights.split(',')]
    impacts = impacts.split(',')

    # Excel to DataFrame Conversion
    if str(input_file).endswith('.csv'):
        original_df = pd.read_csv(input_file)
    else:
        original_df = pd.read_excel(input_file)

    # Validation
    data_validations(original_df, weights, impacts)

    # Main Work
    if want_roll:
        original_df.to_csv(f'101917014-data.csv', index=False)
    _topsis(original_df, weights, impacts)
    original_df.to_csv(output_file, index=False)


from .core import FuzzySet
import numpy as np

# operations module
# from fuzzc import operations
def s_norm(x, y, norm_method=None, l=1):
  """
  Compute S norm for two fuzzy sets.
  :param x: a Fuzzy_Set instance.
  :param y: a Fuzzy_Set instance.
  :param norm_method: s_norm method.
  :param l: l parameter for dombi method.
  :return: S normed Fuzzy_Set instance.
  """
  assert str(type(x)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'x must be a Fuzzy_Set instance.'
  assert str(type(y)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'y must be a Fuzzy_Set instance.'
  assert all(x.fuzzy_set == y.fuzzy_set), ' sets must use the same reference.'
  assert len(x.membership_fn) == len(y.membership_fn)
  if not norm_method:
    s_fn = []
    for a, b in zip(x.membership_fn, y.membership_fn):
      s_fn.append(max(a, b))
    return FuzzySet(x.fuzzy_set, np.array(s_fn))
  elif norm_method == 'dombi':
    # higher lambdas equal in maximum.
    assert l > 0, ' l must be greater than 0.'
    d_fn = []
    for a, b in zip(x.membership_fn, y.membership_fn):
      d_fn.append(1 / ((1 + (((1/a)-1) ** -l + ((1/b)-1) ** -l ) ** (-1 / l))))
    return FuzzySet(x.fuzzy_set, np.array(d_fn))
  else:
    print('Wrong Method.')
    return None

def t_norm(x, y, norm_method=None, l=1):
  """
  Compute T norm for two fuzzy sets.
  :param x: a Fuzzy_Set instance.
  :param y: a Fuzzy_Set instance.
  :param norm_method: s_norm method.
  :param l: l parameter for dombi method.
  :return: T normed Fuzzy_Set instance.
  """
  assert str(type(x)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'x must be a Fuzzy_Set instance.'
  assert str(type(y)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'y must be a Fuzzy_Set instance.'
  assert all(x.fuzzy_set == y.fuzzy_set), ' sets must use the same reference.'
  assert len(x.membership_fn) == len(y.membership_fn)
  if not norm_method:
    s_fn = []
    for a, b in zip(x.membership_fn, y.membership_fn):
      s_fn.append(min(a, b))
    return FuzzySet(x.fuzzy_set, np.array(s_fn))
  elif norm_method == 'dombi':
    # higher lambdas equal in minimum.
    assert l > 0, ' l must be greater than 0.'
    d_fn = []
    for a, b in zip(x.membership_fn, y.membership_fn):
      d_fn.append(1 / ((1 + (((1/a)-1) ** l + ((1/b)-1) ** l ) ** (1 / l))))
    return FuzzySet(x.fuzzy_set, np.array(d_fn))
  else:
     print('Wrong Method.')
     return None

def algebraic_sum(x, y):
  assert str(type(x)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'x must be a Fuzzy_Set instance.'
  assert str(type(y)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'y must be a Fuzzy_Set instance.'
  assert all(x.fuzzy_set == y.fuzzy_set), ' sets must use the same reference.'
  assert len(x.membership_fn) == len(y.membership_fn)
  a_fn = []
  for a, b in zip(x.membership_fn, y.membership_fn):
    a_fn.append((a+b) - (a*b))
  return FuzzySet(x.fuzzy_set, np.array(a_fn))

def algebraic_diff(x, y):
  assert str(type(x)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'x must be a Fuzzy_Set instance.'
  assert str(type(y)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'y must be a Fuzzy_Set instance.'
  assert all(x.fuzzy_set == y.fuzzy_set), ' sets must use the same reference.'
  assert len(x.membership_fn) == len(y.membership_fn)
  a_fn = []
  comp = 1 - y.membership_fn
  for a, b in zip(x.membership_fn, comp):
    a_fn.append(min(a, b))
  return FuzzySet(x.fuzzy_set, np.array(a_fn))

def min_max_avg(x, y, l=0.5):
  # l=1 gives max, and l=0 gives out zero.
  assert str(type(x)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'x must be a Fuzzy_Set instance.'
  assert str(type(y)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'y must be a Fuzzy_Set instance.'
  assert all(x.fuzzy_set == y.fuzzy_set), ' sets must use the same reference.'
  assert len(x.membership_fn) == len(y.membership_fn)
  m_fn = []
  for a,b in zip(x.membership_fn, y.membership_fn):
    m_fn.append((l*max(a,b))+((1-l)*min(a,b)))
  return FuzzySet(x.fuzzy_set, np.array(m_fn))

def cartesian_prod(x, y):
  assert str(type(x)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'x must be a Fuzzy_Set instance.'
  assert str(type(y)) == '''<class 'fuzzc.core.Fuzzy_Set'>''', 'y must be a Fuzzy_Set instance.'
  r = len(x.membership_fn)
  c = len(y.membership_fn)
  c_fn = np.zeros((r, c))
  for i, _ in enumerate(x.membership_fn):
    for j, _ in enumerate(y.membership_fn):
      c_fn[i, j] = min(x.membership_fn[i], y.membership_fn[j])
  return c_fn

# add AE and ML

def enhance(membership_fn, d):
  # enhance by an integer factor.
  membership_fn = membership_fn * d
  membership_fn[membership_fn>=1]=1
  return membership_fn

def weaken(membership_fn, d):
  # weaken by an integer factor.
  membership_fn = membership_fn / d
  return membership_fn

def projection(membership_fn, axis=0):
  if axis==0:
    count = membership_fn.shape[axis]
    fn = np.zeros((count, 1))
    for i in range(count):
      fn[i, 0] = np.amax(membership_fn[i, :])
    return fn
  elif axis==1:
    count = membership_fn.shape[axis]
    fn = np.zeros((1, count))
    for i in range(count):
      fn[0, i] = np.amax(membership_fn[:, i])
    return fn
  else:
    print('Unsupported axes.')
    return None

def cylindrical_extension():
  return None


"""
correlation_spanning_tree.py
--------------

Graph reconstruction algorithm based on Mantegna, R. N. (1999). Hierarchical structure in
financial markets. The European Physical Journal B-Condensed Matter and Complex Systems,
11(1), 193-197. DOI https://doi.org/10.1007/s100510050929
https://link.springer.com/article/10.1007/s100510050929

author: Matteo Chinazzi
Submitted as part of the 2019 NetSI Collabathon.
"""

from .base import BaseReconstructor
import numpy as np
import networkx as nx
from scipy.sparse.csgraph import minimum_spanning_tree

class CorrelationSpanningTree(BaseReconstructor):
    def fit(self, TS, **kwargs):
        """Create a minimum spanning tree connecting the sensors.

        The empirical correlation matrix is used to first compute a distance matrix
        and then to create a minimum spanning tree connecting all the sensors in the data.
        This method implements the methodology described in [1] and applied in the context
        of creating a graph connecting the stocks of a portfolio of generated by looking
        at the correlations between the daily time series of stock prices.

        Params
        ------
        TS (np.ndarray): $N \\times L$ array consisting of $L$ observations
                         from $N$ sensors.

        Returns
        -------
        G (nx.Graph): A reconstructed graph with $N$ nodes.

        Example
        --------

        import numpy as np
        import networkx as nx
        from matplotlib import pyplot as plt
        from netrd.reconstruction import CorrelationSpanningTree

        N = 25
        T = 300
        M = np.random.normal(size=(N,T))

        print('Create correlated time series')
        market_mode = 0.4*np.random.normal(size=(1,T))
        M += market_mode

        sector_modes = {d: 0.5*np.random.normal(size=(1,T)) for d in range(5)}
        for sector_mode, vals in sector_modes.items():
            M[sector_mode*5:(sector_mode+1)*5,:] += vals

        print('Link node colors to sectors')
        colors = ['b','r','g','y','m']
        node_colors = [color for color in colors for __ in range(5)]

        print('Network reconstruction step')
        cst_net = CorrelationSpanningTree()
        G = cst_net.fit(M)

        print('Plot reconstructed spanning tree')
        fig, ax = plt.subplots()
        nx.draw(G, ax=ax, node_color=node_colors)

        References
        ----------
        .. [1] Mantegna, R. N. (1999). Hierarchical structure in financial markets.
        The European Physical Journal B-Condensed Matter and Complex Systems, 11(1), 193-197.
        DOI https://doi.org/10.1007/s100510050929
        https://link.springer.com/article/10.1007/s100510050929

        """
        N, L = TS.shape

        C = np.corrcoef(TS) # Empirical correlation matrix

        D = np.sqrt(2*(1-C)) # Metric distance matrix

        MST = minimum_spanning_tree(D) # Minimum Spanning Tree

        G = nx.from_scipy_sparse_matrix(MST)

        self.results['graph'] = G

        return G


import numpy as np

def rk4(f, x0, y0, x1, n):
    lx = [0] * (n + 1)
    ly = [0] * (n + 1)
    h = (x1 - x0) / float(n)
    lx[0] = x = x0
    ly[0] = y = y0
    for i in range(1, n + 1):
        k1 = h * f(x, y)
        k2 = h * f(x + 0.5 * h, y + 0.5 * k1)
        k3 = h * f(x + 0.5 * h, y + 0.5 * k2)
        k4 = h * f(x + h, y + k3)
        print(k1,k2,k3,k4)
        lx[i] = x = x0 + i * h
        ly[i] = y = y + (k1 + 2*k2 + 2*k3 + k4) / 6
    return lx, ly

def f(x, y):
    return x * np.exp(3*x) - 2*y

lx , ly = rk4(f,0.,0.,0.2,2)

print(lx,ly)

# # h = 0.05
# lx1, ly1 = rk4(f, 0., 2., 2., 40)

# # h = 0.1
# lx2, ly2 = rk4(f, 0., 2., 2., 20)

# # h = 0.2
# lx3, ly3 = rk4(f, 0., 2., 2., 10)

exact = 3 * np.exp(2) - 2 - 1

# print("When h = 0.05 , Difference = %.16f" % np.abs(np.subtract(exact,ly1[40])))
# print("When h = 0.1  , Difference = %.16f" % np.abs(np.subtract(exact,ly2[20])))
# print("When h = 0.2  , Difference = %.16f" % np.abs(np.subtract(exact,ly3[10])))


# zipf distribution

# are used to sample data based on zipf's law

"""
Zipf's law: In a collection the nth common term is 1/n times of the most common term.
e.g. 5th common word in english has occur nearly 1/5 th times as most of the most used word.
"""

# It has two parameters.

# a - distribution parameter

# size - the shape of the returned array

# draw out a sample for zipf distribution with distribution parameter 2 with size 2x3

from numpy import random

x = random.zipf(a = 2, size = (2, 3))

print(x)

# visualization of zipf distribution

# sample 1000 points but plotting only ones with value < 10 for more meanngful chart.

# from numpy import random

import matplotlib.pyplot as plt
import seaborn as sns

x = random.zipf(a = 2, size = 1000)
sns.distplot(x[x < 10], kde = False)

plt.show()