""" Assign weights to distances in a way such that farther values are weighed less """
import numpy as np

def shepards(distances, power=2):
    """ Basic inverse distance weighting function

    Parameters
    ----------
    distances: list/numpy.ndarray
        1D list of numbers (ex. distance results from call to KDTree.query)

    power: int
        Default of 2 used since the referenced paper stated an exponent of 2 "gives seemingly
        satisfactory results"

    Returns
    -------
    numpy.ndarray
        1D list of numbers that sum to 1, represents weights of provided distances, in order.

    References
    ----------

    Shepard, Donald (1968). "A two-dimensional interpolation function for irregularly-spaced data".
    Proceedings of the 1968 ACM National Conference. pp. 517-524. doi:10.1145/800186.810616
    """
    return to_percentage(1/np.power(distances, power))

def to_percentage(vec):
    """ Converts list of real numbers into a list of percentages """
    return vec/np.sum(vec)


import numpy as np

def loaddataset():
    """
    Reads the dataset file and returns the dataset as an array
    :return: The dataset array.
    """
    datafile = "../UCIdata-exercise1/pima-indians-diabetes.data"
    namesfile = "../UCIdata-exercise1/pima-indians-diabetes.names"

    names = open(namesfile).readlines()
    for i in names: print(i)

    data = np.genfromtxt(datafile, delimiter=",")

    return data

def gaussian(X, mu, sigma, dim=None):
    """
    Calculates the gaussian probability for a given set.
    :param X: The variable vector in the gaussian calculation.
    :param mu: The mean of the wanted distribution.
    :param sigma: The (co)variance of the wanted distribution.
    :param dim: Indicator about whether we need the 1-dim or multi-dim gaussian case.
    :return: The resulting likelihood.
    """
    if dim != 1:
        x_len = len(X)
        denominator = (2 * np.pi) ** (x_len / 2) * np.sqrt(np.linalg.det(sigma))
        # exp = (-1/2)*np.dot(np.matmul(X-mu, np.linalg.inv(sigma)), X-mu)
        nominator = np.exp(-0.5 * np.dot(np.dot(np.transpose(X - mu), np.linalg.inv(sigma)), (X - mu)))
    else:
        z_score = (X - mu) / sigma
        denominator = sigma * np.sqrt(2 * np.pi)
        nominator = np.exp(-0.5 * np.dot(z_score.T, z_score))

    probability = (nominator / denominator)

    # uncomment below to debug overflow error
    # from scipy.stats import multivariate_normal
    # gaussian = multivariate_normal.pdf(X, mean=mu, cov=sigma)#, allow_singular=True)

    return probability if probability != 0 else 10 ** -100  # hardcoded min because log(0) threw warning and inf result.

def question_a(X):
    """
    Covariance matrix is diagonal, with elements being equal, while the distribution is gaussian.

    :param X: The datapoints that belong to a specific class
    :return: mean vector and covariance matrix
    """
    mus = X.mean(axis=0)

    diff = (X - mus)
    su = np.sum(np.dot(diff.T, diff)) / (8 * X.shape[0])

    sigmas = su * np.eye(X.shape[1])

    return mus, sigmas

def question_b(X):
    """
    Covariance matrix is non-diagonal, while the distribution is gaussian.

    :param X: The datapoints that belong to a specific class
    :return: mean vector and covariance matrix
    """

    mus = np.mean(X, axis=0)

    diff = (X - mus)
    sigmas = np.dot(diff.T, diff) / X.shape[0]

    return mus, sigmas

def question_c(X):
    """
    Features are i.i.d. with gaussian marginal distributions.

    :param X: The datapoints that belong to a specific class
    :return: mean vector and covariance matrix
    """

    mus = np.mean(X, axis=0)

    diff = (X - mus)

    sigmas = np.eye(X.shape[1])
    for i in range(mus.shape[0]):
        sigmas[i, i] = np.sum(np.square(diff[:, i])) / X.shape[0]

    return mus, sigmas

def question_d(X, x_var):
    """
    Features are i.i.d. with unknown marginal distributions.
    Window kernels are standard gaussians.

    :param X: The datapoints that belong to a specific class.
    :param x_var: The variable we want to derive the likelihood for.
    :return: the iid result vector of the pdf for some sample x_i.
    """
    N = X.shape[0]
    d = X.shape[1]

    kernel_mu = 0
    kernel_sigma = 1

    h = np.sqrt(N)
    scale_factor = - d * np.log(h * N)

    sum_over_d = 0
    for j in range(d):
        sum_over_N = 0
        for i in range(N):
            x_tmp = (X[i, j] - x_var[j]) / h
            sum_over_N += gaussian(x_tmp, kernel_mu, kernel_sigma, dim=1)

        sum_over_d += np.log(sum_over_N)  # The naive beyes rule with log probability

    likelihood = scale_factor + sum_over_d

    return likelihood


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

data = pd.read_csv('Howell1.csv', delimiter=';')
#4.1
'''

d2 = data[data['age'] >= 18]

height = d2['height']
weight = d2['weight']

weightBar = np.mean(weight)

with pm.Model() as centered:
	alpha = pm.Normal('alpha', mu=178, sigma=20)
	beta = pm.Lognormal('beta', mu=0, sigma=1)

	s = pm.Uniform('sigma', 0, 50)

	h = pm.Normal('height', mu=alpha + beta*(weight-weightBar), sigma=s, observed=height)

	mean_q = pm.find_MAP()

	hessian = pm.find_hessian(mean_q, vars=[alpha, beta, s])

	covariance_q = np.linalg.inv(hessian)

	std_q = np.sqrt(np.diag(covariance_q))

samples = np.random.multivariate_normal([mean_q['alpha'], mean_q['beta'], mean_q['sigma']], covariance_q, size=10000)

a_map, b_map, s_map = np.mean(samples,0)

ww = np.array([46.95, 43.72, 64.78, 32.59, 54.63])
pred = a_map + b_map * (ww-weightBar)

mus = samples[:, 0 ] + samples[:, 1] * np.tile(ww.reshape(1,ww.shape[0]) - weightBar, (samples.shape[0],1)).T

ci89 = np.percentile(mus, [5.5, 94.5], axis=1).T

for w, hp, cc in zip(ww, pred, ci89):
    print('%.2f\t%.2f\t[%.2f, %.2f]' % (w, hp, cc[0], cc[1]))

#4.2
d2 = data[data['age'] < 18]

height = d2['height']
weight = d2['weight']

weightBar = np.mean(weight)

with pm.Model() as normal_approximation:
	alpha = pm.Normal('alpha', mu=120, sigma=20)
	beta = pm.Lognormal('beta', mu=0, sigma=1)

	s = pm.Uniform('sigma', 0, 20)

	h = pm.Normal('height', mu=alpha + beta*(weight-weightBar), sigma=s, observed=height)

	mean_q = pm.find_MAP()

	hessian = pm.find_hessian(mean_q, vars=[alpha, beta, s])

	covariance_q = np.linalg.inv(hessian)

	std_q = np.sqrt(np.diag(covariance_q))

#draw samples from posterior
samples = np.random.multivariate_normal([mean_q['alpha'], mean_q['beta'], mean_q['sigma']], covariance_q, size=10000)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(weight, height, color='w', edgecolor='C0', alpha=0.5)

a_map, b_map, s_map = np.mean(samples,0)

ww = np.arange(0, 65)
ax.plot(ww, a_map + b_map * (ww-weightBar), color='k')

mus = samples[:, 0 ] + samples[:, 1] * np.tile(ww.reshape(1,ww.shape[0]) - weightBar, (samples.shape[0],1)).T

ci89 = np.percentile(mus, [5.5, 94.5], axis=1).T

ax.plot(ww, ci89[:,0], color='k', linestyle='--', alpha=0.7)
ax.plot(ww, ci89[:,1], color='k', linestyle='--', alpha=0.7)

ax.fill_between(ww, ci89[:,0], ci89[:,1], color='k', alpha=0.2)

posteriorDraws = np.random.normal(mus, samples[:,2])
posteriorCi89 = np.percentile(posteriorDraws, [5.5, 94.5], axis=1).T

ax.fill_between(ww, posteriorCi89[:,0], posteriorCi89[:,1], color='k', alpha=0.1)
ax.set_title('4.2')
print('%f kg / 10 cm' % 10 * b_map)

# not a good fit,
# changing to a "better" prior didn't help a~N(120,20), b~LogN(0,1.5)
# many points away from the mean
# especially at the extreme weights
# consistently overestimates or underestimates true height
# in children, age is an important covariate
# well, to now choose a different model is difficult, because I've looked at the scatter plot

#4.3
height = data['height']
weight = data['weight']

weight = np.log(weight)

weightBar = np.mean(weight)

with pm.Model() as normal_approximation:
	alpha = pm.Normal('alpha', mu=178, sigma=20)
	beta = pm.Lognormal('beta', mu=0, sigma=1)

	s = pm.Uniform('sigma', 0, 20)

	h = pm.Normal('height', mu=alpha + beta*(weight-weightBar), sigma=s, observed=height)

	mean_q = pm.find_MAP()

	hessian = pm.find_hessian(mean_q, vars=[alpha, beta, s])

	covariance_q = np.linalg.inv(hessian)

	std_q = np.sqrt(np.diag(covariance_q))

#draw samples from posterior
samples = np.random.multivariate_normal([mean_q['alpha'], mean_q['beta'], mean_q['sigma']], covariance_q, size=10000)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(np.exp(weight), height, color='w', edgecolor='C0', alpha=0.5)

a_map, b_map, s_map = np.mean(samples,0)

wwe = np.arange(4, 64)
ww = np.log(wwe)
ax.plot(wwe, a_map + b_map * (ww-weightBar), color='k')
mus = samples[:, 0 ] + samples[:, 1] * np.tile(ww.reshape(1,ww.shape[0]) - weightBar, (samples.shape[0],1)).T

ci89 = np.percentile(mus, [1.5, 98.5], axis=1).T

ax.plot(wwe, ci89[:,0], color='k', linestyle='--', alpha=0.7)
ax.plot(wwe, ci89[:,1], color='k', linestyle='--', alpha=0.7)

ax.fill_between(wwe, ci89[:,0], ci89[:,1], color='k', alpha=0.2)

posteriorDraws = np.random.normal(mus, samples[:,2])
posteriorCi89 = np.percentile(posteriorDraws, [1.5, 98.5], axis=1).T

ax.fill_between(wwe, posteriorCi89[:,0], posteriorCi89[:,1], color='k', alpha=0.1)
ax.set_title('4.3')
#pretty good fit?

'''

#4.4
N = 50
alphas = np.random.normal(178, 20, size=N)
beta1s = np.exp(np.random.normal(0, 1, size=N))
beta2s = -np.abs(np.random.normal(0, 2, size=N))
sigmas = 50 * np.random.rand(N)

height = data['height']
weight = data['weight']

weight = np.array(weight)
height = np.array(height)

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
weightS = ss.fit_transform(weight.reshape(-1,1)).reshape(-1,)

weightS2 = weightS ** 2

xxu = np.linspace(np.min(weight), np.max(weight), 200).reshape(-1,1)
xx = ss.transform(xxu).reshape(-1,)
xx2 = xx ** 2

xx = np.tile(xx, (N,1))
xx2 = np.tile(xx2, (N,1))

mus = (alphas + beta1s * xx.T + beta2s * xx2.T).T

fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(N):
	ax.plot(xxu, mus[i], 'k')

# function should be non-decreasing, i.e. 1st derivative positive at least in the range we are interested in
# h(w) = a + β_1 * (w-wbar) + β_2 * (w-wbar)^2
# h'(w) = β_1 + 2 * β_2 * (w-wbar)

plt.show()


import numpy as np
import cmsisdsp.datatype as dt

def frequencyToMelSpace(freq):
    return 1127.0 * np.log(1.0 + freq / 700.0)

def melSpaceToFrequency(mels):
    return 700.0 * (np.exp(mels / 1127.0) - 1.0)

def melFilterMatrix(dtype,fmin, fmax, numOfMelFilters,fs,FFTSize):

    filters = np.zeros((numOfMelFilters,int(FFTSize/2+1)))
    zeros = np.zeros(int(FFTSize // 2 ))

    fmin_mel = frequencyToMelSpace(fmin)
    fmax_mel = frequencyToMelSpace(fmax)
    mels = np.linspace(fmin_mel, fmax_mel, num=numOfMelFilters+2)

    linearfreqs = np.linspace( 0, fs/2.0, int(FFTSize // 2 + 1) )
    spectrogrammels = frequencyToMelSpace(linearfreqs)[1:]

    filtPos=[]
    filtLen=[]
    totalLen = 0
    packedFilters = []
    for n in range(numOfMelFilters):

      upper = (spectrogrammels - mels[n])/(mels[n+1]-mels[n])
      lower = (mels[n+2] - spectrogrammels)/(mels[n+2]-mels[n+1])

      filters[n, :] = np.hstack([0,np.maximum(zeros,np.minimum(upper,lower))])
      nb = 0
      startFound = False
      for sample in filters[n, :]:
        if not startFound and sample != 0.0:
            startFound = True
            startPos = nb

        if startFound and sample == 0.0:
           endPos = nb - 1
           break
        nb = nb + 1
      filtLen.append(endPos - startPos+1)
      totalLen += endPos - startPos + 1
      filtPos.append(startPos)
      packedFilters += list(filters[n, startPos:endPos+1])

    return filtLen,filtPos,dt.convert(packedFilters,dtype)

def dctMatrix(dtype,numOfDctOutputs, numOfMelFilters):

    result = np.zeros((numOfDctOutputs,numOfMelFilters))
    s=(np.linspace(1,numOfMelFilters,numOfMelFilters) - 0.5)/numOfMelFilters

    for i in range(0, numOfDctOutputs):
        result[i,:]=np.cos(i * np.pi*s) * np.sqrt(2.0/numOfMelFilters)

    return dt.convert(result.reshape(numOfDctOutputs*numOfMelFilters),dtype)


"""
Authors: Aditya Jain
Contact : https://adityajain.me
"""

import numpy as np

class KNeighborsRegressor():
	"""
	K Nearest Neighbor Regressor which find sample point based on majority of k nearby sample values.

	Parameters
	----------
	n_neighbors : integer (Default 5), number of neighbors to consider

	metric : str ( 'minkowski', 'euclidean', 'manhatten' ) (Default : 'minkowski')

	p : integer (Default 2), metric used in minkowski distance

	normalize : boolean, normalize data before calculating distance

	"""
	def __init__(self, n_neighbors=5, metric='minkowski', p=2, normalize=False):
		self.__n_neighbors = n_neighbors
		self.__X = None
		self.__y = None
		self.__normalize = normalize
		self.__metric = { 'minkowski': self.__minkowski, 'euclidean':self.__euclidean, 'manhatten':self.__manhatten }[metric]
		self.__p = p
		self.__n_classes = None
		self.__means = None
		self.__std = None

	def __euclidean(self,X1,X2):
		return np.sqrt(np.sum(np.square(X1-X2),axis=1))

	def __manhatten(self,X1,X2):
		return np.sum(np.abs(X1-X2),axis=1)

	def __minkowski(self,X1,X2):
		return np.power(np.sum(np.power(np.abs(X1-X2),self.__p),axis=1),1/self.__p)

	def __normalizeX(self,X):
		return (X-self.__means)/self.__std

	def fit(self,X,y):
		"""
		Fit X using y

		Parameters
		----------
		X : 2D numpy array, independent variables

		y : 1D numpy array, dependent variable

		"""
		self.__y, self.__n_classes = y, len(np.unique(y))
		if self.__normalize:
			self.__means, self.__std = X.mean(axis=0), X.std(axis=0)
			self.__X = self.__normalizeX(X)
		else:
			self.__X = X

	def predict(self,X):
		"""
		Predict dependent variable

		Parameters
		---------
		X : numpy array, independent variables

		Returns
		-------
		Predicted classes

		"""
		if self.__normalize: X = self.__normalizeX(X)
		probs = []
		for sample in X:
			x = np.expand_dims(sample,axis=0)
			distances = self.__metric(self.__X, x)
			top_k_index = distances.argsort()[:self.__n_neighbors]
			probs.append(np.mean(self.__y[top_k_index]))
		return np.array(probs)

	def score(self,X,y):
		"""
		Computer Coefficient of Determination (rsquare)

		Parameters
		----------
		X : 2D numpy array, independent variables

		y : numpy array, dependent variables

		Returns
		-------
		r2 values

		"""
		return 1-(np.sum(((y-self.predict(X))**2))/np.sum((y-np.mean(y))**2))


import matplotlib.pyplot as plt
import numpy as np

def julia(progress_bar, frame_text, separation, iterations, st_fig):
    m, n, s = 960, 640, 400
    x = np.linspace(-m / s, m / s, num=m).reshape((1, m))  # real axis
    y = np.linspace(-n / s, n / s, num=n).reshape((n, 1))  # imaginary axis

    for frame_num, a in enumerate(np.linspace(0.0, 4 * np.pi, 100)):
        fig, ax = plt.subplots(1, 1, figsize=(10, 10))
        # Here were setting value for these two elements.
        progress_bar.progress(frame_num)
        frame_text.text("Frame %i/100" % (frame_num + 1))

        # Performing some fractal wizardry.
        c = separation * np.exp(1j * a)
        Z = np.tile(x, (n, 1)) + 1j * np.tile(y, (1, m))
        C = np.full((n, m), c)
        M: Any = np.full((n, m), True, dtype=bool)
        N = np.zeros((n, m))

        for i in range(iterations):
            Z[M] = Z[M] * Z[M] + C[M]
            M[np.abs(Z) > 2] = False
            N[M] = i

        # formatting options: remove ticks
        # ax = plt.axes()
        ax.set_xticks([], [])
        ax.set_yticks([], [])

        ax.imshow(1.0 - (N / N.max()), interpolation="hanning", cmap="magma_r")
        # Update the fig placeholder by calling the pyplot() function on it.
        st_fig.pyplot(fig, cmap="magma", clear_figure=True)

def animate_julia(a, ax, x, y, separation, iterations):
    a = a * (4 * np.pi) / 100
    ax.clear()
    ax.set_xticks([], [])
    ax.set_yticks([], [])
    m, n, s = 960, 640, 400
    # Performing some fractal wizardry.
    c = separation * np.exp(1j * a)
    Z = np.tile(x, (n, 1)) + 1j * np.tile(y, (1, m))
    C = np.full((n, m), c)
    M: Any = np.full((n, m), True, dtype=bool)
    N = np.zeros((n, m))

    for i in range(iterations):
        Z[M] = Z[M] * Z[M] + C[M]
        M[np.abs(Z) > 2] = False
        N[M] = i

    img = ax.imshow(1.0 - (N / N.max()), interpolation="hanning", cmap="magma_r")

    return [img]


#!/usr/bin/env python3

import numpy as np
from scipy.integrate import solve_ivp
from scipy.signal import find_peaks
import matplotlib.pyplot as plt
import logging

from ..utils.modelargs import parse_args

logging.basicConfig(level = logging.INFO)
logger = logging.getLogger(__name__)

# Susceptible -> Infected -> Recovered model
class SIR:

    def __init__(self, N, beta, gamma, I0, R0, tau):
        logger.info('Intializing SIR model ...')
        self.N = N # Total population (assumed constant)
        self.beta = beta # Daily contact rate (for adequate contact)
        self.gamma = gamma # Proportionality constant of daily recovery
        self.I0 = I0 # Initial infected population (number, not fraction)
        self.R0 = R0 # Initial recovered population (number, not fraction)
        # Initial susceptible population (number, not a fraction)
        self.S0 = N - I0 - R0
        self.tau = tau # Time window in days over which to model
        self.t = np.linspace(0, self.tau, self.tau)
        self.S = None
        self.I = None
        self.R = None

    # Solve the differential equatons for this model
    def solve(self):

        def diffeqns(t, y, N, beta, gamma):

            S, I, R = y
            dSdt = -beta * S * I / N
            dIdt = beta * S * I / N - gamma * I
            dRdt = gamma * I

            dydt = [dSdt, dIdt, dRdt]
            return dydt

        y0 = [self.S0, self.I0, self.R0] # Initial values

        # Solve differntial equations
        tspan = [0, self.tau]
        sol = solve_ivp(diffeqns, tspan, y0,
                     t_eval = self.t, args=(self.N, self.beta, self.gamma))

        self.S = sol.y[0]
        self.I = sol.y[1]
        self.R = sol.y[2]

    # Find the peak infection (day, number infected)
    def peak(self):
        if self.I is None:
            logger.error('solve() method has not been invoked yet')
            raise ValueError("peak() method invoked before invoking solve()")

        p = find_peaks(self.I, height = 0)
        day = p[0][0]
        infec = p[1]['peak_heights'][0]
        return day, infec

    # Plot the S, I and R curves
    def plot(self):
        if self.S is None or self.I is None or self.R is None:
            logger.error('solve() method has not been invoked yet')
            raise ValueError("plot() method invoked before invoking solve()")

        logger.info('Plotting SIR model ...')
        S = self.S
        I = self.I
        R = self.R
        t = self.t
        N = self.N

        fig = plt.figure()
        ax = fig.add_subplot(111)

        ax.plot(t, S, label='Susceptible Population')
        ax.plot(t, I, label='Infected Population')
        ax.plot(t, R, label='Recovered Population')
        ax.set_xlabel('Days')
        ax.set_ylabel('Number of People')

        ax.set_ylim(0, N+100)
        legend = ax.legend()

        plt.show()

def usage():
    usagestr0 = './sir.py N=<N> I0=<I0> R0=<R0> beta=<beta> gamma=<gamma> tau=<tau>, where: \n'
    usagestr1 = 'N = total population, assumed constant \n'
    usagestr2 = 'I0 = initial number of infected people \n'
    usagestr3 = 'R0 = initial number of recovered people \n'
    usagestr4 = 'beta = daily contact rate \n'
    usagestr5 = 'gamma = proportionality constant of daily recovery \n'
    usagestr6 = 'tau = duration in days over which the model should be constructed. \n'
    usagestr7 = 'Note: order of arguments passsed is not important. Any other argument will be ignored. \n'
    usagestr8 = '\nExample: ./sir.py N=1000 I0=1 R0=0 beta=0.2 gamma=0.1 tau=150 \n'

    print(usagestr0 + usagestr1 + usagestr2 + usagestr3 + usagestr4 +
            usagestr5 + usagestr6 + usagestr7 + usagestr8)

if __name__ == "__main__":

    res = parse_args()
    if res is None:
        logger.error('No argument passed.')
        usage()
        quit()

    if res == 'usage':
        usage()
        quit()

    if isinstance(res, dict):
        miss = []
        if 'N' in res:
            N = res['N']
        else:
            miss.append('N')

        if 'beta' in res:
            beta = res['beta']
        else:
            miss.append('beta')

        if 'gamma' in res:
            gamma = res['gamma']
        else:
            miss.append('gamma')

        if 'I0' in res:
            I0 = res['I0']
        else:
            miss.append('I0')

        if 'R0' in res:
            R0 = res['R0']
        else:
            miss.append('R0')

        if 'tau' in res:
            tau = res['tau']
        else:
            miss.append('tau')

        if len(miss) > 0:
            logger.error('Some required arguments are missing: ' + ','.join(miss))
            usage()
            quit()

    model = SIR(N=N, beta=beta, gamma=gamma, I0=I0, R0=R0, tau=tau)

    model.solve()

    model.plot()


#!/usr/bin/env python

"""
    多项式回归问题
    可以通过调整degree参数来比较训练后的结果
    并以此判断哪种是最合适的模型
    但是要防止过拟合现象
"""

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

# 代表使用几次多项式回归模型
degree = 2

# 自己构造数据集
x = np.linspace(5, 30, 20)
y = (5+ x**2) + np.random.randn(20) * 5
x = x[:,np.newaxis]

# training set
x_train = x[:-2]
y_train = y[:-2]

# test set
x_test = x[-2:]
y_test = y[-2:]

# 用多项式对x做变换 degree代表 n次多项式
quadratic_featurizer = PolynomialFeatures(degree=degree)
x_quadratic = quadratic_featurizer.fit_transform(x)
x_train_quadratic = x_quadratic[:-2]
x_test_quadratic = x_quadratic[-2:]
regressor_quadratic = LinearRegression()
regressor_quadratic.fit(x_train_quadratic, y_train)

print("系数：{} 误差：{}".format(regressor_quadratic.coef_, regressor_quadratic.intercept_))
print("预测结果：{} 得分：{}".format(regressor_quadratic.predict(x_test_quadratic), regressor_quadratic.score(x_test_quadratic, y_test)))

plt.scatter(x, y, color='black')
plt.plot(x, regressor_quadratic.predict(x_quadratic), 'g-')
plt.show() # 展示图像


import numba
import numpy as np

@numba.njit
def _perlin2d_internal(hperiod: int, vperiod: int, angles: np.ndarray) -> np.ndarray:
      grad_x = np.cos(angles).reshape(angles.shape[0], 1, angles.shape[1], 1)
      grad_y = np.sin(angles).reshape(angles.shape[0], 1, angles.shape[1], 1)

      hoffsets = np.linspace(0, 1, hperiod + 1)[:-1].reshape(1, 1, 1, -1)
      voffsets = np.linspace(0, 1, vperiod + 1)[:-1].reshape(1, -1, 1, 1)

      hsmooth = ((6 * hoffsets - 15) * hoffsets + 10) * hoffsets ** 3
      vsmooth = ((6 * voffsets - 15) * voffsets + 10) * voffsets ** 3

      ul = grad_x[:-1, :, :-1, :] * hoffsets + grad_y[:-1, :, :-1, :] * voffsets
      ur = grad_x[:-1, :, 1:, :] * (hoffsets - 1) + grad_y[:-1, :, 1:, :] * voffsets
      bl = grad_x[1:, :, :-1, :] * hoffsets + grad_y[1:, :, :-1, :] * (voffsets - 1)
      br = grad_x[1:, :, 1:, :] * (hoffsets - 1) + grad_y[1:, :, 1:, :] * (voffsets - 1)

      u = (1 - hsmooth) * ul + hsmooth * ur
      b = (1 - hsmooth) * bl + hsmooth * br
      img = (1 - vsmooth) * u + vsmooth * b
      return img

def perlin2d(width: int, height: int,
             hperiod: int, vperiod: int,
             rng: np.random.Generator) -> np.ndarray:
      grid_shape = np.ceil((height / vperiod, width / hperiod)).astype(np.int64) + 1
      angles = 2 * np.pi * rng.random(grid_shape)
      img = _perlin2d_internal(hperiod, vperiod, angles)
      img = img.reshape((grid_shape - 1) * (vperiod, hperiod))[:height, :width]
      return img

def fractal2d(width: int, height: int,
              hperiod: int, vperiod: int,
              octaves: int, persistence: float,
              rng: np.random.Generator) -> np.ndarray:
      amp = (1 - persistence) / (1 - persistence ** octaves)
      img = np.zeros((height, width))
      for _ in range(octaves):
            img += amp * perlin2d(width, height, hperiod, vperiod, rng)
            amp *= persistence
            hperiod = hperiod >> 1
            vperiod = vperiod >> 1
      return img


import numpy as np

__all__ = ['uv_to_spddir', 'spddir_to_uv']

def uv_to_spddir(u, v, direction=False):
    """
    Calculates the wind speed from u and v components.
    Will calculate direction as well if parameter direction = True.
    Takes into account the wind direction coordinates is different than
    the trig unit circle coordinate. If the wind direction is 360,
    then return zero.
    Args:
        u : (array like) u (easterly) wind component
        v : (array like) v (northerly) wind component
        direction: (bool, optional, default=False)
    Returns:
        An array of wind speed (and an array of wind direction if direction=True)
    """
    u = np.array(u)
    v = np.array(v)

    wdir = (270 - np.rad2deg(np.arctan2(v, u))) % 360
    wspd = np.sqrt(u * u + v * v)

    return wspd, wdir if direction else wspd

def spddir_to_uv(wspd, wdir):
    """
    Calculate the u and v wind components from wind speed and direction.
    Args:
        wspd : (array like) wind speed
        wdir : (array like) wind direction in degrees
    Returns:
        The u,v wind vector components.
    """
    wspd = np.array(wspd, dtype=float)
    wdir = np.array(wdir, dtype=float)

    rad = 4.0 * np.arctan(1) / 180.
    u = -wspd * np.sin(rad * wdir)
    v = -wspd * np.cos(rad * wdir)

    # If the speed is zero, then u and v should be set to zero (not NaN)
    if wspd == 0:
        u = float(0)
        v = float(0)

    return u, v


import scipy.integrate as spi
import numpy as np

print('Single integral computed by SciPy romberg')
print('Example 1-01 romberg')
print('Integral of 2xe^-x from x=1 to x=5')

integrand = lambda x : 2 * x * np.exp(-x)
a = 1.
b = 5.

result = spi.romberg(integrand, a, b)
print('Result is ', result)


from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize as opt
from math import exp
import scipy.stats as st
import sys
sys.path.append('..')

from rto_l1 import *

np.random.seed(100872)

# forward function and Jacobian
f_fnc = lambda x, theta: theta[0]*(1 - np.exp(-theta[1]*x))

Jf_fnc = lambda x, theta: np.stack((1 - np.exp(-theta[1]*x), theta[0] * x * np.exp(-theta[1]*x)), axis=1)

# observation positions
xObs = np.array([0.3, 0.5, 1.0, 1.8, 3.3, 5.8])

# ground truth parameter
thetatruth = np.array([1.0, 0.3])

# forward function for fixed observation positions
f = lambda theta: f_fnc(xObs, theta)
Jf = lambda theta: Jf_fnc(xObs, theta)

# observational noise
sigma = 0.2

# generate data
y = f(thetatruth) + np.random.normal(0, sigma, xObs.shape)

# Laplace prior scale (both parameters)
gamma = 0.05
lambdas = 1/gamma*np.ones(2,)

# starting point for optimization
theta0 = np.random.normal(0, gamma, thetatruth.shape)

############## Stuff for didactical purposes, not necessary for sampling:
# Plot of posterior negative logdensity
xs = np.linspace(0, 6, 300)

misfit = lambda theta: 1/(2*sigma**2)*np.dot((y-f(theta)).T, y-f(theta))

# find MAP optimizer (by grid iteration)
posteriorlogdensity = lambda theta: misfit(theta) + 1/gamma*abs(theta[0]) + 1/gamma*abs(theta[1])

N_contours = 300
theta1s = np.linspace(-3, 3, N_contours)
#theta1s = np.linspace(0.6, 1.8, N_contours)
theta2s = np.linspace(-1, 3, N_contours)
#theta2s = np.linspace(0.04, 0.2, N_contours)

T1, T2 = np.meshgrid(theta1s, theta2s)
postvals = np.zeros((N_contours, N_contours))
misvals = np.zeros((N_contours, N_contours))
for n, t1 in enumerate(theta1s):
    for m, t2 in enumerate(theta2s):
        postvals[m, n] = posteriorlogdensity(np.array([t1, t2]))
        misvals[m, n] = misfit(np.array([t1, t2]))

indmin = np.unravel_index(np.argmin(postvals, axis=None), misvals.shape)
thetaMAP_grid = np.array([theta1s[indmin[1]], theta2s[indmin[0]]])

N_samples = 1000;
# RTO sampling
res = rto_l1(f, Jf, y, sigma, lambdas, np.random.normal(0, 1, (2,)), N_samples = 1000, init_method="previous") # you can also try init_method = "fixed" or "previous", but will work worse

# extract data
samples_plain = res["samples_plain"]
samples_corrected = res["samples_corrected"]
thetaMAP = res["thetaMAP"]
logweights = res["logweights"]
num_bad_opts = res["num_bad_opts"]
num_bad_QR = res["num_bad_QR"]

# plot results
plt.figure(1); plt.ion()
plt.title("parameter space")
plt.contourf(theta1s, theta2s, np.log(postvals), 20, cmap=plt.get_cmap("viridis"))
plt.plot(samples_corrected[:, 0], samples_corrected[:, 1], '.', label="samples")
plt.plot(thetatruth[0], thetatruth[1], 'go', markersize=10, label="th_true")
plt.plot(thetaMAP_grid[0], thetaMAP_grid[1], 'yo', markersize=10, label="th_MAP (grid search)")

plt.plot(thetaMAP[0], thetaMAP[1], 'mo', markersize=10, label="th_MAP (optimization)")
plt.legend(numpoints=1)

plt.figure(2); plt.clf()
inds = np.random.choice(range(samples_corrected.shape[0]), 500, replace=False)
plt.plot(xs, f_fnc(xs, np.reshape(samples_corrected[0], thetatruth.shape)), '0.9', linewidth=1, label="samples")
for ind in inds:
	plt.plot(xs, f_fnc(xs, np.reshape(samples_corrected[ind], thetatruth.shape)), '0.9', linewidth=1)

plt.plot(xObs, y, 'rx', label="observation")
plt.plot(xs, f_fnc(xs, thetatruth), 'g', linewidth=3, label="th_true")
plt.plot(xs, f_fnc(xs, thetaMAP_grid), 'y', linewidth=3, label="th_MAP (grid search)")
plt.plot(xs, f_fnc(xs, thetaMAP), 'm', linewidth=3, label="th_MAP (optimization)")
plt.legend(numpoints=1)
plt.show()


import numpy as np
from scipy.optimize import curve_fit

def gaus(x, a, b, c):
    """
    3-parameter Gaussian function.
    """
    return a*np.exp( -(x - b)**2 / (2*c**2) )

def lin(x, m, b):
    """
    Linear function, m = slope, b = intercept.
    """
    return m*x + b

def gaus_pol1(x, a, b, c, m, yint):
    """
    Gaussian function on top of linear background.
    """
    return gaus(x, a, b, c) + lin(x, m, yint)

def gaus_pol1_param_estimator(x, y):
    """
    Use input x, y data to determine initial parameter estimates for the
    gaus_pol1 model.
    """
    # Amplitude estimate
    a = np.max(y)
    # Centroid
    b = x[np.argmax(y)]
    # Std. dev
    half_max_domain = x[np.where(y > 0.5*a)]
    fwhm = half_max_domain[-1] - half_max_domain[0]
    c = fwhm / 2.355
    # Linear slope
    m = (y[-1] - y[0]) / (x[-1] - x[0])
    # Y-intercept of line
    yint = y[0] - m*x[0]
    # Return parameter estimates
    return (a, b, c, m, yint)

class Fitter(object):
    def __init__(self, xdata=None, ydata=None, model=gaus_pol1,
                 estimator=gaus_pol1_param_estimator):
        # Inputs
        self.xdata = xdata
        self.ydata = ydata
        self.xmin, self.xmax = None, None
        self.model = model
        self.estimator = estimator
        # Outputs
        self.popt = None
        self.pcov = None
        self.fit_history = []

    @property
    def data_mask(self):
        return np.logical_and(self.xdata >= self.xmin,
                              self.xdata <= self.xmax)
    @property
    def xf(self):
        return self.xdata[self.data_mask]

    @property
    def yf(self):
        return self.ydata[self.data_mask]

    @property
    def perr(self):
        if self.popt is None or self.pcov is None: return None
        return np.sqrt(np.diag(self.pcov))

    def set_data(self, x, y):
        self.xdata, self.ydata = x, y

    def fit(self):
        """
        Find optimal parameter estimates using scipy.curve_fit
        """
        # Initialize parameter estimates
        if self.estimator is not None:
            param_estimates = self.estimator(self.xf, self.yf)
        else: param_estimates = None
        self.popt, self.pcov = curve_fit(self.model, self.xf, self.yf,
                                         p0=param_estimates)
        self.fit_history.append({"popt" : self.popt, "pcov" : self.pcov})


# -*- coding: utf-8 -*-
"""
:Author: Jaekyoung Kim
:Date: 2018. 1. 30.
"""
import numpy as np
from scipy.optimize import minimize

from data import data_column
from data.data_reader import get_all_data, get_police_data, get_corporate_buyer_data

# Setting data
COST = 15000
MSRP = 25000

# Make an initial parameter guess as average of cost and MSRP.
INITIAL_GUESS = np.array([(COST + MSRP) / 2])

def get_logistic_probability(intercept, beta_1, unit_prices):
    """
    Calculate a logistic probability.

    :param intercept: (float) The intercept value.
    :param beta_1: (float) The list of beta.
    :param unit_prices: (np.arrayp[float]) The list of x.

    :return logistic_probability: (float)
        ln(alpha + beta_1 * x_1 + beta_2 * x_2 + ...) / (1 + ln(alpha + beta_1 * x_1 + beta_2 * x_2 + ...))
    """
    logistic_probability = np.exp(intercept + beta_1 * unit_prices) / (1 + np.exp(intercept + beta_1 * unit_prices))
    return logistic_probability

def get_negative_expected_margin(unit_price, *args):
    intercept = args[0]
    beta_1 = args[1]
    probability = get_logistic_probability(intercept, beta_1, unit_prices=unit_price / MSRP)
    unit_margin = unit_price - COST
    negative_expected_margin = -probability * unit_margin
    return negative_expected_margin

def get_negative_log_likelihood(params, *args):
    intercept = params[0]
    beta_1 = params[1]

    y_observations = np.array(args[0])
    unit_prices = np.array(args[1])

    # Calculate the predicted values from the initial parameter guesses
    win_probabilities = get_logistic_probability(intercept, beta_1, unit_prices)

    # Calculate the log-likelihood.
    negative_log_likelihood = -get_log_likelihood_sum(y_observations, win_probabilities)

    # Return the negative log likelihood.
    return negative_log_likelihood

def get_log_likelihood_sum(y_observations, win_probabilities):
    log_likelihood_sum = np.sum(
        np.log(np.power(win_probabilities, y_observations) * np.power((1 - win_probabilities), (1 - y_observations))))
    return log_likelihood_sum

def maximize_log_likelihood(y, x):
    # Make a list of initial parameter guesses (intercept, beta_1)
    initial_guess = np.array([0, 0])

    # Minimize a negative log likelihood for maximizing a log likelihood.
    results = minimize(get_negative_log_likelihood, x0=initial_guess, args=(y, x))

    intercept = results.x[0]
    beta_1 = results.x[1]

    return intercept, beta_1

def get_data_y_x(get_data_function):
    data = get_data_function()
    # Set up your observed y values.
    y_observation = data[data_column.WIN].values
    # Set up your x values.
    x = (data[data_column.UNIT_PRICE] / MSRP).values

    return data, y_observation, x

def get_optimal_price(intercept, beta_1):
    # Minimize a negative margin for maximizing a margin.
    optimal_price = minimize(get_negative_expected_margin, INITIAL_GUESS, args=(intercept, beta_1)).x[0]
    return optimal_price

if __name__ == '__main__':
    # 1_A
    print('1_A. What are the value of a and b that maximize the sum of log likelihood?')
    all_data, all_y_observation, all_x = get_data_y_x(get_all_data)
    all_intercept, all_beta_1 = maximize_log_likelihood(all_y_observation, all_x)
    print('a:{:.3f}, b:{:.3f}'.format(all_intercept, all_beta_1))
    print('-' * 70)

    # 1_B
    print('1_B. What is the optimum price Fjord should offer, '
          'assuming it is going to offer a single price for each bid?')
    all_optimal_price = get_optimal_price(all_intercept, all_beta_1)
    print(all_optimal_price)
    print('-' * 70)

    # 1_C
    print('1_C. What would the expected total contribution have been for the 4,000 bids?')
    all_optimal_total_contribution = -get_negative_expected_margin(all_optimal_price, all_intercept, all_beta_1) * all_data[
        data_column.UNIT_NUMBER].sum()
    print(all_optimal_total_contribution)
    print('-' * 70)

    # 1_D
    print('1_D. How does this compare to the contribution that Fjord actually received?')
    actual_total_contribution = all_data[data_column.TOTAL_MARGIN].sum()
    print('The optimal total contribution is {:.3f} times the actual total contribution.'.format(
        all_optimal_total_contribution / actual_total_contribution))
    print('-' * 70)

    # 2_A
    print('2_A. What are the corresponding values of a and b for each?')
    print('The police')
    police_data, police_y_observation, police_x = get_data_y_x(get_police_data)
    police_intercept, police_beta_1 = maximize_log_likelihood(police_y_observation, police_x)
    print('a:{:.3f}, b:{:.3f}'.format(police_intercept, police_beta_1))

    print('Corporate buyers')
    corporate_buyer_data, corporate_buyer_y_observation, corporate_buyer_x = get_data_y_x(
        get_corporate_buyer_data)
    corporate_buyer_intercept, corporate_buyer_beta_1 = maximize_log_likelihood(
        corporate_buyer_y_observation,
        corporate_buyer_x)
    print('a:{:.3f}, b:{:.3f}'.format(corporate_buyer_intercept, corporate_buyer_beta_1))
    print('-' * 70)

    # 2_B
    print('2_B. What are the optimum prices Fjord should offer to the police?')
    police_optimal_price = get_optimal_price(police_intercept, police_beta_1)
    print(police_optimal_price)
    print('-' * 70)

    # 2_C
    print('2_C. What are the optimum prices Fjord should offer to corporate buyer?')
    corporate_buyer_optimal_price = get_optimal_price(corporate_buyer_intercept, corporate_buyer_beta_1)
    print(corporate_buyer_optimal_price)
    print('-' * 70)

    # 2_D
    print('2_D. What would the expected contribution have been '
          'if Fjord had used the prices in the 4,000 bids in the database?')
    police_optimal_total_contribution = -get_negative_expected_margin(
        police_optimal_price, police_intercept, police_beta_1
    ) * police_data[data_column.UNIT_NUMBER].sum()
    corporate_buyer_optimal_total_contribution = -get_negative_expected_margin(
        corporate_buyer_optimal_price, corporate_buyer_intercept, corporate_buyer_beta_1
    ) * corporate_buyer_data[data_column.UNIT_NUMBER].sum()
    optimal_total_contribution_sum = police_optimal_total_contribution + corporate_buyer_optimal_total_contribution
    print(optimal_total_contribution_sum)
    print('-' * 70)

    # 2_E
    print('2_E. What is the difference between the contribution actually received and the best '
          'that Fjord could do when it could not differentiate between the police and corporate buyers?')
    print('The sum of the police and corporate buyer optimal total contribution is {:.3f} times the actual total '
          'contribution.'.format(optimal_total_contribution_sum / actual_total_contribution))
    print('-' * 70)


import numpy as np
import matplotlib.pyplot as plt

class Perceptron:
    def __init__(self, x, y, learningRate=0.01):
        self.x = x
        self.y = y
        self.addExtraColumnToXSample()
        self.w = np.zeros(len(self.x[0]))
        self.lr = learningRate

    def addExtraColumnToXSample(self):
        self.x = np.hstack((self.x, np.ones((self.x.shape[0], 1), dtype=self.x.dtype)))
        return self.x

    @staticmethod
    def checkSample(sample):
        if len(sample) == 2:
            sample = list(sample)
            sample.append(1)
        return np.array(sample)

    def predict(self, sample):
        sample = self.checkSample(sample)
        activation = np.dot(self.w, sample)
        return 1.0 if activation >= 0 else 0

    def train(self, epoch):
        for _ in range(epoch):
            for k, p in zip(self.x, self.y):
                pri = self.predict(sample=k)
                self.updateParameter(pri, p, k)

    def updateParameter(self, predict, trueLabel, xData):
        self.w += self.lr * (trueLabel - predict) * xData
        return self.w

if __name__ == '__main__':
    data = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
    label = np.array([1, 1, 1, 0])
    per = Perceptron(data, label)
    per.train(100)
    print(per.w)
    print(per.predict([0, 0]))


from __future__ import annotations

import numpy as np

from edutorch.typing import NPArray

from .module import Module

class BatchNorm(Module):
    def __init__(
        self,
        num_features: int,
        train_mode: bool = True,
        eps: float = 1e-5,
        momentum: float = 0.9,
    ) -> None:
        super().__init__()
        self.train_mode = train_mode
        self.eps = eps
        self.momentum = momentum

        self.running_mean = np.zeros(num_features)
        self.running_var = np.ones(num_features)
        self.gamma = np.ones(num_features)
        self.beta = np.zeros(num_features)
        self.set_parameters("running_mean", "running_var", "gamma", "beta")

    def forward(self, x: NPArray) -> NPArray:
        """
        Forward pass for batch normalization.
        Uses minibatch statistics to compute the mean and variance, use
        these statistics to normalize the incoming data, and scale and
        shift the normalized data using gamma and beta.

        During training the sample mean and (uncorrected) sample variance are
        computed from minibatch statistics and used to normalize the incoming data.
        During training we also keep an exponentially decaying running mean of the mean
        and variance of each feature, and these averages are used to normalize data
        at test-time.

        At each timestep we update the running averages for mean and variance using
        an exponential decay based on the momentum parameter:

        running_mean = momentum * running_mean + (1 - momentum) * sample_mean
        running_var = momentum * running_var + (1 - momentum) * sample_var

        Note that though you should be keeping track of the running
        variance, you should normalize the data based on the standard
        deviation (square root of variance) instead!
        Referencing the original paper (https://arxiv.org/abs/1502.03167)
        might prove to be helpful.

        Note that the batch normalization paper suggests a different test-time
        behavior: they compute sample mean and variance for each feature using a
        large number of training images rather than using a running average. For
        this implementation we have chosen to use running averages instead since
        they do not require an additional estimation step; the torch7 implementation
        of batch normalization also uses running averages.

        Input:
        - x: Data of shape (N, D)
        - gamma: Scale parameter of shape (D,)
        - beta: Shift parameter of shape (D,)
        - bn_param: Dictionary with the following keys:
            - mode: 'train' or 'test'; required
            - eps: Constant for numeric stability
            - momentum: Constant for running mean / variance.
            - running_mean: Array of shape (D,) giving running mean of features
            - running_var Array of shape (D,) giving running variance of features

        Returns a tuple of:
        - out: of shape (N, D)
        - cache: A tuple of values needed in the backward pass
        """
        if self.train_mode:
            # Compute output
            mu = x.mean(axis=0)
            xc = x - mu
            var = np.mean(xc ** 2, axis=0)
            std = np.sqrt(var + self.eps)
            xn = xc / std
            out = self.gamma * xn + self.beta

            # Update running average of mean
            self.running_mean *= self.momentum
            self.running_mean += (1 - self.momentum) * mu

            # Update running average of variance
            self.running_var *= self.momentum
            self.running_var += (1 - self.momentum) * var

        else:
            # Using running mean and variance to normalize
            std = np.sqrt(self.running_var + self.eps)
            xn = (x - self.running_mean) / std
            out = self.gamma * xn + self.beta

        self.cache = (xn, std)

        return out

    def backward(self, dout: NPArray) -> tuple[NPArray, ...]:
        """
        Alternative backward pass for batch normalization.

        For this implementation you should work out the derivatives for the batch
        normalizaton backward pass on paper and simplify as much as possible. You
        should be able to derive a simple expression for the backward pass.

        Note: This implementation should expect to receive the same cache variable
        as batchnorm_backward, but might not use all of the values in the cache.

        If you get stuck, check out a worked-out solution:
        https://kevinzakka.github.io/2016/09/14/batch_normalization/

        Inputs / outputs: Same as batchnorm_backward
        """
        xn, std = self.cache

        dx_hat = dout * self.gamma
        dx = (
            dx_hat - np.mean(dx_hat, axis=0) - xn * np.mean(dx_hat * xn, axis=0)
        ) / std

        dgamma = np.sum(dout * xn, axis=0)
        dbeta = np.sum(dout, axis=0)

        return dx, dgamma, dbeta

    def backward_naive(self, dout: NPArray) -> tuple[NPArray, ...]:
        """
        Backward pass for batch normalization.

        For this implementation, you should write out a computation graph for
        batch normalization on paper and propagate gradients backward through
        intermediate nodes.

        Inputs:
        - dout: Upstream derivatives, of shape (N, D)
        - cache: Variable of intermediates from batchnorm_forward.

        Returns a tuple of:
        - dx: Gradient with respect to inputs x, of shape (N, D)
        - dgamma: Gradient with respect to scale parameter gamma, of shape (D,)
        - dbeta: Gradient with respect to shift parameter beta, of shape (D,)
        """
        xn, std = self.cache

        if self.train_mode:
            N = dout.shape[0]
            dbeta = dout.sum(axis=0)
            dgamma = np.sum(xn * dout, axis=0)
            dxn = self.gamma * dout
            dxc = dxn / std
            dstd = -np.sum(  # pylint: disable=invalid-unary-operand-type
                (dxn * xn) / std, axis=0
            )
            dvar = 0.5 * dstd / std
            dxc += (2 / N) * (xn * std) * dvar
            dmu = np.sum(dxc, axis=0)
            dx = dxc - dmu / N

        else:
            dbeta = dout.sum(axis=0)
            dgamma = np.sum(xn * dout, axis=0)
            dxn = self.gamma * dout
            dx = dxn / std

        return dx, dgamma, dbeta


import math
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
startTime = datetime.now()

def angular_momentum(posArray, velArray, massArray):
    '''calculates the total angular momentum for a system of objects
    '''
    numObjects=len(massArray)
    numDimensions=len(posArray[0])
    momentum=[[0.0]*numDimensions for j in range(numObjects)]
    angMomen=[[0.0]*numDimensions for j in range(numObjects)]
    angMomenTot=[0.0]*numDimensions

    for j in range(numObjects):
        #take cross product of postion and velocity
        angMomen[j]=np.cross(posArray[j],velArray[j])
        #multiply each component by mass
        for i in range(numDimensions):
            angMomen[j][i]=massArray[j]*angMomen[j][i]
        #print angMomen[j]
    #sum up all angular momenta
    for j in range(numObjects):
        for i in range(numDimensions):
            angMomenTot[i]=angMomen[j][i]+angMomenTot[i]
    return angMomenTot

def total_energy(posArray, velArray, massArray):
    '''calculates the total energy (gravitational and kinetic) for a system of objects
    '''
    numObjects=len(massArray)
    numDimensions=len(posArray[0])
    G=math.pow(2.0*math.pi,2.0)
    gravPotential=0.0
    kineticEnergy=0.0
    speedArray=np.linalg.norm(velArray,axis=1)

    for j in range(numObjects):
        for k in range(j+1,numObjects):
            r = pythag_pos_diff(posArray[j],posArray[k])
            gravPotential+=(-G*massArray[j]*massArray[k])/r
    for j in range(numObjects):
        kineticEnergy+=(1.0/2.0)*massArray[j]*(speedArray[j]**2.0)

    energyTot=gravPotential+kineticEnergy
    return energyTot

def pythag_pos_diff(objPosArray1,objPosArray2):

    #calculates the pythagorian position difference between two n-dimensional position arrays
    pythagSum=0
    for l in range(len(objPosArray1)):
        pythagSum+=math.pow(objPosArray1[l]-objPosArray2[l],2)
    return math.pow(pythagSum,1.0/2.0)

def nbody_sim_leapfrog(posArray,velArray, massArray,stepSize,stepCount):
    '''Returns an array of computed position steps for the inputed objects
    '''
    numObjects=len(massArray)
    numDimensions=len(posArray[0])
    angStart=angular_momentum(posArray, velArray, massArray)
    energyStart=total_energy(posArray, velArray, massArray)
    #0. calculate first velocity step with forward euler
    #1. update position
    #2. compute acceleration
    #3. update velocity
    G=math.pow(2.0*math.pi,2.0)
    historicPosArray=[[[]for j in range(numDimensions)] for j in range(numObjects)]
    historicVelArray=[[[]for j in range(numDimensions)] for j in range(numObjects)]
    historicAngMomenDrift=[]
    historicEngDrift=[]

    #start with forward Euler
    accelArray=[[0]*numDimensions for j in range(numObjects)]
    for j in range(numObjects):
        for l in range(numDimensions):
            for k in range(j+1,numObjects):
                #print posArray[j],posArray[k]
                newAccel=G*massArray[k]*(posArray[k][l]-posArray[j][l]) / math.pow(pythag_pos_diff(posArray[j],posArray[k]),3.0)
                oppositeNewAccel=-newAccel*massArray[j]/massArray[k]
                accelArray[j][l]+=newAccel
                accelArray[k][l]+=oppositeNewAccel
    #print accelArray[1]
    #update velocity
    for j in range(numObjects):
        for l in range(numDimensions):
            velArray[j][l]+=(1.0/2.0)*stepSize*accelArray[j][l]
            historicVelArray[j][l].append(velArray[j][l])

    #simulation loop using leap frog
    for i in range(stepCount):
        #update positon
        for j in range(numObjects):
            for l in range(numDimensions):
                historicPosArray[j][l].append(posArray[j][l])
                posArray[j][l]+=stepSize*velArray[j][l]
        #compute acceleration
        accelArray=[[0]*numDimensions for j in range(numObjects)]
        for j in range(numObjects):
            for l in range(numDimensions):
                for k in range(j+1,numObjects):
                    #print posArray[j],posArray[k]
                    newAccel=G*massArray[k]*(posArray[k][l]-posArray[j][l]) / math.pow(pythag_pos_diff(posArray[j],posArray[k]),3.0)
                    oppositeNewAccel=-newAccel*massArray[j]/massArray[k]
                    accelArray[j][l]+=newAccel
                    accelArray[k][l]+=oppositeNewAccel
        #print accelArray[1]
        #update velocity
        for j in range(numObjects):
            for l in range(numDimensions):
                velArray[j][l]+=stepSize*accelArray[j][l]
                historicVelArray[j][l].append(velArray[j][l])

        #compute drift
        ang=angular_momentum(posArray, velArray, massArray)
        energy=total_energy(posArray, velArray, massArray)
        angMomenDrift=np.subtract(ang,angStart)
        historicAngMomenDrift.append((angMomenDrift[0]**2 + angMomenDrift[1]**2 + angMomenDrift[2]**2)**(1.0/2.0))
        historicEngDrift.append((energy-energyStart))

    print 'Execution Duration: '+str(datetime.now() - startTime)
    speedup=((3.154E+07)*stepSize*stepCount)/((datetime.now() - startTime).total_seconds())
    print 'Speedup: '+str(speedup)
    print 'total drift'
    print np.subtract(ang,angStart), (energy-energyStart)
    return historicPosArray, historicAngMomenDrift, historicEngDrift

def plot_planets(historicPosArray,numObjects, numDimensions):

    #for j in range(numDimensions-1):
    for i in range(1):
        plt.plot(historicPosArray[i][0],historicPosArray[i][1],'.-')
    plt.gca().set_aspect('equal', adjustable='box')

numObjects=9
numDimensions=3
#Quantiy      Units
#time      |   Year
#distance  |   AU
#velocity  |   AU/Year
#mass      |   Solar Mass

#Number       Object
#0         |   Sun
#1         |   Mercury
#2         |   Venus
#3         |   Earth + Moon
#4         |   Mars
#5         |   Jupiter
#6         |   Saturn
#7         |   Uranus
#8         |   Neptune

#generate velocity and position vectors
#the arrays are defined as ____Array[jth object][dimensions x,y,z: 0,1,2]
#velocity array is half a timestep ahead of the position and acceleration arrays
posArray=[[0.0]*numDimensions for j in range(numObjects)]
velArray=[[0.0]*numDimensions for j in range(numObjects)]

#generate massArray[jth object]
massArray=[1.0, 1.661E-07, 2.4484E-06, 3.00346E-06, 3.2279E-07, 0.0009543, 0.0002857, 4.36576E-05, 5.15E-05]

#positions and velocitys of solar system bodies in baryocentric coords
#all starting values at A.D. 1994-Mar-12 00:00:00.0000
#SUN
posArray[0]=[7.971719296098350E-04,  6.530924435763692E-03, -3.840865188581198E-05]
velArray[0]=[-5.057483005901317E-06*365,  3.950592533314976E-06*365,  1.250632236911193E-07*365]

#MERCURY
posArray[1]=[-3.168209006763542E-01, -3.100284070655648E-01,  3.261781129133621E-03]
velArray[1]=[1.413036973396787E-02*365, -1.863818179319557E-02*365, -2.820247511064388E-03*365]

#VENUS
posArray[2]=[ 6.703870134057690E-01,  2.820919488225764E-01, -3.492924483480292E-02]
velArray[2]=[-7.770139352355757E-03*365,  1.861901186591109E-02*365,  7.024925476467198E-04*365]

#EARTH
posArray[3]=[-9.813301325021555E-01,  1.574386351629199E-01, -3.957367973686485E-05]
velArray[3]=[-2.899220177422116E-03*365, -1.707155547951476E-02*365,  1.254070235790866E-07*365]

#MARS
posArray[4]=[ 1.078786065897782E+00, -8.625912141839485E-01, -4.475462451602934E-02]
velArray[4]=[ 9.309976370119377E-03*365,  1.209485051343706E-02*365,  2.432439495215345E-05*365]

#JUPITER
posArray[5]=[ -4.391049819964502E+00, -3.196505626109847E+00,  1.115744883801592E-01]
velArray[5]=[ 4.346257193870669E-03*365, -5.749413180499637E-03*365, -7.354330890512936E-05*365]

#SATURN
posArray[6]=[ 8.733336994200078E+00, -4.345364839040485E+00, -2.714746726539586E-01]
velArray[6]=[ 2.183425528529507E-03*365,  4.983355546867565E-03*365, -1.738662890388426E-04*365]

#URANUS
posArray[7]=[ 7.679161474619261E+00, -1.807440948712653E+01, -1.666412541349566E-01]
velArray[7]=[ 3.590748782173861E-03*365,  1.355454603714086E-03*365, -4.154112618083728E-05*365]

#NEPTUNE
posArray[8]=[ 1.095828259071641E+01, -2.811168975971997E+01,  3.263530816155578E-01]
velArray[8]=[  2.904104193585754E-03*365,  1.157377132972549E-03*365, -9.086645981465949E-05*365]

posArrayF=[[0.0]*numDimensions for j in range(numObjects)]
velArrayF=[[0.0]*numDimensions for j in range(numObjects)]
#positions and velocitys of solar system bodies in baryocentric coords
#all final values at A.D. 2016-Feb-29 00:00:00.0000
#SUN
posArrayF[0]=[3.769360061446780E-03,  1.812773374712511E-03, -1.624014729877611E-04]
velArrayF[0]=[2.116907618849916E-07*365,  6.980633760687217E-06*365, -1.203681274902981E-08*365]

#MERCURY
posArrayF[1]=[6.384933295823990E-02, -4.515747976027313E-01, -4.272075514855849E-02]
velArrayF[1]=[2.224830448309151E-02*365,  5.147225564402190E-03*365, -1.621110695570192E-03*365]

#VENUS
posArrayF[2]=[1.167830458441351E-01, -7.165914711359284E-01, -1.653385613745591E-02]
velArrayF[2]=[1.984550800517364E-02*365,  3.079327873621045E-03*365, -1.103086914976536E-03*365]

#EARTH
posArrayF[3]=[-9.247648258319329E-01,  3.469717738912940E-01, -1.730700077332298E-04]
velArrayF[3]=[-6.279271560859209E-03*365, -1.617967468331688E-02*365,  2.694319332791631E-07*365]

#MARS
posArrayF[4]=[-1.510114581167425E+00, -5.693088681586485E-01,  2.502401748406479E-02]
velArrayF[4]=[5.461536539056124E-03*365, -1.189036297311848E-02*365, -3.833644710566484E-04*365]

#JUPITER
posArrayF[5]=[-5.291527066741596E+00,  1.182309344528905E+00,  1.134242057706169E-01]
velArrayF[5]=[-1.733768918092524E-03*365, -7.008096404329502E-03*365,  6.792695786000429E-05*365]

#SATURN
posArrayF[6]=[-3.421132666518896E+00, -9.407865807544542E+00,  2.997343479755205E-01]
velArrayF[6]=[4.937187945581996E-03*365, -1.922883900630874E-03*365, -1.633640215930448E-04*365]

#URANUS
posArrayF[7]=[1.879301283705500E+01,  6.762792046709805E+00, -2.183506612863105E-01]
velArrayF[7]=[-1.360455775595364E-03*365,  3.517436778076412E-03*365,  3.073947954095653E-05*365]

#NEPTUNE
posArrayF[8]=[ 2.801943446698039E+01, -1.060190333542911E+01, -4.274100493913166E-01]
velArrayF[8]=[1.090032425561670E-03*365,  2.955023769315658E-03*365, -8.560834225044430E-05*365]

print '\n\n--------------------------------------------------\nLEAPFROG REAL DATA\n--------------------------------------------------'
#print 'Start Postions',posArray
#print 'Start Velocities',velArray
#print 'Masses',massArray

stepSize=1/(365.25)#*100000000*0.928514127163)
stepCount=8025
print 'Step Size: ' +str(stepSize*365.25) +' days'
print 'Simulation Duration: '+str(stepSize*stepCount) +' years OR '+str(stepSize*stepCount*365.25)+' days'

historicPosArray,historicAngMomenDrift, historicEngDrift = nbody_sim_leapfrog(posArray,velArray,massArray,stepSize,stepCount)

plot_planets(historicPosArray, numObjects, numDimensions)
plt.title('Leapfrog Method\nReal Solar System Data from 3/12/1994\n'+str(stepCount)+' steps of '+str(stepSize*365.25)+' days',fontsize=15)
plt.xlabel('AU',fontsize=20)
plt.ylabel('AU',fontsize=20)
plt.gca().set_aspect('equal', adjustable='box')
plt.show()

#plt.plot(historicAngMomenDrift)
#plt.title('Real Solar System Data from 3/12/1994\n'+str(stepCount)+' steps of '+str(stepSize*365.25)+' days',fontsize=15)
#plt.xlabel('Steps',fontsize=20)
#plt.ylabel('Total Angular Momentum Drift',fontsize=15)
#plt.show()
#
#plt.plot(historicEngDrift)
#plt.title('Real Solar System Data from 3/12/1994\n'+str(stepCount)+' steps of '+str(stepSize*365.25)+' days',fontsize=15)
#plt.xlabel('Steps',fontsize=20)
#plt.ylabel('Total Energy Drift',fontsize=15)
#plt.show()
#
#diffArray = np.absolute(np.subtract(posArray,posArrayF))
#
#print 'Initial\n', np.array(posArray)
#print '\nActual\n',np.array(posArrayF)
#print '\nAbsolute Difference\n',diffArray
#
#plt.plot(diffArray)
#plt.title('Real Solar System Data from 3/12/1994\n'+str(stepCount)+' steps of '+str(stepSize*365.25)+' days',fontsize=15)
#plt.xlabel('Object',fontsize=20)
#plt.ylabel('TDiffence in position - AU',fontsize=15)
#plt.show()
#for i in range(numObjects):
#    plt.plot(posArray[i][0],posArray[i][1],'.-r')
#    plt.plot(posArrayF[i][0],posArrayF[i][1],'.-b')
#plt.title('Object Position Difference\n'+str(stepCount)+' steps of '+str(stepSize*365.25)+' days',fontsize=15)
#plt.xlabel('AU',fontsize=20)
#plt.ylabel('AU',fontsize=20)
#plt.gca().set_aspect('equal', adjustable='box')
#plt.show()


# -*- coding: utf-8 -*-
"""
Created on Fri Jan 29 14:49:34 2016

@author: manuel.pasieka@vbcf.ac.at
"""

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

N = 10
NoiseScale = 0.5

#Generate data points following a line with some noise
[lIntercept, lSlope] = (np.random.random(2) * 2.0) - 1.0
noise = ((np.random.random(N) * 2.0) - 1.0) * NoiseScale
X = np.linspace(-1, 1, N)
Y = []
for i in range(N):
    Y.append(X[i]*lSlope + lIntercept + noise[i])

print('Data generated by line: Slope %f, Intercept %f + Noise abs %f' % (lSlope, lIntercept, np.abs(noise).sum()) )

slope, intercept, r_value, p_value, std_err = stats.linregress(X, Y)
print('Results: Slope = %f, Intercept = %f, r %f' % (slope, intercept, r_value))

f = plt.figure()
plt.title('Simple Linear Regression Example')
plt.xlabel('X - Indepened Variable')
plt.ylabel('Y - Depended Variable')

#Print Points
plt.scatter(X, Y, label='Points')

#Regression Line
rL_X = [-1.0, 0.0, 1.0]
rL_Y = [(x * slope) + intercept  for x in rL_X]
plt.plot(rL_X, rL_Y, color='r', label='Regression Line')

#Original Line
lY = [(x * lSlope) + lIntercept  for x in rL_X]
plt.plot(rL_X, lY, color='b', linestyle='--', label='Original Line')

plt.legend()


import numpy as np
from scipy.stats import scoreatpercentile as sap

#from scipy.stats import norm

def _select_sigma(X):
    """
    Returns the smaller of std(X, ddof=1) or normalized IQR(X) over axis 0.

    References
    ----------
    Silverman (1986) p.47
    """
#    normalize = norm.ppf(.75) - norm.ppf(.25)
    normalize = 1.349
#    IQR = np.subtract.reduce(percentile(X, [75,25],
#                             axis=axis), axis=axis)/normalize
    IQR = (sap(X, 75) - sap(X, 25))/normalize
    return np.minimum(np.std(X, axis=0, ddof=1), IQR)

## Univariate Rule of Thumb Bandwidths ##
def bw_scott(x):
    """
    Scott's Rule of Thumb

    Parameter
    ---------
    x : array-like
        Array for which to get the bandwidth

    Returns
    -------
    bw : float
        The estimate of the bandwidth

    Notes
    -----
    Returns 1.059 * A * n ** (-1/5.)

    A = min(std(x, ddof=1), IQR/1.349)
    IQR = np.subtract.reduce(np.percentile(x, [75,25]))

    References
    ---------- ::

    Scott, D.W. (1992) `Multivariate Density Estimation: Theory, Practice, and
        Visualization.`
    """
    A = _select_sigma(x)
    n = len(x)
    return 1.059 * A * n ** -.2

def bw_silverman(x):
    """f
    Silverman's Rule of Thumb

    Parameter
    ---------
    x : array-like
        Array for which to get the bandwidth

    Returns
    -------
    bw : float
        The estimate of the bandwidth

    Notes
    -----
    Returns .9 * A * n ** (-1/5.)

    A = min(std(x, ddof=1), IQR/1.349)
    IQR = np.subtract.reduce(np.percentile(x, [75,25]))

    References
    ---------- ::

    Silverman, B.W. (1986) `Density Estimation.`
    """
    A = _select_sigma(x)
    n = len(x)
    return .9 * A * n ** -.2

## Plug-In Methods ##

## Least Squares Cross-Validation ##

## Helper Functions ##

bandwidth_funcs = dict(scott=bw_scott,silverman=bw_silverman)

def select_bandwidth(X, bw, kernel):
    """
    Selects bandwidth
    """
    bw = bw.lower()
    if bw not in ["scott","silverman"]:
        raise ValueError("Bandwidth %s not understood" % bw)
#TODO: uncomment checks when we have non-rule of thumb bandwidths for diff. kernels
#    if kernel == "gauss":
    return bandwidth_funcs[bw](X)
#    else:
#        raise ValueError("Only Gaussian Kernels are currently supported")


"""
@file
@brief Functions about the `Gini coefficient <https://en.wikipedia.org/wiki/Gini_coefficient>`_.
"""
import numpy

def gini(Y, X=None):
    """
    Computes the
    `Gini coefficients <https://en.wikipedia.org/wiki/Gini_coefficient>`_.

    @param  Y           Y values (or revenues)
    @param  X           None for a uniform population or not None for already order value.
    @return             a curve ``(x, Gini(x))``
    """
    n = len(Y)
    couples = numpy.empty((n, 2))
    if X is None:
        couples[:, 0] = 1
    else:
        couples[:, 0] = X
    couples[:, 1] = Y
    couples = couples
    couples = numpy.cumsum(couples, axis=0)
    couples[:, 0] /= max(couples[n - 1, 0], 1e-7)
    couples[:, 1] /= max(couples[n - 1, 1], 1e-7)

    g = 0.
    n = couples.shape[0]

    for i in range(0, n):
        dx = couples[i, 0] - couples[i - 1, 0]
        y = couples[i - 1, 1] + couples[i, 1]
        g += dx * y

    return (1. - g) / 2


import numpy as np

class Gaussian_mean:

    def __init__(self, name, num_clusters, data, variance=None, means=None):

        self.name = name

        self.c = num_clusters

        self.type = 'gaussian_mean'

        self.n_iter = 0

        if variance:
            self.std = np.sqrt(variance)
        else:
            # Default is standard error
            self.std = np.sqrt(np.var(data.flatten())) / np.sqrt(len(data.flatten()))

        # Can be a single parameter or a vector of parameters, usually the latter
        if not isinstance(means, np.ndarray):
            # If none are given generate a vector of rate normally distributed around the sample mean with sample variance
            self.params_init = np.random.normal(loc=np.mean(data), scale=self.std, size=self.c)
            self.params = self.params_init

        else:
            self.initial_params = means
            self.params = means

        # Observation of the normal random variable, should be a length n column vector where n is the number of observations
        self.data = data.reshape((len(data), 1))

        # Compute likelihood and log likelihood
        self.update()

    def get_likelihood(self, obs):
        # obs must be an integer or a column vector
        return 1 / np.sqrt(2 * np.pi * self.std**2) * np.exp(- (1/(2 * self.std**2)) * (obs - self.params)**2)

    def get_log_likelihood(self, obs):
        # obs must be an integer or a column vector
        return - 1 / (2 * self.std**2) * (obs - self.params)**2

    def maximise(self, q_h):
        self.params_old = self.params

        # Optimise the energy w.r.t to mean parameters, q_h is the optimmised variational distribution output from the expectation step
        self.params = np.sum(q_h * self.data, axis=0) / np.sum(q_h, axis=0)

        self.update()

        self.n_iter += 1

    def update(self):
         # Likelihood of each observation given the current rates
        self.likelihood = self.get_likelihood(self.data)

        # Log likelihood, up to proportionality, of each observation given the current rates
        self.log_likelihood = self.get_log_likelihood(self.data)


from __future__ import division
import numpy as np
import sys

# X_train = np.genfromtxt(sys.argv[1], delimiter=",")
# Y_train = np.genfromtxt(sys.argv[2], delimiter=',')
# X_test = np.genfromtxt(sys.argv[3], delimiter=",")

X_train = np.loadtxt('X_train.csv', delimiter=",")
Y_train = np.loadtxt('y_train.csv', delimiter=",")
X_test = np.loadtxt('X_test.csv', delimiter=",")

def calc_parameters_likelihood_mle(_classes, _x_train, _y_train):
    """
    Calc likelihood MLE
    :param _classes: classes dataset
    :param _x_train: train set x
    :param _y_train: train label
    :return: mus, sigmas, sigma_dets
    """
    mus, sigmas, sigma_dets = {}, {}, {}
    for c in _classes:
        c_id = (_y_train == c)
        X = _x_train[c_id, :]
        mu = np.matrix(np.mean(X, axis=0)).T
        # calculate gaussian covariance mle
        n, _ = X.shape
        sigma = 0
        for i in range(n):
            x = np.matrix(X[i, :]).T
            sigma += (x - mu) * (x - mu).T / n
        sigma_det = np.linalg.det(sigma)
        mus[c], sigmas[c], sigma_dets[c] = mu, sigma, sigma_det

    return mus, sigmas, sigma_dets

def plugin_classifier(x_train, y_train, x_test):
    """
    Implements bayes classifier
    :param x_train:
    :param y_train:
    :param x_test:
    :return: prob_pred for test set
    """

    # calculate prior by MLE
    n = y_train.shape[0]
    classes = np.unique(y_train)

    priors = {}
    for c in classes:
        priors[c] = np.sum(y_train == c) / n

    # calculate parameters of likelihood by MLE
    mus, sigmas, sigma_dets = calc_parameters_likelihood_mle(classes, x_train, y_train)

    c = classes.shape[0]

    n, d = x_test.shape
    prob_pred = np.zeros((n, c))

    for i in range(n):
        x = np.matrix(x_test[i, :]).T

        i_prob = np.zeros(c)
        for j in range(c):
            # calculate Gaussian likelihood
            mu = mus[classes[j]]
            sigma = sigmas[classes[j]]
            sigma_det = sigma_dets[classes[j]]

            # calc multi gaussian prob and proportion of posterior
            i_prob[j] = priors[classes[j]] * np.sqrt(sigma_det) ** (-1) * np.exp(
                - 0.5 * (x - mu).T * sigma.I * (x - mu))

        prob_pred[i, :] = i_prob / np.sum(i_prob)

    return prob_pred

def main():
    # assuming final_outputs is returned from function
    final_outputs = plugin_classifier(X_train, Y_train, X_test)

    # write output to file
    np.savetxt("probs_test.csv", final_outputs, delimiter=",")

if __name__ == '__main__':
    main()


"""
bracketing.py

Returns the uncertainty interval containing the minimizer of the function
X0 - initial guess
func - anonimous function
func_1st_der - anonimous function 1st derivative
"""

import numpy as np

def bracketing(X0, func, func_1st_der):

    epsilon = 0.5;
    d = - func_1st_der(X0) / np.linalg.norm(func_1st_der(X0)); # directional unit vector
    X = np.empty(shape = (100));
    F_at_X = np.empty(shape = (100));
    X[0] = X0;
    F_at_X[0] = func(X[0]);
    X[1] = X0 + 2 * epsilon * d;
    F_at_X[1] = func(X[1]);

    for ii in range(2, 100, 1):
        X[ii] = X0 + 2 * ii * epsilon * d;
        F_at_X[ii] = func(X[ii]);
        if F_at_X[ii - 1] < F_at_X[ii - 2] and F_at_X[ii - 1] < F_at_X[ii] :
            break;

    if (d > 0):
        interval = (X[ii - 2], X[ii]);
    else:
        interval = (X[ii], X[ii - 2]);
    return interval;


import numpy as np
import scipy.spatial.distance

def kmeans(data, centers, delta=.0001, maxiter=500, metric="cityblock"):
    """
    Inputs:
        data    : observations x features
        centers : k x features: the initial centroids; e.g.
                  a random sample of rows from X. These could be found
                  using k++ initialization before calling kmeans.
        delta   : cutoff; iterate until the average distance of the
                  observations to the centeroids is within delta of the
                  previous average distance to the centroids; i.e,
                  prevavgdist*(1-delta) <= current avgdist <= prevavgdist
        maxiter : maximum iterations of the algorithm if the
                  delta cutoff isn't reached
        metric  : cityblock = l1 norm or manhattan distance

    Outputs:
        centroids : k x features; the final centroids
        xlbl      : codebook; maps each feature in data to its nearest centroid, k
    """
    N, dim = data.shape
    k = centers.shape[0]
    all_obs = np.arange(N)
    prevdist = 0
    for jth_iter in range(maxiter):
        D = scipy.spatial.distance.cdist(data, centers, metric=metric)
        xlbl = D.argmin(axis=1)
        distances = D[all_obs, xlbl]
        avdist = distances.mean()

        if ((1-delta)*prevdist <= avdist <= prevdist) or (jth_iter == maxiter):
            break

        prevdist = avdist

        # Update centers
        for jc in range(k):
            c = np.where(xlbl == jc)[0]
            if len(c) > 0:
                centers[jc] = data[c].mean(axis=0)
    return centers, xlbl, jth_iter


# for computing the distance between points.  Periodi
# Tim Tyree
# 6.8.2021

import numpy as np
from numba import njit, jit, float32

#############################################################
# Example Usage: L2 Distance using Periodic Boundary Conditions
# distance_L2_pbc = get_distance_L2_pbc(width=200,height=200)
# distance_L2_pbc(np.array([1.,1.]),np.array([199.,199.]))
#############################################################

@njit
def pbc_2D(x,y, width, height):
	'''
	(x, y) coordinates that go from 0 to width or height, respectively.
	tight boundary rounding is in use.'''
	if ( x < 0  ):				# // Left P.B.C.
		x = width - 1
	elif ( x > (width - 1) ):	# // Right P.B.C.
		x = 0
	if( y < 0 ):				# //  Bottom P.B.C.
		y = height - 1
	elif ( y > (height - 1)):	# // Top P.B.C.
		y = 0
	return x,y

def get_distance_L2_pbc(width=1,height=1):
    '''returns a function for the euclidean (L2) distance measure for a 2D rectangle with periodic boundary conditions.
    width, height are the shape of that 2D rectangle.'''
    @jit('f8(f8[:],f8[:])', nopython=True)
    def distance_L2_pbc(point_1, point_2):
        '''assumes getting shortest distance between two points with periodic boundary conditions in 2D.  point_1 and point_2 are iterables of length 2'''
        mesh_shape=np.array((width,height))
        dq2 = 0.
        #     for q1, q2, width in zip(point_1[:2], point_2[:2], mesh_shape):
        for q1, q2, wid in zip(point_1, point_2, mesh_shape):
            dq2 = dq2 + min(((q2 - q1)**2, (q2 + wid - q1 )**2, (q2 - wid - q1 )**2))
        return np.sqrt(dq2)
    return distance_L2_pbc


import numpy as np
from scipy.sparse import csc_matrix, diags, vstack, hstack
from scipy.sparse.linalg import inv, spsolve

def simplex(A, c, b):

    nr = len(b)

    I = diags(np.ones(nr))

    # form tableau blocks
    t1 = vstack((c, A))
    t2 = vstack((np.zeros((1, nr)), I))
    t3 = vstack(())

def interior_point(A, c, x0, tol=1e-6, max_iter=100):
    """
    Interior point solver for linear systems
    Source: Computational methods for electric power systems (3rd Ed.) - Mariesa L- Crow  (CRC Press)
    Args:
        A: Restrictions matrix
        c: Objective function coefficients
        x0: Feasible solution
        tol: Tolerance
        max_iter: Maximum number of iterations
    Returns: Optimal solution x
    """
    n = len(c)

    e = np.ones(n)

    I = diags(e)

    x = x0.copy()

    x_prev = x0.copy()

    converged = False

    iterations = 0

    last_f = 1e20

    while not converged and iterations < max_iter:

        D = diags(x)

        Ap = A * D

        cp = D * c

        # Pp = I - Ap.transpose() * inv(Ap * Ap.transpose()) * Ap

        Pp = I - Ap.transpose() * spsolve(Ap * Ap.transpose(), Ap)  # avoid using matrix inversions...

        p0 = - Pp * cp

        alpha = 0.9

        theta = - p0.min()

        xp = e + (alpha / theta) * p0

        x = D * xp

        f = c.dot(x)

        # back track
        b_iter = 0
        while f > last_f and b_iter < 10:

            alpha *= 0.25

            xp = e + (alpha / theta) * p0

            x = D * xp

            f = c.dot(x)

            b_iter += 1

            print('\talpha:', alpha)

        error = np.linalg.norm(x - x_prev, np.inf)

        converged = error < tol

        x_prev = x.copy()

        last_f = f

        iterations += 1

        print('f:', f, '\terror:', error)

    return x

if __name__ == '__main__':

    """
    Problem:
    min: -6x1 - 14x2 + 0x3 + 0x4 + 0x5

    s.t:
    2x1 + 1x2 + 1x3          = 12
    2x1 + 3x2 +     1x4      = 15
    1x1 + 7x2 +          1x5 = 21

    x1>=0, x2>=0, x3>=0, x4>=0, x5>=0
    """

    c_ = np.array([-6, -14, 0, 0, 0])

    A_ = csc_matrix([[2, 1, 1, 0, 0],
                     [2, 3, 0, 1, 0],
                     [1, 7, 0, 0, 1]])

    b_ = np.array([12, 15, 21])

    x_0 = np.array([1, 1, 9, 10, 13])

    print('x0', x_0)

    # solve
    x = interior_point(A=A_, c=c_, x0=x_0, tol=1e-8)

    print()
    print('Solution:', x)
    print('Constraints mismatch:', A_ * x - b_)


# Author: Sylvain Lapeyrade (sylla801)
# File: TSKS11-Lab4: Task 2-3

import numpy as np
from scipy import sparse
import pandas as pd
import matplotlib.pyplot as plt

# Link with the path of the txt files
link0 = './task2/mini-network.edgelist.txt'
link1 = './task2/poisson.edgelist.txt'
link2 = './task2/poisson-R.edgelist.txt'
link3 = './task2/collaboration.edgelist.txt'
link4 = './task2/collaboration-R.edgelist.txt'
link5 = './task3/n1.edgelist.txt'
link6 = './task3/n2.edgelist.txt'
link7 = './task3/n3.edgelist.txt'
link8 = './task3/n4.edgelist.txt'
link9 = './task3/n5.edgelist.txt'

link_name = link4  # Name of current path
link_file = open(link_name, 'r')

edgelist = np.loadtxt(link_file, dtype=int)  # Loads all links
nr_nodes = max(map(max, edgelist))+1  # Number of nodes
nr_edges = len(edgelist)  # Number of Edges

j = (edgelist[:, 0]).tolist()  # From Node Id
i = (edgelist[:, 1]).tolist()  # To Node Id

# Sparse matrix used for computation efficiency
sparse_matrix = sparse.csr_matrix(arg1=(np.ones(nr_edges), (i, j)),
                                  shape=(nr_nodes, nr_nodes))

# The network is undirected so we add the transpose of the matrix
network = sparse_matrix + sparse_matrix.transpose()

# Initinalize degree and knns with 0 vectors
degrees = np.zeros(shape=nr_nodes)
knns = np.zeros(shape=nr_nodes)

# Calculate the degree and the knn of each node
for node in range(nr_nodes):
    degrees[node] = np.sum(network[node, :])
    knn = np.sum([np.sum(network[neighbor, :])
                  for neighbor in network[:, node].nonzero()[0]])
    knns[node] = knn / degrees[node]

# Use DataFrame to link degree and knn (and do the mean)
data = pd.DataFrame({'degree': degrees, 'knn': knns})
means = data.groupby('degree').mean()

# *** Coefficient Correlation ***
# Initilise 2 vectors x, y with 0
x, y = np.zeros(shape=(nr_edges)), np.zeros(shape=(nr_edges))

# Assign those vectors with the node degree
for i, edge in enumerate(edgelist):
    x[i], y[i] = degrees[edge[0]], degrees[edge[1]]

# Substract x and y with their mean
xm, ym = x - x.mean(), y - y.mean()

# Pearson Correlation Coefficient implementation
r = np.add.reduce(xm * ym) / np.sqrt(np.sum(xm**2) * np.sum(ym**2))
r = max(min(r, 1.0), -1.0)  # In case abs(r) > 1

print('Network:', link_name)
print('Correlation Coefficient r=', r)

# Plot of the KNNs and their Degree
plt.ylabel("KNN")
plt.xlabel("Degree")
plt.plot(means.index, means['knn'])
plt.show()

# *** TASK 2 ***
# Poisson & Collaboration Graphs hae undergone re-wiring through
#  Degree Preserving Randomization to assess whether the variations
#  in the graphs could simply be artifacts of the graph's inherent structural
#  properties rather than properties unique to the nodes

# Poisson = -0.0028966
# Poisson rewired = -0.00329
# The poisson network was pretty balanced so
#  the rewiring doesnt affect it much
# => This is due to the graph

# Collaboration = 0.134
# Collaboration rewired = -0.005783
# The collaboration network on the other hand is more affected,
#  while there is still some peaks it is more evened out
# => This is due to the nodes

# *** TASK 3 ***
# The Correlation Coefficient are very similar (i.e the knn and Degree also).
#  We can asssume that under Degree Preserving Randomization rewiring
#  we would obtain more or less the sames graphs. So we can deduce that the
#  graphs  share same properies. (Scale free ?)


#coding:utf-8
import numpy as np
from pylab import *

"""
カーネル回帰：カーネル法を利用した曲線フィッティング
"""

N = 10
BETA = 1

# カーネル関数
def kernel(x1, x2):
    return np.exp(-BETA * (x1-x2)**2)

def y(x, xlist, alpha):
    summation = 0
    for i in range(len(xlist)):
        summation += alpha[i] * kernel(xlist[i], x)
    return summation

if __name__ == "__main__":
    # 訓練データを作成
    xlist = np.linspace(0, 1, N)
    tlist = np.sin(2 * np.pi * xlist) + np.random.normal(0, 0.2, xlist.size)

    # 行列Kを作成
    K = zeros((N, N))
    for i in range(N):
        for j in range(N):
            K[i, j] = kernel(xlist[j], xlist[i])

    # 重み係数αを計算
    alpha = np.dot(np.linalg.inv(K), tlist)
    print alpha

    # 連続関数のプロット用X値
    xs = np.linspace(0, 1, 1000)
    ideal = np.sin(2 * np.pi * xs)    # 理想曲線
    model = [y(x, xlist, alpha) for x in xs]

    # グラフを描画
    plot(xlist, tlist, 'bo')  # 訓練データ
    plot(xs, ideal, 'g-')     # 理想曲線
    plot(xs, model, 'r-')     # 推定モデル
    xlim(0.0, 1.0)
    ylim(-1.5, 1.5)
    show()


"""
Simulation for problem 09 of SP1.
"""
import math

import matplotlib.pyplot as plt
import numpy as np

g = 9.8  # Gravitational constant
r = 0.24 * 10 ** -6  # Radius of the resin-spheres
V = math.pi * (4 / 3) * r ** 3  # Volume of the resin-spheres
T = 300.2  # Kelvin

density_resin = 1.2 * 10 ** 3
density_water = 1.0 * 10 ** 3

depths = np.array([0, 18, 33, 46, 57, 71]) * 10 ** -6
spheres = np.array([131, 214, 312, 437, 625, 877])
log_spheres = np.log(spheres)

# noinspection PyTupleAssignmentBalance
fit, cov = np.polyfit(depths, log_spheres, 1, cov=True)
err = np.sqrt(np.diag(cov))

k = (density_resin - density_water) * g * V / (fit[0] * T)

print(f'k = {k:.2e}')
print(f'f(d) = {fit[0]:.2e}±{err[0]:.1e}d + {fit[1]:.2e}±{err[1]:.1e}')

fig, axs = plt.subplots(2, 2, sharex='col')
axs[0, 0].set_title('Original data')
axs[0, 0].plot(depths, spheres)
axs[0, 0].set_ylabel('# spheres')

axs[0, 1].set_title('Original data scaled')
axs[0, 1].plot(depths, log_spheres)
axs[0, 1].set_ylabel('log(# spheres)')

axs[1, 0].set_title('Linear fit on scaled data')
axs[1, 0].scatter(depths, log_spheres)
axs[1, 0].plot(depths, fit[0] * depths + fit[1])
axs[1, 0].set_xlabel('depth [m]')
axs[1, 0].set_ylabel('log(# spheres)')

axs[1, 1].set_title('Fit compared to original data')
axs[1, 1].scatter(depths, spheres)
axs[1, 1].plot(depths, math.e ** (fit[0] * depths + fit[1]))
axs[1, 1].set_xlabel('depth [m]')
axs[1, 1].set_ylabel('# spheres')

plt.savefig('export/problem09.svg')

plt.show()


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import linregress

def draw_plot():

    df = pd.read_csv("epa-sea-level.csv")  # Read data from file

    # Create scatter plot
    fig, ax = plt.subplots(figsize=(6, 6))
    ax.scatter(df["Year"], df["CSIRO Adjusted Sea Level"],
               marker='.', color='c', label="Data")

    # Create first line of best fit
    lreg1 = linregress(df["Year"], df["CSIRO Adjusted Sea Level"])
    x1 = np.array(list(range(1880, 2051)))
    ax.plot(x1, lreg1.intercept + lreg1.slope * x1, 'g',
            label="Linear trend from $1880$-$2013$")
    print(f"\nLinear regression from 1880-2013:\n{lreg1}")

    # Create second line of best fit
    lreg2 = linregress(df[df["Year"] >= 2000]["Year"],
                       df[df["Year"] >= 2000]["CSIRO Adjusted Sea Level"])
    x2 = np.array(list(range(2000, 2051)))
    ax.plot(x2, lreg2.intercept + lreg2.slope * x2, 'r',
            label="Linear trend from $2000$-$2013$")
    print(f"\nLinear regression from 2000-2013:\n{lreg2}")

    # Add labels and title
    ax.set(title="Rise in Sea Level (Extrapolated to $2050$)",
           xlabel="Year",
           ylabel="Sea Level (inches)",
           xlim=(1875, 2060))

    ax.legend()

    # Save plot and return data for testing (DO NOT MODIFY)
    plt.savefig('sea_level_plot.png')

    return ax

if __name__ == "__main__":
    draw_plot()


import numpy as np

def logdet(covariance):
    """
    This should be equivalent to the following:

    >>> covariance_logdet = numpy.linalg.slogdet(covariance)[1]

    so feel free to use either
    """
    L = np.linalg.cholesky(covariance)
    covariance_logdet = 2*np.sum(np.log(np.diagonal(L)))
    return covariance_logdet


import numpy as np
import matplotlib.pyplot as plt

class LinearRegression:
    """
    Architecture Constants:
        N: Total number of input samples of matrix X.
        D: Number of input features of matrix X.

    Hyperparameters:
        epochs: Number of training iterations.
        learn_rate: Rate of change used in gradient descent.
        reg_L1: Sets the penalty for L1 (Lasso) regularization.
        reg_L2: Sets the penalty for L2 (Ridge) regularization.

    Numpy Matrices:
        X [N x D]: Input samples and features.
        T [N x 1]: Output targets.
        Y [N x 1]: Output predictions.
        w [D x 1]: Weights for each input feature.

    To implement the LinearRegression class, insert code that looks
    something like the following:

        from ml_models import LinearRegression

        X = ...
        T = ...

        model = LinearRegression(X=X,
                                 T=T,
                                 epochs=300,
                                 learn_rate=0.001,
                                 reg_L1=0,
                                 reg_L2=0)

        for i in xrange(model.epochs):

            model.make_predictions()
            model.calculate_error()
            model.update_weights()

            if i % 10 == 0:
                print "Iteration: " + str(i) + "   Error:", model.errors[i]

        model.calculate_R2()

        model.plot_errors()
        model.plot_predictions()
    """

    def __init__(self, X=None, T=None, epochs=1000, learn_rate=0.001,
                 reg_L1=0, reg_L2=0):
        """
        Sets the input data X and targets T, sets the number of samples
        N and the number of features D, initalizes an empty list to
        store errors, sets the hyperparameters, and calls the init_weights
        method to initialize the weights.
        """

        self.X = X
        self.T = T
        self.N, self.D = self.X.shape

        self.errors = []

        self.epochs = epochs
        self.learn_rate = learn_rate
        self.reg_L1 = reg_L1
        self.reg_L2 = reg_L2

        self.init_weights()

    def init_weights(self):
        """
        Initializes the weights by randomly sampling from a normal
        distribution with mean equal to zero and standard deviation
        equal to 1 / sqrt(# of features).
        """

        self.w = np.random.randn(self.D) / np.sqrt(self.D)

    def make_predictions(self):
        """
        Makes predictions Y by taking the dot product of input matrix X
        and weight vector w.
        """

        self.Y = self.X.dot(self.w)

    def calculate_error(self):
        """
        Calculates the mean squared error between predictions Y and
        targets T according to the following equation:

            error = (Y - T)**2 / N

        Then, the error is formatted to two significant figures and
        appended to a list called 'self.errors' to store the errors
        over iterations for a plot.
        """

        delta = self.Y - self.T
        error = delta.dot(delta) / self.N
        error = format(error, '.5f')

        self.errors.append(error)

    def update_weights(self):
        """
        The model takes a gradient descent approach to optimizing the
        weights. The derivative of the cost function with respect to the
        weights dJ/dw is the transpose of X times the difference between
        targets T and predictions Y:

            [1]:   self.X.T.dot(self.T - self.Y)

        L1 (Lasso) regularization encourages sparsity of weights and
        helps to prevent overfitting. This is done by subtracting the
        sign of weights times the L1 regularization constant from the
        derivative of the cost function:

            [2]:   [1] - self.reg_L1 * np.sign(self.w)

        L2 (Ridge) regularization encourages small weights for all
        weights and also helps to prevent overfitting. This is done by
        subtracting the L2 regularization times two times the weights
        from the derivative of the cost function.

            [3]:   [2] - self.reg_L2 * 2*self.w

        Finally, the weights are updated by adding to each weight the
        learning rate times the derivative of the cost function minus
        the regularization terms:

            [4]:   self.w += self.learning_rate * [3]
        """

        self.w += self.learn_rate * (self.X.T.dot(self.T - self.Y)
                                     - self.reg_L1 * np.sign(self.w)
                                     - self.reg_L2 * 2*self.w)

    def calculate_R2(self):
        """
        Calculates the R-squared correlation between targets T and
        predictions Y to measure the fit of the model.
        """

        d1 = self.T - self.Y
        d2 = self.T - self.T.mean()

        self.r2 = 1 - d1.dot(d1) / d2.dot(d2)
        self.r2 = format(self.r2, '.3f')

        print ""
        print "R2:", self.r2

    def plot_errors(self):
        """
        Plots the MSE (mean squared error) against iteration i.
        """

        plt.title("Prediction Error")
        plt.plot(self.errors)
        plt.ylabel("MSE (Mean Squared Error)")
        plt.xlabel("Iteration")
        plt.show()

    def plot_predictions(self):
        """
        Plots the targets T and predictions Y to visualize how good of
        a fit the model is.
        """

        plt.title("Targets vs. Predictions")
        plt.plot(self.T, label="Targets")
        plt.plot(self.Y, label="Predictions")
        plt.xlabel("Sample number")
        plt.legend()
        plt.show()


# Calculate terminal velocity, ut, from drag coefficient, Cd, and particle sphericity
# Cd from Ganser1993, Eq 18
# Cd also referenced in Cui2007, Eq 2
# Cd also referenced in Chhabra1999, Eq 6

# according to Chhabra1999, the Ganser1993 Cd correlation is applicable for
# sphericity values from 0.09 to 1.0

# use Python 3 print function and division
from __future__ import print_function
from __future__ import division

# libraries
import numpy as np

#---- Parameters

# air properties at T = 300K, P = 1 atm
rhog = 1.17     # density (kg/m^3)
ug = 1.85e-5    # dynamic viscosity (kg/ms)
g = 9.81        # gravity (m/s^2)

# particle properties
dp = 0.000207   # diameter of particle (m)
rhos = 2500     # density of particle (kg/m^3)
sp = 0.8        # sphericity of the particle, perfect sphere = 1.0

#---- Calculations

# papers Cui2007 and Chhabra1999 leave out the -2.25*dv/D term
K1 = (1/3 + 2/3*(sp**-0.5))**(-1)           # Stokes' shape factor
K2 = 10**(1.8148*((-np.log(sp))**0.5743))   # Newton's shape factor

# guess range for terminal velocity, ut (m/s)
ut = np.arange(0.001, 20, 0.001)

# Re, Reynolds number (-)
# Cd, Ganser1993, drag coefficient as function of Re, K1, K2 (-)
# Cdd, drag coefficient as function of ut, etc. (-)
Re = (dp*rhog*ut)/ug
Cd = (24/(Re*K1))*(1 + 0.1118*((Re*K1*K2)**0.6567)) + (0.4305*K2)/(1+(3305/(Re*K1*K2)))
Cdd = (4*g*dp*(rhos-rhog))/(3*(ut**2)*rhog)

delta = np.abs(Cd-Cdd)  # compare difference between Cd and Cdd
idx = np.argmin(delta)  # find index of minimum value in delta

# print results to console
print('--- Ganser1993 ---')
print('ut =', ut[idx])
print('Re =', Re[idx])
print('Cd =', Cd[idx])
print('Cdd =', Cdd[idx])
print('delta =', delta[idx])


from scipy import stats
import numpy as np
from scipy.optimize import minimize
import pylab as plt

latencies = np.loadtxt('latencies.txt')

cc, bbRaw = np.histogram(latencies,bins=50,density=True)
bb = (bbRaw[:-1]+bbRaw[1:])/2.

#ydata = np.array([0.1,0.15,0.2,0.3,0.7,0.8,0.9, 0.9, 0.95])
#xdata = np.array(range(0,len(ydata),1))

def singleExponential(xdata,k):
    return np.exp(-xdata/k)

def doubleExponential(xdata,k1,k2,theta):
    return theta*np.exp(-xdata/k1) + (1.-theta)*np.exp(-xdata/k2)

def singleExponentialLLE(params):
    k = params[0]
    #x0 = params[1]
    sd = params[1]

    yPred = singleExponential(bb,k)
    #yPred = 1 / (1+ np.exp(-k*(xdata-x0)))

    # Calculate negative log likelihood
    LL = -np.sum( stats.norm.logpdf(cc, loc=yPred, scale=sd ) )

    return(LL)

def doubleExponentialLLE(params):
    k1 = params[0]
    k2 = params[1]
    theta = params[2]
    sd = params[3]

    yPred = doubleExponential(bb,k1,k2,theta)
    #yPred = 1 / (1+ np.exp(-k*(xdata-x0)))

    # Calculate negative log likelihood
    LL = -np.sum( stats.norm.logpdf(cc, loc=yPred, scale=sd ) )

    return(LL)

initParamsSE = [1., 0.2]

resultsSE = minimize(singleExponentialLLE, initParamsSE, method='Nelder-Mead')
print resultsSE.x
print 'single exponential :', singleExponentialLLE(resultsSE.x)

initParamsDE = [0.5, 3., 0.8, 0.1]

resultsDE = minimize(doubleExponentialLLE, initParamsDE, method='Nelder-Mead')
print resultsDE.x
print 'double exponential :', doubleExponentialLLE(resultsDE.x)

estParmsSE = resultsSE.x
yOutSE =  singleExponential(bb,estParmsSE[0]) # 1 / (1+ np.exp(-estParms[0]*(xdata-estParms[1])))

estParmsDE = resultsDE.x
yOutDE =  doubleExponential(bb,estParmsDE[0],estParmsDE[1],estParmsDE[2]) # 1 / (1+ np.exp(-estParms[0]*(xdata-estParms[1])))

plt.clf()
plt.plot(bb,cc, 'go')
plt.plot(bb, yOutSE)
plt.plot(bb, yOutDE)
#plt.hist(cc-yOutDE)
plt.show()


from sympy import *
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from DiffEqSolver import SolveOde

"""INITIATE THE SYMBOLS, FUNCTIONS, AND PRETTY PRINTING"""

x,y,z = symbols('x,y,z', positive = True)
init_printing(use_latex=True)
f,g = symbols('f,g', cls = Function, positive = True)

"""
    CREATE AN EXQUATION AND CONDITION LIKE THE FOLLOWING

    equation = Eq(f(x).diff(x,x,x) + f(x).diff(x),exp(x))
    conditions_dict = {f(0) :0,f(x).diff(x).subs(x,0):0, f(x).diff(x,x).subs(x,0):0}
"""

equation = Eq(f(x).diff(x,x,x) + f(x).diff(x),exp(x))
conditions_dict = {f(0) :0,f(x).diff(x).subs(x,0):0, f(x).diff(x,x).subs(x,0):0}

solve_ode = SolveOde(equation, conditions_dict)
solve_ode.compute_ode()


# type: ignore[arg-type]
from typing import Callable

import numpy as np

def simpson_13(
    func: Callable[..., float], a: float, b: float, eps: float = 0.0001, *args, **kwargs
) -> float:

    """
    Metode simpson 1/3 menggunakan
    kurva polinomial ordo 2 untuk melakukan
    approximasi terhadap fungsi yang akan
    diintegrasi

    Parameter:
    f   = fungsi input
    a   = batas bawah integrasi
    b   = batas atas integrasi
    eps = error relatif maksimal

    >>> simpson_13(lambda x: x**2, 0, 2)
    2.6666666666666665
    >>> simpson_13(lambda x: x**5, 0, 1)
    0.16666679687500002
    """
    try:
        # Iterasi pertama
        n = 10
        h = (b - a) / n
        fx = [func(a + i * h, *args, **kwargs) for i in range(n + 1)]
        L0 = h / 3 * (fx[0] + 4 * sum(fx[1:-1:2]) + 2 * sum(fx[2:-2:2]) + fx[-1])

        # Optimasi
        err = 1
        while err > eps:
            n *= 2
            h = (b - a) / n
            fx = [func(a + i * h, *args, **kwargs) for i in range(n + 1)]
            L1 = h / 3 * (fx[0] + 4 * sum(fx[1:-1:2]) + 2 * sum(fx[2:-2:2]) + fx[-1])
            err = np.abs(L1 - L0) / np.abs(L1)
            L0 = L1
    except Exception:
        raise RuntimeError("Integrasi gagal, pastikan fungsi anda benar!")
    return L1

def simpson_38(
    func: Callable[..., float], a: float, b: float, eps: float = 0.0001, *args, **kwargs
) -> float:

    """
    Metode simpson 3/8 menggunakan
    kurva polinomial ordo 3 untuk melakukan
    approximasi terhadap fungsi yang akan
    diintegrasi

    Parameter:
    f   = fungsi input
    a   = batas bawah integrasi
    b   = batas atas integrasi
    eps = error relatif maksimal

    >>> simpson_38(lambda x: x**2, 0, 2)
    2.666666666666667
    >>> simpson_38(lambda x: x**5, 0, 1)
    0.16666667809785096
    """
    try:
        # Iterasi pertama
        n = 10
        h = (b - a) / n
        fx = [func(a + i * h, *args, **kwargs) for i in range(n + 1)]
        L0 = (
            3
            / 8
            * h
            * (
                fx[0]
                + 3 * sum(fx[1:-2:3])
                + 3 * sum(fx[2:-1:3])
                + 2 * sum(fx[3:-3:3])
                + fx[-1]
            )
        )

        # Optimasi
        err = 1
        while err > eps:
            n *= 3
            h = (b - a) / n
            fx = [func(a + i * h, *args, **kwargs) for i in range(n + 1)]
            L1 = (
                3
                / 8
                * h
                * (
                    fx[0]
                    + 3 * sum(fx[1:-2:3])
                    + 3 * sum(fx[2:-1:3])
                    + 2 * sum(fx[3:-3:3])
                    + fx[-1]
                )
            )
            err = np.abs(L1 - L0) / np.abs(L1)
            L0 = L1
    except Exception:
        raise RuntimeError("Integrasi gagal, pastikan fungsi anda benar!")
    return L1

if __name__ == "__main__":

    def f(x: float) -> float:
        """
        Test Function
        """
        return x ** 4

    print(simpson_13(f, 0, 1))
    print(simpson_38(f, 0, 1))

    import doctest

    doctest.testmod()


# -*- coding: utf-8 -*-
"""
Created on Mon Jul 24 10:52:46 2017

@author: Jason Livingston
"""

import pandas as pd
import numpy as np
from sklearn import linear_model

##CLOSED FORM LINEAR REGRESSION
X = pd.DataFrame()
X['int'] = [1,1,1,1,1]
X['A'] = [1,2,3,4,5]
X['B'] = [3,4,4,6,7]

X = X.values
Y = [4,5,7,7,9]
#Y = Y.values

Xt=X.transpose()

XtX=np.dot(Xt,X)
XtY = np.dot(Xt,Y)
XtXinv = np.linalg.inv(XtX)
B = np.dot(XtXinv,XtY)

##SKLEARN LINEAR REGRESSION FOR COMPARISON
X = pd.DataFrame()
X['A'] = [1,2,3,4,5]
X['B'] = [3,4,4,6,7]

explin = linear_model.LinearRegression(fit_intercept = True)
explin.fit(X,Y)
explin.coef_

##ONLINE GRADIENT DESCENT
def predict(row,coefficients):
    row = row
    yhat = coefficients[0]
    for i in range(len(row) - 1):
        yhat = yhat+coefficients[i+1]*row[i]
    return yhat

def df_to_list_of_lists(df):
    df2 = []
    for i in range(len(df[list(df.columns.values)[0]])):
        templist = []
        for col in list(df.columns.values):
            x = df[col][i]
            templist.append(x)
        df2.append(templist)
    return df2

def coefficients_sgd(train,l_rate,n_epoch):
    if type(train) == pd.core.frame.DataFrame:
        train = df_to_list_of_lists(train)
    coefs = [0 for i in range(len(train[0]))]
    for epoch in range(n_epoch):
        for row in train:
            yhat = predict(row,coefs)
            error = yhat - row[-1]
            coefs[0] = coefs[0] - l_rate*error
            for i in range(len(row)-1):
                coefs[i+1] = coefs[i+1]-l_rate*error*row[i]
    return coefs

X = pd.DataFrame()
#X['int'] = [1,1,1,1,1]
X['A'] = [1,2,3,4,5]
X['B'] = [3,4,4,6,7]
X['Y'] = Y
coefficients = coefficients_sgd(train = X,l_rate = .001,n_epoch = 1000)
print("Intercept = %f Beta_A = %f Beta_B = %f"%tuple(coefficients) )

Linear Regression by OLGD and Closed Form.py


# -*- coding: utf-8 -*-

import numpy as np

def conv(a, b):
    N = len(a)
    M = len(b)
    YN = N + M - 1
    y = [0.0 for i in range(YN)]
    for n in range(YN):
        for m in range(M):
            if 0 <= n - m and n - m < N:
                y[n] += a[n - m] * b[m]
    return y

def conv2(a, b):
    N = len(a)
    M = len(b)
    YN = N + M - 1
    y = [0.0 for i in range(YN)]
    b = np.array(b)[::-1]       # Reverse
    for n in range(YN):
        for m in range(M):
            k = n - M + m + 1;
            if 0 <= k and k < N:
                y[n] += a[k] * b[m]
    return y

def convfft(a, b):
    N = len(a)
    M = len(b)
    YN = N + M - 1
    FFT_N = 2 ** (int(np.log2(YN)) + 1)
    print(FFT_N);
    afft = np.fft.fft(a, FFT_N)
    bfft = np.fft.fft(b, FFT_N)
    abfft = afft * bfft
    y = np.fft.ifft(abfft).real[:YN]
    return y

def time_test():
    import time
    import matplotlib.pyplot as plt

    def run(func, a, b):
        n = 1
        start = time.clock()
        for j in range(n):
            func(a, b)
        end = time.clock()
        run_time = end - start
        return run_time / n

    n_list = []
    t1_list = []
    t2_list = []
    t3_list = []
    for i in range(10):
        count = i * 1000 + 10
        print(count)
        a = np.ones(count)
        b = np.ones(count)
        t1 = run(conv, a, b)    # Direct calculation convolution
        t2 = run(conv2, a, b)
        t3 = run(convfft, a, b) # Fast convotution by FFT
        n_list.append(count)
        t1_list.append(t1)
        t2_list.append(t2)
        t3_list.append(t3)

    # plot
    plt.plot(n_list, t1_list, label='conv')
    plt.plot(n_list, t2_list, label='conv2')
    plt.plot(n_list, t3_list, label='convfft')
    plt.legend()
    plt.title(u"convolve times")
    plt.ylabel(u"run times(ms/point)")
    plt.xlabel(u"length")
    plt.show()

if __name__ == '__main__':
    a = [ 0, 1, 2, 3, 4, 5 ]
    b = [ 0, 1, 2 ]
    print(conv2(a, b))
    print(convfft(a, b))
    print(np.convolve(a, b))
    # time_test()