'''
Obtain the optimal constant leverage ratio in the continuous limit assuming a given time period, volatility,
and underlying return.
'''

import numpy as np
from scipy.optimize import minimize_scalar, minimize

from modules.simulate import simulateLeveragedBoundedGBM

def computeConstantLeverageReturn(leverage_ratio, underlying_return, time_period, volatility):
    '''
    Compute the return from the constant leverage strategy assuming no cost to borrow and no management fee.

    params:

    leverage_ratio:
        the desired constant leverage ratio
    underlying_return:
        return of the underlying asset as a multiple of initial price
    time_period:
        time period in years
    volatility:
        average annualized volatility over the time period
    '''
    l = leverage_ratio
    t = time_period
    vol = volatility
    return (underlying_return**l)*np.exp(((l-l**2)/2)*(vol**2)*t)

def optimizeRatioContinuous(underlying_return, time_period, volatility):
    '''
    Given some basic market conditions, compute the leverage ratio that maximizes the return
    denominated in the debt asset.

    If the solution is below 1, return 1 as it means leveraging can only decrease returns.

    params:

    underlying_return:
        return of the underlying asset as a multiple of initial price
    time_period:
        time period in years
    volatility:
        average annualized volatility over the time period

    returns:

    sol:
        the optimal leverage ratio
    return:
        the corresponding return
    '''
    def computeReturn(leverage_ratio):
        return -computeConstantLeverageReturn(leverage_ratio, underlying_return, time_period, volatility)
    sol = minimize_scalar(computeReturn)
    if sol.x < 1:
        return 1, computeConstantLeverageReturn(1, underlying_return, time_period, volatility)
    return sol.x, abs(sol.fun)

def optimizeAutomationBoundedGBM(initial_portfolio_value, min_ratio, service_fee, gas_price, volatility, start_price, end_price, time_horizon):
    '''
    Given some real world parameters for DeFi Saver, average gas conditions, and user specified
    expectations of start price, end price and volatility for the collateral asset, compute the
    optimal choice of admissible automation settings to maximizes the expected return. If the expected
    return is less than the return of the underlying, return an empty list, signifying that automation
    is not a good choice.
    '''

    # Constraint functions

    # Repay from must be 10% greater than min ratio.
    def constraint0(x):
        return x[0] - min_ratio - 10.1
    # Repay to must be 5% greater than repay from
    def constraint1(x):
        return x[1] - x[0] - 5
    # Boost to must be 5% greater than repay to
    def constraint2(x):
        return x[3] - x[1] - 5
    # Boost from must be 5% greater than boost to
    def constraint3(x):
        return x[2] - x[3] - 5
    # Boost from must be lower than 1000%
    def constraint4(x):
        return 1000 - x[2]

    cons0 = {'type': 'ineq', 'fun': constraint0}
    cons1 = {'type': 'ineq', 'fun': constraint1}
    cons2 = {'type': 'ineq', 'fun': constraint2}
    cons3 = {'type': 'ineq', 'fun': constraint3}
    cons4 = {'type': 'ineq', 'fun': constraint4}
    cons = [cons0, cons1, cons2, cons3, cons4]

    def meanReturnBoundedGBM(automation_settings):
        '''
        Opposite of mean return since the optimization routine is a minimization routine.
        Simulations start at a leverage corresponding to the the "boost to" target.
        '''
        repay_from = automation_settings[0]
        repay_to = automation_settings[1]
        boost_from = automation_settings[2]
        boost_to = automation_settings[3]
        # print("Trying values: ")
        # print("Repay from: ", repay_from)
        # print("Repay to: ", repay_to)
        # print("Boost from: ", boost_from)
        # print("Boost to: ", boost_to, "\n")
        return_in_collateral_asset, _, _, _ = simulateLeveragedBoundedGBM(initial_portfolio_value, boost_to, min_ratio, repay_from, repay_to, boost_from, boost_to, service_fee, gas_price, 200, volatility, start_price, end_price, time_horizon, 0.000114155)
        return -np.mean(return_in_collateral_asset)

    # Look for the optimal leverage ratio in the continuous case to have a good initial guess.
    L, _ = optimizeRatioContinuous(end_price/start_price, time_horizon, volatility)
    R_init = 100*L/(L-1)
    # print("Optimal L in continuous case: ", L)
    # print("Corresponding ratio: ", R_init)
    if R_init < min_ratio + 10:
        initial_guess = [200, 220, 240, 220]
    else:
        initial_guess = [R_init - 5, R_init, R_init + 5, R_init]
    print("Optimizing...")
    # Actual optimization routine
    res = minimize(meanReturnBoundedGBM, initial_guess, constraints = cons, method='COBYLA', options={'catol': 0}, tol=0.1)
    sol = res.x
    repay_from = sol[0]
    repay_to = sol[1]
    boost_from = sol[2]
    boost_to = sol[3]
    returns_col, returns_debt, _, _ = simulateLeveragedBoundedGBM(initial_portfolio_value, boost_to, min_ratio, repay_from, repay_to, boost_from, boost_to, service_fee, gas_price, 100, volatility, start_price, end_price, time_horizon, 0.000114155)
    optimal_expected_return_in_collateral = np.mean(returns_col)
    optimal_expected_return_in_debt = np.mean(returns_debt)
    if optimal_expected_return_in_collateral < 1:
        return [0, 0, 0, 0], 1
    return sol, optimal_expected_return_in_collateral, optimal_expected_return_in_debt


import numpy as np
import math
from copy import deepcopy
import time
import functools

def ReadPrecision():
    return float(input())

def ReadMatrix():
    matrixSize = int(input())

    matrix = [list(map(float, input().split())) for i in range(matrixSize)]

    return matrix

def MaxNonDiag(matrix):
    i, j = 0, 1

    maxVal = abs(matrix[0][1])

    for k in range(len(matrix)):
        for l in range(len(matrix)):
            if maxVal < abs(matrix[k][l]) and k != l:
                i, j = k, l

    return i, j

def CalcAngle(matrix, i, j):
    delimeter = matrix[i][i] - matrix[j][j]

    res = math.atan(2 * matrix[i][j] / delimeter) / 2.0 if delimeter != 0 \
          else math.pi / 4.0

    return res

def MakeOrthMtx(matrix, i, j):
    phiAngle = CalcAngle(matrix, i, j)
    orthMtx = [[0.0] * len(matrix) for k in range(len(matrix))]
    orthMtx[i][j] = -math.sin(phiAngle)
    orthMtx[j][i] = math.sin(phiAngle)
    orthMtx[i][i] = math.cos(phiAngle)
    orthMtx[j][j] = math.cos(phiAngle)
    for m in range(len(matrix)):
        if m != i and m != j:
            orthMtx[m][m] = 1.0

    return orthMtx

def QuadNonDiagSum(matrix):
    sum = 0.0

    for i in range(len(matrix)):
        sum += math.fsum([matrix[i][j] * matrix[i][j] if i != j
                          else 0.0
                          for j in range(len(matrix))])

    return sum

def PrecFunc(matrix):
    return math.sqrt(QuadNonDiagSum(matrix))

def IsClose(iterEps, userEps):
    print("iteration eps = {}; user eps = {}".format(iterEps, userEps))

    return iterEps < userEps

def FindEigVec(matrix, eps):
    mtxFirst = np.transpose(deepcopy(matrix))
    mtxSecond = [[]]
    orthoList = []
    iteration = 0

    while True:
        maxI, maxJ = MaxNonDiag(mtxFirst)
#        print("max elem is {} with i = {}, j = {}".format(mtxFirst[maxI][maxJ], maxI, maxJ))
        orthMtx = MakeOrthMtx(mtxFirst, maxI, maxJ)
        orthoList.append(orthMtx)
        mtxSecond = np.dot(np.dot(np.transpose(orthMtx), mtxFirst), orthMtx)
#        print("ortho:\n{}\nfirst:\n{}\nsecond:\n{}".format(np.transpose(orthMtx), mtxFirst, mtxSecond))

        if IsClose(PrecFunc(mtxSecond), eps):
            break

        iteration += 1
        mtxFirst = deepcopy(mtxSecond)

    res = [mtxSecond[i][i] for i in range(len(matrix))]

    return res, iteration, functools.reduce(np.dot, orthoList)

if __name__ == "__main__":
    prec = ReadPrecision()
    mtx = ReadMatrix()

    eigVals, iterCount, eigVecs = FindEigVec(mtx, prec)

    print("Found Eigen values:\n{}\nAnd Eigen vectors:\n{}\n In {} iterations".format(";\n".join(map(str, eigVals)),
                                                                                eigVecs,
                                                                                iterCount))
    for i in range(len(mtx)):
        lhs = mtx @ eigVecs[:, i]
        rhs = eigVecs[:, i] * eigVals[i]
        print(lhs)
        print(rhs)
        print("{} eigenVals is {}".format(i, np.isclose(lhs, rhs, prec)))


import numpy as np

"""
  converts polar coordinates (r, theta) to cartesian (x,y)
"""
def polarToCartesian(p):
  r     = p[0]
  theta = p[1]

  x = r*np.cos(theta)
  y = r*np.sin(theta)
  return np.array([x, y])

"""
  converts cartesian (x,y) to polar coordinates (r, theta)
"""
def cartesianToPolar(s):
  x = s[0]
  y = s[1]

  r = np.sqrt(s[0]**2 + s[1]**2)
  theta = np.arctan2(y,x)

  return np.array([r, theta])

"""
  solved 2nd degree equation
"""
def solve2ndDegEq(a,b,c):
  d = (b**2) - 4*a*c
  x = np.sqrt(complex(d))
  return (-b + np.array([x,-x]))/(2*a)

#x = np.array([1,0])
#y = cartesianToPolar(x)
#print polarToCartesian(y)


import numpy as np

def predict(X, w, b):
    return X * w + b

def loss (X, Y, w, b):
    predictions = predict(X, w, b)
    return np.average((predictions - Y) ** 2)

def gradient(X, Y, w, b):
    predictions = predict(X, w, b)
    w_gradient = np.average(2 * X * (predictions - Y))
    b_gradient = np.average(2 * (predictions - Y))
    return (w_gradient, b_gradient)

def train_line(X, Y, iterations, learning_rate):
    w = b = 0;
    for i in range(iterations):
        print("%d => Loss: %.10f" % (i, loss(X, Y, w, b)))
        w_gradient, b_gradient = gradient(X, Y, w, b)
        w -= w_gradient * learning_rate
        b -= b_gradient * learning_rate
    return w, b

if __name__ == "__main__":
    X, Y = np.loadtxt("examples.txt", skiprows=1, unpack=True)
    iterations = 20000
    learning_rate = 0.001
    w, b = train_line(X, Y, iterations, learning_rate)

    print("\nw = %.10f, b = %.10f" % (w, b))
    print("\ninput = %d => prediction = %.10f" % (25, predict(25, w, b)))

    input("Press <Enter>")

    import matplotlib.pyplot as plt

    plt.plot(X, Y, "bo")
    plt.xlabel("Input", fontsize=20)
    plt.ylabel("Output", fontsize=20)
    x_edge, y_edge = 50, 50
    plt.axis([0, x_edge, 0, y_edge])
    plt.plot([0, x_edge], [b, predict(x_edge, w, b)], linewidth=1.0, color="g")
    plt.show()


import sys
import math
import numpy as np
import torch
from torch.nn import *
from torch.optim import AdamW
from torch.utils.data import Dataset, DataLoader
from typing import Union

class MatrixFactorize(Module):
    """
    Matrix Factorization Model for Numerical Factorization and Recommender Systems
    """

    def __init__(self, M: Union[torch.Tensor, np.ndarray], dim, mask: Union[torch.Tensor, np.ndarray] = None, bias=True, seed=None):
        """
        Instantiate variables for matrix factorization, i.e. M = A * B + C.
        :param M <torch.Tensor|numpy.ndarray>:      Input 2-D matrix to factorize into A and B (with bias C).
        :param dim <int>:                           Hidden / latent dimension of matrix factorization.
        :param mask <torch.Tensor|numpy.ndarray>:   Element observability mask matrix with shape equivalent to M.
                                                    Non-zero implies True, while zero implies False.
        :param bias <bool>:                         Utilize bias in factorization. Set to False to exclude affine bias C.
        :param seed <int>:                          Random seed fixture for reproducibility.
        """
        super().__init__()

        # Validate matrix.
        if len(M.shape) != 2 or dim <= 0:
            print(
                f"[MatrixInputError] MatrixFactorize() only supports 2-D matrices. " +
                f"Moreover, the hidden dimension is necessarily > 0.",
                file=sys.stderr, flush=True
            )
            return None

        # Class Parameters
        self.M = torch.Tensor(M)
        self.x, self.y = self.M.shape
        self.dim = dim
        self.bias = bias
        self.mask = torch.ones(self.M.shape)
        if mask is not None and mask.shape == self.M.shape:
            # Construct Boolean mask Tensor.
            self.mask = torch.where(torch.Tensor(mask) != 0, 1, 0)

        # Fix random seed.
        self.torch_gen = None
        if seed is not None:
            self.torch_gen = torch.manual_seed(seed)

        # Matrix Factors + Affine Bias
        self.A = Parameter(torch.empty((self.x, self.dim)), requires_grad=True)
        self.B = Parameter(torch.empty((self.dim, self.y)), requires_grad=True)
        self.C = Parameter(torch.empty((self.x, self.y)), requires_grad=True)
        init.xavier_uniform_(self.A)
        init.xavier_uniform_(self.B)
        init.xavier_uniform_(self.C)

        # Track training loss.
        self.loss = float('inf')

    def __repr__(self):
        """
        Output matrix factorization and approximation matrix of M.
        """

        # Avoid scientific notation.
        np.set_printoptions(suppress=True)

        # Collect information.
        output_buffer = f"\nMatrix Factorization Output (M = A * B + C)\n"
        output_buffer += f"\nTarget Matrix:\n\n{self.M.numpy()}\n"
        output_buffer += f"\nMask Matrix:\n\n{self.mask.numpy()}\n"
        output_buffer += f"\nApprox. Matrix:\n\n{self().detach().numpy().round(2)}\n"
        output_buffer += f"\nMatrix A:\n\n{self.A.detach().numpy().round(2)}\n"
        output_buffer += f"\nMatrix B:\n\n{self.B.detach().numpy().round(2)}\n"
        output_buffer += f"\nMatrix C:\n\n{self.C.detach().numpy().round(2)}\n"
        output_buffer += f"\nRegression Loss: {self.loss}\n"

        # Reset notation.
        np.set_printoptions(suppress=False)

        return output_buffer

    def forward(self):
        """
        Compute element of matrix from factorization.
        """

        # Compute product matrix or recommendation.
        output = torch.matmul(self.A, self.B)
        if self.bias:
            # Include affine bias.
            output += self.C
        return output

    def fit(self, cycles=1000, lr=8e-4, regularize=1e-2, patience=3, verbose=False):
        """
        Train the factorization.
        :param cycles <int>:        Number of gradient descent cycles.
        :param lr <float>:          Learning rate. Re-calibrated to order of values in matrix M.
        :param regularize <float>:  Weight decay lambda for regularization in AdamW.
        :param patience <int>:      Number of cycles of convergence before termination.
        :param verbose <bool>:      Output training progress information.
        """

        # Instantiate optimizer. Tune learning rate to order of magnitude of matrix M.
        lr_calibrate = lr * self.M.sum() / torch.numel(self.M)
        optimizer = AdamW(
            self.parameters(),
            lr=lr_calibrate,
            weight_decay=regularize
        )

        # Train factorization.
        factor_opt = dict(self.state_dict())
        timer = 0
        for i in range(cycles):

            # Clear gradients in optimizer.
            self.zero_grad()

            # Compute loss of matrix factorization.
            loss = torch.linalg.norm(
                (self() - self.M) * self.mask
            ) ** 2

            # Back-propagate.
            loss.backward()

            # Apply gradients.
            optimizer.step()

            # Validate training.
            if i % 100 == 0 and verbose:
                print(
                    f"Training Cycle: {i+1} / {cycles} | Factorization Loss: {loss.item()}",
                    file=sys.stdout, flush=True
                )
            if loss.item() < self.loss:
                # Update optimal factorization.
                factor_opt = dict(self.state_dict())
                # Update optimal loss.
                self.loss = loss.item()
                # Reset patience timer.
                timer = 0
            else:
                # Increment patience timer.
                timer += 1
                if timer > patience:
                    # Model convergence. Revert to optimal factorization. Terminate training.
                    self.load_state_dict(factor_opt)
                    break

class FactorizationMachine(Module):
    """
    [Factorization Machine Recommendation Model]
    Learns latent space features to characterize similarity of dataset features
    to compute a recommendation as a function of dataset features. Dataset
    features can be mixed / hybrid such that you can combine information
    on both the recommended object and the recommendation target to generate
    an informed similarity or recommendation / ranking metric.
    """

    def __init__(self, data_dim, hidden_dim=25, seed=None) -> None:
        """
        Instantiate class attributes for FM. Constructs a feature similarity matrix
        F of shape (x_features, hidden_dim) to learn implicit representations of
        all trainable features in the data for recommendation or ranking.
        :param data_dim <int>:      Number of features to learn from in the dataset.
        :param hidden_dim <int>:    Dimension of the latent space of features.
        :param seed <int>:          Random seed fixture for reproducibility.
        """
        super().__init__()

        # Parameters
        self.input_dim = data_dim       # X
        self.hidden_dim = hidden_dim    # H

        # Fix random seed.
        self.torch_gen = None
        if seed is not None:
            self.torch_gen = torch.manual_seed(seed)

        """ Matrix Factorization """

        # Feature Similarity Matrix
        self.F = Parameter(
            torch.empty((self.input_dim, self.hidden_dim)),
            requires_grad=True
        )
        init.xavier_uniform_(self.F)

        """ Linear Regression """

        # Feature Weight Vector and Bias
        self.V = Parameter(
            torch.empty((self.input_dim, 1)),
            requires_grad=True
        )
        init.xavier_uniform_(self.V)
        self.bias = Parameter(
            torch.zeros(1),
            requires_grad=True
        )

        """ Gaussian Regression """

        self.gaussian_dist = Linear(
            in_features=self.hidden_dim,
            out_features=2
        )

    def forward(self, x: torch.Tensor):
        """
        Compute FactorizationMachine(x). Returns a mean and standard deviation for the recommendation.
        :param x <torch.Tensor>:    Factorization machine input Tensor of shape (N, input_dim).
        """

        # Compute square of sum and sum of squares.
        # (N, X) * (X, H) -> (N, H)
        sq_sm = torch.matmul(x, self.F) ** 2
        sm_sq = torch.matmul(x ** 2, self.F ** 2)

        # Compute linear regression model.
        # (N, H) * (H, 1) -> (N, 1)
        lin_reg = torch.matmul(x, self.V)

        # Compute latent feature matrix of shape (N, H).
        latent = self.bias + lin_reg + 0.5 * sq_sm - sm_sq

        # Fit Gaussian distribution to recommendation.
        # (N, H) -> (N, 2)
        output = self.gaussian_dist(latent)

        # Output recommendation / ranking score distribution, i.e. FM(x).
        return output[:, 0], torch.abs(output[:, 1])

    def fit(
        self,
        X: Union[torch.Tensor, np.ndarray],
        Y: Union[torch.Tensor, np.ndarray],
        mask: Union[torch.Tensor, np.ndarray] = None,
        cycles=100,
        lr=2e-3,
        batch_frac=0.01,
        regularize=1e-2,
        patience=3,
        verbose=False
    ):
        """
        Train the Factorization Machine.
        :param X <torch.Tensor>:        Input training data features of shape (N, X).
        :param Y <torch.Tensor>:        Target training data class / score vector of shape (N, 1).
        :param mask <torch.Tensor>:     Feature observability mask for X of shape (N, X).
        :param cycles <int>:            Number of gradient descent cycles.
        :param lr <float>:              Learning rate. Re-calibrated to order of values in matrix M.
        :param batch_frac <float>:      Fraction of the dataset to set as the batch size.
        :param regularize <float>:      Weight decay lambda for regularization in AdamW.
        :param patience <int>:          Number of cycles of convergence before termination.
        :param verbose <bool>:          Output training progress information.
        """

        # Validate arguments.
        if any([
            len(X.shape) != 2,
            len(Y.shape) != 2,
            mask is not None and mask.shape != X.shape,
            X.shape[1] != self.input_dim,
            Y.shape[1] != 1,
            cycles <= 0,
            lr <= 0,
            batch_frac <= 0,
            regularize < 0
        ]):
            print(
                f"[FactorizationMachine.fit()] Improper training argument(s) to fit(). Aborting... \n" +
                f"""FactorizationMachine.fit() Requirements:
                - X is a (N, data_dim) Tensor and Y is a (N, 1) Tensor.
                - mask is an optional (N, data_dim) Tensor.
                - cycles > 0
                - lr > 0
                - batch_frac > 0
                - regularize >= 0
                """,
                file=sys.stderr, flush=True
            )
            return

        # Convert and instantiate Tensor(s).
        N = X.shape[0]
        if not torch.is_tensor(X):
            X = torch.Tensor(X)
        if not torch.is_tensor(Y):
            Y = torch.Tensor(Y)
        mask_tensor = torch.ones(X.shape)
        if mask is not None:
            # Construct Boolean mask Tensor.
            mask_tensor = torch.where(torch.Tensor(mask) != 0, 1, 0)

        # Instantiate optimizer.
        optimizer = AdamW(
            self.parameters(),
            lr=lr,
            weight_decay=regularize
        )

        # Train Factorization Machine.
        model_opt = dict(self.state_dict())
        loss_opt = float('inf')
        timer = 0
        for i in range(cycles):

            # Train on batches of data.
            for _ in range(math.ceil(1 / batch_frac)):

                # Generate random batches by index.
                rand_idx = torch.randint(
                    N,
                    size=(math.ceil(batch_frac * N),),
                    generator=self.torch_gen
                )

                # Extract batch.
                X_batch = X[rand_idx]
                Y_batch = Y[rand_idx]
                mask_batch = mask_tensor[rand_idx]

                # Clear gradients in optimizer.
                self.zero_grad()

                # Compute model prediction mean and deviation.
                Y_mu, Y_sigma = self(X_batch * mask_batch)

                # Compute Gaussian distributional loss.
                loss = GaussianNLLLoss()(Y_mu, Y_batch, Y_sigma)

                # Back-propagate.
                loss.sum().backward()

                # Apply gradients.
                optimizer.step()

            # Validate training.
            if i % math.ceil(cycles / 5) == 0 and verbose:
                print(
                    f"Training Cycle: {i+1} / {cycles} | Recommendation Loss: {loss.item()}",
                    file=sys.stdout, flush=True
                )
            if loss.sum().item() < loss_opt:
                # Update optimal factorization.
                model_opt = dict(self.state_dict())
                # Update optimal loss.
                loss_opt = loss.sum().item()
                # Reset patience timer.
                timer = 0
            else:
                # Increment patience timer.
                timer += 1
                if timer > patience:
                    # Model convergence. Revert to optimal factorization. Terminate training.
                    self.load_state_dict(model_opt)
                    break


import math
import numpy as np

def sign(diff):
    return 1 if diff == 0 else (-1,1)[diff>0]

def sqr(x):
    return x*x

def dist(x1,y1,x2,y2):
    return math.sqrt(sqr(x1-x2)+sqr(y1-y2))

def distc(p1,p2):
    return dist(*p1,*p2)

def closest(points,target):
    min_dist = 10e50
    min_idx = None
    tx,ty = target
    for idx,(px,py) in enumerate(points):
        d = dist(tx,ty,px,py)
        if d < min_dist:
            min_dist = d
            min_idx = idx
    return min_idx

COORDS_AROUND = ((-1,0),(0,-1),(1,0),(0,1))

def neg(p):
    x,y = p
    return (-x,-y)

def scalar_mul(p,m):
    x,y = p
    return (x*m,y*m)

def sub(p1,p2):
    return add(p1,neg(p2))

def add(p1,p2):
    ax,ay = p1
    bx,by = p2
    return (ax+bx,ay+by)

def midpoint(source,dest):
    vector = sub(dest,source)
    half_vec = scalar_mul(vector,0.5)
    midpoint = add(source,half_vec)
    return midpoint

def raytrace2dgrid(x1,y1,x2,y2):
    RANGE_LEN = 100
    range = np.arange(RANGE_LEN)/RANGE_LEN
    xvec = (x2-x1)*range + x1
    yvec = (y2-y1)*range + y1
    pointvec = np.stack([xvec,yvec],axis=1)
    #alts = np.concatenate([pointvec
    #,pointvec+np.asarray([1,0])
    #,pointvec+np.asarray([0,1])
    #,pointvec+np.asarray([0.5,0.5])
    #,pointvec+np.asarray([0.5,-0.5])],axis=0)
    tuples = pointvec.astype(np.int32).tolist()
    res = []
    prev = None
    for p in tuples:
        if prev != p:
            res.append(tuple(p))
            prev = p
    res.pop()
    return res
    '''cx = int(x1)
    cy = int(y1)
    tx = int(x2)
    ty = int(y2)
    dirx = sign(x2-x1)
    diry = sign(y2-y1)
    #print(dirx)
    #print(diry)
    ratio = (y2-y1+1e-7)/(x2-x1+1e-7)
    coord_list = []
    def dist_line(nx,ny):
        return abs((y1)+ratio*(nx-(x1)) - ny)
    while not (cx == tx and cy == ty):
        # if abs(y1+ratio*(cx-x1) - y1)
        if dist_line(cx+dirx,cy) < dist_line(cx,cy+diry):
            cx += dirx
        else:
            cy += diry
        #print((cx,cy))
        coord_list.append((cx,cy))
        #if len(coord_list) > 10:
        #    return

    if len(coord_list):
        coord_list.pop()# remove x2,y2 from list

    return coord_list'''

def get_rays(cen,num_rays,radius):
    rays = []
    ax,ay = cen
    for angle in range(num_rays):
        radians = math.pi * 2 * angle / num_rays
        tx = ax + math.cos(radians)*radius
        ty = ay + math.sin(radians)*radius
        rays.append((tx,ty))

    return rays

if __name__=="__main__":
    print(raytrace2dgrid(1.5,1,3,-2))
    print(raytrace2dgrid(0,0,10,-0.2))
    print(raytrace2dgrid(0,0,0,10))
    #exit(0)
    # tot_list = []
    # for x in range(100000):
    #     tot_list.append(raytrace2dgrid(1,1,10,5)[0])
    # print(tot_list[-3])


from numpy import *
from numpy.linalg import solve,norm

#
# -1- Droite au sens de moindres carrés usuels
#

def superLineInitialGuest(X,U):

    A = array([power(X,i) for i in range(2)]).T
    b,a = solve(A.T@A, A.T@U)

    return array([a,b])

#
# -------------------------------------------------------------------------
#
# -2- Iteration de Newton-Raphson pour obtenir
#     les coefficients d'une droite minimisant la "vraie distance" entre
#     les données et la droite
#

def superLineIterate(X,U,alpha):

    a,b = alpha

    # Variables intermédiaires :
    z = 1 + a*a
    y = z*z
    dist = U - a*X - b

    # Dérivées partielles premières :
    part_a = -(2*a/y)*(dist@dist) - (2/z)*(dist@X)
    part_b = -(2/z)*sum(dist)

    gradient = array([part_a, part_b])

    # Dérivées partielles secondes :
    part_a_a = ((-2*z + 8*a*a)/(y*z))*(dist@dist) + (4*a/y)*(X@dist) + (4*a/y)*sum(dist) + (2/z)*(X@X)
    part_a_b = (4*a/y)*sum(dist) + (2/z)*sum(X)
    part_b_b = (2/z)*len(X)

    hessienne = array([[part_a_a, part_a_b],[part_a_b, part_b_b]])

    dalpha = solve(hessienne, -gradient)

    return dalpha


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

def gaussian(x, u, sigma):
    return math.exp(-(x - u) ** 2 / (2 * sigma * sigma)) / math.sqrt(2 * math.pi * sigma * sigma)

def importance_sampling_test(ori_sigma, sample_sigma):
    origin = []
    for n in range(10):
        sum = 0
        for i in range(100000):
            a = np.random.normal(1.0, ori_sigma)
            sum += a
        origin.append(sum)

    isample = []
    for n in range(10):
        sum2 = 0
        for i in range(100000):
            a= np.random.normal(1.0, sample_sigma)
            ua = gaussian(a, 1.0, sample_sigma)
            na = gaussian(a, 1.0, ori_sigma)
            sum2 += a * na / ua
        isample.append(sum2)

    origin = np.array(origin)
    isample = np.array(isample)
    print np.mean(origin), np.std(origin)
    print np.mean(isample), np.std(isample)

importance_sampling_test(1.0, 1.0)
importance_sampling_test(1.0, 0.5)
importance_sampling_test(1.0, 2)

xs = np.linspace(-5, 6, 301)
y1 = [gaussian(x, 1.0, 1.0) for x in xs]
y2 = [gaussian(x, 1.0, 0.5) for x in xs]
y3 = [gaussian(x, 1.0, 2) for x in xs]

fig = plt.figure(figsize=(8,5))
plt.plot(xs, y1, label='sigma=1.0')
plt.plot(xs, y2, label='sigma=0.5', linestyle=':')
plt.plot(xs, y3, label='sigma=2.0', linestyle='--')
plt.legend()
plt.show()


from math import sqrt
from statistics import stdev
from scipy.stats import norm, t, chi2, f
from numpy import array

DecnWords = {True: "SUCCESS to REJECT null hypothesis.",
             False: "FAIL to REJECT null hypothesis."}

class SampleGroup():
    def __init__(self, popStdevKnown, n, xbar, sigma):
        '''
sigma --->  Positive real number.
            It stands for sample deviation if popStdevKnown parameter is False,
            stands for population deviation if popStdevKnown parameter is True
popStdevKnown ---> True if population deviation is known, False if population deviation is unknown
'''
        self.n = n
        self.xbar = xbar
        self.sigma = sigma
        self.is_popVarianceKnown = popStdevKnown

def used_test(SampleGroup):
    if SampleGroup.is_popVarianceKnown:
        return("z-score test is applied.")
    else:
        return("t-student test is applied.")

#----------------------------------------------------------------------------------------------------------------------
class SampleProp():
    def __init__(self, prop, n):
        self.prop = prop
        self.n = n

#======================================================================================================================
                               # Normal distributions
#======================================================================================================================

def zalpha_RTT(alpha):
    zalpha = norm.ppf(1-alpha)
    return(zalpha)

def zalpha_LTT(alpha):
    zalpha = norm.ppf(alpha)
    return(zalpha)

def zalpha_2TT(alpha):
    zalpha = abs(norm.ppf(alpha/2))
    return(zalpha)

zalphaTails_Dict = {'>': zalpha_RTT,
                    '<': zalpha_LTT,
                    '!=': zalpha_2TT}
#======================================================================================================================

def talpha_RTT(alpha, dof):
    talpha = t.ppf(1-alpha, dof)
    return(talpha)

def talpha_LTT(alpha, dof):
    talpha = t.ppf(alpha, dof)
    return(talpha)

def talpha_2TT(alpha, dof):
    talpha = abs(t.ppf(alpha/2, dof))
    return(talpha)

talphaTails_Dict = {'>': talpha_RTT,
                    '<': talpha_LTT,
                    '!=': talpha_2TT}
#======================================================================================================================

def decn_RTT(vtest, valpha):
    if vtest < valpha: return(False)  #Fail to reject null hypothesis
    if vtest >= valpha: return(True)  #Success to reject null hypothesis

def decn_LTT(vtest, valpha):
    if vtest <= valpha: return(True)    #Success to reject null hypothesis
    if vtest > valpha: return(False)  #Fail to reject null hypothesis

def decn_2TT(vtest, valpha):
    if -valpha<vtest<valpha: return(False)                  #Fail to reject null hypothesis
    if (vtest<-valpha or vtest>valpha): return(True)        #Success to reject null hypothesis

Decision = {'>': decn_RTT,
            '<': decn_LTT,
            '!=': decn_2TT}
#======================================================================================================================
                                       # Chi-Square distributions
#======================================================================================================================

def x2alpha_RTT(alpha, dof):
    x2alpha = chi2.ppf(1-alpha, dof)
    return(x2alpha)

def x2alpha_LTT(alpha, dof):
    x2alpha = chi2.ppf(alpha, dof)
    return(x2alpha)

def x2alpha_2TT(alpha, dof):
    x2alpha = alpha/2
    x2alpha_lt = chi2.ppf(x2alpha, dof)
    x2alpha_rt = chi2.ppf(1-x2alpha, dof)
    return((x2alpha_lt, x2alpha_rt))

chi2_alphaTails_Dict = {'>': x2alpha_RTT,
                    '<': x2alpha_LTT,
                    '!=': x2alpha_2TT}

def decn_2TT_chi2(vtest, chi_tuple):
    if(chi_tuple[0] < vtest < chi_tuple[1]): return(False)          #Fail to reject null hypothesis
    if(vtest<chi_tuple[0] or vtest>chi_tuple[1]): return(True)      #Success to reject null hypothesis

Decision_chi2 = {'>': decn_RTT,
                 '<': decn_LTT,
                 '!=': decn_2TT_chi2}
#======================================================================================================================


import math
import random
import numpy as np

#this algorithm is a MINIMIZATION  specific implementation of a discrete method called Ant Colony Optimization.

#method/function space
def object_funct_eval(path, var_table):
    """
    Given a path and the array with all the discrete values per layer, the value of the obj. Function is returned as a result
    :param path: the path of a specific ant
    :param var_table: the array representing the discrete values of the layers
    :return: the value of the objective function for the specific path
    """
    length = len(path)
    my_vars = []
    for i in range(length):
        j = path[i]
        my_vars.append(var_table[i][j])
    #print(my_vars)
    #objective function - Ackley
    #my_value = -20*math.exp(-0.2*math.sqrt(0.5*((my_vars[0]**2 + (my_vars[1]**2))))) - math.exp(0.5*(math.cos(my_vars[0]*2*math.pi) + math.cos(my_vars[1]*2*math.pi))) +math.e + 20
    #Booth (1, 3)
    my_value = (my_vars[0] + 2*my_vars[1] -7)**2 + (2*my_vars[0] + my_vars[1] - 5)**2
    #my_value = my_vars[0]**2 - my_vars[0] - 11
    #beale (3, 0.5)
    #my_value = (1.5 - my_vars[0] + my_vars[0] * my_vars[1]) ** 2 + (2.25 - my_vars[0] + my_vars[0] * (my_vars[1] ** 2)) ** 2 + (2.625 - my_vars[0] + my_vars[0] * (my_vars[1] ** 3)) ** 2
    return my_value
def calc_discrete_values(upper, lower, r):
    """

    :param range: range of accuracy for the permissible discrete values
    :param upper: upper bounds
    :param lower: lower bounds
    :return: d the number of discrete values per variable
    """
    d = (upper[0] - lower[0]) /r + 1
    return d

def create_pheromone_table(n_var, disc):
    """
     My pheromone table acts like a neighbor-table for describing the arcs of my graph
     and the pheromones in the trails. Its cells contain the amount of pheromone in the arc
     connecting the row with the collumns. The pheromone value for all the arc is initialized as 1.
     IT MUST BE THE SAME FOR ALL THE ARCS INITIALLY. The last row remains table, it represents the food source.

     The node or layer  'zero' meaning the first row  is considered the home. (since we count beginning from zero)
    :param n_var: how many variables the object function has
    :param disc: number for permissible discrite values for each design variable

    :return: the initial form of the 2d-numpy array for the pheromone table

    """
    #numpy array N-dimensions . rows 1 for home + n_var, columns for the discrete values [0 ...d-1]
    ph_array = np.ones((n_var + 1, disc))
    #note : MIGHT need to change some nodes to zero
    return ph_array

def pheromone_trail_update(pher_table,bestants, worstants, fbest, fworst,bestpath):
    """

    :param pher_table: the pheromone array . *using a numpy array
    :param bestants: list of the best ants represented by their position in the colony
    :param worstants: the list of the worst ants
    :param fbest: the best obj.value for the current iteration
    :param fworst: the worst obj.value for the current iteration
    :param bestpath: the path the best ants have followed
    :return: the changes are directly made to the array (matrix) itself  thus i don't need to return a new array
    """
    #trail update, initialize my parameters
    scaling_par = 3
    decay_factor = 0.005
    #the added sum is only useful to the best path
    added_sum = 0
    b_len = len(bestants)
    w_len = len(worstants)

    added_sum = (scaling_par * b_len * fbest)/ (w_len * fworst)
    #print("added sum =", added_sum)
    length = len(pher_table) - 1
    #update the paths, check if an arc belongs to the best one
    for i in range(length):
        for j in range(len(pher_table[0])):
            if j == bestpath[i]:
                pher_table[i][j] += added_sum
            else:
                pher_table[i][j] = (1 - decay_factor) * pher_table[i][j]

def find_best_path(bestants, colony):
    """
    Given the ids of the best ants in the colony (at least one) ,the best path is returned.
    :param bestants: a list which contains at least one element, it's the ants with the best (min) value for the obj. function
    :param colony: the colony of the ants
    :return: a list of length the same as the number of variables of the obj.function. It's the best path in the iteration
    """
    my_ant = bestants[0]
    print("I m checking ant :", my_ant)
    path = colony[my_ant][0]
    return path

def create_layer_table(n_var, r, lower, upper):
    """
    Creates the design variables table. It represents the permitted values for each variable during the optimization.
    The permitted values get created according to a specific range given.
    :param n_var: number of variables
    :param lower, upper: lower and upper bounds
    :param r: we spread the values by adding r for each permitted discrete value (r:range)
    :return: 2-d array of n_var x p to represent the discrete values of each design variable
    """
    d = (upper[0] - lower[0]) / r + 1
    layer_array = np.zeros((n_var, d))
    #counter is used for future implementations when the limits for each variable change, for this first version the value
    #of d remains the same and the functions used have the same limit for each variable
    counter = 0
    iterator = lower[counter]
    for j in range(n_var):
        for i in range(int(d)):
            layer_array[j][i] = iterator
            iterator = iterator + r
        iterator = lower[counter]
    return layer_array

def create_ant(var_num):
    """

    :param var_num: number of variables needed for the obj.function
    :return: a combined list of 2 elements. Element 0 is the path as a list. Element 1 is the obj. value.
    """

    path = []
    #for initial values we believe the ants chose the 0-th discrete value. (count method 0 ...n-1)
    for i in range(var_num):
        path.append(0)
    #for initial value i choose a big one , but it depends on the nature of the obj. function
    value = 1000
    ant = []
    ant.append(path)
    ant.append(value)
    return ant

def create_colony(N, var_num):
    """
    creates the initial colony of ants, it is in a list form
    :param N: size of colony
    :param var_num: number of variables - it's needed to create ants individually before adding them to the colony
    :return:
    """
    colony = []
    for i in range(N):
        colony.append(create_ant(var_num))
    return colony

def prob_handling(var_table, var_tag, d, ph_table):
    """
    A roulette stohastic method of choosing which path to follow.
    :param var_table: the numpy array representing the discrete values
    :param var_tag: tag of the variable
    :param d: number of discrete values per variable
    :param ph_table: pheromone trail array
    :return: returns whick discrete value the ant k picked for a specific layer
    """
    #this is probability handling for ONE ant k regarding its choice for ONE variable
    prob_list=[]
    my_sum = 0
    #print("vartag",var_tag)
    for i in range(d):
        my_sum += ph_table[var_tag][i]

    #print("my sum",my_sum)
    for i in range(d):
        prob_list.append(ph_table[var_tag][i]/my_sum)
    #print("prob list", prob_list)
    #the way the ant picks a specific route is with a roulette selection on the prob.list
    roll = round(random.uniform(0, 1),3)
    #print("my roll:", roll)
    my_sum = 0
    my_pick= 0
    for i in range(d):
        my_sum += prob_list[i]
        if (roll<= my_sum or i == d-1):
            my_pick = i
            break
    #print("my pick is:",my_pick)
    #I return the ant's choice
    return my_pick
def count_ants(colony, value):
    ant_list = []
    for i in range(len(colony)):
        if colony[i][1] == value:
            ant_list.append(i)
    return ant_list

def check_convergence(antlist, N):
    flag = False
    if len(antlist) == int(N):
        flag = True
    return flag
def find_solution(bpath, var_table):
    """

    :param bpath: the best path
    :param var_table: table containing the discrete values
    :return: the discrete values representing given path
    """
    solution = []
    length = len(bpath)
    for i in range(length):
        j = bpath[i]
        solution.append(var_table[i][j])
    return solution

#main space
def mainloop():
    #create the parameters and run the algorithm via the functions
    N = 30
    myrange = 0.5
    l_bound = [-10, -10]
    u_bound = [10, 10]
    n_var = 2
    #d = number of discrete values for each variable
    d = int(calc_discrete_values(u_bound,l_bound,myrange))
    test_array_layer = create_layer_table(n_var, myrange, l_bound, u_bound)
    print("array layer:", test_array_layer)
    test_ph_array = create_pheromone_table(n_var, d)
    print("ph array:", test_ph_array)
    iteration = 1
    iteration_limit = 1000
    test_colony = create_colony(N,n_var)

    convergence_flag = False

    while convergence_flag == False and iteration <= iteration_limit:
        #for the colony each ant chooses a path going from Layer-to-Layer
        var_counter = 0
        while var_counter < n_var :
            #print("Choosing for variable:", var_counter)
            for ant in test_colony:
                #print("var counter",var_counter)
                ant[0][var_counter] = prob_handling(test_array_layer,var_counter,d,test_ph_array)
            var_counter += 1
        for ant in test_colony:
            ant[1] = object_funct_eval(ant[0], test_array_layer)

        #initialize best and worst values
        bestf = test_colony[0][1]
        worstf = test_colony[0][1]
        bestants = []
        worstants = []

        for ant in test_colony:
            if ant[1]<= bestf:
                bestf = ant[1]
        for ant in test_colony:
            if ant[1]>= worstf:
                worstf = ant[1]

        bestants = count_ants(test_colony,bestf)
        worstants = count_ants(test_colony, worstf)
        #print("my colony:", test_colony)
        print("best value and worst value ", bestf, ",", worstf)
        print("best ants", bestants)
        #print("worst ants", worstants)
        best_path = find_best_path(bestants,test_colony)
        print("best_path:", best_path)
        pheromone_trail_update(test_ph_array, bestants, worstants, bestf, worstf,best_path)
        print("new trails", test_ph_array)
        convergence_flag = check_convergence(bestants,N)
        #creating a new colony for the following iteration
        #test_colony = create_colony(N,n_var)
        iteration += 1

    solution = find_solution(best_path,test_array_layer)
    print("The min of the objective value is :", solution, "and the value is :", object_funct_eval(best_path, test_array_layer) )

if __name__ == '__main__':
    mainloop()


# Start initialization
import numpy as np
import pylab as p

# Make an x,z grid
grid = np.linspace(-6,6,201)
x, z = np.meshgrid(grid,grid)
mu=4*np.pi  # dipole strength (in z-direction)
# and the 2D cross section of the potential (scalar field)
phi = mu * z / (4 * np.pi * (x**2+z**2)**(3/2))
# End initialization

# Start contour plot
from matplotlib import colors
p.figure(figsize=(6,6))
heights = np.linspace(-0.6,0.6,7)
CS = p.contour(x,z,phi,heights,colors='k')
p.clabel(CS, inline=1, fontsize=10)
p.xlabel(r'$x$')
p.ylabel(r'$z$')
# End contour plot
p.savefig('dipole.png')

# Start gradient plot
#--p.figure(figsize=(6,6))
#--grid_course =  np.linspace(-10000,10000,11)
#--x_c, y_c = np.meshgrid(grid_course,grid_course)
#--radius = 2000
#--outside = x_c**2 + y_c**2 > radius**2
#--gradh_x = - 2*h0 / (R0**2 * (1 + (x_c**2+y_c**2)/R0**2)**2) * x_c
#--gradh_y = - 2*h0 / (R0**2 * (1 + (x_c**2+y_c**2)/R0**2)**2) * y_c
#--p.quiver(x_c[outside]/1000,y_c[outside]/1000,gradh_x[outside],gradh_y[outside],scale=3)
#--p.xlabel(r'$x$ (km)')
#--p.ylabel(r'$y$ (km)')
#--# End gradient plot
#--p.savefig('hojd_gradient.png')

#p.show()


import numpy as np
import warnings
import scipy.optimize as op

pi = np.pi

#####

__all__ = ["H", "D", "C", "Cmax"]

def H(p, normalize_output=True):
    """
    Calculates Shannon information (in nats) from a probability vector.

    Parameters
    ----------
    p : array-like
        vector of probabilities; will be normalized if not done so already
    normalize_output: bool
        boolean flag to normalize output to range (0,1); default=True

    Returns
    -------
    Hout : Shannon information
    """
    # check probabilities normalization
    if np.isclose(np.sum(p),1.0) != True:
        warnings.warn('Input probability vector was not normalized...fixing automatically')
        p = p/np.sum(p)

    # calculate entropy
    N = len(p)

    if normalize_output:
        K = 1/np.log(N)
    else:
        K = 1.0

    return -K*np.sum(p*np.log(p))

def D(p, normalize_output=True):
    """
    Calculates disequlibrium from a probability vector

    p : array-like
        vector of probabilities; will be normalized if not done so already
    normalize_output: bool
        boolean flag to normalize output to range (0,1); default=True

    Returns
    -------
    Dout : Disequilibrium
    """
    # check probabilities normalization
    if np.isclose(np.sum(p),1.0) != True:
        warnings.warn('Input probability vector was not normalized...fixing automatically')
        p = p/np.sum(p)

    # calculate disequilibrium
    N = len(p)

    if normalize_output:
        K = N/(N-1)
    else:
        K = 1.0

    return K*np.sum((p-1/N)**2)

def C(p, normalize_output=True):
    """
    Calculates LMC complexity from a probability vector (Lopez-Ruiz, Mancini, & Calbet 1995)

    p : array-like
        vector of probabilities; will be normalized if not done so already
    normalize_output: bool
        boolean flag to normalize output to range (0,1); default=True

    Returns
    -------
    Cout : LMC Complexity
    """
    # check probabilities normalization
    if np.isclose(np.sum(p),1.0) != True:
        warnings.warn('Input probability vector was not normalized...fixing automatically')
        p = p/np.sum(p)

    # calculate disequilibrium
    N = len(p)

    if normalize_output:
        K = 1/Cmax(N)

    else:
        K = 1.0

    return K * H(p, False)*D(p, False)

def ap9(p,N):
    """
    Helper fucntion for Cmax; Eq.9 from Anteneodo & Plastino (1996) for fixed n=1
    """
    return (2-3*p+1/N)*np.log((1-p)/(N-1)) + (3*p-1/N)*np.log(p)

def ap10(p,N):
    """
    Helper function for Cmax; Eq.10 from Anteneodo & Plastino (1996) for fixed n=1
    """
    return (1-2*p+p/N)*np.log((1-p)/(N-1)) + p*(2-1/N)*np.log(p) - (p-1/N)

def Cmax(N):
    """
    Calculates maximum complexity (Cmax) for a given N
    Numerically solves equations from Anteneodo & Plastino (1996)

    Parameters
    ----------
    N : array-like
        all entries expected to be integers >= 2; returns np.nan for any N < 2
    """
    N = np.atleast_1d(N)

    # check than N is
    for n in N:
        if n % 1 != 0:
            raise ValueError('N must be in integer')

    Cout = np.zeros_like(N, dtype='float')
    for i, n in enumerate(N):
        if n < 2:
            Cout[i] = np.nan
        else:
            if n == 2: p0 = 0.85
            else:      p0 = 2/3

            popt9  = op.fsolve(ap9, p0, args=(n))
            popt10 = op.fsolve(ap10, p0, args=(n))

            pall = np.zeros(n)
            pall[0] = popt9
            pall[1:] = (1-popt9)/(n-1)

            Cout[i] = -np.sum(pall*np.log(pall))*np.sum((pall-1/n)**2)

    return Cout


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Feb  9 19:15:08 2019

@author: alankar
"""
import numpy as np
from scipy.special.orthogonal import p_roots #Legendre Polynomial roots
import matplotlib.pyplot as plt

def gauss_quad(func,a,b,n,*args):#Legendre
    [x,w] = p_roots(n+1)
    I_G = 0.5*(b-a)*np.sum(w*func(0.5*(b-a)*x+0.5*(b+a),*args))
    return I_G

V = lambda x:x**4
eps = 1e-15
m = 1
N = 20

f = lambda x,a:4/np.sqrt((2/m)*(V(a)-V(x)+eps))

amplitude = np.linspace(0.1,2,100)

period = np.abs(np.array([gauss_quad(f,a,0,N,a) for a in amplitude]))

plt.figure(figsize=(13,10))
plt.plot(amplitude[1:],period[1:])
plt.tick_params(axis='both', which='major', labelsize=15)
plt.tick_params(axis='both', which='minor', labelsize=12)
plt.grid()
plt.title(r'Anharmonic Oscillator Time period',size=25,y=1.02)
plt.xlabel(r'Amplitude',size=22)
plt.ylabel(r'Time period',size=22)
plt.savefig('10.png')
plt.show()


# for decimal division
from __future__ import division

import cvxopt
import numpy as np
from pylab import *
import math

from cvxpy import *

# Taken from CVX website http://cvxr.com/cvx/examples/
# Example: CVX Textbook exercise 4.3: Solve a simple QP with inequality constraints
# Ported from cvx matlab to cvxpy by Misrab Faizullah-Khan
# Original comments below

# From Boyd & Vandenberghe, "Convex Optimization"
# Joelle Skaf - 09/26/05
#
# Solves the following QP with inequality constraints:
#           minimize    1/2x'*P*x + q'*x + r
#               s.t.    -1 <= x_i <= 1      for i = 1,2,3
# Also shows that the given x_star is indeed optimal

# Generate data
n = 3
P = cvxopt.matrix([	13, 12, -2,
					12, 17, 6,
					-2, 6, 12], (n,n))
q = cvxopt.matrix([-22, -14.5, 13], (n,1))
r = 1
x_star = cvxopt.matrix([1, 1/2, -1], (n,1))

# Frame and solve the problem

x = Variable(n)
objective = Minimize(  0.5 * quad_form(x, P)  + q.T * x + r )
constraints = [ x >= -1, x <= 1]

p = Problem(objective, constraints)
# The optimal objective is returned by p.solve().
result = p.solve()


# -*- coding: utf-8 -*-
"""
Author: Paschalis Giakoumoglou
Date: Thu Jun 17 19:16:15 2021
"""
import numpy as np
import math
import sympy as symb
import pandas as pd

def lagrange(f, x):
    """ 4.3 Lagnrance (p.71) """
    a = pd.Series(data=[[i for i in range(len(x))],x,f], index=['i','x','f(x)'])
    print(a)
    print()
    X = symb.Symbol('x')
    l = []
    exL = []
    fun = 0
    expandedFun = 0
    for j in range(len(f)):
        l.append(1)
        exL.append(1)
        temp = 1
        for i in range(len(f)):
            if i!=j:
                l[j] *= (X-x[i])
                temp *= (x[j] - x[i])

        l[j] /= temp
        exL[j] = symb.expand(fun)
        print(f"l{j}(x) = {l[j]}")
        fun += f[j]*l[j]
        expandedFun += symb.expand(f[j]*l[j])
    print()
    print(f"f(x) = {fun}")
    print(f"f(x) = {expandedFun}")

def divided_diff(f, x):
    """ 4.4 Divided Differences (p.74) """
    a = pd.Series(data=[[i for i in range(len(x))],x,f], index=['i','x','f(x)'])
    print("Input:")
    print(a)
    print()
    X = symb.Symbol('x')
    n = len(x)

    D = np.zeros((n,n)) * np.nan # Divided Differences Array
    d = np.zeros(n) # Polynomial Coeffs
    D[:,0] = f

    # Calculate D
    for j in range(1,n):
        k = j
        for i in range(j, n):
            D[i,j] = (D[i, j-1] - D[i-1, j-1]) / (x[i]-x[i-k])
            print(f"D[{i},{j}] = ({D[i, j-1]} - {D[i-1, j-1]}) / ({x[i]} - {x[i-k]}) = {D[i,j]}")

    # Calculate d
    for i in range(n):
        d[i] = D[i, i]

    print()
    print("Divided Differences Array D = ")
    print(D)
    print()
    print("Coefficients of Interpolation polynomial d = diag(D) = ")
    print(d)
    print()
    p = f[0]
    for i in range(1,len(d)):
        temp = d[i]
        for j in range(i):
            temp *= (X-x[j])
        p += temp
    print(f"Interpolation Polynomial p(x) = {p} = {symb.expand(p)}")

def finite_diff(f, x):
    """ 4.5 Finite Differences (p.78) """
    a = pd.Series(data=[[i for i in range(len(x))],x,f], index=['i','x','f(x)'])
    print(a)
    print()
    X = symb.Symbol('x')
    h = x[1] - x[0]
    n = len(x)

    Delta = np.zeros((n,n)) * np.nan # Finite Differences Array
    D = np.zeros((n,n)) * np.nan # Divided Differences Array
    d = np.zeros(n) # Polynomial Coeffs

    # Calculate Delta
    Delta[:,0] = f
    for j in range(1,n):
        k = j
        for i in range(j, n):
            Delta[i,j] = Delta[i,j-1] - Delta[i-1,j-1]

    # Calculate D
    for i in range(1,n):
        for j in range(n):
            D[i,j] = Delta[i,j] / (math.factorial(i) * (h ** i))

    # Calculate d
    for i in range(n):
        d[i] = D[i, i]

    print()
    print("Finite Differences Array Δ = ")
    print(Delta)
    print()
    print(f"Coefficients of polynomial for r = (x-x[0])/h = (x-{x[0]})/{h} is")
    print(f"{Delta[0,0]} + Σi=1:{n}( diag(Δ) * combination(r per i) )")
    print()
    print("Divided Differences Array D = ")
    print(D)
    print()
    print("Coefficients of Interpolation polynomial d = diag(D) = ")
    print(d)
    print()
    p = f[0]
    for i in range(1,len(d)):
        temp = d[i]
        for j in range(i):
            temp *= (X-x[j])
        p += temp
    print(f"Interpolation Polynomial p(x) = {p} = {symb.expand(p)}")

def aitken(f, x, z):
    """ 4.6 Aitken (p.82) """
    a = pd.Series(data=[[i for i in range(len(x))],x,f], index=['i','x','f(x)'])
    print(a)
    print()
    n = len(x)
    xz = x - z
    A = np.zeros((n,n))
    A[:, 0] = f
    print("Calculating A[r, k] = (xz[k-1]*A[r, k-1] - xz[r]*A[k-1, k-1]) / (x[k-1]-x[r]) where xz = x-z")
    for k in range(1, n):
        for r in range(k ,n):
            A[r, k] = (xz[k-1]*A[r, k-1] - xz[r]*A[k-1, k-1]) / (x[k-1]-x[r])
            print(f"A[{r},{k}] = ({xz[k-1]} * {A[r, k-1]} - {xz[r]} * {A[k-1, k-1]}) / ({x[k-1]} - {x[r]})")
    print()
    print("A = ")
    print(A)

if __name__ == "__main__":

    # Example Lagrange
    x = np.array([-1,0,1])
    f = np.array([1,1,2])
    lagrange(f, x)

    # Example Divided Differences
    x = np.array([0,1,2,4])
    f = np.array([1,1,2,5])
    divided_diff(f, x)

    # Example Finite Differences
    x = np.array([1,2,3,4,5])
    f = np.array([1,-1,1,-1,1])
    finite_diff(f, x)

    # Example Aitken
    x = np.array([2,4,6,8])
    f = np.array([1,-2,3,5])
    z = 5
    aitken(f, x, z)

    #Example 2018
    x = np.array([1,2,4,5,7])
    f = np.array([52,5,-5,-40,10])
    lagrange(f, x)
    divided_diff(f, x)

    #Example 2019
    x = np.array([0,1,2])
    f = np.array([0,1,9])
    divided_diff(f, x)
    aitken(f, x, 0.5)

    #Example 2020
    x = np.array([1,2,3,4,5,6,7,8,9,10])
    f = np.array([112, 0, 0, 0, 0 ,0 ,0 ,0 ,0, 2])
    finite_diff(f, x)
    aitken(f, x, 0)

    # Example 2021a
    x = np.array([-2,-1,0,1,2])
    def f(x):
        return 3 ** x
    f = np.array([f(-2),f(-1),f(0),f(1),f(2)])
    aitken(f,x,np.sqrt(3))

    # Example 2021b
    x = np.array([0,1,2,4,5])
    def f(x):
        return np.sqrt(x)
    f = np.array([f(0),f(1),f(2),f(4),f(5)])
    aitken(f,x,np.sqrt(3))


""" Spectral-K Distance

Given two graphs :math:`G` and :math:`H`, we can use their :math:`k` largest positive
eigenvalues of their Laplacian counterparts to compute their distance.

.. math::
    d(G, H) = \\left\{\\begin{matrix} \\sqrt{\\frac{ \\sum_{i=1}^k{(g_i - h_i)^2} }{ \\sum_{i=1}^l{g_i^2} }} & ,\\sum_{i=1}^l{g_i^2} \\leq \\sum_{j=1}^l{h_j^2}
    \\\\
    \\sqrt{\\frac{ \\sum_{i=1}^k{(g_i - h_i)^2} }{ \\sum_{j=1}^l{g_i^2} }} & , \\sum_{i=1}^l{g_i^2} > \\sum_{j=1}^l{h_j^2}
    \\end{matrix}\\right.

Where :math:`g` and :math:`h` denote the spectrums of the Laplacian matrices.

This measure is non-negative, separated, symmetric and it satisfies the triangle
inequality.

|

----

.. [Jakobson2000] Jakobson, D., & Rivin, I. (2000). Extremal metrics on graphs I. arXiv preprint math/0001169.
.. [Pincombe2007] Pincombe, B. (2007). Detecting changes in time series of network graphs using minimum mean squared error and cumulative summation. ANZIAM Journal, 48, 450-473.
"""
# Author: Avraam Marimpis <avraam.marimpis@gmail.com>

import numpy as np
import scipy

def spectral_k_distance(X: np.ndarray, Y: np.ndarray, k: int) -> float:
    """ Spectral-K Distance

    Use the largest :math:`k` eigenvalues of the given graphs to compute the
    distance between them.

    Parameters
    ----------
    X : array-like, shape(N, N)
        A weighted matrix.

    Y : array-like, shape(N, N)
        A weighted matrixY

    k : int
        Largest `k` eigenvalues to use.

    Returns
    -------
    distance : float
        Estimated distance based on selected largest eigenvalues.
    """
    l_mtx_a = scipy.sparse.csgraph.laplacian(X, normed=False)
    l_mtx_b = scipy.sparse.csgraph.laplacian(Y, normed=False)

    w_a, _ = scipy.sparse.linalg.eigs(l_mtx_a, k=k)
    w_a = np.real(w_a)
    w_a = np.sort(w_a)[::-1]

    w_b, _ = scipy.sparse.linalg.eigs(l_mtx_b, k=k)
    w_b = np.real(w_b)
    w_b = np.sort(w_b)[::-1]

    num = np.sum(np.power(w_a - w_b, 2))
    denom = np.min((np.sum(np.power(w_a, 2)), np.sum(np.power(w_b, 2))))

    distance = np.sqrt(num / denom)

    return distance


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

class OneDConsolidation:
    """
    z = 0, free flow boundary condition
    z = H, impermeable boundary condition
    Parameters:
        1. Cv, coefficient of consolidation;
        2. Es, one dimensional compressive modulus
        3. u0, initial pore pressure;
        4. H, depth of soil;
        5. error_ratio, used to control the calculation precision.
    """
    def __init__(self, Cv, Es, u0, H, error_ratio = 1.0e-3):
        self.Cv = Cv
        self.Es = Es
        self.u0 = u0
        self.H = H
        # Final settlement
        self.dH_final = -H * u0 / Es
        self.error_ratio = error_ratio

    def calPorePressure(self, t, z):
        Tv = self.Cv * t / (self.H * self.H)
        p = 0.0
        z = z / self.H
        i = 0
        while True:
            M = (2*i+1) * math.pi / 2.0
            inc = 2.0/M * math.sin(M*z) * math.exp(-M*M*Tv)
            p += inc
            i += 1
            if abs(inc) < self.error_ratio:
                break
        if (p > 1.0): p = 1.0
        p *= self.u0
        return p

    def calSettlement(self, t):
        Tv = self.Cv * t / (self.H * self.H)
        dH = 0.0
        i = 0
        while True:
            M = (2*i+1) * math.pi / 2.0
            inc = 2.0/(M*M) * math.exp(-M*M*Tv)
            dH += inc
            i += 1
            if abs(inc) < self.error_ratio:
                break
        dH = self.dH_final * (1.0 - dH)
        return dH

if __name__ == "__main__":
    Es = 40.0e6
    kv = 1.0e-5
    miu = 1.0 # dynamic viscosity
    Cv = kv * Es / miu
    u0 = 40.0e3
    H = 10.0
    con_res = OneDConsolidation(Cv, Es, u0, H)

    fig = plt.figure()
    plot1 = fig.subplots(1, 1)
    plot1.set_title('Settlement - Time relation')
    plot1.set_xlabel('Time')
    plot1.set_ylabel('Settlement')

    data_num = 100
    t_list = np.zeros(data_num)
    p_list = np.zeros(data_num)
    u_list = np.zeros(data_num)
    for i in range(data_num):
        t_list[i] = 0.01 * float(i)
        p_list[i] = con_res.calPorePressure(t_list[i], 10.0)
        u_list[i] = con_res.calSettlement(t_list[i])

    plot1.set_xlim([t_list[0], t_list[data_num-1]])

    plot1.plot(t_list, p_list, 'k--')
    #plot1.plot(t_list, u_list, 'k--')

    plt.show()


#-*-conding:utf-8-*-

from math import exp, sqrt
import random
import numpy as np

'''
Parameters:
s0 = initial stock price
k = strike price
r = risk-less short rate
sig = volatility of stock value
dt = t/T = time to maturity
m = the number of path nodes
n = the number of simulation
'''

def asian_option_mc(s0, k, r, dt, sig, m, n):
    # It is an arithmetic solution by using Monte Carlo method
    delta_t = dt / m  # length of time interval
    c = []
    p = []
    for i in range(0, n):
        s = [s0]
        for j in range(0, m):
            s.append(s[-1] * exp((r - 0.5 * sig ** 2) * delta_t + (sig * sqrt(delta_t) * random.gauss(0, 1))))

        avg = np.mean(s)
        c.append(max((avg - k), 0))
        p.append(max((k - avg), 0))

    c_value = np.mean(c) * exp(-r * dt)
    c_standard_error = np.std(c) / np.sqrt(n)

    p_value = np.mean(p) * exp(-r * dt)
    p_standard_error = np.std(p) / np.sqrt(n)

    return {'call_MC': c_value, 'standard error(c)': c_standard_error, 'put_MC': p_value,
            'standard error(p)': p_standard_error}

'''
trial:
print(asian_option_mc(5200, 5200, 0.03, 1, 0.25, 100, 20000))
'''


import math
from sympy import *

init_printing()

x = symbols("x")
y = E**-x + x**2 - 2

print("Function: ")
pprint(y)
print("1st derivative: ")
pprint(diff(y))
print("2nd derivative: ")
pprint(diff(y, x, 2))
plot(y, (x, -2, 2))

x_0 = float(input("Enter x_0: "))
epsilon = float(input("Choose precision: "))

f = lambdify("x", y)
f_deriv = lambdify("x", diff(y))

print("\nNewton's method")

x_n = x_0
steps = 0
while abs(f(x_n)) > epsilon:
    x_n = x_n - f(x_n) / f_deriv(x_n)
    print("f(%f) = %f" % (x_n, f(x_n)))
    steps += 1

print("Answer: %f, steps: %d" % (x_n, steps))
input("Press Enter to continue.")

print("\nModified Newton's method")

x_n = x_0
f_deriv0 = f_deriv(x_0)
steps = 0
while abs(f(x_n)) > epsilon:
    x_n = x_n - f(x_n) / f_deriv0
    print("f(%f) = %f" % (x_n, f(x_n)))
    steps += 1

print("Answer: %f, steps: %d" % (x_n, steps))


import numpy as np
class Distance_metrics:
    """
    Calculate distance between each corresponding points
    of two arrays using different distance metrics
    """
    def Eucledian_Distance(X1,X2):
        """"
        Returns the list of eucledian distance
        between two corresponding points of
        two arrays

        PARAMETERS
        ==========
        X1:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        X2:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        RETURNS
        =========

        distance:list
        Returns the list of eucledian distance
        between two corresponding points of
        two arrays
        """
        distance=[]
        for i in range(len(X1)):
            single=0
            single=np.sum((X1[i]-X2[i])**2)
            distance.append(np.sqrt(single))
        return(distance)

    def Manhattan_Distance(X1,X2):
        """"
        Returns the list of manhattan distance
        between two corresponding points of
        two arrays

        PARAMETERS
        ==========
        X1:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        X2:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        RETURNS
        =========

        distance:list
        Returns the list of manhattan distance
        between two corresponding points of
        two arrays
        """
        distance=[]
        for i in range(len(X1)):
            single=0
            single=np.sum(abs(X1[i]-X2[i]))
            distance.append(single)
        return(distance)

    def Chebyshev_Distance(X1,X2):
        """"
        Returns the list of chebyshev distance
        between two corresponding points of
        two arrays

        PARAMETERS
        ==========
        X1:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        X2:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        RETURNS
        =========

        distance:list
        Returns the list of chebyshev distance
        between two corresponding points of
        two arrays
        """
        distance=[]
        for i in range(len(X1)):
            single=0
            single=np.sum(max(X1[i]-X2[i]))
            distance.append(single)
        return(distance)

    def Minkowski_Distance(X1,X2,p):
        """"
        Returns list of minkowski distance of order 'p'
        between two corresponding vectors of
        two arrays

        PARAMETERS
        ==========
        X1:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        X2:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        p:float
        input order value between 1 and 2 inclusive

        RETURNS
        =========

        distance:list
        Returns the list of minkowski distance
        between two corresponding vectors of
        two arrays
        """
        distance=[]
        for i in range(len(X1)):
            single=0
            single=np.sum((abs(X1[i]-X2[i]))**p)
            distance.append((single)**(1/p))
        return(distance)

    def WMinkowski_Distance(X1,X2,p,W):
        """"
        Returns list of weighted minkowski distance of order 'p'
        between two corresponding vectors weighted by W of
        two arrays

        PARAMETERS
        ==========
        X1:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        X2:ndarray(dtype=int,axis=1)
        input array with more than 1 dimension

        p:float
        input order value between 1 and 2 inclusive

        W:array(dtype=int,axis=1)
        input 1 dimensional array

        RETURNS
        =========

        distance:list
        Returns the list of weighted minkowski distance
        between two corresponding vectors of
        two arrays
        """
        distance=[]
        for i in range(len(X1)):
            single=0
            single=np.sum((abs(W*(X1[i]-X2[i])))**p)
            distance.append((single)**(1/p))
        return(distance)


from random import *
from math import *
from matplotlib.pyplot import *
from numpy import *

def pdf(x, a, b, c):
    if x < a:
        return 0
    elif x >= a and x < c:
        return (2 * (x-a)) / ((b-a)*(c-a))
    elif x == c:
        return 2 / (b-a)
    elif x > c and x <= b:
        return (2 * (b-x)) / ((b-a)*(b-c))
    elif x > b:
        return 0
    else:
        print("Error")

a = 1
b = 10
c = 7

X = arange(0, b+1, 0.1)
Y = []

xlabel('X', fontsize=15)
ylabel('f(x)', fontsize=15)

gca().axes.get_xaxis().set_ticks( np.arange(0, b+1, 1.0) )

for x in X:
    Y.append( pdf(x, a, b, c) )

plot(X, Y, linewidth=2)

# Show figure on screen
show()

# Save figure to hard disk
savefig('triangular_pdf.pdf', format='pdf', bbox_inches='tight')


#!/usr/bin/python3.6
# -*- coding: utf-8 -*-
"""
@author: sergiossc@gmail.com
"""
import numpy as np
import scipy.stats as st

def conf_interval(x, conf_level):

    alpha = 1 - conf_level/100
    sample_size = len(x)
    sample_dist = np.sqrt(np.sum((x - np.mean(x)) ** 2)/(sample_size-1))

    if (sample_dist == 0.0 and sample_size < 30):
        print ('sample size too small for normal dist')
        return 0

    ci_values = None
    sample_mean = np.mean(x)
    sem = sample_dist/np.sqrt(sample_size) # Standard Error of Mean

    if (sample_dist == 1.0 or sample_size < 30):
	# using T-student distribution
        if sample_size < 30:
            print(f'Small sample size: {sample_size}. It should be used only when the population has a Normal distribution.');
        ci_values = st.t.interval(conf_level, df=len(x)-1, loc=sample_mean, scale=sem)
        print (f't-student: {ci_values}')
    else:
        # using normal distribution
        ci_values = st.norm.interval(conf_level, loc=sample_mean, scale=sem)
        print (f'normal: {ci_values}')
    return sample_mean, ci_values

#x = np.array([-13.7,  13.1,  -2.8,  -1.1,  -3. ,   5.6])
#x = np.array([1.5, 2.6, -1.8, 1.3, -0.5, 1.7, 2.4])
x = np.array([3.1, 4.2, 2.8, 5.1, 2.8, 4.4, 5.6, 3.9, 3.9, 2.7, 4.1, 3.6, 3.1, 4.5, 3.8, 2.9, 3.4, 3.3, 2.8, 4.5, 4.9, 5.3, 1.9, 3.7, 3.2, 4.1, 5.1, 3.2, 3.9, 4.8, 5.9, 4.2])

sample_mean, ci_values = conf_interval(x, 0.90)
print (sample_mean)


import os
import sys
import numpy as np
import math
from scipy.signal import get_window
import matplotlib.pyplot as plt

sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../software/models/'))
import stft
import utilFunctions as UF
eps = np.finfo(float).eps

"""
A4-Part-2: Measuring noise in the reconstructed signal using the STFT model

Write a function that measures the amount of noise introduced during the analysis and synthesis of a
signal using the STFT model. Use SNR (signal to noise ratio) in dB to quantify the amount of noise.
Use the stft() function in stft.py to do an analysis followed by a synthesis of the input signal.

A brief description of the SNR computation can be found in the pdf document (A4-STFT.pdf, in Relevant
Concepts section) in the assignment directory (A4). Use the time domain energy definition to compute
the SNR.

With the input signal and the obtained output, compute two different SNR values for the following cases:

1) SNR1: Over the entire length of the input and the output signals.
2) SNR2: For the segment of the signals left after discarding M samples from both the start and the
end, where M is the analysis window length. Note that this computation is done after STFT analysis
and synthesis.

The input arguments to the function are the wav file name including the path (inputFile), window
type (window), window length (M), FFT size (N), and hop size (H). The function should return a python
tuple of both the SNR values in decibels: (SNR1, SNR2). Both SNR1 and SNR2 are float values.

Test case 1: If you run your code using piano.wav file with 'blackman' window, M = 513, N = 2048 and
H = 128, the output SNR values should be around: (67.57748352378475, 304.68394693221649).

Test case 2: If you run your code using sax-phrase-short.wav file with 'hamming' window, M = 512,
N = 1024 and H = 64, the output SNR values should be around: (89.510506656299285, 306.18696700251388).

Test case 3: If you run your code using rain.wav file with 'hann' window, M = 1024, N = 2048 and
H = 128, the output SNR values should be around: (74.631476225366825, 304.26918192997738).

Due to precision differences on different machines/hardware, compared to the expected SNR values, your
output values can differ by +/-10dB for SNR1 and +/-100dB for SNR2.
"""

def computeSNR(inputFile, window, M, N, H):
    """
    Input:
            inputFile (string): wav file name including the path
            window (string): analysis window type (choice of rectangular, triangular, hanning, hamming,
                    blackman, blackmanharris)
            M (integer): analysis window length (odd positive integer)
            N (integer): fft size (power of two, > M)
            H (integer): hop size for the stft computation
    Output:
            The function should return a python tuple of both the SNR values (SNR1, SNR2)
            SNR1 and SNR2 are floats.
    """
    ## your code here
    (fs, x) = UF.wavread(inputFile)

    w = get_window(window, M)

    y = stft.stft(x, w, N, H)

    #SNR1
    diff = x - y
    x_sum = np.linalg.norm(x) ** 2
    diff_sum = np.linalg.norm(diff) ** 2
    SNR1 = 10 * np.log10(x_sum / diff_sum)

    #SNR2
    x_s = x[M:-M]
    y_s = y[M:-M]
    diff_s = x_s - y_s
    x_sum_s = np.linalg.norm(x_s) ** 2
    diff_sum_s = np.linalg.norm(diff_s) ** 2
    SNR2 = 10 * np.log10(x_sum_s / diff_sum_s)

    return (SNR1, SNR2)

vals = computeSNR('./rain.wav', 'hamming', 512, 1024, 64)
print(vals)


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

# here is a mathematical relationship between an infant's weight and total body surface area (BSA), given by

w = symbols( 'w' )
A = 4.688 * w ** ( 0.8168 - 0.0154*log( w, 10 ) )

# where w is the weight (in grams) and A(w) is the BSA in square centimeters.

# Find the BSA for an infant who weighs.
weight = 4143

bsa = A.subs( { w: weight } ).evalf()
# (Round to the nearest integer as needed.)
round( bsa )

# Find Upper A' right parenthesis.
dA = Derivative( A, w ).doit()
bsap = dA.subs( { w: weight } ).evalf()
round( bsap, 2 )

# graph A(w) on [2000, 10,000] by [0, 6000]

g_xlim = [ 2000, 10000 ]
g_ylim = [ 0, 6000 ]

lam_a = lambdify( w, A, np )

x_vals = np.linspace( g_xlim[0], g_xlim[1], 1000, endpoint=True )
y_vals = lam_a( x_vals )
plt.plot( x_vals, y_vals )
plt.show()


from sympy import *
from sympy.physics.vector.functions import *

a_x,a_y,a_z,b_x,b_y,b_z = symbols('a_x a_y a_z b_x b_y b_z')
a,b,c,d = symbols('a b c d')
line_symbols=[a_x, a_y, a_z, b_x, b_y, b_z]
all_symbols = line_symbols

l = Matrix([b_x-a_x, b_y-a_y, b_z-a_z]).vec()
p = Matrix([a_x, a_y, a_z]).vec()
n = Matrix([a, b, c]).vec()

target_value_norm = 1
model_function_norm = sqrt(l[0]*l[0] + l[1]*l[1] + l[2]*l[2])
residual_norm = Matrix([target_value_norm - model_function_norm]).vec()
residual_norm_jacobian = residual_norm.jacobian(all_symbols)

target_value = Matrix([0,0,0,0]).vec()
model_function = Matrix([a * a_x + b * a_y + c * a_z + d, a * b_x + b * b_y + c * b_z + d, p.dot(l), l.dot(n)]).vec()
residual = Matrix([target_value - model_function]).vec()
residual_jacobian = residual.jacobian(all_symbols)

with open("sheaf_of_planes_observation_equation_jacobian.h",'w') as f_cpp:
    f_cpp.write("inline void sheaf_of_planes_observation_equation(Eigen::Matrix<double, 4, 1> &residual, double a_x, double a_y, double a_z, double b_x, double b_y, double b_z, double a, double b, double c, double d)\n")
    f_cpp.write("{")
    f_cpp.write("residual.coeffRef(0,0) = %s;\n"%(ccode(residual[0])))
    f_cpp.write("residual.coeffRef(1,0) = %s;\n"%(ccode(residual[1])))
    f_cpp.write("residual.coeffRef(2,0) = %s;\n"%(ccode(residual[2])))
    f_cpp.write("residual.coeffRef(3,0) = %s;\n"%(ccode(residual[3])))
    f_cpp.write("}")
    f_cpp.write("\n")
    f_cpp.write("inline void sheaf_of_planes_observation_equation_jacobian(Eigen::Matrix<double, 4, 6> &j, double a_x, double a_y, double a_z, double b_x, double b_y, double b_z, double a, double b, double c, double d)\n")
    f_cpp.write("{")
    for i in range (4):
        for j in range (6):
            f_cpp.write("j.coeffRef(%d,%d) = %s;\n"%(i,j, ccode(residual_jacobian[i,j])))
    f_cpp.write("}")
    f_cpp.write("inline void line_direction_norm_observation_equation(Eigen::Matrix<double, 1, 1> &residual, double a_x, double a_y, double a_z, double b_x, double b_y, double b_z)\n")
    f_cpp.write("{")
    f_cpp.write("residual.coeffRef(0,0) = %s;\n"%(ccode(residual_norm[0])))
    f_cpp.write("}")
    f_cpp.write("\n")
    f_cpp.write("inline void line_direction_observation_equation_jacobian(Eigen::Matrix<double, 1, 6> &j, double a_x, double a_y, double a_z, double b_x, double b_y, double b_z)\n")
    f_cpp.write("{")
    for i in range (1):
        for j in range (6):
            f_cpp.write("j.coeffRef(%d,%d) = %s;\n"%(i,j, ccode(residual_norm_jacobian[i,j])))
    f_cpp.write("}")


import sympy as sp

def get_4th_order_rungekutta(dydx, x0, y0, n:int, h, x = sp.Symbol('x'), y = sp.Symbol('y')):
    """
    Method to get the values of x, y and dy/dx using fourth-order Runge-Kutta method in a form of a 2d list

    Parameters:
    dydx: Equation to get the derivative
    x0: initial value of x
    y0: initial value of y
    n: number of iterations
    h: value of increment for x
    x: x Symbol object
    y: y Symbol object
    """
    sets = []
    sets.append([x0, y0, dydx.evalf(subs={x: x0, y: y0})])
    for i in range(1, n+1):
        xOld = sets[i-1][0]
        yOld = sets[i-1][1]
        k1 = dydx.evalf(subs={x:xOld, y:yOld})
        k2 = dydx.evalf(subs={x:xOld + h/2, y:yOld + h*k1/2})
        k3 = dydx.evalf(subs={x:xOld + h/2, y:yOld + h*k2/2})
        k4 = dydx.evalf(subs={x:xOld + h, y:yOld + k3 * h})

        yNew = yOld + (1.0/6.0) * (k1 + 2*k2 + 2*k3 + k4) * h
        xNew = xOld + h

        sets.append([xNew, yNew, dydx.evalf(subs={x:xNew, y:yNew})])

    return sets

def example():
    #Usage example
    sets = get_4th_order_rungekutta(sp.Symbol('y'), 0, 1, 3, 1)

    for s in sets:
        print(s)


# coding: utf-8
__title__ = 'Entropy'
__author__ = 'JieYuan'
__mtime__ = '2017/9/29'

import pandas as pd
import numpy as np
from math import log
import random

def entropy(data_classes, base=2):
    '''
    Computes the entropy of a set of labels (class instantiations)
    :param base: logarithm base for computation
    :param data_classes: Series with labels of examples in a dataset
    :return: value of entropy
    '''
    if not isinstance(data_classes, pd.core.series.Series):
        raise AttributeError('input array should be a pandas_utils series')
    classes = data_classes.unique()
    N = len(data_classes)
    ent = 0  # initialize entropy

    # iterate over classes
    for c in classes:
        partition = data_classes[data_classes == c]  # data with class = c
        proportion = len(partition) / N
        #update entropy
        ent -= proportion * log(proportion, base)

    return ent

def cut_point_information_gain(dataset, cut_point, feature_label, class_label):
    '''
    Return de information gain obtained by splitting a numeric attribute in two according to cut_point
    :param dataset: pandas_utils dataframe with a column for attribute values and a column for class
    :param cut_point: threshold at which to partition the numeric attribute
    :param feature_label: column label of the numeric attribute values in data
    :param class_label: column label of the array of instance classes
    :return: information gain of partition obtained by threshold cut_point
    '''
    if not isinstance(dataset, pd.core.frame.DataFrame):
        raise AttributeError('input dataset should be a pandas_utils data frame')

    entropy_full = entropy(dataset[class_label])  # compute entropy of full dataset (w/o split)

    #split data at cut_point
    data_left = dataset[dataset[feature_label] <= cut_point]
    data_right = dataset[dataset[feature_label] > cut_point]
    (N, N_left, N_right) = (len(dataset), len(data_left), len(data_right))

    gain = entropy_full - (N_left / N) * entropy(data_left[class_label]) - \
        (N_right / N) * entropy(data_right[class_label])

    return gain

# from sklearn.datasets import load_iris
# iris = load_iris()
# X, y = iris.data[:100], iris.target[:100]
# df = pd.DataFrame(np.hstack([X, y.reshape(-1, 1)]), columns=list('abcde'))
# for i in np.arange(df.a.min(), df.a.max(), 0.01):
#     print(i, cut_point_information_gain(df, i, 'a', 'e')) # i=5.5 熵最大？？？

# python PyTest.py --in_path='F:\\JieYuan\\2_WorkProject\\data.csv' --out_path='F:\\JieYuan\\2_WorkProject' --class_label=e


#-----------------------------------------------------------------#
# Perform z-value detection on input data
#-----------------------------------------------------------------#
import numpy as np

def get_z_outliers(case, case_type):
    '''Get outliers based on z value scores'''

    data_std = np.std(case['data'])
    data_mean = np.mean(case['data'])

    low_limit = data_mean - data_std*3
    high_limit = data_mean + data_std*3

    anom_bool = np.logical_or(case['data'] > high_limit, case['data'] < low_limit)
    anom_bool = np.where(anom_bool == True, 1, anom_bool)
    anom_bool = np.where(anom_bool == False, 0, anom_bool)

    case[f'anomaly prediction {case_type}'] = anom_bool.tolist()

    #print(case.columns)
    return case


import numpy as np

A = np.arange(2, 14).reshape((3, 4))

print(A)
print(A.dot(A.T)) # transpose of matrix A
print(np.clip(A, 5, 9)) # set elements <= 5 --> 5 and >= 9 --> 9
print(np.mean(A, axis = 0)) # column mean
print(np.mean(A, axis = 1)) # row mean
print(A[2]) # print row 2
print(A[1][1]) # print row 1 col 1
print(A[1, 1:3]) # print row 1 col 1 and 2

# for loop to print every row
for row in A:
    print(row)
# for loop to print every column
for column in A.T:
    print(column)
print(A.flatten()) # transform A to one row matrix
# transform A to one row matrix, then print every elements
for item in A.flat:
    print(item)


'''
Integre numericamente o sistema de equações do modelo SIR usando método de RK2. Para simplificar a exploração do
 modelo use como parâmetros \gamma=0.5  e varie o parâmetro \beta e as condições iniciais.

     Trace um gráfico para e evolução de S, I e R para \beta=1, S=99, I=1 e R=0.
'''
import numpy as np
import matplotlib.pyplot as plt

def rk2SIR(s0, i0, r0, tf, dt, b, g):
    n0 = s0 + i0 + r0
    fs = lambda i0, s0: -(b * i0 * s0 / n0)
    fi = lambda i0, s0: (b * i0 * s0) / n0 - (g * i0)
    fr = lambda i0: g * i0
    s, i, r, n = [s0], [i0], [r0], [n0]
    for t in np.arange(0, tf, dt):
        saux = s0 + fs(i0, s0)*(dt/2)
        iaux = i0 + fi(i0, s0) * (dt / 2)
        s0 += fs(iaux, saux)*dt
        s.append(s0)
        i0 += fi(iaux, saux)*dt
        i.append(i0)
        r0 += fr(iaux)*dt
        r.append(r0)
        n0 = s0 + i0 + r0
        n.append(n0)
    return s, i, r, n

s0, i0, r0, tf, dt, b, g = 99, 1, 0, 25, 0.1, 1, 0.5
t = np.arange(0, tf+dt, dt)

plt.plot(t, rk2SIR(s0, i0, r0, tf, dt, b, g)[0], label='Suscetível')
plt.plot(t, rk2SIR(s0, i0, r0, tf, dt, b, g)[1], label='Infectados')
plt.plot(t, rk2SIR(s0, i0, r0, tf, dt, b, g)[2], label='Removidos')
plt.plot(t, rk2SIR(s0, i0, r0, tf, dt, b, g)[3], label='População')
plt.grid()
plt.legend()
plt.title('SIR: Runge-Kutta\n'+r'$\beta=$'+f'{b}'+r' | $\gamma=$'+f'{g}')
plt.savefig('rk2SIR.png')
#plt.show()


import math

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import odeint

matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42

def dy(y, t, zeta, w0):
    x, p = y[0], y[1]
    dx = p
    dp = -2 * zeta * w0 * p - w0**2 * x
    return [dx, dp]

y0 = [-0.5, 0.0]
t = np.linspace(0, 10, 1000)
w0 = 1 * math.pi * 1.0

y1 = odeint(dy, y0, t, args=(0.0, w0))
y2 = odeint(dy, y0, t, args=(0.2, w0))
y3 = odeint(dy, y0, t, args=(1.0, w0))
y4 = odeint(dy, y0, t, args=(5.0, w0))

# color_list = ['#2A9D8F', '#E9C46A', '#F4A261', '#E76F51', '#264653']
color_list = ['#68A691', '#4361EE', '#BF0603', '#7209B7', '#F72585']
plt.figure(figsize=(6.4, 3))
plt.plot(t, y1[:, 0], color=color_list[0], label='undamped')
plt.plot(t, y2[:, 0], color=color_list[1], label='under-damped')
plt.plot(t, y3[:, 0], color=color_list[2], label='critically-damped')
plt.plot(t, y4[:, 0], color=color_list[3], label='over-damped')

plt.hlines(0,
           0,
           plt.xlim()[1],
           colors=color_list[4],
           linestyles='dashed',
           label='step excitation')
plt.vlines(0, 0, -0.5, colors=color_list[4], linestyles='dashed')

plt.xticks([])
plt.yticks([])
plt.xlabel('Time (s)', fontsize='12')
plt.ylabel('Throughput (Mbps)', fontsize='12')
plt.legend()
plt.savefig('dampOscillation.pdf', bbox_inches='tight')


import numpy as np
from numpy.polynomial import Polynomial
from scipy import constants, integrate

@np.vectorize
def y_deflection(initial_trajectory, speed, flight_length):
    """
    The vertical displacement of an object moving in a parabolic path.

    Parameters
    ----------
    initial_trajectory : float
        The initial angular trajectory of the path (degrees), measured from
        the x-axis. A positive angle is in an anticlockwise direction.
    speed : float
        The initial speed of the object (m/s)
    flight_length : float
        The horizontal component of the distance of the object from the origin
        (m).

    Returns
    -------
    displacement : float
        Vertical displacement of the object (m).
    """
    eqn = parabola(initial_trajectory, speed)
    return eqn(flight_length)

def elevation(initial_trajectory, speed, flight_length):
    """
    Angle between x-axis and tangent of flight path at a given horizontal
    distance from the origin.

    Parameters
    ----------
    initial_trajectory : float
        The initial angular trajectory of the path (degrees), measured from
        the x-axis. A positive angle is in an anticlockwise direction.
    speed : float
        The initial speed of the object (m/s)
    flight_length : float
        The horizontal component of the distance of a point on the line from
        the origin (m).

    Returns
    -------
    elevation : float
        The direction in which the object is currently moving (degrees). The
        angle is measured relative to the x-axis, with a positive angle in an
        anticlockwise direction.
    """
    # eqn = parabola(initial_trajectory, speed)
    # dydx = eqn.deriv()
    # return np.degrees(np.arctan(dydx(flight_length)))
    traj_rad = np.radians(initial_trajectory)
    # o_0 = 0
    o_1 = np.tan(traj_rad)
    o_2 = -constants.g / 2.0 / (speed * np.cos(traj_rad)) ** 2.0

    # y = o_0 + o_1*x + o_2*x**2
    # need to work out derivative of y, dy/dx.
    dydx = o_1 + 2 * o_2 * flight_length
    return np.degrees(np.arctan(dydx))

def find_trajectory(flight_length, theta, speed):
    """
    Find the initial trajectory of an object that has to pass through a certain
    point on a parabolic path.  This point is specified by the horizontal
    distance component and an angle (polar coordinates).

    Parameters
    ----------
    flight_length : float
        The horizontal component of the distance of a point on the line from
        the origin (m).
    theta : float
        The angle between the x-axis and the point (degrees). A positive angle
        is in an anticlockwise direction.
    speed : float
        The initial speed of the object (m/s)

    Returns
    -------
    trajectory : float
        Initial trajectory of the object (degrees).  A positive angle lies
        above the x-axis.
    """
    theta_rad = np.radians(theta)
    vertical_deflection_vertex = np.tan(theta_rad) * flight_length

    # # now find trajectory that will put object through defined point
    # def traj(trajectory):
    #     return (vertical_deflection_vertex -
    #             y_deflection(trajectory, speed, flight_length))
    #
    # trajectory = newton(traj, 0)
    # return trajectory

    # https://en.wikipedia.org/wiki/Trajectory_of_a_projectile
    x = flight_length
    y = vertical_deflection_vertex
    v = speed
    g = constants.g

    # num0 = (v ** 2 + np.sqrt(v ** 4 - g * (g * x ** 2 + 2 * y * v ** 2)))
    num1 = v ** 2 - np.sqrt(v ** 4 - g * (g * x ** 2 + 2 * y * v ** 2))
    # there are two trajectories that could hit the target
    # we only need one branch.
    # alpha1 = np.arctan2(num0, g * x)
    alpha2 = np.arctan2(num1, g * x)

    return np.degrees(alpha2)

def parabola(initial_trajectory, speed):
    """
    Find the quadratic form of the parabolic path

    Parameters
    ----------
    initial_trajectory : float
        The initial angular trajectory of the path (degrees), measured from
        the x-axis. A positive angle is in an anticlockwise direction.
    speed : float
        The initial speed of the object (m/s)

    Returns
    -------
    eqn : np.polynomial.Polynomial object
        Equation of parabolic path
    """
    traj_rad = np.radians(initial_trajectory)
    eqn = Polynomial(
        [
            0,
            np.tan(traj_rad),
            -constants.g / 2.0 / (speed * np.cos(traj_rad)) ** 2.0,
        ]
    )
    return eqn

@np.vectorize
def parabola_line_intersection_point(
    flight_length, theta, initial_trajectory, speed, omega
):
    """
    Find the intersection point of the parabolic motion path and a line.
    The line is specified by an angle and a point through which the line
    goes.

    Parameters
    ----------
    flight_length : float
        The horizontal component of the distance of a point on the line from
        the origin (m).
    theta : float
        The declination of a point on the line from the origin (degrees). A
        positive angle is in an anticlockwise direction.
    initial_trajectory : float
        The initial trajectory of the object (degrees). A positive angle is in
        an anticlockwise direction.
    speed : float
        The initial speed of the object (m/s).
    omega : float
        Included angle between the line and line drawn between the point on the
        line and the origin.

    Returns
    -------
    intersect_x, intersect_y, x_prime, elev : float, float, float, float
        Co-ordinates of intersection point of parabola and line, distance
        from the intersection to the point used to specify the line, and
        elevation at the intersection point
    """
    omega_rad = np.radians(omega)
    theta_rad = np.radians(theta)

    # omega_prime is the angle between the line and the x-axis. It tells us
    # about the gradient of the line.
    omega_prime = omega_rad + theta_rad
    line_gradient = np.tan(omega_prime)

    # equation of line
    line_eqn = Polynomial(
        [(flight_length * (np.tan(theta_rad) - line_gradient)), line_gradient]
    )

    # equation of parabola
    parab_eqn = parabola(initial_trajectory, speed)

    # find the intersection
    diff = parab_eqn - line_eqn
    intersection_x = np.max(diff.roots())

    # find y location at intersection
    intersection_y = line_eqn(intersection_x)

    # distance between parabola-line intersection and 'point on line'
    distance = (intersection_x - flight_length) ** 2 + (
        intersection_y - flight_length * np.tan(theta_rad)
    ) ** 2
    x_prime = np.sqrt(distance)

    if intersection_x < flight_length:
        x_prime *= -1.0

    # calculate the elevation
    elev = elevation(initial_trajectory, speed, flight_length)

    return intersection_x, intersection_y, x_prime, elev

def arc_length(p, a, b):
    """
    Calculates the arc length of a Polynomial

    Parameters
    ----------
    p: np.polynomial.Polynomial
    a: float
        Lower limit of arc
    b: float
        Upper limit of arc

    Returns
    -------
    length: float
        arc length of polynomial
    """
    p_prime = p.deriv()

    def kernel(x):
        return np.sqrt(1 + p_prime(x) ** 2)

    return integrate.quad(kernel, a, b)[0]


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

# function for image compression using PCA
file_name='Lenna.png'
def compress(I,numpc=100):
    cov_mat=I-np.mean(I.T,axis=1)
    var=np.cov(I-np.mean(I.T,axis=1))
    eig_val, eig_vec = np.linalg.eigh(np.cov(cov_mat))
    p = np.size(eig_vec, axis =1)
    idx = np.argsort(eig_val)
    idx = idx[::-1]
    eig_vec = eig_vec[:,idx]
    eig_val = eig_val[idx]
    if numpc <p and numpc >0:
        eig_vec = eig_vec[:, range(numpc)]
    score = np.dot(eig_vec.T, cov_mat)
    return eig_val,eig_vec,score

img=cv2.imread(file_name)
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
numpc =50 # number of principle components

eig_val,eig_vec,score=compress(img ,numpc)
recon = np.dot(eig_vec, score) + np.mean(img.T, axis = 1)
recon_img_mat = np.uint8(np.absolute(recon)) # reconstructed image from eigens

cv2.imwrite("recon_image.jpg",recon_img_mat)
mse=np.sum((img.astype('float')-recon_img_mat.astype('float'))**2)/float(255*255)#/float(I.shape[0]*recon_img_mat.shape[1])
r=65025/mse
PSNR=10* math.log(r,10)
print(' The MSE is: ',mse)
#print('The PSNR is {} dB'.format(r))


from math import factorial
import numpy as np
from numpy.polynomial.hermite import hermval
from numpy.polynomial.legendre import leggauss

class FCFSpec():
    # convention: hbar = 1.0
    '''
    This code takes as input:
        - Upper bound of ground and excited vibrational states allowed for
          transitions
        - Reduced mass of H2 molecule (same as H2+)
        - Frequency of the H2 molecule  (ground state, 0)
        - Frequency of the H2+ molecule (excited state, p)
        - Equilibrium bond lengths (the difference is the displacement)
        - Difference between potential minima of the electronic states
          (ionization energy)

    This code outputs:
        - FCFs for each pair of ground and excited vibrational states up to a
          threshold, using the n_H2 = 0, n_H2+ = 0 Franck-Condon Factor as the
          reference.
        - Spectral positions, SP
    '''

    def __init__(self, n_0, n_p):
        self.n_0 = n_0
        self.n_p = n_p

        # unit analysis
        self.invcm_to_invEh = 1.0/219474.63136320
        self.amu_to_me = 1822.888486209
        self.ang_to_bohr = 1.88973

        self.initialize_constants()
        self.initialize_integration_params()

    def initialize_constants(self):
        # hard set for H2 (0) and H2+ (p)
        self.reduced_mass = self.amu_to_me*1.00784/2.
        self.omega_0 = self.invcm_to_invEh*4401.0
        self.omega_p = self.invcm_to_invEh*2322.0
        self.x_eq_0 = self.ang_to_bohr*0.742
        self.x_eq_p = self.ang_to_bohr*1.057
        self.ionization_energy = self.invcm_to_invEh*124418.457

    def initialize_integration_params(self):
        # to calculate overlap integral numerically
        self.R_min = self.ang_to_bohr*(-5.0)
        self.R_max = self.ang_to_bohr*5.0
        self.quadrature_points = 5000

    def H2_energy(self, n):
        return self.omega_0*(n + 0.5) / self.invcm_to_invEh

    def H2p_energy(self, n):
        return self.omega_p*(n + 0.5) / self.invcm_to_invEh + self.ionization_energy

    def H2_psi(self, x, n):
        # n'th harmonic wavefunction for H2
        tmp = self.reduced_mass*self.omega_0
        prefactor = pow(tmp / np.pi, 0.25) / np.sqrt(2.0**n * factorial(n))
        coeffs = np.zeros(n+1, float)
        coeffs[n] = 1.0
        hermpoly = hermval(np.sqrt(tmp)*(x - self.x_eq_0), coeffs)
        return prefactor*np.exp(-0.5*tmp*(x - self.x_eq_0)**2)*hermpoly

    def H2p_psi(self, x, n):
        # n'th harmonic wavefunction for H2+
        tmp = self.reduced_mass*self.omega_p
        prefactor = pow(tmp / np.pi, 0.25) / np.sqrt(2.0**n * factorial(n))
        coeffs = np.zeros(n+1, float)
        coeffs[n] = 1.0
        hermpoly = hermval(np.sqrt(tmp)*(x - self.x_eq_p), coeffs)
        return prefactor*np.exp(-0.5*tmp*(x - self.x_eq_p)**2)*hermpoly

    def spectrum_analysis(self):
        # calculate FCFs
        GLquad = leggauss(self.quadrature_points)

        all_data = []

        for k in range(self.n_0+1):
            E0 = self.H2_energy(k)
            for l in range(self.n_p+1):
                Ep = self.H2p_energy(l)

                overlap = 0
                for p in range(self.quadrature_points):

                    new_point = 0.5*(self.R_max - self.R_min)*GLquad[0][p] + 0.5*(self.R_max + self.R_min)
                    new_weight = 0.5*(self.R_max - self.R_min)*GLquad[1][p]
                    overlap += self.H2_psi(new_point, k) * self.H2p_psi(new_point, l) * new_weight

                FCF = overlap**2.

                # n_0   n_p   FCF
                data = np.zeros(3)

                if (k==0 and l==0):
                    reference = FCF

                FCF /= reference

                data[0] = k
                data[1] = l
                data[2] = FCF

                all_data.append(data)

        return np.array(all_data)


import math
import numpy as np

def euclidean_dist(pointA, pointB):
    if(len(pointA) != len(pointB)):
        raise Exception("expected point dimensionality to match")
    total = float(0)
    for dimension in range(0, len(pointA)):
        total += (pointA[dimension] - pointB[dimension])**2
    return math.sqrt(total)

def gaussian_kernel(distance, bandwidth):
    euclidean_distance = np.sqrt(((distance)**2).sum(axis=1))
    val = (1/(bandwidth*math.sqrt(2*math.pi))) * np.exp(-0.5*((euclidean_distance / bandwidth))**2)
    return val

def multivariate_gaussian_kernel(distances, bandwidths):

    # Number of dimensions of the multivariate gaussian
    dim = len(bandwidths)

    # Covariance matrix
    cov = np.multiply(np.power(bandwidths,2), np.eye(dim))

    # Compute Multivariate gaussian (vectorized implementation)
    exponent = -0.5 * np.sum(np.multiply(np.dot(distances, np.linalg.inv(cov)), distances), axis=1)
    val = (1 / np.power((2 * math.pi), (dim/2)) * np.power(np.linalg.det(cov), 0.5)) * np.exp(exponent)

    return val


"""Single objective test functions"""

import numpy as np
import math

def sphere(x):
    return sum([y**2 for y in x])

def rosenbrock(x1, x2):
    return sum([100*((x**2 - y)**2) + (x - 1)**2 for (x, y) in zip(x1,x2)])

def ackley(x):
    return -20 * np.exp(-0.2 * (sum([y**2 for y in x])/len(x) ** 0.5)) - \
          np.exp(sum([np.cos(2 * math.pi * y)/len(x) for y in x])) + 20 + math.e

def griewank(x):
    return sum([y**2 / 4000 for y in x]) - np.prod([np.cos(y/((i+1)**0.5)) for i, y in enumerate(x)]) + 1

def rastrigin(x):
    return sum([y**2 - 10*np.cos(2*math.pi*y) + 10 for y in x])

def weierstrass(x):
    a = 0.5
    b = 3
    k_max = 20

    def sub_sum(x):
        return sum([a**k * np.cos(2*math.pi*(b**k)*(x + 0.5)) for k in range(k_max)])

    val = sum([sub_sum(x0) for x0 in x]) - (len(x) * sum([a**k * np.cos(2*math.pi*(b**k)*0.5) for k in range(k_max)]))

    return val


import numpy as np
import matplotlib.pyplot as plt

def PCA(X, Y):
    xbar = X.mean(axis=1).reshape(-1,1)
    Xtilde = X - xbar
    _, v = np.linalg.eigh(Xtilde.dot(Xtilde.T))
    d1 = v[:,-1]        # vector along which data varies the most
    d2 = v[:,-2]        # vector along which data varies second most
    plt.scatter(X.T.dot(d1), X.T.dot(d2), marker='o', c=Y, s=4)
    # plt.scatter(X[:, 398:].T.dot(d1), X[:, 398:].T.dot(d2), marker='.', c=Y[398:], s=2)
    plt.show()

# embeddings, labels = np.load('/Users/zarnihpyoe/Projects/instag/faces/embeddings.npy')
# embeddings, labels = np.load('/Users/zarnihpyoe/wpi/mqp/data3/used_faces_maj/embeddings.npy')
# embeddings, labels = np.load('/Users/zarnihpyoe/wpi/mqp/data/0.2/embeddings.npy')
# embeddings, labels = np.load('/Users/zarnihpyoe/wpi/mqp/data/0.3/embeddings.npy')
embeddings, labels = np.load('/Users/zarnihpyoe/wpi/mqp/data5/embeddings.npy')

# embeddings = np.load('/Users/zarnihpyoe/wpi/mqp/data3/used_faces_maj/ext_embeddings.npy')
# labels = np.load('/Users/zarnihpyoe/wpi/mqp/data3/used_faces_maj/labels.npy')

print(embeddings.shape, len(labels))
PCA(embeddings, labels)