import numpy as np

# Compute outer product of vectors
v = np.array([1,2,3])  # v has shape (3,)
w = np.array([4,5])    # w has shape (2,)
# To compute an outer product, we first reshape v to be a column
# vector of shape (3, 1); we can then broadcast it against w to yield
# an output of shape (3, 2), which is the outer product of v and w:
# [[ 4  5]
#  [ 8 10]
#  [12 15]]
print(np.reshape(v, (3, 1)) * w)

# Add a vector to each row of a matrix
x = np.array([[1,2,3], [4,5,6]])
# x has shape (2, 3) and v has shape (3,) so they broadcast to (2, 3),
# giving the following matrix:
# [[2 4 6]
#  [5 7 9]]
print(x + v)

# Add a vector to each column of a matrix
# x has shape (2, 3) and w has shape (2,).
# If we transpose x then it has shape (3, 2) and can be broadcast
# against w to yield a result of shape (3, 2); transposing this result
# yields the final result of shape (2, 3) which is the matrix x with
# the vector w added to each column. Gives the following matrix:
# [[ 5  6  7]
#  [ 9 10 11]]
print((x.T + w).T)
# Another solution is to reshape w to be a column vector of shape (2, 1);
# we can then broadcast it directly against x to produce the same
# output.
print(x + np.reshape(w, (2, 1)))

# Multiply a matrix by a constant:
# x has shape (2, 3). Numpy treats scalars as arrays of shape ();
# these can be broadcast together to shape (2, 3), producing the
# following array:
# [[ 2  4  6]
#  [ 8 10 12]]
print(x * 2)


import numpy as np
from numpy import matmul as matmul
from numpy.linalg import norm
import time

class LinearConjugateGradient:
    def __init__(self, A, b, x=None):
        A = np.array(A)
        b = np.array(b)
        b = np.reshape(b, (-1, 1))
        assert np.shape(b)[0] == np.shape(A)[0]
        if not x:
            x = np.random.rand(np.shape(A)[1], 1)
        else:
            x = np.reshape(x, (-1, 1))
            assert np.shape(x)[0] == np.shape(A)[1]

        self.A = A
        self.b = b
        self.x = x

    def residual(self):
        return np.matmul(self.A, self.x) - self.b

    _MAX_ITER, _TOLERANCE = 100000, .00000001
    def solve(self):
        r = self.residual()
        p = -r

        A = self.A
        b = self.b
        x = self.x

        k = 0

        time_start_sec = time.time()
        while k <= self._MAX_ITER and norm(r) > self._TOLERANCE:
            pAp = matmul(matmul(p.T, A), p)
            alpha = - matmul(r.T, p) / pAp
            x += alpha * p
            r = self.residual()
            beta = matmul(matmul(r.T, A), p) / pAp
            p = -r + beta * p

            k += 1

        time_end_sec = time.time()

        return x, (time_end_sec - time_start_sec)


import numpy as np

## Metoda coborârii pe gradient

def l2_norm(x):
    "Calculează norma L2 pentru vectorul `x`"
    return np.linalg.norm(x, ord=2)

def positive_semidefinite(M):
    "Verifică ca matricea `M` să fie pozitiv semi-definită."
    for i in range(M.shape[0]):
        # Folosesc criteriul lui Sylvester,
        # calculez determinanții minorilor principali
        if np.linalg.det(M[:i, :i]) < 0:
            return False
    return True

## Datele de intrare
# Matricea coeficienților
A = np.array([
    [3, 2],
    [2, 6]
], dtype=float)

# Matricea termenilor liberi
b = np.array([
    [2],
    [-8]
], dtype=float)

if not positive_semidefinite(A):
    print("Matricea A nu este pozitiv semidefinită!")
else:
    # Inițializez cu valori random
    x = np.random.randn(*b.shape)

    residue = b - A @ x

    # Ne oprim dacă norma reziduului scade sub această valoare
    STOPPING_EPSILON = 1e-10

    num_iterations = 0
    while l2_norm(residue) > STOPPING_EPSILON:
        learning_rate = (residue.T @ residue) / (residue.T @ A @ residue)

        x = x + learning_rate * residue
        residue = b - A @ x

        num_iterations += 1

    print("x =", x[:, 0])


#Find Sphenic Number
from sympy import isprime
def SphenicNumber(num):
    for i in range(1,num):
        if(num%i==0 and isprime(i)):
            for j in range(1,num):
                if(num%j==0 and isprime(j) and j != i and i*j<num):
                    for k in range(1,num):
                        if(num%k==0 and isprime(k) and k != j and i*j*k==num):
                            return (i,j,k)
    return False

def doTest(toPrint=False,toProgress=False,start=1,toEnd=1000,algo="s"):
    s=set()
    KK=10000
    from IPython.display import clear_output
    for i in range(start,toEnd+1):
        if(toProgress and (i<KK or (i>=KK and i%(KK/100)==0))):
            clear_output(wait=True)
            print(i,end="\t")
        if(algo=="s"):
            soc=SphenicNumber(i)
        if(soc):
            s.add(soc)
            if(toPrint and not toProgress):
                print(i,soc,end=", ")
        if(toProgress and (i<KK or (i>=KK and i%(KK/100)==0))):
            print(s)
    if(not toPrint):
        return s

#SphenicNumber(30)
#doTest()


"""
Created on Sun Mar 17 20:01:22 2019
@author: nahid
"""
import numpy as np

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

# add 1 to every element
print ("Adding 1 to every element:", a+1)

# subtract 3 from each element
print ("Subtracting 3 from each element:", a-3)

# multiply each element by 10
print ("Multiplying each element by 10:", a*10)

# square each element
print ("Squaring each element:", a**2)

# modify existing array
a *= 2
print ("Doubled each element of original array:", a)

# transpose of array
a = np.array([[1, 2, 3], [3, 4, 5], [9, 6, 0]])

print ("\nOriginal array:\n", a)
print ("Transpose of array:\n", a.T)

#------------------------------------------------------------
#maximum element of the array
print('Largest element is:', a.max())

#print raw and coloum based maximum and minmum element
#for raw using axis = 1 and for coloum = 0
print ("Row-wise maximum, minimum elements:",
                    a.max(axis = 1), a.min(axis = 1))

print ("Column-wise maximum, minimum elements:",
                        a.max(axis = 0), a.min(axis = 0))

#sum of array elements
print('Sum of array elements = ', a.sum())

#cumulative sum along each row
print ("Cumulative sum along each row:\n",
                        a.cumsum(axis = 1))

#----------------------------------------------------------
# create an array of sine values
a = np.array([0, np.pi/2, np.pi])
print ("Sine values of array elements:", np.sin(a))

# exponential values
a = np.array([0, 1, 2, 3])
print ("Exponent of array elements:", np.exp(a))

# square root of array values
print ("Square root of array elements:", np.sqrt(a))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
BE523 Biosystems Analysis & Design
HW4 - Problem 4. Polymerase chain reaction

Created on Tue Jan 26 13:36:57 2021
@author: eduardo
"""
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm  # allows linear regression without intercept

P0 = 1e-12  # initial condition
r = 1  # rate of change
steps = 30  # cicles
dt = 1  # time interval
dP = np.zeros(steps)

t = np.linspace(0, (steps-1)*dt, steps)  # actual time vector

# Generate the growth data with model: P(t+1) = P[0]*(r+1)^t
P = P0 * (r + 1)**t

for i in range(1, steps):
    dP[i] = P[i] - P[i-1]  # difference between time steps

# Perform a linear regression with P and dP, then plot (dP vs P)
model = sm.OLS(dP, P)  # No intercept by default, force through the origin??
results = model.fit()
slope = results.params[0]  # growth rate
print("slope=", slope)  # should be close to 'r'

# Figure 1, plotting dP vs P
plt.figure(1)
plt.plot(P, dP, 'kx', P, slope*P, 'b-')
plt.legend(['data', 'linear regression $R^2$=%.2f' % results.rsquared], loc='best')
plt.xlabel('P')
plt.ylabel('dP')
# plt.savefig('p4_polymerase_linear2.png', dpi=300, bbox_inches='tight')

# Generate an exponential equation (exact solution)
tdouble = np.log(2)/np.log(1+slope)*dt
print('tdouble =', tdouble)
K = np.log(2)/tdouble
Pexp = P[0] * np.exp(K*t/dt)

# Generate predictions with the model (numerical solution)
Pmodel = P[0]*(slope+1)**(t/dt)
print("The DNA amount after %d cicles is: %g" % (steps, Pmodel[-1]))

# Figure 2, plotting P (from data and model) vs t
plt.figure(2)
plt.plot(t, Pmodel, 'bo', t, Pexp, 'r-')
plt.legend([r'numerical P=%g*(1+%.2f)$^t$' % (P[0], slope),
            'exact P=%g*exp(%.4f*t)' % (P[0], K)],
            loc='best')
plt.xlabel('Time (cicles)')
plt.ylabel('Amount of DNA')
# plt.savefig('p4_polymerase_model2.png', dpi=300, bbox_inches='tight')


import pathlib

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

# Check Exercise 7.3 for definition of create_ecdf
from create_ecdf import create_ecdf

src_dir = pathlib.Path(__file__).resolve().parent.parent
dat_path = src_dir.joinpath("data", "fijiquakes.dat")

df = pd.read_table(dat_path, sep="\s+", index_col=0)
magnitudes = df["mag"]
alpha = 0.05
epsilon_n = np.sqrt(1 / (2 * magnitudes.size) * np.log(2 / alpha))

ecdf = create_ecdf(magnitudes)
xs = np.linspace(magnitudes.min() - 0.1, magnitudes.max() + 0.1, 200)
l = np.maximum(ecdf(xs) - epsilon_n, 0)
u = np.minimum(ecdf(xs) + epsilon_n, 1)

plt.plot(xs, ecdf(xs), label="empirical CDF")
plt.plot(xs, l, "--", label="0.95 lower bound")
plt.plot(xs, u, "--", label="0.95 upper bound")
plt.ylabel("Cumulative probability")
plt.xlabel("Earthquake magnitude")
plt.legend()
plt.savefig("07-07.png", bbox_inches="tight")

# We compute the confidence interval using Exercise 7.6
b = 4.9
a = 4.3
theta_hat = ecdf(b) - ecdf(a)
theta_se = np.sqrt(theta_hat * (1 - theta_hat) / magnitudes.size)
z = stats.norm.ppf(1 - alpha / 2)
l = theta_hat - z * theta_se
u = theta_hat + z * theta_se

print(f"F({b}) - F({a}) is approximately {theta_hat}.")
print(f"A 95% CI for this value is given by [{l:.4}, {u:.4}].")


import numpy as np
import scipy.optimize

class ZeroSumGame:
    def __init__(self, get_score, first_actions, second_actions):
        """
        Calculate Nash equilibrium in mixed strategies for zero-sum games.
        :param get_score: get_score(first_action, second_action) is a function that returns score of the game.
        :param first_actions: first_actions is a list of possible actions for the first player.
        :param second_actions: second_actions is a list of possible actions for the second player.
        """
        self._get_score = get_score
        self._first_actions = first_actions
        self._second_actions = second_actions
        self.optimal_policy = None
        self.game_price = self.calc_best_policy_for_the_first_player()

    def calc_best_policy_for_the_first_player(self):
        n = len(self._first_actions)
        m = len(self._second_actions)

        price_matrix = np.array(
            [[self._get_score(f_act, s_act) for f_act in self._first_actions]
             for s_act in self._second_actions])

        # First n variables are probabilities of actions for
        # the first players.
        # Introduced price of the game for the first player
        # with the last index.
        c = np.zeros(n + 1)
        c[n] = -1

        # By min-max theorem the first player should get at
        # least the price of the game against each pure strategy
        # of the second player.
        A_ub = np.hstack((-price_matrix, np.ones((m, 1))))
        b_ub = np.zeros(m)

        # Normalization of probabilities.
        # sum(probability_i-th_action) = 1
        A_eq = np.ones((1, n + 1))
        A_eq[0][n] = 0
        b_eq = np.ones(1)

        # Probabilities are non-negative.
        # Price of the game can be negative.
        bounds = [(0, None) for _ in range(n)] + [(None, None)]

        # Used simplex method to solve linear programming problem.
        # In the worst case asymptotic is exponential but in
        # real-life games it's almost polynomial.
        res = scipy.optimize.linprog(c=c,
                                     A_ub=A_ub, b_ub=b_ub,
                                     A_eq=A_eq, b_eq=b_eq,
                                     bounds=bounds)

        # Policy is a distribution over actions for the first player.
        self.optimal_policy = res.x[:n]
        return -res.fun

    def gen_action(self):
        """
        :return: Generate sample of the optimal distribution over actions for the first player.
        """
        return np.random.choice(self._first_actions, p=self.optimal_policy)


# solve a 2-d Poisson equation by differentiating the discretized
# Poisson equation and then substituting in the inverse Fourier
# transform and solving for the amplitudes in Fourier space.
#
# This is the standard way that texts deal with the Poisson equation
# (see, e.g., Garcia and NR)
#
# Note: we need a periodic problem for an FFT

from __future__ import print_function

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

# Use LaTeX for rendering
mpl.rcParams['mathtext.fontset'] = 'cm'
mpl.rcParams['mathtext.rm'] = 'serif'
mpl.rcParams['font.size'] = 12
mpl.rcParams['legend.fontsize'] = 'large'
mpl.rcParams['figure.titlesize'] = 'medium'

# the analytic solution
def true(x,y):
    pi = np.pi
    return np.sin(2.0*pi*x)**2*np.cos(4.0*pi*y) + \
        np.sin(4.0*pi*x)*np.cos(2.0*pi*y)**2

# the righthand side
def frhs(x,y):
    pi = np.pi
    return 8.0*pi**2*np.cos(4.0*pi*y)*(np.cos(4.0*pi*x) -
                                          np.sin(4.0*pi*x)) - \
           16.0*pi**2*(np.sin(4.0*pi*x)*np.cos(2.0*pi*y)**2 +
                       np.sin(2.0*pi*x)**2 * np.cos(4.0*pi*y))

def doit(Nx, Ny, do_plot=False):

    # create the domain -- cell-centered finite-difference / finite-volume
    xmin = 0.0
    xmax = 1.0

    ymin = 0.0
    ymax = 1.0

    dx = (xmax - xmin)/Nx
    dy = (ymax - ymin)/Ny

    x = (np.arange(Nx) + 0.5)*dx
    y = (np.arange(Ny) + 0.5)*dy

    x2d = np.repeat(x, Ny)
    x2d.shape = (Nx, Ny)

    y2d = np.repeat(y, Nx)
    y2d.shape = (Ny, Nx)
    y2d = np.transpose(y2d)

    # create the RHS
    f = frhs(x2d, y2d)

    # FFT of RHS
    F = np.fft.fft2(f)

    # get the wavenumbers -- we need these to be physical, so divide by dx
    kx = np.fft.fftfreq(Nx)/dx
    ky = np.fft.fftfreq(Ny)/dy

    # make 2-d arrays for the wavenumbers
    kx2d = np.repeat(kx, Ny)
    kx2d.shape = (Nx, Ny)

    ky2d = np.repeat(ky, Nx)
    ky2d.shape = (Ny, Nx)
    ky2d = np.transpose(ky2d)

    # here the FFT frequencies are in the order 0 ... N/2-1, -N/2, ...
    # the 0 component is not a physical frequency, but rather it is
    # the DC signal.  Don't mess with it, since we'll divide by zero
    oldDC = F[0,0]
    F = 0.5*F/( (np.cos(2.0*np.pi*kx2d/Nx) - 1.0)/dx**2 +
                (np.cos(2.0*np.pi*ky2d/Ny) - 1.0)/dy**2)

    F[0,0] = oldDC

    # transform back to real space
    fsolution = np.real(np.fft.ifft2(F))

    # since x is our row in the array, we transpose for the
    # plot
    if do_plot:
        plt.imshow(np.transpose(fsolution),
                   origin="lower", interpolation="nearest",
                   extent=[xmin, xmax, ymin, ymax])

        plt.xlabel("x")
        plt.ylabel("y")

        plt.colorbar()

        plt.tight_layout()

        plt.savefig("poisson_fft.pdf")

    # return the error, compared to the true solution
    return np.sqrt(dx*dx*np.sum( ( (fsolution - true(x2d,y2d))**2).flat))

N = [16, 32, 64, 128, 256]
plot = [False]*len(N)
plot[N.index(64)] = True

err = []
for n, p in zip(N, plot):
    err.append(doit(n, n, do_plot=p))

# plot the convergence
plt.clf()

N = np.array(N, dtype=np.float64)
err = np.array(err, dtype=np.float64)

print(N)
print(type(N))
print(err)

plt.scatter(N, err, marker="x", color="r")
plt.plot(N, err[0]*(N[0]/N)**2, "--", color="k", label="$\mathcal{O}(\Delta x^2)$")

ax = plt.gca()

ax.set_xscale('log')
ax.set_yscale('log')

plt.legend(frameon=False)

plt.xlabel("number of zones")
plt.ylabel("L2 norm of abs error")

f = plt.gcf()
f.set_size_inches(5.0,5.0)

plt.savefig("fft-poisson-converge.pdf", bbox_inches="tight")


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

def cosine_similarity(vecA, vecB):
  """
  Return the cosine simularity between two vectors vecA and vecB.
  @return float between 0 and 1 inclusive. One indicates identical.
  """
  csim = np.dot(vecA, vecB) / (np.linalg.norm(vecA) * np.linalg.norm(vecB))
  if np.isnan(np.sum(csim)):
    return 0
  return csim

def angular_similarity(vecA, vecB):
  """
  Return the angular simularity between two vectors vecA and vecB.
  @return float between 0 and 1 inclusive. One indicates identical.
  """
  # Ensure cosine is between zero and one
  cosdist = max(0, min(cosine(vecA, vecB), 1))
  return 1 - math.acos(1 - cosdist) / math.pi


import os
import numpy as np

def calculate_distance(rA, rB):
    """Compute the distance between points A and B. Assumes rA and rB are numpy arrays."""
    dist_vec = (rA-rB)
    distance = np.linalg.norm(dist_vec)
    return distance

def calculate_distance_list(rA, rB):
    """Calculate the distance between points A and B. Assumes rA and rB are lists."""
    squared_sum = 0
    for dim in range(len(rA)):
        squared_sum += (rA[dim] - rB[dim])**2

    distance = np.sqrt(squared_sum)
    return distance

def build_bond_list(coordinates, max_bond=2.93, min_bond=0):
    """Build list of bonds from atomic coordinates based on distance.

    Parameters
    ----------
    coordinates : np.array
        An array of atomic coordinates
    max_bond : float, optional
        Maximum distance between atoms to be considered a bond. Default is 2.93 bohr
    min_bond: float, optional
        Minimum distance between atoms to be considered a bond. Default is 0.

    Returns
    -------
    bonds : dict
        Dictionary of bonds with atom pair tuples as keys, and calculate bond lengths as values

    """
    num_atoms = len(coordinates)

    bonds = {}

    for atom1 in range(num_atoms):
        for atom2 in range(atom1, num_atoms):
            distance = calculate_distance(coordinates[atom1], coordinates[atom2])

            if distance > min_bond and distance < max_bond:
                bonds[(atom1, atom2)] = distance

    return bonds


import numpy as np
from scipy import stats

def calculate_t_score():
    """
    计算上alpha分位数值，相当于已知某个点的上分位数(1-cdf)，求对于的t score
    :return:
    """
    n = 20
    df = n - 1  # 自由度
    alpha = 0.05
    t_score = stats.t(df).isf(alpha/2)  # 相当于计算t_0.025, 上0.025分位数
    print(t_score)
calculate_t_score()  # 2.09302405441

def calculate_ci(ci_value, data):
    """
    calculate (ci value%)-confidence interval(CI)
    :param ci_value: confidence coefficient (0, 1)
    :param data: an array
    :return: confidence interval with confidence coefficient of ci_value
    """
    df = len(data) - 1  # degrees of freedom
    ci = stats.t.interval(ci_value, df, loc=np.mean(data),
                          scale=stats.sem(data))
    return ci
norm_dis = stats.norm(0, 2)
demo_data1 = norm_dis.rvs(10)
print(demo_data1)
alpha2 = 0.95
# (-0.2217121415878075, 1.7026114809498547)
print(calculate_ci(alpha2, demo_data1))

# standard deviation vs standard error of the mean(SEM)
# SEM: 平均值标准误差
a = [69, 54, 80]
b = [47, 68, 52]
print(np.std(a), np.std(b))  # 样本的标准差
print(stats.sem(a), stats.sem(b))  # 样本均值的标准差(对SEM的估计)
# 10.6562449088 8.95668589503
# 7.53510303697 6.33333333333

def calculate_p_value(data, ref_value):
    """
    假设检验，计算p-value
    :param data:
    :param ref_value: 与data均值进行比较的参考值
    :return: p-value
    """
    t_val = (ref_value - np.mean(data)) / stats.sem(data)
    t_dist = stats.t(len(data) - 1)
    return 2*t_dist.sf(t_val)
# 计算p值，t-test
# 零假设：学生的平均成绩与110分没有差别
scores = np.array([109.4, 76.2, 128.7, 93.7, 85.6, 117.7,
                   117.2, 87.3, 100.3, 55.1])
print(calculate_p_value(data=scores, ref_value=110))
# 0.0995384365279, p-value不显著


import numpy as np

def calc_iou(box1, box2):
    # box: left, top, right, bottom
    w = min(box1[2], box2[2]) - max(box1[0], box2[0])
    h = min(box1[3], box2[3]) - max(box1[1], box2[1])
    if w <= 0 or h <= 0:
        return 0
    intersection = w * h
    s1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
    s2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
    union = max(s1 + s2 - intersection, 1e-5)
    iou = intersection / union
    return iou

def nms(results, iou_threshold=0.4):
    '''
    Args:
        results: [num_boxes, Dict]
            Dict: left, top, right, bottom, name, color, confidence
        outputs: [K, Dict]
            K: the number of valid boxes
            Dict: left, top, right, bottom, name, color, confidence
    '''

    outputs = []
    while len(results) > 0:
        ix = np.argmax([result['confidence'] for result in results])
        result = results[ix]
        outputs.append(result)
        del results[ix]

        box1 = [result['left'], result['top'], result['right'], result['bottom']]
        to_delete = []
        for jx in range(len(results)):
            box2 = [results[jx]['left'], results[jx]['top'], results[jx]['right'], results[jx]['bottom']]
            iou = calc_iou(box1, box2)
            if iou >= iou_threshold:
                to_delete.append(jx)
        for jx in to_delete[::-1]:
            del results[jx]

    return outputs

def soft_nms(results, threshold, sigma=0.5):
    '''
    Args:
        results: [num_boxes, Dict]
            Dict: left, top, right, bottom, name, color, confidence
        outputs: [K, Dict]
            K: the number of valid boxes
            Dict: left, top, right, bottom, name, color, confidence
    '''

    outputs = []
    while len(results) > 0:
        ix = np.argmax([result['confidence'] for result in results])
        result = results[ix]
        outputs.append(result)
        del results[ix]

        # soft-nms with a Gaussian penalty function
        box1 = [result['left'], result['top'], result['right'], result['bottom']]
        to_delete = []
        for jx in range(len(results)):
            box2 = [results[jx]['left'], results[jx]['top'], results[jx]['right'], results[jx]['bottom']]
            iou = calc_iou(box1, box2)
            penalty = np.e ** (-iou ** 2 / sigma)
            results[jx]['confidence'] = results[jx]['confidence'] * penalty
            if results[jx]['confidence'] < threshold:
                to_delete.append(jx)

        for jx in to_delete[::-1]:
            del results[jx]

    return outputs


import numpy as np

########################################################################################################################
"""
GROUP: Regularization
	-Performs regularization at necessary steps
	-At present I can only see this existing as helper functions for specific times in forward/cost/backpropagtion
	 so most will externally exist to other functions

EXTERNAL FUNCTIONS:
					1)cost_l2_regularization - computes the l2 regularization term when computing cost
					2)backward_propagation_l2_regularization - computes the l2 regularization term for backpropagation
INTERNAL FUNCTIONS:

"""
########################################################################################################################

### EXTERNAL FUNCTIONS ###

def cost_l2_regularization(Y,parameters,lambd):
	"""
	computes the L2 regularization term of a cost function. See formula...

	Arguments:
	Y -- "true" labels vector, of shape (output size, number of examples)
	parameters -- python dictionary containing parameters of the model
	lamdb -- regularization term for scaling of "smoothing"

	Returns:
	L2_regularization_cost - value of the regularized loss function term for computing cost
	"""
	#Number of layers
	L = len(parameters) // 2
	m = Y.shape[1]
	#compute the squared weights summation
	l2_weight_sum=0
	for l in range(L):
		l2_weight_sum = l2_weight_sum + np.sum(np.square(parameters["W" + str(l+1)]))

	#compute L2_regularization cost
	L2_regularization_cost = (1.0/m)*(lambd/2.0)*(l2_weight_sum)

	return L2_regularization_cost

def backward_propagation_l2_regularization(m,W,lambd):
	"""
	computes the l2 regularization term for backpropagation of a single layer

	Arguments:
	m -- number of examples
	W -- weights of the layer
	lamdb -- regularization term for scaling of "ssmoothing"

	Returns:
	L2_regularization_backpropagation - value of the regularized loss function term for backpropagation
	"""
	L2_regularization_backpropagation = ((lambd/m)*W)

	return L2_regularization_backpropagation

def forward_propagation_droput(AL,keep_prob):
	"""
	Implements dropout of a single layer in forward propagation

	Arguments:
	AL - the output of a layer in the network postactivation function, of size[neurons_in_layer,1]
	keep_prob - probability of keeping a neuron active during drop-out, scalar

	Returns:
	AL_dropout-- output of the forward propagation of each neuron in a layer with dropout applied
	DL-- represents the dropout matrix of what neurons are active (1) and non-active(0), should be added to cache
	"""
	# Step 1: initialize matrix DL = np.random.rand(..., ...)
	DL = np.random.rand(AL.shape[0],AL.shape[1])
	# Step 2: convert entries of DL to 0 or 1 (using keep_prob as the threshold)
	DL = (DL<keep_prob)
	#print(DL)
	# Step 3: shut down some neurons of Al
	AL = np.multiply(AL,DL)
	# Step 4: scale the value of neurons that haven't been shut down
	AL = AL/keep_prob

	return AL, DL

def backward_propagation_dropout(dAL,DL,keep_prob):
	"""
	Implements dropout of a single layer in backward propagation

	Arguments:
	dAL - the gradient of a layer in the backpropagation process, of size[neurons_in_layer,1]
	DL-- represents the dropout matrix of what neurons are active (1) and non-active(0) in the layer
	keep_prob - probability of keeping a neuron active during drop-out, scalar

	Returns:
	dAL_dropout-- gradient of the backward propagation of each neuron in a layer with dropout applied
	"""
	# Step 1: Apply mask D2 to shut down the same neurons as during the forward propagation
	dAL = np.multiply(dAL,DL)
	# Step 2: Scale the value of neurons that haven't been shut down
	dAL = dAL/keep_prob

	return dAL


import numpy as np

"""
KOHONEN

SIGMA = Gaussian radius. It is the neighborhood selector
ALPHA = Learning rate constant
"""
# SIGMA = 8
# ALPHA = 0.5
# n_epocas = 100

# w_arrays = np.array([[9, 4, 3],
#                      [3, 5, 8],
#                      [1, 3, 5]])
#
# entry = np.array([4, 7, 1])

def kohonen(w_arrays, entry, SIGMA, ALPHA, n_epocas):
    def calc_euclidian_distance(entry, w_arrays):
        euclidian_distances_aux = (entry - w_arrays) ** 2
        euclidian_distances_aux = sum(euclidian_distances_aux.T)
        euclidian_distances = euclidian_distances_aux ** (0.5)

        for i in range(euclidian_distances.__len__()):
            if euclidian_distances[i] == min(euclidian_distances):
                winner = w_arrays[i]
                min_euclidian_distance = euclidian_distances[i]
                return euclidian_distances, winner, min_euclidian_distance

    def calc_neighborhood(euclidian_distances):
        return np.e ** (-(euclidian_distances ** 2) / (2 * (SIGMA ** 2)))

    def calc_wight_updating(w_arrays, neighborhood,ALPHA, entry):
        return np.asarray([list(w_arrays[i] + ALPHA * (entry - w_arrays[i]) * neighborhood[i]) for i in range(len(w_arrays))])

    # print('w_arrays of the Neural Network')
    # print(w_arrays)
    # print('Entry')
    # print(entry)
    # print('-' * 50)

    for n_epoca in range(n_epocas):

        """
        Step 1: Euclidian distances between entries weight array and network weight arrays
        """

        euclidian_distances_1, winner_1, min_distance_1 = calc_euclidian_distance(entry=entry, w_arrays=w_arrays)
        # print(euclidian_distances_1, winner_1, min_distance_1)

        """
        Step 2: Euclidian distances between the winner network weigth array and all network weigth arrays
        """

        euclidian_distances_2, winner_2, min_distance_2 = calc_euclidian_distance(entry=winner_1, w_arrays=w_arrays)
        # print(euclidian_distances_2, winner_2, min_distance_2)

        """
        Step 3: Neighborhood
        """

        neighborhood = calc_neighborhood(euclidian_distances=euclidian_distances_2)
        # print(neighborhood)

        """
        Step 4: Network weights updating
        """

        # print('\nNew weights')

        w_arrays_2 = calc_wight_updating(w_arrays=w_arrays, ALPHA=ALPHA, neighborhood=neighborhood, entry=entry)
        # print(w_arrays_2)
        w_arrays = w_arrays_2

    return w_arrays


import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage
from scipy.ndimage.filters import generic_filter, maximum_filter, minimum_filter

def Sobel(img, threshold=50):
    def kernel(p):
        return (np.abs((p[0] + 2 * p[1] + p[2]) - (p[6] + 2 * p[7] + p[8])) +
                np.abs((p[2] + 2 * p[6] + p[7]) - (p[0] + 2 * p[3] + p[6])))

    res = generic_filter(img, kernel, (3, 3))
    res = np.array(list(map(lambda x: [255 if xx > threshold else 0 for xx in x], res)), dtype=res.dtype)
    return res

def HoughSpace(img_edges, rho=1, theta=np.pi/180/10):
    x_max, y_max = img_edges.shape
    theta_max = np.pi
    r_max = np.hypot(x_max, y_max)
    r_dim = int(r_max/rho)
    theta_dim = int(theta_max/theta)
    hough_space = np.zeros((r_dim, theta_dim))
    for x in range(x_max):
        for y in range(y_max):
            if img_edges[x][y]:
                for theta_i in range(theta_dim):
                    theta = theta_i*theta_max/theta_dim
                    r = x*np.cos(theta) + y*np.sin(theta)
                    r_i = int(r_dim*r/r_max)
                    hough_space[r_i][theta_i] = hough_space[r_i][theta_i] + 1
    return hough_space  # thetas, rhos

def HoughLines(hough_space, threshold=100, neighborhood_size=20):
    data_max = maximum_filter(hough_space, neighborhood_size)
    maxima = (hough_space == data_max)
    data_min = minimum_filter(hough_space, neighborhood_size)
    diff = ((data_max - data_min) > threshold)
    maxima[diff == 0] = 0
    labeled, num_objects = ndimage.label(maxima)
    slices = ndimage.find_objects(labeled)
    thetas, rhos = [], []
    for d_rho, d_theta in slices:
        theta_center = (d_theta.start + d_theta.stop - 1)/2
        thetas.append(theta_center)
        rho_center = (d_rho.start + d_rho.stop - 1)/2
        rhos.append(rho_center)
    return thetas, rhos

def plot_hs(hs):
    plt.imshow(hs)
    r_dim, theta_dim = hs.shape
    plt.ylim(0, r_dim)
    tick_locs = [i for i in range(0, theta_dim, int(theta_dim/20))]
    tick_lbls = [round((i*np.pi)/theta_dim, 1) for i in range(0, theta_dim, int(theta_dim/20))]
    plt.xticks(tick_locs, tick_lbls)
    tick_locs = [i for i in range(0, r_dim, int(r_dim/10))]
    tick_lbls = [round(i, 1) for i in range(0, r_dim, int(r_dim/10))]
    plt.yticks(tick_locs, tick_lbls)
    plt.xlabel(r'Theta')
    plt.ylabel(r'rho')
    plt.title('Hough Space')
    plt.show()


# -*- coding: utf-8 -*-
"""
Created on Sun Aug  8 21:43:54 2021

@author: oiseth
"""

#%% import necessary modules and packages
import numpy as np
from matplotlib import pyplot as plt

#%% Make scatter plot that illustrates linear correlation
mean = np.array([0, 0]) # Mean values
sigma1 = 1.0 # Standard deviation of X1
sigma2 = 1.0 # Standard deviation of X2
rho12 = 0.5 # correlation coefficient between -1 and 1
Nsim = 1000 # Number of points
cov = np.array([[sigma1**2, sigma1*sigma2*rho12], [sigma1*sigma2*rho12, sigma2**2]]) # Covariance matrix
X = np.random.multivariate_normal(mean,cov,Nsim) # Monte Carlo simulation of correlated Gaussian (normal) variables

# Scatter plot
plt.figure()
plt.show()
plt.scatter(X[:,0],X[:,1])
plt.xlabel('$X_1$')
plt.ylabel('$X_2$')
plt.grid()
plt.title(r'$\rho=' + str(rho12) + '$')

#%% Define auto-correlation function
dt = 0.2
t = np.arange(0.,100.,dt) # Time vector
tau = t-np.max(t)/2
omega_c = 1.0; # Cut-off frequency
sigma = 1.0
R = sigma**2/(omega_c*tau)*np.sin(omega_c*tau); # Auto-correlation function
plt.figure()
plt.show()
plt.plot(tau,R)
plt.ylim(-sigma,sigma)
plt.grid()
plt.ylabel(r'$R(\tau)$')
plt.xlabel(r'$\tau$')
#%% Use auto-correlation function to generate stochastic time series
tau_mat = np.abs(np.array([t])-np.array([t]).T) # Matrix of all possible time lags
tau_mat[tau_mat==0] = np.finfo(float).eps # Avoid the singularity when \tau = 0
mean = np.zeros((t.shape[0]))
cov = sigma**2/(omega_c*tau_mat)*np.sin(omega_c*tau_mat); # Auto-correlation function
X = np.random.multivariate_normal(mean,cov,3)

fig, axs = plt.subplots(3,1)
axs[0].plot(tau, R)
axs[0].set_ylabel(r'$R(\tau)$')
axs[0].set_xlabel(r'$\tau$')
axs[0].set_ylim(-sigma,sigma)
axs[0].grid(True)

axs[1].plot(t, X[0,:])
axs[1].set_ylabel(r'$X_1$')
axs[1].grid(True)

axs[2].plot(t, X[1,:])
axs[2].set_ylabel(r'$X_1$')
axs[2].grid(True)


#台形公式による数値積分プログラム
import numpy as np  #NumPyライブラリ
import matplotlib.pyplot as plt  #データ可視化ライブラリ

#定積分したい関数
def func_f(x):
    return 3.0*x**2.0

#台形公式（関数、定積分の開始点、定積分の終了点、刻み幅）
def trapezoidal(func_f, x_min, x_max, dx=1e-2):
    num_calc = 0  #計算回数
    x_div = (x_max-x_min)/dx  #格子分割数

    x = x_min  #独立変数x
    y = func_f(x)  #従属変数y
    print("x = {:.7f},  y = {:.7f}".format(x, y))

    #グラフ用データを追加
    x_list = [x]
    y_list = [y]

    #x = x_min
    area = 0.0  #積分値（面積）
    while(True):
        num_calc += 1  #計算回数を数える

        x += dx
        delta_area = (func_f(x-dx) +func_f(x))*dx/2.0
        area += delta_area

        #グラフ用データを追加
        x_list.append(x)
        y_list.append(func_f(x))

        #「計算回数が格子分割数以上」ならば終了
        if(x_div<=num_calc):
            break

        #「計算回数が閾値以上」かつ「面積が微小」ならば終了
        #if(x_div/2.0<=num_calc and delta_area<=1e-10):
            #break

    print("n = {:3d}:  area = {:.15f}".format(num_calc, area))

    return area, x_list, y_list

#可視化
def visualization(func_f, area, x_list, y_list):
    plt.xlabel("$x$")  #x軸の名前
    plt.ylabel("$f(x)$")  #y軸の名前
    plt.grid()  #点線の目盛りを表示
    plt.axhline(0, color='#000000')  #f(x)=0の線

    #関数
    exact_x = np.arange(x_list[0],x_list[-1], (x_list[-1]-x_list[0])/500.0)
    exact_y = func_f(exact_x)

    plt.plot(exact_x,exact_y, label="$y(t)$", color='#ff0000')  #折線グラフで表示
    plt.fill_between(x_list,y_list, alpha=0.2)  #塗りつぶし
    plt.text(x_list[0],y_list[0], "$x$ = {:.9f}".format(area), va='bottom', color='#0000ff')
    plt.show()  #グラフを表示

#メイン実行部
if (__name__ == '__main__'):
    #台形公式で定積分を求める
    area, x_list, y_list = trapezoidal(func_f, -1.0, 1.0)

    #結果を可視化
    visualization(func_f, area, x_list, y_list)


import math

import numpy as np

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

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

    Returns
    -------
    MSE of given predictions
    """
    return ((y_true - y_pred) ** 2).mean(axis=0)

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

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

    Returns
    -------
    Misclassification of given predictions
    """
    subtraction_vec = np.subtract(y_true, y_pred)
    # We will sum over all the indexes that had different true and predicted values
    num_of_errors = np.sum(np.where(subtraction_vec != 0, 1, 0))
    return num_of_errors if not normalize else num_of_errors / y_true.shape[0]

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

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

    Returns
    -------
    Accuracy of given predictions
    """
    return 1 - misclassification_error(y_true, y_pred, False) / y_true.shape[0]

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

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

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


"""Fit a polynomial to a given set of data points using optimization."""

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import scipy.optimize as spo

def error_poly(C, data): # error function
    """Compute error between given polynomial and observed data.

    Parameters
    ----------
    C: numpy.poly1d object or equivalent array representing polynomial coefficients
    data: 2D array where each row is a point (x, y)

    Returns error as a single real value.
    """
    # Metric: Sum of squared Y-axis differences
    err = np.sum((data[:, 1] - np.polyval(C, data[:, 0])) ** 2)
    return err

def fit_poly(data, error_func, degree = 3):
    """ Fit a polynomial to given data, using supplied error function.

    Parameters
    ----------
    data: 2D array where each row is a point (X0, Y)
    error_func: function that computes the error between a polynomial and observed data
    degree: polynomial degree

    Returns line that optimizes the error function.

    """

    # Generate initial guess for polynomial model (all coeffs = 1)
    Cguess = np.poly1d(np.ones(degree + 1, dtype = np.float32))

    # Plot initial guess (optional)
    x = np.linspace(-5, 5, 21)
    plt.plot(x, np.polyval(Cguess, x), 'm--', linewidth = 2.0, label = 'Initial guess')

    # Call optimizer to minimize error function
    result = spo.minimize(error_func, Cguess, args = (data, ), method = 'SLSQP', options = {'disp': True})
    return np.poly1d(result.x) # convert optimal result into a poly1d object

def test_run():
    # Define original polynomial
    Corig = np.poly1d(np.float32([1.5, -10, -5, 60, 50]))
    print "Original polynomial:\n{}".format(Corig)
    Xorig = np.linspace(-5, 5, 21)
    Yorig = np.polyval(Corig, Xorig)
    plt.plot(Xorig, Yorig, 'b--', linewidth = 2.0, label = "Original line")

    # Generate noisy data point
    noise_sigma = 30.0
    noise = np.random.normal(0, noise_sigma, Yorig.shape)
    data = np.asarray([Xorig, Yorig + noise]).T
    plt.plot(data[:, 0], data[:, 1], 'go', label = "Data points")

    # Try to fit a line to this data
    p_fit = fit_poly(data, error_poly, 4)
    print "Fitted poly:\n{}".format(p_fit)
    plt.plot(data[:, 0], np.polyval(p_fit, data[:, 0]), 'r--', linewidth = 2.0, label = "Fitted line")

    # Add a legend and show plot
    plt.legend(loc = 'upper left')
    plt.show()

if __name__ == "__main__":
    test_run()


# -*- coding: utf-8 -*-
"""
Created on Mon Dec 11 20:02:37 2017

@author: tzave
"""

import numpy as np

def swap(r, p, E, cols=None):
    if cols is None:
        b = np.copy(E[r, :])
        E[r, :] = E[p, :]
        E[p, :] = np.copy(b)
    else:
        b = np.copy(E[:, r])
        E[:, r] = E[:, p]
        E[:, p] = np.copy(b)

def ForwardSubstitution(A, b):
    rows = A.shape[0]
    y = np.zeros(rows)
    for i in range(rows):
        s = 0.
        for j in range(i):
            s = s + A[i, j] * y[j]
        y[i] = (b[i] - s) / A[i, i]
    return y

def BackSubstitution(A, b):
    rows = A.shape[0]
    x = np.zeros(rows)
    for i in reversed(range(rows)):
        s = 0
        for j in range(i + 1, rows):
            s = s + A[i, j] * x[j]
        x[i] = (b[i] - s) / A[i, i]
    return x

def foundNonZeroPivot(r, E):
    rows = E.shape[0]
    PivotFound = False
    for p in range(r, rows - 1):
        if np.isclose(E[p, r], 0):  # Keep looking for non-zero pivot
            continue
        else:  # if pivot is found
            PivotFound = True
            if p > r:  # Only swap if p>r
                swap(r, p, E)
            break
    return PivotFound

def partialPivot(r, A):
    rows = A.shape[0]  # Number of rows
    Amax = np.abs(A[r, r])
    rmax = r
    for p in range(r, rows):
        Apr = np.abs(A[p, r])
        if Apr > Amax:
            Amax = Apr
            rmax = p
    if rmax != r:
        swap(r, rmax, A)
    return

def completePivot(r, A):
    rows, cols = A.shape
    cols = cols - 1  # ignore the last column of the augmented matrix
    Amax = np.abs(A[r, r])
    rmax = r
    cmax = r
    for i in range(r, rows):
        for j in range(r, cols):
            Aij = np.abs(A[i, j])
            if Aij > Amax:
                Amax = Aij
                rmax = i
                cmax = j
    if (rmax != r) and (cmax != r):
        swap(r, rmax, A)
        swap(r, cmax, A, True)
    return

def GaussElimination(A, b, pivot=None):
    isSingular = False
    rows = A.shape[0]
    b = b.reshape(rows, 1)
    E = np.append(A, b, axis=1)  # Append b as extra column
    for r in range(rows - 1):
        if pivot == 'partial':
            partialPivot(r, E)
        elif pivot == 'complete':
            completePivot(r, E)
        else:  # Simple pivot is required to avoid division by 0
            isSingular = not foundNonZeroPivot(r, E)
            if isSingular:
                break
        for i in range(r + 1, rows):
            if np.isclose(E[i, r], 0):  # skip line if pivot is already 0
                continue
            m = - E[i, r]/E[r, r]
            E[i][r] = 0
            for j in range(r + 1, rows + 1):
                E[i, j] = E[i, j] + m * E[r, j]
    if isSingular:
        print("Matrix is singular")
    elif np.isclose(E[rows-1, rows-1], 0):
        print("There is no unique solution")
    else:
        y = E[:, rows]
        E = np.delete(E, [rows], axis=1)
        x = BackSubstitution(E, y)
    return {'E': E, 'x': x, 'isSingular': isSingular}

def LU(A):
    rows, cols = A.shape
    assert (rows == cols)
    U = np.copy(A)
    L = np.identity(rows)
    for k in range(rows-1):
        for j in range(k+1, rows):
            L[j, k] = U[j, k] / U[k, k]
            for p in range(k, rows):
                U[j, p] = U[j, p] - L[j, k] * U[k, p]
    return {'L': L, 'U': U}

def inverseU(U):
    rows = U.shape[0]
    Uinv = np.zeros(U.shape)
    unit = np.identity(rows)
    for j in range(rows):
        b = unit[:, j]
        Uinv[:, j] = BackSubstitution(U, b)
    return Uinv

def IterativeMethod(A, d, tol, tau=0.1, N=None):
    rows = A.shape[0]
    Dinv = np.diag(1./A.diagonal())
    CL = -np.tril(A, -1)
    CU = -np.triu(A, 1)

    L = np.dot(Dinv, CL)
    U = np.dot(Dinv, CU)

    xk = d
    M = np.identity(rows) - U
    Minv = inverseU(M)
    C = np.dot(Dinv, d)
    C = tau * np.dot(Minv, C)
    T = (1.-tau) * np.identity(rows) + tau * np.dot(Minv, L)
    i = 1
    while (True if N is None else (i < N)):
        x = np.dot(T, xk) + C
        dx = x - xk  # Check if scheme converges
        if np.sqrt(np.dot(dx, dx)) < tol:
            break
        i = i + 1
        xk = x  # Prepare for next iteration
    return {'x': x, 'dx': dx, 'iterations': i}


import numpy as np

def exp_growth(amp1, amp2, dur1, dur2):
    t = np.arange(0, dur1)
    Y = np.exp(t / dur2)
    # Want Y[0]=amp1
    # Want Y[-1]=amp2
    Y = Y / (Y[-1] - Y[0]) * (amp2 - amp1)
    Y = Y - Y[0] + amp1
    return Y

def exp_decay(amp1, amp2, dur1, dur2):
    Y = exp_growth(amp2, amp1, dur1, dur2)
    # used to be flip, but that was not supported by older versions of numpy
    Y = np.flipud(Y)
    return Y

def smooth_it(Y, t):
    Z = np.zeros(Y.size)
    for j in range(-t, t + 1):
        Z = Z + np.roll(Y, j)
    return Z

def synthesize_single_waveform(*, N=800, durations=[200, 10, 30, 200], amps=[0.5, 10, -1, 0]):
    durations = np.array(durations).ravel()
    if np.sum(durations) >= N - 2:
        durations[-1] = N - 2 - np.sum(durations[0:durations.size - 1])

    amps = np.array(amps).ravel()

    timepoints = np.round(
        np.hstack((0, np.cumsum(durations) - 1))).astype('int')

    t = np.r_[0:np.sum(durations) + 1]

    Y = np.zeros(len(t))
    Y[timepoints[0]:timepoints[1] + 1] = exp_growth(0, amps[0], timepoints[1] + 1 - timepoints[0], durations[0] / 4)
    Y[timepoints[1]:timepoints[2] + 1] = exp_growth(amps[0], amps[1], timepoints[2] + 1 - timepoints[1], durations[1])
    Y[timepoints[2]:timepoints[3] + 1] = exp_decay(amps[1], amps[2], timepoints[3] + 1 - timepoints[2], durations[2] / 4)
    Y[timepoints[3]:timepoints[4] + 1] = exp_decay(amps[2], amps[3], timepoints[4] + 1 - timepoints[3], durations[3] / 5)
    Y = smooth_it(Y, 3)
    Y = Y - np.linspace(Y[0], Y[-1], len(t))
    Y = np.hstack((Y, np.zeros(N - len(t))))
    Nmid = int(np.floor(N / 2))
    peakind = np.argmax(np.abs(Y))
    Y = np.roll(Y, Nmid - peakind)

    return Y

# Y=smooth_it(Y,3);
# Y=Y-linspace(Y(1),Y(end),length(Y));
#
# Y=[Y,zeros(1,N-length(Y))];
#
# Nmid=floor(N/2);
# [~,peakind]=max(abs(Y));
# Y=circshift(Y,[0,Nmid-peakind]);
#
# end
#
# function test_synth_waveform
# Y=synthesize_single_waveform(800);
# figure; plot(Y);
# end
#
# function Y=exp_growth(amp1,amp2,dur1,dur2)
# t=1:dur1;
# Y=exp(t/dur2);
# % Want Y(1)=amp1
# % Want Y(end)=amp2
# Y=Y/(Y(end)-Y(1))*(amp2-amp1);
# Y=Y-Y(1)+amp1;
# end
#
# function Y=exp_decay(amp1,amp2,dur1,dur2)
# Y=exp_growth(amp2,amp1,dur1,dur2);
# Y=Y(end:-1:1);
# end
#
# function Z=smooth_it(Y,t)
# Z=Y;
# Z(1+t:end-t)=0;
# for j=-t:t
#    Z(1+t:end-t)=Z(1+t:end-t)+Y(1+t+j:end-t+j)/(2*t+1);
# end;
# end

if __name__ == '__main__':
    Y0 = synthesize_single_waveform()
    import matplotlib.pyplot as plt

    plt.plot(Y0)


import numpy as np
import pandas as pd
# import matplotlib.pyplot as plt
import argparse
# import seaborn as sns
import csv

def load_data(file_name, has_label=True):

    df = pd.read_csv(file_name, header=None)
    y = None
    if has_label:
        y = df[[0]]
        x = df.drop([0], axis=1)

        #   if v == 3, y = 1.0; if v == 5, y = -1.0
        def translate(v):
            return 1.0 if v == 3 else -1.0
        y = y.applymap(translate)

        #   translate to np.array
        x = np.array(x)
        y = np.array(y)

        #   insert bias
        x = np.insert(x, 0, values=1.0, axis=1)

        #   transfer label to array, not matrix
        y = y.T[0]
    else:
        x = df
        #   translate to np.array
        x = np.array(x)

        #   insert bias
        x = np.insert(x, 0, values=1.0, axis=1)
    return x, y

def predict(w, x):
    res = np.matmul(w, np.transpose(x))
    vect_sign = np.vectorize(np.sign)
    return vect_sign(res)

def test_accuracy(w, x, y):
    pre_res = predict(w, x)
    sum_diff = 0
    for i in range(len(pre_res)):
        if pre_res[i] != y[i]:
            sum_diff += 1
    return 1 - sum_diff / len(y)

def online_perceptron(x_train, y_train, x_valid, y_valid, iters=15):
    w = np.zeros(len(x_train[0]))
    acc_train, acc_valid = [], []
    print("iteration number\taccuracy on the training set\taccuracy on the validation set")
    for i in range(iters):
        for t in range(len(x_train)):
            u = np.sign(x_train[t].dot(w))
            if u * y_train[t] <= 0:
                w += y_train[t] * x_train[t]
        acc_train.append(test_accuracy(w, x_train, y_train))
        acc_valid.append(test_accuracy(w, x_valid, y_valid))
        print("%d\t%f\t%f" % (i+1, acc_train[i], acc_valid[i]))
    return w, acc_train, acc_valid

def average_perceptron(x_train, y_train, x_valid, y_valid, iters=15):
    w = np.zeros(len(x_train[0]))
    w_a = np.zeros(len(x_train[0]))
    acc_train, acc_valid = [], []
    c, s = 0, 0
    print("iteration number\taccuracy on the training set\taccuracy on the validation set")
    for i in range(iters):
        for t in range(len(x_train)):
            u = np.sign(x_train[t].dot(w))
            if u * y_train[t] <= 0:
                if s + c > 0:
                    w_a = (s * w_a + w * c) / (s + c)
                s = s + c
                w += y_train[t] * x_train[t]
                c = 0
            else:
                c += 1
        if c > 0:
            w_a = (s * w_a + w * c) / (s + c)
        acc_train.append(test_accuracy(w_a, x_train, y_train))
        acc_valid.append(test_accuracy(w_a, x_valid, y_valid))
        print("%d\t%f\t%f" % (i+1, acc_train[i], acc_valid[i]))
    return w_a, acc_train, acc_valid

def kernel_function(x, y, p):
    # return (1 + np.dot(x, y)) ** p
    return np.power((np.matmul(x, y.T) + 1), p)

def kernel_perceptron(x_train, y_train, x_valid, y_valid, p=3, iters=15):
    acc_train, acc_valid = [], []
    N = len(x_train)
    alpha = np.zeros(N)

    #   Gram Matrix
    K_train = kernel_function(x_train, x_train, p)
    K_validation = kernel_function(x_valid, x_train, p)
    print("iteration number\taccuracy on the training set\taccuracy on the validation set")
    for it in range(iters):
        for i in range(N):
            u = np.sign(np.dot(K_train[i], np.multiply(alpha, y_train)))
            if y_train[i] * u <= 0:
                alpha[i] += 1

        pred = predict_kernel(K_train, alpha, y_train)
        acc_train.append(test_accuracy_kernel(pred, y_train))

        pred = predict_kernel(K_validation, alpha, y_train)
        acc_valid.append(test_accuracy_kernel(pred, y_valid))
        print("%d\t%f\t%f" % (it+1, acc_train[it], acc_valid[it]))
    return alpha, acc_train, acc_valid

def predict_kernel(gram_matrix, alpha, y_train):
    #   Gram Matrix
    K = gram_matrix
    return np.sign(np.matmul(K, np.multiply(alpha, y_train)))

def test_accuracy_kernel(pre, y):
    sum_diff = 0
    for i in range(len(pre)):
        if pre[i] != y[i]:
            sum_diff += 1
    return 1 - sum_diff / len(y)

def plot_accuracy(acc_train, acc_valid, title):
    iters = range(1, len(acc_train)+1)
    plt.figure()
    plt.plot(iters, acc_train, "b-", linewidth=1, label="training accuracy")
    plt.plot(iters, acc_valid, "r-", linewidth=1, label="validation accuracy")
    plt.legend()
    plt.xlabel("Iterations")
    plt.ylabel("Accuracy")
    plt.title("Accuracy vs. Iterations (" + title + ")")
    plt.show()

def save_result(file_name, results):
    with open(file_name, mode='w') as file:
        writer = csv.writer(file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        for i in range(len(results)):
            writer.writerow([results[i]])

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Perceptron Implementation')

    parser.add_argument('--run', help="run method: op (Online Perceptron), ap (Average Perceptron), kp (Kernel Perceptron)", default='')
    parser.add_argument("-i", "--iterations", help="iteration number (default: 15)", default='15')
    parser.add_argument("-p", "--p", help="p for the kernel function (default: 3)", default='3')
    args = parser.parse_args()

    if args.run == '':
        print('usage: main.py [--runfunc RUNFUNC: op, ap, kp] [-p p]')
        print('main.py: error: invalid parameter')
        exit(0)

    sample_train, label_train = load_data("pa2_train.csv")
    sample_valid, label_valid = load_data("pa2_valid.csv")
    sample_test, _ = load_data("pa2_test_no_label.csv", has_label=False)
    #
    if args.run == 'op':
        w_op, acc_t_op, acc_v_op = online_perceptron(sample_train, label_train, sample_valid, label_valid, iters=int(args.iterations))
        # plot_accuracy(acc_t_op, acc_v_op, "Online Perceptron")
    elif args.run == 'ap':
        w_ap, acc_t_ap, acc_v_ap = average_perceptron(sample_train, label_train, sample_valid, label_valid, iters=int(args.iterations))
        # plot_accuracy(acc_t_ap, acc_v_ap, "Average Perceptron")
    elif args.run == 'kp':
        a_kp, acc_t_kp, acc_v_kp = kernel_perceptron(sample_train, label_train, sample_valid, label_valid, p=int(args.p), iters=int(args.iterations))
        # plot_accuracy(acc_t_kp, acc_v_kp, "Kernel Perceptron")

    #   Online Perceptron
    # w_op, acc_t_op, acc_v_op = online_perceptron(sample_train, label_train, sample_valid, label_valid, iters=14)
    # plot_accuracy(acc_t_op, acc_v_op, "Online Perceptron")
    # #   predict the test data set
    # results = predict(w_op, sample_test)
    # save_result("oplabel.csv", results)

    #   Average Perceptron
    # w_ap, acc_t_ap, acc_v_ap = average_perceptron(sample_train, label_train, sample_valid, label_valid, iters=15)
    # plot_accuracy(acc_t_ap, acc_v_ap, "Average Perceptron")

    #   Kernel Perceptron
    # p = 3
    # a_kp, acc_t_kp, acc_v_kp = kernel_perceptron(sample_train, label_train, sample_valid, label_valid, p=p, iters=15)
    # plot_accuracy(acc_t_kp, acc_v_kp, "Kernel Perceptron")
    # # predict the test data set
    # K_test = kernel_function(sample_test, sample_train, p)
    # save_result("kplabel.csv", predict_kernel(K_test, a_kp, label_train))


# ou_sim.py
#
# Simulates an Ornstein-Uhlenbeck process.
#
# Jason Blevins <jrblevin@sdf.lonestar.org>
# Durham, March 24, 2008 09:16 EDT

import numpy
from numpy import exp, sqrt

def ou_sim(T, sigma=1.0, eta=1.0, mu=0.0):
    """Ornstein-Uhlenbeck Simulator

    Parameters
    ----------

    T -- number of periods to simulate

    sigma -- standard deviation of the Brownian Motion
    eta -- speed of mean reversion
    mu -- mean

    Returns
    -------

    x -- an array containing the realization of the process
    """
    x = numpy.ones((T)) * mu                  # Initialize storage for x

    # Store a series of independent Normal(0,1) draws
    omega = numpy.random.normal(size=T)

    for t in numpy.arange(1,T):
        x[t] = x[t-1] * exp(-eta) + mu * (1 - exp(-eta)) \
            + sigma * sqrt((1 - exp(-2*eta))/(2*eta)) * omega[t]

    return x

if __name__ == '__main__':
    import pylab

    sigma = 0.01
    eta = 0.03
    mu = 0.0

    x = ou_sim(250, sigma, eta, mu)

    pylab.plot(x, label = ("eta = %0.2f, sigma=%0.2f" % (eta, sigma)))
    pylab.title('Ornstein-Uhlenbeck process')
    pylab.legend(loc='upper left')
    pylab.show()


"""
Problem Statement

mean

The mean tool computes the arithmetic mean along the specified axis.

import numpy

my_array = numpy.array([ [1, 2], [3, 4] ])

print numpy.mean(my_array, axis = 0)        #Output : [ 2.  3.]
print numpy.mean(my_array, axis = 1)        #Output : [ 1.5  3.5]
print numpy.mean(my_array, axis = None)     #Output : 2.5
print numpy.mean(my_array)                  #Output : 2.5
By default, the axis is None. Therefore, it computes the mean of the
flattened array.

var

The var tool computes the arithmetic variance along the specified axis.

import numpy

my_array = numpy.array([ [1, 2], [3, 4] ])

print numpy.var(my_array, axis = 0)         #Output : [ 1.  1.]
print numpy.var(my_array, axis = 1)         #Output : [ 0.25  0.25]
print numpy.var(my_array, axis = None)      #Output : 1.25
print numpy.var(my_array)                   #Output : 1.25
By default, the axis is None. Therefore, it computes the variance of the
flattened array.

std

The std tool computes the arithmetic standard deviation along the specified
axis.

import numpy

my_array = numpy.array([ [1, 2], [3, 4] ])

print numpy.std(my_array, axis = 0)         #Output : [ 1.  1.]
print numpy.std(my_array, axis = 1)         #Output : [ 0.5  0.5]
print numpy.std(my_array, axis = None)      #Output : 1.11803398875
print numpy.std(my_array)                   #Output : 1.11803398875
By default, the axis is None. Therefore, it computes the standard deviation
of the flattened array.

Task

You are given a 2-D array of size NXM.
Your task is to find:

The mean along axis `1`
The var along axis `0`
The std along axis `None`
Input Format

The first line contains the space separated values of N and M.
The next N lines contains M space separated integers.

Output Format

First, print the mean.
Second, print the var.
Third, print the std.

Sample Input

2 2
1 2
3 4
Sample Output

[ 1.5  3.5]
[ 1.  1.]
1.11803398875
"""
import numpy

n, m = map(int, raw_input().split())
a = numpy.array([map(int, raw_input().split()) for i in range(n)],
                dtype=numpy.int)
print numpy.mean(a, axis=1)
print numpy.var(a, axis=0)
print numpy.std(a)


'''
How is it optimal?

The function np.polyfit() that you used to get your regression parameters finds the optimal slope and
intercept. It is optimizing the sum of the squares of the residuals, also known as RSS (for residual
sum of squares). In this exercise, you will plot the function that is being optimized, the RSS, versus
the slope parameter a. To do this, fix the intercept to be what you found in the optimization. Then,
plot the RSS vs. the slope. Where is it minimal?

INSTRUCTIONS
100XP
-Specify the values of the slope for which to compute the RSS. Use np.linspace() to get 200 points
in the range between 0 and 0.1. For example, to get 100 points in the range between 0 and 0.5, you
could use np.linspace() like so: np.linspace(0, 0.5, 100).
-Initialize an array, rss, to contain the RSS using np.empty_like() and the array you created above.
The empty_like() function returns a new array with the same shape and type as a given array
(in this case, a_vals).
-Write a for loop to compute the sum of RSS of the slope. Hint: the RSS is given by
np.sum((y_data - a * x_data - b)**2). The variable b you computed in the last exercise is already in
your namespace. Here, fertility is the y_data and illiteracy the x_data.
-Plot the RSS (rss) versus slope (a_vals).
Hit 'Submit Answer' to see the plot!
'''
import numpy as np
import matplotlib.pyplot as plt

# Specify slopes to consider: a_vals
a_vals = np.linspace(0, 0.1, 200)

# Initialize sum of square of residuals: rss
rss = np.empty_like(a_vals)

# Compute sum of square of residuals for each value of a_vals
for i, a in enumerate(a_vals):
    rss[i] = np.sum((fertility - a*illiteracy - b)**2)

# Plot the RSS
plt.plot(a_vals, rss, '-')
plt.xlabel('slope (children per woman / percent illiterate)')
plt.ylabel('sum of square of residuals')

plt.show()


"""Implements Gaussian Discriminant Analysis from Stanford 229."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from collections import namedtuple

import tensorflow as tf
import numpy as np

def regression(x, y):
    """IImplements Gaussian Discriminant Analysis from Stanford 229.
    (http://cs229.stanford.edu/notes/cs229-notes2.pdf)
    Args:
      x: The covariates or factors of the model in an n by m array (n is number)
        of data points and m is number of factors
      y: The targets or labels of the model in an n by 1 array (either 0 or 1)
    Raises:
      TODO
    Returns:
      A (p, u0, u1, Sigma) tuple, where p is the probability of the target being
      1, u0 is the gaussian mean of the Y=0 distribution, u1 for the Y=1, and
      Sigma is their joint covariance matrix.
    """
    num_predictors = len(x[0])
    num_data = len(x)

    x = np.array(x)
    y = np.array(y)

    print(x)
    x0 = x[np.where( y == 0)]
    print(x0)

    x1 = x[np.where( y == 1)]

    with tf.Graph().as_default() as _:
        Y = tf.placeholder(tf.float32, [num_data])
        X0 = tf.placeholder(tf.float32, [len(x0), num_predictors])
        X1 = tf.placeholder(tf.float32, [len(x1), num_predictors])

        # sum along the num_data axis
        U0 = tf.reduce_mean(X0, 0)
        U1 = tf.reduce_mean(X1, 0)

        Sigma0 = tf.matmul(tf.transpose(X0 - U0), (X0 - U0))
        Sigma1 = tf.matmul(tf.transpose(X1 - U1), (X1 - U1))
        Sigma = (Sigma1 + Sigma0)/num_data

        P = tf.reduce_mean(Y)

        init = tf.initialize_all_variables()

        with tf.Session() as sess:
            sess.run(init)

            p, u0, u1, sigma = sess.run(
                [P, U0, U1, Sigma],
                feed_dict={X0:x0, X1: x1, Y:y})

            Parameters = namedtuple("Parameters", ["Probability_of_target",
                "Gaussian_mean_of_the_Y0_distribution",
                "Gaussian_mean_of_the_Y1_distribution",
                "Joint_covariance_matrix"])
            return Parameters(p, u0, u1, sigma)

if __name__ == "__main__":
    X_TEST = np.reshape([[0.5, 0.2], [0.5, 0.2], [0.5, 0.2],
        [0.25, 1.0], [0.25, 1.0], [0.25, 1.0]], (6, 2))
    Y_TEST = np.reshape([0, 0, 0, 1, 1, 1], (6))

    print(regression(X_TEST, Y_TEST))


# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    maths.py                                           :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: alngo <alngo@student.42.fr>                +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2020/02/24 09:45:07 by alngo             #+#    #+#              #
#    Updated: 2020/03/02 11:25:39 by alngo            ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

import numpy as np
import sys

def mean_squared_error(p0, p1, X, y):
    cost = ((p0 + (p1 * X)) - y) * ((p0 + (p1 * X)) - y)
    return sum((1 / (2 * len(X))) * cost)

def normalize(list):
    minValue = min(list)
    maxValue = max(list)
    newList = (list - minValue) / (maxValue - minValue)
    return [newList, minValue, maxValue]

def denormalize_theta(dataset, normalized_dataset, theta0, theta1, min, max):
    x0 = dataset.iloc[0, 0]
    x1 = dataset.iloc[1, 0]
    y0 = dataset.iloc[0, 1]
    nx0 = normalized_dataset[0]
    nx1 = normalized_dataset[1]
    hy0 = theta0 + (nx0 * theta1)
    hy1 = theta0 + (nx1 * theta1)

    try:
        p0 = (x1 / (x1 - x0)) * (upscale(hy0, min, max) - (x0 / x1 * upscale(hy1, min, max)))
        p1 = (y0 - p0) / x0
    except ZeroDivisionError:
        print(f'Zero division error')
        sys.exit(1)
    return p0, p1

def scale(value, min, max):
    try:
        res = np.float64((value - min) / (max - min))
    except ZeroDivisionError:
        print(f'Zero division error')
        sys.exit(1)
    return res

def upscale(value, min, max):
    return np.float64((value * (max - min)) + min)


from scipy.spatial.distance import pdist, squareform
from scipy.linalg import eigh

import numpy as np

def rbf_kernel_pca(X, gamma, n_components):
    """
    RBF kernel PCA implementation.

    Parameters
    ------------
    X: {NumPy ndarray}, shape = [n_examples, n_features]

    gamma: float
        Tuning parameter of the RBF kernel

    n_components: int
        Number of principal components to return

    Returns
    -----------
    X_pc: {NumPy ndarray}, shape = [n_examples, k_features]
        Projected dataset

    """
    # Calculate pairwise squared Euclidean distances in the
    # MxN dimensional dataset.
    sq_dists = pdist(X, 'sqeuclidean')

    # Convert pairwise distances into a square matrix.
    mat_sq_dists = squareform(sq_dists)

    # Compute the symmetric kernel matrix.
    K = np.exp(-gamma * mat_sq_dists)

    # Center the kernel matrix.
    N = K.shape[0]
    one_n = np.ones((N, N)) / N
    K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)

    # Obtaining eigenpairs from the centered kernel matrix
    # scipy.linalg.eigh returns them in ascending order
    eigvals, eigvecs = eigh(K)
    eigvals, eigvecs = eigvals[::-1], eigvecs[:, ::-1]

    # Collect the top k eigenvectors (projected examples)
    alphas = np.column_stack([eigvecs[:, i] for i in range(n_components)])

    # Collect the corresponding eigenvalues
    lambdas = [eigvals[i] for i in range(n_components)]

    return alphas, lambdas


from sympy import *

# input
x1, y1, dx1, dy1 = symbols('x1 y1 dx1 dy1')
x2, y2, dx2, dy2 = symbols('x2 y2 dx2 dy2')

# intermediate: arcs
ax1, ay1, ax2, ay2 = symbols('ax1 ay1 ax2 ay2')

# output: arc radiuses
r1, r2 = symbols('r1 r2')

solutions = solve(
   [
    r2 - r1,  # radiuses are equal
    x1 + r1*dy1 - ax1,
    y1 - r1*dx1 - ay1,
    x2 + r2*dy2 - ax2,
    y2 - r2*dx2 - ay2,
    (ax1-ax2)**2 + (ay1-ay2)**2 - (r1+r2)**2
], (ax1, ay1, ax2, ay2, r1, r2))

for solution, i  in zip(solutions, range(1, len(solutions)+1)):
    print('const ax1_'+str(i)+' = ' + jscode(solution[0]))
    print('const ay1_'+str(i)+' = ' + jscode(solution[1]))
    print('const ax2_'+str(i)+' = ' + jscode(solution[2]))
    print('const ay2_'+str(i)+' = ' + jscode(solution[3]))
    print('const r1_'+str(i)+' = ' + jscode(solution[4]))
    print('const r2_'+str(i)+' = ' + jscode(solution[5]))
    print('')


"""

"""
import numpy as np
import nashpy

# Matching pennies game
A = np.array([[1, -1], [-1, 1]])
matching_pennies = nash.Game(A)
print(matching_pennies)
equilibria = matching_pennies.support_enumeration()
for eq in equilibria:
    print(eq)
# zero sum game with payoff matices


import os
from montepython.likelihood_class import Likelihood
import math as m
import statistics as s
#from scipy import stats
#import scipy.linalg as la
import numpy as np
#from scipy.integrate import quad

#defines a simple linear regression to be used later by the york linear regression
def lin_reg(x,y):

    #length of data set
	n = len(x)

    #summing independent variable
	x_sum = sum(x)
    #summing dependent variable
	y_sum = sum(y)

    #mean of independent variable
	x_mean = s.mean(x)

    #mean of dependent variable
	y_mean= s.mean(y)

    #sum of x squared
	x_sqr = []
	for i in range(len(x)):
		x_temp = x[i]**2
		x_sqr.append(x_temp)
	x_sqr_sum = sum(x_sqr)

    #sum of y squared
	y_sqr = []
	for i in range(len(y)):
		y_temp = y[i]**2
		y_sqr.append(y_temp)
	y_sqr_sum = sum(y_sqr)

    #sum of xy product
	xy_prod = []
	for i in range(len(y)):
		xy_temp = y[i]*x[i]
		xy_prod.append(xy_temp)
	xy_prod_sum = sum(xy_prod)

    #numerator and denominator of slope estimate
	S_xx = x_sqr_sum - (x_sum**2/n)
	S_xy = xy_prod_sum - (x_sum*y_sum/n)

    #slope estimate
	B_1 = S_xy/S_xx

    #intercept estimate
	B_0 = y_mean - B_1*x_mean

	return B_0, B_1

# linear regression using error as a weighting scheme, fixing slope and slope error
def weighted_fixed_slope(x,y,m,dm,dx,dy):
    #wx = 1/dx^2
    #wy = 1/dy^2
	w = 1/(dx**2+dy**2)

	ybar = sum(w*y)/sum(w)
	xbar = sum(w*x)/sum(w)

	B0 = ybar - m*xbar

	r = y - (B0 +m*x)
	wr = np.sqrt(w)*r
	n = len(x)

	SE_wr = np.sqrt(sum(wr**2)/(n-2))
	dB0 = np.sqrt((SE_wr**2/sum(w))+dm*xbar**2)
	B1 = m
	dB1 = dm

	return B0, B1, dB0, dB1

#york linear regression

# York correction to linear regression including error in both x and y
# https://aapt.scitation.org/doi/abs/10.1119/1.1632486

def york_fit(x,y,sigma_x,sigma_y,r,tol,n_max):
#make sure inputs are a numpy array
	#if the error is 0, replace with something very very small to
	# to prevent nan
	sigma_x[sigma_x == 0] = 10**-15
	sigma_y[sigma_y == 0] = 10**-15

#define an array which tracks the changes in slope, B_1
	b_hist = np.ones(n_max)

#1) choose an approximate initial value for the slope, b
	# -> simple linear regression
# B_0 is intercept, B_1 is slope from simple linear regression
	[B_0_simple, B_1_simple] = lin_reg(x,y)
	b_hist[0] = B_1_simple
	B_0 = B_0_simple
	B_1 = B_1_simple

#2) determine the weights omega of each point for both x and y
	# usually 1/sigma where sigma is the error associated with x and y
	# at the i'th point

	omega_x = 1/np.square(np.array(sigma_x))
	omega_y = 1/np.square(np.array(sigma_y))

#3) use these weights with B_1 and the correlation r (if any) to
	# evaluate W_i for each point
	alpha = np.sqrt(omega_x*omega_y)
#6) calculate B_1_new until the difference between B_1_new and B_1 is
	# less than the tolerance provided
	counter = 1
	while counter < n_max:
		W = (omega_x*omega_y)/(omega_x + (B_1**2)*omega_y - 2*B_1*r*alpha)

#4) use the observed points and W to calculate x_bar and y_bar from
    # from which U V and beta can be evaluated for each point

		x_bar = sum(W*x)/sum(W)
		y_bar = sum(W*y)/sum(W)

		U = x - x_bar
		V = y - y_bar
		beta = W*((U/omega_y)+(B_1*V/omega_x)-(B_1*U+V)*(r/alpha))

#5) use W U V and beta to calculate a new estimate of B_1

		B_1_new = sum(W*beta*V)/sum(W*beta*U)
		b_hist[counter] = B_1_new

		if(abs(B_1_new-B_1)< tol):
			B_1 = B_1_new
			break

		counter += 1
		B_1 = B_1_new

#7) using the final value of B_1, x_bar, y_bar, calculate B_0

	B_0 = y_bar - B_1*x_bar

#8) for each point x and y, calculate the adjusted values
	x_adj = x_bar + beta
	y_adj = y_bar + B_1*beta

#9) use x_adj and W to calc x_bar_adj and u abd v
	x_bar_adj = sum(W*x_adj)/sum(W)
    #y_bar_adj = sum(W*y_adj)/sum(W)

	u = x_adj - x_bar_adj
    #v = y_adj - y_bar_adj

#10) use W x_bar and u to calculate sigma_a and sigma_b

	var_b = 1/(sum(W*u**2))
	var_a = 1/sum(W)+(x_bar**2)*var_b

	sigma_a_new = np.sqrt(var_a)
	sigma_b_new = np.sqrt(var_b)

	return B_0, B_1, sigma_a_new, sigma_b_new, b_hist, B_0_simple, B_1_simple

#######################################################################################
#CLASS DEFINITIONS OF STEPS OF THE DISTANCE LADDER#
#######################################################################################

# This class defines the structure in which Anchors with known distances
# and contain cepheids are imported

class Anchor:
	"This class defines a structure which holds data for objects that have geometric distance measurements, and cepheid variables."

	def __init__(self,Name='',Dist=0,dDist=0):

		self.Name = Name
		self.Dist = Dist
		self.dDist = dDist
		self.mu = 5*np.log10(self.Dist)-5
		self.dmu = 5*np.log10(np.exp(1))*self.dDist/self.Dist

	#computes the absolute magnitude of cepheids in the anchor galaxy, assuming cepheid data is available
	def Compute_abs_ceph_mag(self,period,dperiod,mh,dmh):
		r = 0
		tol = 10**-15
		n = 20
		[B_0, B_1, sigma_B_0, sigma_B_1, b_save, B_0_simple, B_1_simple] = york_fit(period,mh,dperiod,dmh,r,tol,n)

		self.Mceph = B_0 - self.mu
		self.dMceph = np.sqrt(np.power(sigma_B_0,2)+np.power(self.dmu,2))

# This class defines the structure in which the SHOES cepheid data is
# imported, and the DM calculated to those cepheids

class SHOES_ceph_data:
	"This class creates a structure which holds SHOES cepheid data for a given host"

	def __init__(self,Host='',ID='',Period=0,V=0,dV=0,I=0,dI=0,NIR=0,dNIR=0,OH=0):

		self.Host = Host
		self.ID = ID
		self.Period = Period
		self.NIR = NIR
		self.dNIR = dNIR
		self.V = V
		self.dV = dV
		self.I = I
		self.dI = dI
		# R value is a correlation coeffecient, forced to be the same
		#as what is used in previous analysis
		self.R = 0.386
		self.mh = NIR - self.R*(V-I)
		self.dmh = np.sqrt(np.power(dNIR,2)+self.R*np.power(dV,2)+self.R*np.power(dI,2))

	# Using the absolute magnitude of cepheids, the distance modulus to SH0ES cepheids is calculated.
	def proto_Compute_mu(self,mh,dmh,period,dperiod,Mceph,dMceph,slope,dslope):

		[B0, B_1, dB0, dB1] = weighted_fixed_slope(period,mh,slope,dslope,dperiod,dmh)

		self.mu = B0 - Mceph
		self.dmu = np.sqrt(np.power(dB0,2)+np.power(dMceph,2))

# This class defines the structure in which the LMC cepheid data is imported, and the DM calculated to those cepheids

class LMC_ceph_data:
	"This class creates a structure which holds cepheid data in the LMC"

	def __init__(self,Host='',ID='',Period=0,mh=0,dmh=0):

		self.Host = Host
		self.ID = ID
		self.Period = Period
		self.mh = mh
		self.dmh = dmh

	# Using the absolute magnitude of cepheids, the distance modulus to LMC cepheids is calculated.
	def proto_Compute_mu(self,mh,dmh,period,dperiod,Mceph,dMceph,slope,dslope):

		[B0, B_1, dB0, dB1] = weighted_fixed_slope(period,mh,slope,dslope,dperiod,dmh)

		self.mu = B0 - Mceph
		self.dmu = np.sqrt(np.power(dB0,2)+np.power(dMceph,2))

# This class defines the structure in which the supernova calibarted using the TRGB method is imported
class TRGB_sn_data:
	def __init__(self,Host='',ID='',mu=0,dmu=0,m=0,dm=0):
		self.Host = Host
		self.ID = ID
		self.mu = mu
		self.dmu = dmu
		self.m = m
		self.dm = dm

# This class defines the structure in which the SN which are nearby and calibrated are imported

class Local_SN_data:
	"This class creates a structure which holds SN data for a given host."

	def __init__(self,Host='',ID='',m=0,dm=0):

		self.Host = Host
		self.ID = ID
		self.m = m
		self.dm = dm

	def Compute_abs_sn_mag(self,m,dm,mu,dmu):

		x = mu
		y = m
		xerror = dm
		yerror = dmu
		[Msn, B1, dMsn, sigma_B1] = weighted_fixed_slope(x,y,1,0,xerror,yerror)
		self.Msn = Msn
		self.dMsn = dMsn

# This class defines the structure in which hubble flow SN are imported

class Hubble_SN_data:
	"This class creates a structure which holds SN data in the hubble flow."

	def __init__(self,ID='',z_hel = 0,z_cmb=0,dz=0,m=0,dm=0):

		self.ID = ID
		self.m = m
		self.dm = dm
		self.z_hel = z_hel
		self.z_cmb = z_cmb
		self.dz = dz

	def Compute_hubble_mu(self,m,dm,Msn,dMsn):
		#self.mu = hubble_sn.m - Msn
		#self.dmu = np.sqrt(np.power(hubble_sn.dm,2)+np.power(dMsn,2))
		self.mu = m - Msn
		self.dmu = np.sqrt(np.power(dm,2)+np.power(dMsn,2))

class distanceladder(Likelihood):

	# initialization routine. Here we will establish the subclasses needed to calculate the
	#attributes of the distance ladder, up until the distance modulus calculation of
	#hubble flow SN

	def __init__(self, path, data, command_line):

		#initialization of Likelihood class
		Likelihood.__init__(self,path,data,command_line)

				#simple linear regression used by Yorkfit for initial parameter estimation

##########################################################################################
#TABLE READERS#
##########################################################################################
		# reads in anchor distance data
		def anchor_reader(file,index_array,header_length,delim):

			base_dir = self.data_directory

		    #stable method to read in tabular data
			file = open(base_dir + file)
			table = file.readlines()
			file.close()

		    #defining the length of the actual data of the table
			i = len(table)-header_length

		    #preallocating the arrays for memory
			host_list = []
			dist_np = np.zeros(i)
			ddist_np = np.zeros(i)

			lc = 0

			for line in table:

				lc += 1
				i = lc - header_length - 1
				data = line.strip('\n').split(delim)

				if lc>header_length:
					if index_array[0] is not np.NaN:
						host_list.append(data[index_array[0]])
					else:
						host_list.append(np.NaN)

					if index_array[1] is not np.NaN:
						dist_np[i] = data[index_array[1]]
					else:
						dist_np[i] = np.NaN

					if index_array[2] is not np.NaN:
						ddist_np[i] = data[index_array[2]]
					else:
						ddist_np[i] = np.NaN

			name = []
			for a in range(len(host_list)):
				name.append([host_list[a],dist_np[a],ddist_np[a]])

			return name

		# reads in the SHOES cepheid data
		def SHOES_ceph_table_reader(file,index_array,header_length,delim):
		    #file(string): location of table wished to be read in
		    #index_array(array): array containing the column index of the
			#following attributes:
			#host,ID,period,V,dV,I,dI,NIR,dNIR,OH
			# if attribute does not occur in table, put -1
			#host: index of host column in table
			    # list, strings
			#ID: index of ID column in table
			    # list, strings
			#period: index of period column in table
			    # np array, float
			# the remainder of entries are the index of said variable in table
			    # all are np array's, with float values
		    #header_length(int): line number of last row of header
		    #name(string):user desired prefix for data
			# name_host, name_ID, etc
		    #cc(string): character which splits your data

		    #All data should be located in this parent folder
			base_dir = self.data_directory

		    #stable method to read in tabular data
			file = open(base_dir + file)
			table = file.readlines()
			file.close()

		    #defining the length of the actual data of the table
			i = len(table)-header_length

		    #preallocating the arrays for memory
			host_list = []
			ID_list = []
			period_np = np.zeros(i)
			V_np = np.zeros(i)
			dV_np = np.zeros(i)
			I_np = np.zeros(i)
			dI_np = np.zeros(i)
			NIR_np = np.zeros(i)
			dNIR_np = np.zeros(i)
			OH_np = np.zeros(i)

			lc = 0

			for line in table:

				lc += 1
				i = lc - header_length - 1
				data = line.strip('\n').split(delim)

				if lc>header_length:
					if index_array[0] is not np.NaN:
						host_list.append(data[index_array[0]])
					else:
						host_list.append(np.NaN)

					if index_array[1] is not np.NaN:
						ID_list.append(data[index_array[1]])
					else:
						ID_list.append(np.NaN)

					if index_array[2] is not np.NaN:
						period_np[i] = data[index_array[2]]
					else:
						period_np[i] = np.NaN

					if index_array[3] is not np.NaN:
						V_np[i] = data[index_array[3]]
					else:
						V_np[i] = np.NaN

					if index_array[4] is not np.NaN:
						dV_np[i] = data[index_array[4]]
					else:
						dV_np[i] = np.NaN

					if index_array[5] is not np.NaN:
						I_np[i] = data[index_array[5]]
					else:
						I_np[i] = np.NaN

					if index_array[6] is not np.NaN:
						dI_np[i] = data[index_array[6]]
					else:
						dI_np[i] = np.NaN

					if index_array[7] is not np.NaN:
						NIR_np[i] = data[index_array[7]]
					else:
						NIR_np[i] = np.NaN

					if index_array[8] is not np.NaN:
						dNIR_np[i] = data[index_array[8]]
					else:
						dNIR_np[i] = np.NaN

					if index_array[9] is not np.NaN:
						OH_np[i] = data[index_array[9]]
					else:
						OH_np[i] = np.NaN

				name = []
			for a in range(len(host_list)):
				name.append([host_list[a],ID_list[a],period_np[a],V_np[a],dV_np[a],I_np[a],dI_np[a],NIR_np[a],dNIR_np[a],OH_np[a]])

			return name

		# reads in the LMC data
		def LMC_ceph_reader(file,index_array,header_length,delim):
			#file(string): location of table wished to be read in
			#index_array(array): array containing the column index of the following attributes:
			#host,ID,period,V,dV,I,dI,NIR,dNIR,OH
			# if attribute does not occur in table, put -1
			#host: index of host column in table
			    # list, strings
			#ID: index of ID column in table
			    # list, strings
			#period: index of period column in table
			    # np array, float
			# the remainder of entries are the index of said variable in table
			    # all are np array's, with float values
			#header_length(int): line number of last row of header
			#name(string):user desired prefix for data
			# name_host, name_ID, etc
			#cc(string): character which splits your data

			#All data should be located in this parent folder
			base_dir = self.data_directory

			#stable method to read in tabular data
			file = open(base_dir + file)
			table = file.readlines()
			file.close()

			#defining the length of the actual data of the table
			i = len(table)-header_length

			#preallocating the arrays for memory
			host_list = []
			ID_list = []
			period_np = np.zeros(i)
			mHW_np = np.zeros(i)
			dmHW_np = np.zeros(i)

			lc = 0
			for line in table:

				lc += 1
				i = lc - header_length - 1
				data = line.strip('\n').split(delim)
				if lc>header_length:
					if index_array[0] is not np.NaN:
						host_list.append(data[index_array[0]])
					else:
						host_list.append(np.NaN)

					if index_array[1] is not np.NaN:
						ID_list.append(data[index_array[1]])
					else:
						ID_list.append(np.NaN)

					if index_array[2] is not np.NaN:
						period_np[i] = data[index_array[2]]
					else:
						period_np[i] = np.NaN

					if index_array[3] is not np.NaN:
						mHW_np[i] = data[index_array[3]]
					else:
						mHW_np[i] = np.NaN

					if index_array[4] is not np.NaN:
						dmHW_np[i] = data[index_array[4]]
					else:
						dmHW_np[i] = np.NaN

			name = []
			for a in range(len(host_list)):
				if period_np[a] > .8:
					name.append(['LMC',ID_list[a],period_np[a],mHW_np[a],dmHW_np[a]])

			return name

		#reads in the calibrated TRGB supernova
		def TRGB_sn_reader(file,index_array,header_length,delim):

			#All data should be located in this parent folder
			base_dir = self.data_directory

			#stable method to read in tabular data
			file = open(base_dir + file)
			table = file.readlines()
			file.close()

			#defining the length of the actual data of the table
			i = len(table)-header_length

			#preallocating the arrays for memory
			host_list = []
			ID_list = []
			mu_np = np.zeros(i)
			dmu_np = np.zeros(i)
			m_np = np.zeros(i)
			dm_np = np.zeros(i)

			lc = 0

			for line in table:

				lc += 1
				i = lc - header_length - 1
				data = line.strip('\n').split(delim)

				if lc>header_length:

					if index_array[0] is not np.NaN:
						host_list.append(data[index_array[0]])
					else:
						host_list.append(np.NaN)

					if index_array[1] is not np.NaN:
						ID_list.append(data[index_array[1]])
					else:
						ID_list.append(np.NaN)
					if index_array[2] is not np.NaN:
						mu_np[i] = data[index_array[2]]
					else:
						mu_np[i] = np.NaN

					if index_array[3] is not np.NaN:
						dmu_np[i] = data[index_array[3]]
					else:
						dmu_np[i] = np.NaN
					if index_array[4] is not np.NaN:
						m_np[i] = data[index_array[4]]
					else:
						m_np[i] = np.NaN

					if index_array[5] is not np.NaN:
						dm_np[i] = data[index_array[5]]
					else:
						dm_np[i] = np.NaN

			name = []
			for a in range(len(host_list)):
				name.append([host_list[a],ID_list[a],mu_np[a],dmu_np[a],m_np[a],dm_np[a]])

			return name

		# reads in cepheid calibrated SN data
		def SHOES_sn_table_reader(file,index_array,header_length,delim):

		    #All data should be located in this parent folder
			base_dir = self.data_directory

		    #stable method to read in tabular data
			file = open(base_dir + file)
			table = file.readlines()
			file.close()

		    #defining the length of the actual data of the table
			i = len(table)-header_length

		    #preallocating the arrays for memory
			host_list = []
			ID_list = []
			m_np = np.zeros(i)
			dm_np = np.zeros(i)

			lc = 0

			for line in table:

				lc += 1
				i = lc - header_length - 1
				data = line.strip('\n').split(delim)

				if lc>header_length:

					if index_array[0] is not np.NaN:
						host_list.append(data[index_array[0]])
					else:
						host_list.append(np.NaN)

					if index_array[1] is not np.NaN:
						ID_list.append(data[index_array[1]])
					else:
						ID_list.append(np.NaN)

					if index_array[2] is not np.NaN:
						m_np[i] = data[index_array[2]]
					else:
						m_np[i] = np.NaN

					if index_array[3] is not np.NaN:
						dm_np[i] = data[index_array[3]]
					else:
						dm_np[i] = np.NaN

			name = []
			for a in range(len(host_list)):
				name.append([host_list[a],ID_list[a],m_np[a],dm_np[a]])

			return name

		#reads in the pantheon hubble flow supernova data
		def panth_sn_table_reader(file,index_array,header_length,delim):

			#All data should be located in this parent folder
			base_dir = 'data/'

			#stable method to read in tabular data
			file = open(base_dir + file)
			table = file.readlines()
			file.close()

			#defining the length of the actual data of the table
			i = len(table)-header_length

			#preallocating the arrays for memory
			ID_list = []
			z_hel_np = np.zeros(i)
			z_cmb_np = np.zeros(i)
			dz_cmb_np = np.zeros(i)
			m_np = np.zeros(i)
			dm_np = np.zeros(i)

			lc = 0

			for line in table:

				lc += 1
				i = lc - header_length - 1
				data = line.strip('\n').split(delim)

				if lc>header_length:

					if index_array[0] is not np.NaN:
						ID_list.append(data[index_array[0]])
					else:
						ID_list.append(np.NaN)

					if index_array[1] is not np.NaN:
						z_hel_np[i] = data[index_array[1]]
					else:
						z_hel_np[i] = np.NaN

					if index_array[2] is not np.NaN:
						z_cmb_np[i] = data[index_array[2]]
					else:
						z_cmb_np[i] = np.NaN

					if index_array[3] is not np.NaN:
						dz_cmb_np[i] = data[index_array[3]]
					else:
						dz_cmb_np[i] = np.NaN

					if index_array[4] is not np.NaN:
						m_np[i] = data[index_array[4]]
					else:
						m_np[i] = np.NaN

					if index_array[5] is not np.NaN:
						dm_np[i] = data[index_array[5]]
					else:
						dm_np[i] = np.NaN

			name = []
			for a in range(len(ID_list)):
				if z_cmb_np[a] > 0.0023:
					if z_cmb_np[a] < 0.15:
						 name.append([ID_list[a],z_hel_np[a],z_cmb_np[a],dz_cmb_np[a],m_np[a],dm_np[a]])
			return name

		#reads in the CSP hubble flow supernova data
		def csp_sn_table_reader(file,index_array,header_length,delim):

			base_dir = self.data_directory

			#stable method to read in tabular data
			file = open(base_dir + file)
			table = file.readlines()
			file.close()

			#defining the length of the actual data of the table
			i = len(table)-header_length

			#preallocating the arrays for memory
			ID_list = []
			filter_list = []
			z_hel_np = np.zeros(i)
			z_cmb_np = np.zeros(i)
			dz_cmb_np = np.zeros(i)
			m_np = np.zeros(i)
			dm_np = np.zeros(i)

			lc = 0

			for line in table:

				lc += 1
				i = lc - header_length - 1
				data = line.strip('\n').split(delim)

				if lc>header_length:

					if index_array[0] is not np.NaN:
						ID_list.append(data[index_array[0]])
					else:
						ID_list.append(np.NaN)

					if index_array[1] is not np.NaN:
						filter_list.append(data[index_array[1]])
					else:
						filter_list.append(np.NaN)

					if index_array[2] is not np.NaN:
						z_hel_np[i] = data[index_array[2]]
					else:
						z_hel_np[i] = np.NaN

					if index_array[3] is not np.NaN:
						z_cmb_np[i] = data[index_array[3]]
					else:
						z_cmb_np[i] = np.NaN

					if index_array[4] is not np.NaN:
						m_np[i] = data[index_array[4]]
					else:
						m_np[i] = np.NaN

					if index_array[5] is not np.NaN:
						dm_np[i] = data[index_array[5]]
					else:
						dm_np[i] = np.NaN

			name = []

			for a in range(len(ID_list)):
				if z_cmb_np[a] > 0.0023:
					if z_cmb_np[a] < 0.15:
						if filter_list[a] == 'B':
							name.append([ID_list[a],z_hel_np[a],z_cmb_np[a],dz_cmb_np[a],m_np[a],dm_np[a]])
			return name
		################################################################################################
#READ IN TABULAR DATA#
################################################################################################

		#read in the data from the tables
		#file location
		file = '/distanceladder/anchor_data.txt'
                #columns to be read in
		index_array = [0,1,2]
		#length of header
		header_length = 1
		#deliminator
		delim = ' '

		anchor_dat = anchor_reader(file,index_array,header_length,delim)

		if self.calib == 'cepheid':
			file = '/distanceladder/SHOES_cepheid_data.txt'
			index_array = [0,1,2,3,4,5,6,7,8,9]
			header_length = 1
			delim = ' '

			SHOES_ceph = SHOES_ceph_table_reader(file,index_array,header_length,delim)

			file = "/distanceladder/LMC_ceph_data.txt"
			index_array = [0,0,2,12,22]
			header_length = 1
			delim = ' '
			LMC_ceph = LMC_ceph_reader(file,index_array,header_length,delim)

			# This reads in local SN data from Riess16 table 4

			file = '/distanceladder/SHOES_sn_data.txt'
			index_array = [0,1,2,3]
			header_length = 1
			delim = ' '

			R16_local_sn = SHOES_sn_table_reader(file,index_array,header_length,delim)

		if self.calib == 'TRGB':

			#placeholder function if CSP is added later, currently not functioning
			if self.supernova_data == 'csp':
				file = "/distanceladder/bprime_TRGB_sn_data.txt"
				index_array = [0,1,2,3,4,5]
				header_length = 1
				delim = ' '

				TRGB_sn = TRGB_sn_reader(file,index_array,header_length,delim)

			#reads in local SN data from Freedman table 2, using hubble photometry
			if self.supernova_data == 'panth':
				file = "/distanceladder/b_TRGB_sn_data.txt"
				index_array = [0,1,2,3,4,5]
				header_length = 1
				delim = ' '

				TRGB_sn = TRGB_sn_reader(file,index_array,header_length,delim)
		if self.calib == 'concordant':

			# reads in the local SN data which agrees between Riess and Freedman to one sigma
			if self.supernova_data == 'panth':
				file = "/distanceladder/combined_localsn_data.txt"
				index_array = [0,1,2,3,4,5]
				header_length = 1
				delim = ' '

				TRGB_sn = TRGB_sn_reader(file,index_array,header_length,delim)

		# This block is where the hubble flow SN data will be loaded and organized
		# Pantheon
		# Steinhardt
		if self.supernova_data == 'panth':
			file = '/distanceladder/panth_sn_data.txt'
			index_array = [0,1,2,3,4,5]
			header_length = 1
			delim = ' '

			PS_sn = panth_sn_table_reader(file,index_array,header_length,delim)
		#placeholder for future itteration, currently not functioning
		if self.supernova_data == 'csp':
			file = "/distanceladder/csp_sn_data.txt"
			index_array = [0,3,1,2,6,7]
			header_length = 1
			delim = ' '

			csp_sn = csp_sn_table_reader(file,index_array,header_length,delim)

################################################################################################
#CONSTRUCT DATA DICTIONARIES#
################################################################################################

		# This takes the imported anchor data, and places it into an anchor
		#data class instance

		# NGC4258 Megamaser
		# LMC DEB
		anchor_dict = {}

		for i in range(len(anchor_dat)):
			key = anchor_dat[i][0]
			value = Anchor(anchor_dat[i][0],anchor_dat[i][1],anchor_dat[i][2])
			anchor_dict[key] = value

		# This takes the imported cepheid data, creates a dictionary where
		# the elements of the dictionary are instances
		# of the cephied class.
		# For clarity the dictionary contains elements organized by host galaxy,
		# each element containing all cephieds in that host.
		if self.calib == 'cepheid':
			hosts=[]
			for i in range(len(SHOES_ceph)):
				hosts.append(SHOES_ceph[i][0])
			hosts = np.unique(hosts)

			ceph_dict = {}

			for i in range(len(hosts)):
				temp=[]

				for j in range(len(SHOES_ceph)):
					if hosts[i] == SHOES_ceph[j][0]:
						temp.append(SHOES_ceph[j])

				k = len(temp)
				host = []
				ID = []
				per = np.zeros(k)
				V = np.zeros(k)
				dV = np.zeros(k)
				I = np.zeros(k)
				dI = np.zeros(k)
				NIR = np.zeros(k)
				dNIR = np.zeros(k)
				OH = np.zeros(k)

				key = hosts[i]

				for l in range(len(temp)):
					host.append(temp[l][0])
					ID.append(temp[l][1])
					per[l] = temp[l][2]
					V[l] = temp[l][3]
					dV[l] = temp[l][4]
					I[l] = temp[l][5]
					dI[l] =  temp[l][6]
					NIR[l] = temp[l][7]
					dNIR[l] = temp[l][8]
					OH[l] = temp[l][9]

				value = SHOES_ceph_data(host,ID,per,V,dV,I,dI,NIR,dNIR,OH)
				ceph_dict[key] = value

			host = [i[0] for i in LMC_ceph]
			idceph =[i[1] for i in LMC_ceph]
			period = [i[2] for i in LMC_ceph]
			mh = [i[3] for i in LMC_ceph]
			dmh = [i[4] for i in LMC_ceph]
			value = LMC_ceph_data(host,idceph,period,mh,dmh)
			ceph_dict['LMC'] = value
			ceph_dict['LMC'].Period = 10**np.array(ceph_dict['LMC'].Period)
			ceph_dict['LMC'].mh = np.array(ceph_dict['LMC'].mh)
			ceph_dict['LMC'].dmh = np.array(ceph_dict['LMC'].dmh)

# This takes the imported TRGB SN data, creates a diction where where the elements of the dictionary are instances
# of the local SN class
		if self.calib == 'TRGB' or self.calib == 'concordant':
			hosts=[]
			for i in range(len(TRGB_sn)):
				hosts.append(TRGB_sn[i][0])
			hosts = np.unique(hosts)

			TRGB_sn_dict = {}

			for i in range(len(hosts)):
				temp=[]

				for j in range(len(TRGB_sn)):
					if hosts[i] == TRGB_sn[j][0]:
						temp.append(TRGB_sn[j])

				k = len(temp)
				host = []
				ID = []
				mu = np.zeros(k)
				dmu = np.zeros(k)
				m = np.zeros(k)
				dm = np.zeros(k)

				key = hosts[i]

				for l in range(len(temp)):
					host.append(temp[l][0])
					ID.append(temp[l][1])
					mu[l] = temp[l][2]
					dmu[l] = temp[l][3]
					m[l] = temp[l][4]
					dm[l] = temp[l][5]

				value = TRGB_sn_data(host,ID,mu,dmu,m,dm)
				TRGB_sn_dict[key] = value

		# This takes the imported local SN data, creates a diction
		#where where the elements of the dictionary are instances
		# of the local SN class
		if self.calib == 'cepheid':
			hosts=[]
			for i in range(len(R16_local_sn)):
				hosts.append(R16_local_sn[i][0])
			hosts = np.unique(hosts)

			local_sn_dict = {}

			for i in range(len(hosts)):
				temp=[]

				for j in range(len(R16_local_sn)):
					if hosts[i] == R16_local_sn[j][0]:
						temp.append(R16_local_sn[j])

				k = len(temp)
				host = []
				ID = []
				m = np.zeros(k)
				dm = np.zeros(k)

				key = hosts[i]

				for l in range(len(temp)):
					host.append(temp[l][0])
					ID.append(temp[l][1])
					m[l] = temp[l][2]
					dm[l] = temp[l][3]

				value = Local_SN_data(host,ID,m,dm)
				local_sn_dict[key] = value

		# this block is where the hubble flow sn data will be oragnized
		#into the hubble flow sn class
		if self.supernova_data == 'panth':
			k = len(PS_sn)
			ID = []
			z_hel = np.zeros(k)
			z_cmb = np.zeros(k)
			dz = np.zeros(k)
			m = np.zeros(k)
			dm = np.zeros(k)

			for i in range(len(PS_sn)):

				ID.append(PS_sn[i][0])
				z_hel[i] = PS_sn[i][1]
				z_cmb[i] = PS_sn[i][2]
				dz[i] = PS_sn[i][3]
				m[i] = PS_sn[i][4]
				dm[i] = PS_sn[i][5]

			hubble_sn = Hubble_SN_data(ID,z_hel,z_cmb,dz,m,dm)
		#place holder function, currently not working.
		if self.supernova_data == 'csp':
			k = len(csp_sn)
			ID = []
			z_hel = np.zeros(k)
			z_cmb = np.zeros(k)
			dz = np.zeros(k)
			m = np.zeros(k)
			dm = np.zeros(k)

			for i in range(len(csp_sn)):

				ID.append(csp_sn[i][0])
				z_hel[i] = csp_sn[i][1]
				z_cmb[i] = csp_sn[i][2]
				dz[i] = csp_sn[i][3]
				m[i] = csp_sn[i][4]
				dm[i] = csp_sn[i][5]

			hubble_sn = Hubble_SN_data(ID,z_hel,z_cmb,dz,m,dm)

##############################################################################################
#CALCULATIONS#
##############################################################################################
		if self.calib == 'cepheid':
			# This block is where M_ceph will be calculated from each Anchor
			for i in self.anchor:
				# period is divided by 10 as does by Esthafio (2020)
				period = np.log10(ceph_dict[i].Period/10)
				dperiod = np.zeros(len(period))
				mh = ceph_dict[i].mh
				dmh = ceph_dict[i].dmh

				anchor_dict[i].Compute_abs_ceph_mag(period,dperiod,mh,dmh)
			num = 0
			dem = 0
			Mceph = 0
			dMceph = 0
			for i in self.anchor:
				num += anchor_dict[i].dMceph*anchor_dict[i].Mceph
				dem += anchor_dict[i].dMceph
				dMceph += anchor_dict[i].dMceph**2
			Mceph = num/dem
			dMceph = np.sqrt(dMceph)
			# This is where the slope of the cephied PL relationship is defined

			slope_array = np.zeros(len(ceph_dict))
			dslope_array = np.zeros(len(ceph_dict))
			w_slope_array = np.zeros(len(ceph_dict))
			w_dslope_array = np.zeros(len(ceph_dict))
			count = 0
			tot = 0
			# the following 3 lines are parameters for the york fit and may be
			#removed in future updates
			r = 0
			tol = 10**-15
			n = 20

			for key in ceph_dict:
				x = np.log10(ceph_dict[key].Period/10)
				xerror = np.zeros(len(x))
				y = ceph_dict[key].mh
				yerror = ceph_dict[key].dmh

				[B_0, B_1, sigma_B_0, sigma_B_1, b_save, B_0_simple, B_1_simple] = york_fit(x,y,xerror,yerror,r,tol,n)

			    # this calculates the weighted slope and weighted error of the slope for
			#each cephied host galaxy
				weight = len(x)
				tot += weight
				w_slope_array[count] = B_1*weight
				w_dslope_array[count] = np.power(sigma_B_1,2)*weight
				count+=1

			# This calculates the overall slope of the PL relationship for cephieds, and its error
			slope = sum(w_slope_array)/tot
			dslope = np.sqrt(sum(w_dslope_array)/tot)/np.sqrt(len(ceph_dict))

			for key in ceph_dict:
				period = np.log10(ceph_dict[key].Period/10)
				dperiod = np.zeros(len(period))
				mh = ceph_dict[key].mh
				dmh = ceph_dict[key].dmh

				ceph_dict[key].proto_Compute_mu(mh,dmh,period,dperiod,Mceph,dMceph,slope,dslope)

		# This block is where Msn will be calculated from SN hosts
		x = []
		y = []
		xerror = []
		yerror = []

		if self.calib == 'cepheid':

			for key in local_sn_dict:
				local_sn_dict[key].mu = ceph_dict[key].mu
				local_sn_dict[key].dmu = ceph_dict[key].dmu

				x.append(local_sn_dict[key].mu)
				y.append(float(local_sn_dict[key].m))
				xerror.append(local_sn_dict[key].dmu)
				yerror.append(float(local_sn_dict[key].dm))

			x = np.array(x)
			y = np.array(y)
			xerror = np.array(xerror)
			yerror = np.array(yerror)

			[Msn, B1, dMsn, sigma_B1] = weighted_fixed_slope(x,y,1,0,xerror,yerror)

			# This block is where DM_sn_obs will be calculated for each SN

		if self.calib == 'TRGB' or self.calib == 'concordant':

			for key in TRGB_sn_dict:
				cc = TRGB_sn_dict[key].mu
				for i in range(len(cc)):
					xtemp = TRGB_sn_dict[key].mu
					x.append(xtemp[i])
					ytemp = TRGB_sn_dict[key].m
					y.append(ytemp[i])
					xerrortemp = TRGB_sn_dict[key].dmu
					xerror.append(xerrortemp[i])
					yerrortemp = TRGB_sn_dict[key].dm
					yerror.append(yerrortemp[i])

			x = np.array(x)
			y = np.array(y)
			xerror = np.array(xerror)
			yerror = np.array(yerror)

			[Msn, B1, dMsn, sigma_B1] = weighted_fixed_slope(x,y,1,0,xerror,yerror)

		m = hubble_sn.m
		dm = hubble_sn.dm
		hubble_sn.Compute_hubble_mu(m,dm,Msn,dMsn)

		#passes data to loglkl
		self.hubble_mu = hubble_sn.mu
		self.hubble_dmu = hubble_sn.dmu
		self.hubble_z = hubble_sn.z_cmb
		self.hubble_dz = hubble_sn.dz
		self.hubble_dm = dm
		self.hubble_dMsn = dMsn

		if self.calib == 'cepheid':
			print("Cepheid Calibration")
			print("Anchors Used:", self.anchor)
			print("Abs. Ceph. Mag:", Mceph)
			print("Abs. Ceph. Mag Error:",dMceph)
			print('')
			print("P-L Slope:", slope)
			print("P-L Slope Error:", dslope)
			print('')
		if self.calib == 'TRGB':
			print("TRGB Calibration")
			print("Abs. TRGB. Mag:",0)
			print("Abs. TRGB. Mag error:",0)
			print('')
		print("Msn:",Msn)
		print("dMsn:",dMsn)

	def loglkl(self, cosmo, data):

		z = self.hubble_z
		dz = self.hubble_dz
		dMsn = self.hubble_dMsn
		dm = self.hubble_dm

		k = len(self.hubble_dmu)

		cosmo_mu = np.zeros(k)
		jac = np.zeros(k)

		# Compute the distance modulus according the to presented cosmological model
		for i in range(k):

			cosmo_mu[i] = 5*np.log10(cosmo.luminosity_distance(z[i]))+25
			jac[i] = ((1+z[i])/cosmo.Hubble(z[i]))+(cosmo.luminosity_distance(z[i])/(1+z[i]))

		# compute the difference between distance modulus from the cosmological model and the local distance ladder
		residuals = np.zeros(k)
		residuals = self.hubble_mu - cosmo_mu

		cov = np.diag(dm**2+(jac*dz)**2)

		systematic = np.ones((k,k))*dMsn**2

		cov = cov + systematic

		cov = la.cholesky(cov, lower=True, overwrite_a=True)

		residuals = la.solve_triangular(cov,residuals, lower=True, check_finite=False)

		chi2 = (residuals**2).sum()

		lkl = -0.5*chi2

		return lkl