#!/usr/local/bin/python3

import math
import numpy as np

# get prime factors unduplicatedly, optimized
def getPrimes( num ):
    pset = set()
    if 0 == num % 2:
        pset.add(2)
    for i in range(3, num+1, 2):
        if 0 == num % i:
            isprime = True
            for j in range(3, int(math.sqrt(i))+1, 2):
                if 0 == i % j and i != j:
                    isprime = False
                    break
            if isprime:
                pset.add(i)
    if len(pset) == 0:
        pset.add(num)
    return pset

# get prime factor lists, optimized: sorted by set length
def getPrimesLists( start, end ):
    plist = list()
    for i in range(start, end+1):
        plist.append(getPrimes(i))
    plist.sort(key=lambda ps:len(ps))
    return plist

# find frequent itemsets, to be optimized: implemented in multi-round map-reduce
def findFrequentItemsets( buckets, candset, cursize, thrd ):
    # print(len(buckets), len(candset), cursize, thrd)
    filist = list()
    newcandset = list()
    # count frequent item sets in current loop
    for itemset in buckets:
        if len(itemset) == cursize:
            maybe = False
            if len(candset) == 0:
                maybe = True
            else:
                for cand in candset:
                    if set(cand).issubset(set(itemset)):
                        maybe = True
            if maybe:
                count = 0
                for bucket in buckets:
                    if set(itemset).issubset(set(bucket)):
                        count += 1
                        if count >= thrd:
                            existed = False
                            for check in filist:
                                if itemset == check:
                                    existed = True
                                    break
                            if not existed:
                                filist.append(itemset)
                            break
    # construct candidate item sets for next loop
    # print(filist)
    for i in range(len(filist)-1):
        for j in range(i+1, len(filist)):
            cand = list(set(filist[i]).union(set(filist[j])))
            if len(cand) == cursize+1:
                existed = False
                for check in newcandset:
                    if cand == check:
                        existed = True
                        break
                if not existed:
                    newcandset.append(cand)
    if len(newcandset) == 0:
        return filist
    # next loop
    filist.extend(findFrequentItemsets( buckets, newcandset, cursize+1, thrd ))
    # return current result
    return filist

# sort frequent itemsets list & output
def sortFISandOutput( filist, outputfile ):
    outlist = list()
    dtype = list()
    order = list()
    for i in filist:
        outlist.append(tuple(sorted(list(i))))
    print(outlist)
    maxfield = len(outlist[len(outlist)-1])
    for i in range(1, maxfield+1):
        dtype.append((str(i), int))
        order.append(str(i))
    # print(dtype, order)
    outlist = np.array(outlist, dtype = dtype)
    outlist.sort(order = order)
    with open(outputfile, 'w') as f:
        for out in outlist:
            # print(out)
            for i in out:
                f.write("%2d\t" % i)
            f.write("\n")
    return 0

if __name__ == "__main__":
    start = 2
    end = 10000
    dimstart = 3
    threshold = 50
    outputfile = './B.txt'
    buckets = getPrimesLists(start, end)
    sortFISandOutput( findFrequentItemsets(buckets, [], dimstart, threshold), outputfile)
    # print( findFrequentItemsets(buckets, set([]), dimstart, threshold))


import numpy as np
import h5py

# Normalized between 0-1
def rescale(rmat):
    min_x = np.min(rmat)
    max_min_x = np.max(rmat) - min_x
    norm_rmat = (rmat - min_x)/ max_min_x
    return norm_rmat

# Shifting to non-negative by adding the minimum number
def shifting_min(rmat):
    min_x = np.min(rmat)*-1
    norm_rmat = rmat + min_x
    return norm_rmat

# Z-score
def z_score(rmat):
    mean_x = np.mean(rmat)
    std_x = np.std(rmat)
    norm_rmat = (rmat - mean_x)/std_x
    return norm_rmat

# Variance
def variance_neuron_rank(input):
    rank = []
    for i in range(input.shape[0]):
        slice_neuron = input[i]
        unfold_slice_neuron = slice_neuron.flatten()
        var = np.var(unfold_slice_neuron)
        mean = np.average(unfold_slice_neuron)
        rank.append((i, var, mean))
    rank = np.array(sorted(rank, reverse=True, key=lambda pair: pair[1]))
    return rank

# Coefficient of variation
def std_mean_neuron_rank(input):
    rank = []
    for i in range(input.shape[0]):
        slice_neuron = input[i]
        unfold_slice_neuron = slice_neuron.flatten()
        std = np.std(unfold_slice_neuron)
        mean = np.average(unfold_slice_neuron)
        rank.append((i, std/mean))
    rank = np.array(sorted(rank, reverse=True, key=lambda pair: pair[1]))
    return rank

# Signal to noise ratio
def signal_to_noise_ratio(rmat, marking):
    snr_list = []
    for i in range(rmat.shape[0]):
        signals = []
        for j in range(4):  # 4 condition stimuli
            marks = np.where(marking == j+1)[0]
            values = rmat[i,:,marks[0]:marks[-1]+1] # At ith neuron, all timesample, at marking trial
            timesample_mean = np.mean(values, axis=1) # Compute mean of each timesample (17,)
            signals.append(timesample_mean)
        signals_var = np.var(signals)
        total_var = np.var(rmat[i])
        snr = signals_var/total_var # signal/noise
        snr_list.append([i, snr])
    rank = np.array(sorted(snr_list, reverse=True, key=lambda pair: pair[1]))
    return rank

# Limit variance with IQR
def IQR(rank):
    Q1 = np.percentile(rank[:,1], 25)
    Q3 = np.percentile(rank[:,1], 75)
    IQR = Q3 - Q1
    min_iqr = Q1 - (1.5 * IQR)
    max_iqr = Q3 + (1.5 * IQR)
    print(f'Q1 = {Q1} Q3={Q3}, min_iqr = {min_iqr}, max_iqr = {max_iqr}, iqr = {IQR}')

    outlier_mask = np.where((rank[:,1] > max_iqr) | (rank[:,1] < min_iqr), True, False)
    outlier_mask_lower = np.where(rank[:,1] < min_iqr, True, False)
    outlier_mask_upper = np.where(rank[:,1] > max_iqr, True, False)

    outlier_neuron_no = rank[outlier_mask]
    outlier_per = f'Overall outlier percentage: {(np.sum(outlier_mask)/len(rank))*100:.3f}% Upper IQR outlier: {(np.sum(outlier_mask_upper)/len(rank))*100:.3f}% Lower IQR outlier: {(np.sum(outlier_mask_lower)/len(rank))*100:.3f}%'
    print('Outlier percentage:', outlier_per)
    return outlier_neuron_no[:,0]

def lower_boundary_threshold(rank, percentage=0.2):
    rank_upper, rank_lower = np.split(rank,[int((1 - (percentage/100)) * rank.shape[0])])
    return rank_lower[:,0]

def order_by_trial(rmat_act, olfactory_path, visual_path, masked_trial_no):
    f_olfactory = h5py.File(olfactory_path, 'r') # olfactory trial sequences
    f_visual = h5py.File(visual_path, 'r') # visual trial sequences

    olfactory = f_olfactory[list(f_olfactory.keys())[-1]]
    ref = [olfactory[0,0], olfactory[1,0]]
    olfactory_vertical = np.array(f_olfactory[ref[0]]).squeeze() # matlab file conversion swap col/row
    olfactory_angled = np.array(f_olfactory[ref[1]]).squeeze()

    visual = f_visual[list(f_visual.keys())[-1]]
    ref = [visual[0,0], visual[1,0]]
    visual_vertical = np.array(f_visual[ref[0]]).squeeze()
    visual_angled = np.array(f_visual[ref[1]]).squeeze()

    stimuli_mark = np.concatenate((np.ones(len(visual_vertical)), np.ones(len(olfactory_vertical))*2, np.ones(len(visual_angled))*3, np.ones(len(olfactory_angled))*4))
    seq_trial = np.concatenate((visual_vertical, olfactory_vertical, visual_angled, olfactory_angled))
    # mask out the nan
    seq_trial = seq_trial[masked_trial_no]
    stimuli_mark = stimuli_mark[masked_trial_no]
    # init index
    index_seq_trial = np.arange(len(seq_trial))
    # Sort by seq w/o nan
    sorted_index_seq_trial = np.array([x for y, x in sorted(zip(seq_trial, index_seq_trial),key=lambda pair: pair[0])])
    sorted_stimuli_mark = np.array([x for y, x in sorted(zip(seq_trial, stimuli_mark), key=lambda pair: pair[0])])

    return sorted_index_seq_trial, sorted_stimuli_mark, stimuli_mark

# Loop to find which trial include nan and return the trial no. with nan
def find_nan_trial(rmat_act):
    counter = []
    trial_no = []
    for i in range(rmat_act.shape[2]):
        if np.isnan(np.min(rmat_act[:,:,i])):
            counter.append((i,np.count_nonzero(np.isnan(rmat_act[:,:,i]))))
            trial_no.append(i)
    return counter, trial_no # return the trial no. with nan


# import dependencies
import numpy as np
import pandas as pd
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier as KNN

def generate_data(n_samples, tst_frac=0.2, val_frac=0.2):
    # Generate a non-linear data set
    X, y = make_moons(n_samples=n_samples, noise=0.25, random_state=42)

    # Take a small subset of the data and make it VERY noisy; that is, generate outliers
    m = 30
    np.random.seed(30) # Deliberately use a different seed
    ind = np.random.permutation(n_samples)[:m]
    X[ind, :] += np.random.multivariate_normal([0, 0], np.eye(2), (m, ))
    y[ind] = 1 - y[ind]

    # Plot this data
    cmap = ListedColormap(['#b30065', '#178000'])
    plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap, edgecolors='k')

    # First, we use train_test_split to partition (X, y) into training and test sets
    X_trn, X_tst, y_trn, y_tst = train_test_split(X, y, test_size=tst_frac,
                                                random_state=42)
    # Next, we use train_test_split to further partition (X_trn, y_trn) into tra ining and validation sets
    X_trn, X_val, y_trn, y_val = train_test_split(X_trn, y_trn, test_size=val_frac, random_state=42)
    return (X_trn, y_trn), (X_val, y_val), (X_tst, y_tst)

def main(args):
    # generate data
    n_samples = 300
    (X_trn, y_trn), (X_val, y_val), (X_tst, y_tst) = generate_data(n_samples)

    # effect of regularization parameter, C
    print('Effect of regularization parameter, C')
    C_range = np.arange(-3.0, 6.0, 1.0)
    C_values = np.power(10.0, C_range)
    models, trnErr, valErr = dict(), dict(), dict()
    for C in C_values:
        models[C] = SVC(C = C, kernel = 'rbf', gamma = 'scale')
        models[C].fit(X_trn, y_trn)
    max_score = 0
    best_model = None
    for C in C_values:
        # compute training and validation errors
        # training
        score = models[C].score(X_trn, y_trn)
        trnErr[str(models[C])] = score
        # validation
        score = models[C].score(X_val, y_val)
        valErr[str(models[C])] = score
        print("Score of {} = {}".format(models[C], score))
        if score > max_score:
            best_model = models[C]
            max_score = score
    print("The best model is {}".format(best_model))
    print("Accuracy of the best model {} is {}".format(best_model, best_model.score(X_tst, y_tst)))
    print()

    # effect of the RBF kernel parameter, y
    # Learn support vector classifiers with a radial-basis function kernel with # fixed C = 10.0 and different values of gamma
    print("Effect of the RBF kernal parameter, y")
    gamma_range = np.arange(-2.0, 4.0, 1.0)
    gamma_values = np.power(10.0, gamma_range)
    models = dict()
    trnErr = dict()
    valErr = dict()
    for G in gamma_values:
        models[G] = SVC(C = 10.0, kernel = 'rbf', gamma = G)
        models[G].fit(X_trn, y_trn)

    max_score = 0
    best_model = None
    for G in gamma_values:
        # compute training and validation errors
        # training
        score = models[G].score(X_trn, y_trn)
        trnErr[str(models[G])] = score
        # validation
        score = models[G].score(X_val, y_val)
        valErr[str(models[G])] = score
        print("Score of {} = {}".format(models[G], score))
        if score > max_score:
            best_model = models[G]
            max_score = score
    print("The best model is {}".format(best_model))
    print("Accuracy of the best model {} is {}".format(best_model, best_model.score(X_tst, y_tst)))
    print()

    # breast cancer diagnosis with SVM
    print("Breast Cancer Diagnosis with Support Vector Machine")
    # load data
    train_set = pd.read_csv('./wdbc_trn.csv', names = ['label'] + list(range(30)))
    val_set = pd.read_csv('./wdbc_val.csv', names = ['label'] + list(range(30)))
    tst_set = pd.read_csv('./wdbc_tst.csv', names = ['label'] + list(range(30)))
    # select model
    trnErr = []
    valErr = []
    models = dict()
    gamma_range = np.arange(-3.0, 3.0, 1.0)
    gamma_values = np.power(10.0, gamma_range)
    C_range = np.arange(-2.0, 5.0, 1.0)
    C_values = np.power(10.0, C_range)

    # training
    for C in C_values:
        trnErr.append([])
        for gamma in gamma_values:
            features, label = train_set[list(range(30))], train_set['label']
            svc = SVC(C = C, kernel = 'rbf', gamma = gamma)
            svc.fit(features, label)
            trnErr[-1].append(svc.score(features, label))
            models[str('C:{}_gamma:{}'.format(C, gamma))] = svc

    # validation
    max_score = 0
    best_model = None
    for C in C_values:
        valErr.append([])
        for gamma in gamma_values:
            features, label = val_set[list(range(30))], val_set['label']
            valErr[-1].append(models[str('C:{}_gamma:{}'.format(C, gamma))].score(features, label))
            if valErr[-1][-1] > max_score:
                max_scoree = valErr[-1]
                best_model = models[str('C:{}_gamma:{}'.format(C, gamma))]

    print("The best model is {}".format(best_model))

    # print training and validation errors
    # print training and validation errors
    trnErrArr = np.array(trnErr)
    valErrArr = np.array(valErr)

    # to dataframe
    trnErrArr = pd.DataFrame(data = trnErrArr,
                         columns = ['G={}'.format(x) for x in gamma_values],
                         index = ['C={}'.format(x) for x in C_values])

    valErrArr = pd.DataFrame(data = valErrArr,
                         columns = ['G={}'.format(x) for x in gamma_values],
                         index = ['C={}'.format(x) for x in C_values])
    print("Training Errors of SVM over various C and gamma values")
    print(trnErrArr)
    print()
    print("Validation Errors of SVM over various C and gamma values")
    print(valErrArr)

    features, label = tst_set[list(range(30))], tst_set['label']
    print("Test accuracy of the best model {} is {}".format(best_model, best_model.score(features, label)))
    print()

    # breast cancer diagnosis with k-nearest-neighbors
    k_values = [1, 5, 11, 15, 21]

    trnErr = []
    valErr = []
    models = dict()
    # training
    for k in k_values:
        features, label = train_set[list(range(30))], train_set['label']
        models[k] = KNN(n_neighbors = k, algorithm = 'kd_tree')
        models[k].fit(features, label)
        trnErr.append(models[k].score(features, label))
    # validation
    max_score = 0
    best_model = None
    best_k = 0
    for k in k_values:
        features, label = val_set[list(range(30))], val_set['label']
        valErr.append(models[k].score(features, label))
        if valErr[-1] > max_score:
            max_score = valErr[-1]
            best_model = models[k]
            best_k = k
    print("The best model is {} with k= {}".format(best_model, best_k))
    features, label = tst_set[list(range(30))], tst_set['label']
    print("Test accuracy of the best model {} with k = {} is {}".format(best_model, best_k, best_model.score(features, label)))

    return None

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


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

def anal_sol(H_plot, radius=10, velocity=20e3, density=3000, strength=10e5, angle=45,
               init_altitude=100e3, radians=False):
    '''
    Solves analytical solution for meteroid impact

    Parameters
    ----------

    radius : float
        The radius of the asteroid in meters

    velocity : float
        The entery speed of the asteroid in meters/second

    density : float
        The density of the asteroid in kg/m^3

    strength : float
        The strength of the asteroid (i.e., the ram pressure above which
        fragmentation and spreading occurs) in N/m^2 (Pa)

    angle : float
            The initial trajectory angle of the asteroid to the horizontal
            By default, input is in degrees. If 'radians' is set to True, the
            input should be in radians

    init_altitude : float, optional
        Initial altitude in m

    radians : logical, optional
        Whether angles should be given in degrees or radians. Default=False
        Angles returned in the DataFrame will have the same units as the
        input

    Returns
    -------
    Result : DataFrame
            pandas dataFrame with collumns:
            altitude, velocity, dedz

    '''
    # define constants
    Cd = 1 # drag coefficient
    H = 8000 # atomspheric consatnt
    rho = 1.2 # air density at the ground

    # define initial conditions

    m = 4/3 * np.pi * radius**3 * density # mass, asteroid to be assumed as spheric shape
    A = np.pi * radius**2 # cross-sectional area

    if radians is False: # converts degrees to radians
        angle = angle * (np.pi)/180

    # constant in analytical solution
    c = velocity/(np.exp((-Cd * A * rho * H / (2 * m * np.sin(angle))) * np.exp(-init_altitude/H)))

    def v_h(h):
        return c * np.exp((-Cd * A * rho * H / (2 * m * np.sin(angle))) * np.exp(-h/H))

    C2 = -Cd * A * rho * H / (2 * m * np.sin(angle))

    def dEdz(z):
        return c * np.exp(C2 * np.exp(-z/H)) * C2 * np.exp(-z/H) * (-1/H) * m * v_h(z)

    #H_plot = np.linspace(100000, 0, 200)
    v_plot = v_h(H_plot)

    dedz = np.zeros((len(v_plot),)) # create array to store dedz results
    dedz[0] = 0 # initial dedz
    for i in range(1,len(v_plot)): # loop through all rows of result
            energy = ((1/2 * m * v_plot[i]**2) - (1/2 * m * v_plot[i-1]**2))/4.184e12
            alt = (H_plot[i] - H_plot[i-1])/1e3
            dedz[i] = energy / alt
    #dEdz_plot = dedz(H_plot)

    result = pd.DataFrame({'altitude':H_plot, 'velocity':v_plot, 'dedz':dedz})
    #result = result.sort_values(by='altitude', ascending=False)

    return result


import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn')

def u(tau, V, t):
	"""
	membrane potential as a function of time
	"""

	return V*(1-np.exp(-t/tau))

def T(tau, theta, V):
	"""
	the time between consecutive spikes
	"""

	return tau*np.log(V/(V-theta))

def adjusted_u(tau, theta, V, t):
	"""
	membrane potential adjusted for threshold
	"""

	if V > theta:
		period = T(tau, theta, V)
		adjusted_t = t - (t/period).astype(int)*period
		return u(tau, V, adjusted_t)
	else:
		return u(tau, V, t)

Theta = [15, 20, 25]		# mV
Tau = [8, 10]				# ms
V = [30, 35]				# mV

Theta, Tau, V = np.meshgrid(Theta, Tau, V)
Theta = Theta.flatten()
Tau = Tau.flatten()
V = V.flatten()

plt.figure(figsize = (24,15))
plt.suptitle('(b) Membrane potential as a function of time')

for i in range(12):

	theta, tau, v = Theta[i], Tau[i], V[i]

	Time = np.arange(0, 3.5*T(tau, theta, v), .05)

	# plot setup
	plt.subplot(3, 4, i+1)
	plt.title(f'$\\theta$ = {theta} mV, $\\tau_m$ = {tau} ms, $V_i$ = {v} mV')
	plt.xlabel('Time $t$ (ms)')
	plt.ylabel('Membrane potential $u$ (mV)')

	# plot
	plt.plot(Time, adjusted_u(tau, theta, v, Time), color = 'g')

plt.savefig('P2b.jpg')


import numpy as np

def get_orbit(initial_pt,a=0.1,alpha=3.1,iters=100):
    '''
    Gets the orbit of a given point fixing alpha and a of the function
    f(a,alpha,x) = x - a*sin(2pi*x)+alpha
    Inputs:
    initial_pt: A float of the initial point
    a: A float fixing the value of a
    alpha: A float fixing the value of alpha
    iters: An integer counting the number of times we want to iterate this map

    Returns:
    orbit_list: A list of floats each float coressponding to an iterate of the map
    '''
    orbit_lst = [initial_pt]
    new_pt = initial_pt
    for i in range(iters):
        new_pt = new_pt-a*np.sin(2*np.pi*new_pt)+alpha
        new_pt = new_pt%1
        orbit_lst.append(new_pt)
    return np.array(orbit_lst)

def fixed_noise_otbit(initial_pt,a=0.1,alpha=None):
    '''
    Gets the orbit of two points under some fixed vector of noise realisations alpha
    with the same function as the get_orbit function except alpha changes at each iterate
    Inputs:
    initial_pt: : A float of the initial point
    a: A float fixing the value of a
    alpha: A nx1 numpy array of noise realisations
    Returns:
    orbit_list: A list of floats each float coressponding to an iterate of the map
    '''
    orbit_lst = [initial_pt]
    new_pt = initial_pt
    iters = len(alpha)
    for i in range(iters):
        new_pt = new_pt-a*np.sin(2*np.pi*new_pt)+alpha[i]
        new_pt = new_pt%1
        orbit_lst.append(new_pt)
    return np.array(orbit_lst)


import numpy as np
from sklearn.datasets import make_regression
import matplotlib.pyplot as plt

class LinearRegression:
    W = None
    Ws = []
    training_errors = []

    def init_weights(self, n_features):
        limit = 1 / np.sqrt(n_features)
        self.W = np.random.uniform(-limit, limit, (n_features, ))

    def fit(self, X, y, n_iterations=100, learning_rate=0.01):
        X = np.insert(X, 0, 1, axis=1)
        self.training_errors = []

        self.init_weights(X.shape[1])

        # do gradient descent for n_iterations
        for i in range(n_iterations):
            y_pred = X.dot(self.W)

            # calculate l2 loss
            mse = np.mean(0.5 * (y - y_pred)**2)
            self.training_errors.append(mse)
            self.Ws.append(self.W.tolist())

            # gradient of l2 loss wrt w
            grad_W = -(y - y_pred).dot(X)

            # update weights
            self.W -= learning_rate * grad_W

    def predict(self, X):
        X = np.insert(X, 0, 1, axis=1)
        y_pred = X.dot(self.W)
        return y_pred

def loss_fn(W, X, y):
    return np.mean(0.5 * (y - X.dot(W))**2)

bias = 10
X, y, coef = make_regression(n_samples=100, n_features=1, noise=30, bias=bias, coef=True)

lc = LinearRegression()
lc.fit(X, y)

print(f'true linear model: {bias} + {coef}*x')
print(f'learned linear model: {lc.W[0]} + {lc.W[1]}*x')

# plot loss surface
# https://jakevdp.github.io/PythonDataScienceHandbook/04.12-three-dimensional-plotting.html
sz = max(np.abs(bias), np.abs(coef))
w1 = np.linspace(bias-2*sz, bias+2*sz, 30)
w2 = np.linspace(coef-2*sz, coef+2*sz, 30)
W1, W2 = np.meshgrid(w1, w2)
WW = np.meshgrid(w1, w2)
XX = np.insert(X, 0, 1, axis=1)

z = np.mean((y[:,np.newaxis] - XX.dot(np.stack(WW).reshape(2,30*30)))**2, axis=0).reshape(30,30)

fig = plt.figure(figsize=(8,8))
ax = plt.axes(projection="3d")
ax.plot_surface(W1, W2, z, rstride=1, cstride=1, cmap='terrain', edgecolor=None, alpha=0.7)
ax.plot(np.array(lc.Ws)[:,0], np.array(lc.Ws)[:,1], np.zeros_like(np.array(lc.Ws)).shape[0])
plt.show()

# plot loss surface and proxy loss surface
XX2 = XX[:2]
y2 = y[:2]
z2 = np.mean((y2[:,np.newaxis] - XX2.dot(np.stack(WW).reshape(2,30*30)))**2, axis=0).reshape(30,30)

fig = plt.figure(figsize=(8,8))
ax = plt.axes(projection="3d")
ax.plot_surface(W1, W2, z, rstride=1, cstride=1, cmap='terrain', edgecolor=None, alpha=0.7)
ax.plot_surface(W1, W2, z2, rstride=1, cstride=1, cmap='viridis', edgecolor=None, alpha=0.7)
plt.show()

print('min of true function',np.unravel_index(z.argmin(), z.shape))
print('min of proxy function', np.unravel_index(z2.argmin(), z2.shape))


import numpy as np
import networkx as nx

def whits(G, normalized=True, weight=None):
    """Returns HITS hubs and authorities values for nodes.

    The HITS algorithm computes two numbers for a node.
    Authorities estimates the node value based on the incoming links.
    Hubs estimates the node value based on outgoing links.

    Parameters
    ----------
    G : graph
      A NetworkX graph

    normalized : bool (default=True)
       Normalize results by the sum of all of the values.

    Returns
    -------
    (hubs,authorities) : two-tuple of dictionaries
       Two dictionaries keyed by node containing the hub and authority
       values.

    Examples
    --------
    >>> G = nx.path_graph(4)

    The `hubs` and `authorities` are given by the eigenvectors corresponding to the
    maximum eigenvalues of the hubs_matrix and the authority_matrix, respectively.

    The ``hubs`` and ``authority`` matrices are computed from the adjancency
    matrix:

    >>> adj_ary = nx.to_numpy_array(G)
    >>> hubs_matrix = adj_ary @ adj_ary.T
    >>> authority_matrix = adj_ary.T @ adj_ary

    `whits` maps the eigenvector corresponding to the maximum eigenvalue
    of the respective matrices to the nodes in `G`:

    >>> hubs, authority = whits(G)

    Notes
    -----
    The eigenvector calculation uses NumPy's interface to LAPACK.

    The HITS algorithm was designed for directed graphs but this
    algorithm does not check if the input graph is directed and will
    execute on undirected graphs.

    References
    ----------
    .. [1] A. Langville and C. Meyer,
       "A survey of eigenvector methods of web information retrieval."
       http://citeseer.ist.psu.edu/713792.html
    .. [2] Jon Kleinberg,
       Authoritative sources in a hyperlinked environment
       Journal of the ACM 46 (5): 604-32, 1999.
       doi:10.1145/324133.324140.
       http://www.cs.cornell.edu/home/kleinber/auth.pdf.
    """

    if len(G) == 0:
        return {}, {}
    adj_ary = nx.to_numpy_array(G, weight=weight)
    # Hub matrix
    H = adj_ary @ adj_ary.T
    e, ev = np.linalg.eig(H)
    # eigenvector corresponding to the maximum eigenvalue
    h = ev[:, np.argmax(e)]
    # Authority matrix
    A = adj_ary.T @ adj_ary
    e, ev = np.linalg.eig(A)
    # eigenvector corresponding to the maximum eigenvalue
    a = ev[:, np.argmax(e)]
    if normalized:
        h = h / h.sum()
        a = a / a.sum()
    else:
        h = h / h.max()
        a = a / a.max()
    hubs = dict(zip(G, map(float, h)))
    authorities = dict(zip(G, map(float, a)))
    return hubs, authorities


"""
Ankit Khandelwal
15863
Exercise 8
"""

import matplotlib.pyplot as plt
import numpy as np

x_values = np.linspace(0, 1, 101)
y = []

for i in x_values:
    y.append(924 * i ** 6 - 2772 * i ** 5 + 3150 * i ** 4 - 1680 * i ** 3 + 420 * i ** 2 - 42 * i + 1)
plt.plot(x_values, y)
plt.grid()

A = [0.0, 0.2, 0.4, 0.6, 0.8, 1.0]

def der(x):
    h = 0.001
    return (fx(x + h) - fx(x)) / h

def fx(x):
    return 924 * x ** 6 - 2772 * x ** 5 + 3150 * x ** 4 - 1680 * x ** 3 + 420 * x ** 2 - 42 * x + 1

X = []

for guess in A:
    while abs(fx(guess)) > 10 ** -11:
        guess = guess - fx(guess) / der(guess)
    X.append(guess)
print('The solutions are: ', X)

for i in X:
    plt.scatter(i, 0)
plt.xlabel('X')
plt.ylabel('f(x)')
plt.show()

Ankit Khandelwal_HW3/Exercise 8/exercise 8.py


# -*- coding: utf-8 -*-
"""
Ejercicios 3 y 4: Cálculo del polinomio de aproximación (caso continuo).
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate
np.set_printoptions(precision = 2)   # solo dos decimales
np.set_printoptions(suppress = True) # no usar notación exponencial

#-----------------------------------------------------------------------------
# Ejercicio 3
#-----------------------------------------------------------------------------
f = lambda x : np.cos(x)

# Construimos la matriz A del sistema y el vector b de términos independientes
g = 2                               # grado del polinomio
A = np.zeros((g + 1,g + 1)) # matriz de coeficientes
b = np.zeros(g + 1)             # término independiente
for i in range(g + 1):          # recorremos las filas de A
    for j in range(g + 1):      # recorremos las columnas de A
        integrando_A = lambda x : x**(i+j) # tenemos que integrar x**(i+j)
        # integrate.quad devuelve la integral y una cota del error (dos coordenadas)
        A[i,j] = integrate.quad(integrando_A,-1,1)[0] # tomamos sólo el valor de la integral (coordenada 0)
    # Para el término independiente b
    integrando_b = lambda x : (x**i)*f(x) # tenemos que integrar x*i * f(x)
    b[i] = integrate.quad(integrando_b,-1,1)[0]  # tomamos sólo el valor de la integral (coordenada 0)

print('Matriz del sistema =\n', A)    # mostramos la matriz A
print('Término independiente =', b)   # mostramos el vector b

# Resolvemos el sistema
p = np.linalg.solve(A, b)
# Reordenamos los coeficientes del polinomio p
# para que parezcan de mayor a menor potencia de x
p = p[::-1]
print('Coeficientes del polinomio p =', p)

# Para hacer la representación gráfica del polinomio
plt.close('all')

xx = np.linspace(-1,1)   # para hacer la gráfica del polinomio p en [-1,1]
yy = np.polyval(p,xx)   # evaluamos p en xx

plt.figure()
plt.plot(xx,f(xx),'red',label = 'exacta')  # dibujamos la función cos x (en rojo)
plt.plot(xx,yy, label = 'aproximada')  # dibujamos el polinomio
plt.grid()
plt.legend()
plt.show()

# Calculamos el error relativo
error_rel = np.linalg.norm(f(xx) - yy)/np.linalg.norm(f(xx))
print('Error relativo = ', error_rel)

#-------------------------------------------------------------------------------------
# Ejercicio 4 (se resuelve como en el caso anterior pero con los datos del ejercicio 4)
#-------------------------------------------------------------------------------------

f = lambda x : np.cos(np.arctan(x)) - np.exp(x**2)*np.log(x+2)

# Construimos la matriz A del sistema y el vector b de términos independientes
g = 4             # grado del polinomio
A = np.zeros((g + 1,g + 1))             # matriz de coeficientes
b = np.zeros(g + 1)            # término independiente

for i in range(g + 1):          # recorremos las filas de A
    for j in range(g + 1):      # recorremos las columnas de A
        integrando_A = lambda x : x**(i+j) # tenemos que integrar x**(i+j)
        # integrate.quad devuelve la integral y una cota del error (dos coordenadas)
        A[i,j] = integrate.quad(integrando_A,-1,1)[0] # tomamos sólo el valor de la integral (coordenada 0)
    # Para el término independiente b
    integrando_b = lambda x : (x**i)*f(x) # tenemos que integrar x*i * f(x)
    b[i] = integrate.quad(integrando_b,-1,1)[0]  # tomamos sólo el valor de la integral (coordenada 0)

print('Matriz del sistema =\n', A)    # mostramos la matriz A
print('Término independiente =', b)   # mostramos el vector b

# Resolvemos el sistema
p = np.linalg.solve(A, b)
# Reordenamos los coeficientes del polinomio p
# para que parezcan de mayor a menor potencia de x
p = p[::-1]
print('Coeficientes del polinomio p =', p)

# Para hacer la representación gráfica del polinomio
plt.close('all')

xx = np.linspace(-1,1)   # para hacer la gráfica del polinomio p en [-1,1]
yy = np.polyval(p,xx)   # evaluamos p en xx

plt.figure()
plt.plot(xx,f(xx),'red',label = 'exacta')  # dibujamos la función cos x (en rojo)
plt.plot(xx,yy, label = 'aproximada')  # dibujamos el polinomio
plt.grid()
plt.legend()
plt.show()

# Calculamos el error relativo
error_rel = np.linalg.norm(f(xx) - yy)/np.linalg.norm(f(xx))
print('Error relativo = ', error_rel)


import numpy as np

class BaseRegression:

    def __init__(self, dataset):
        self.dataset = dataset

        # Use last column as a output. Others are input.
        self.inputs = self.dataset[..., :-1]
        self.outputs = self.dataset[..., -1:]

        # Store len of training sets and count of features.
        self.len_dataset, self.features_count = self.inputs.shape

        # Create randomized weight vector.
        self.weights = np.random.uniform(0, 1, self.features_count + 1)

        # Epoch of training.
        self.epoch = 1

        # Some prepared matrix/vectors for future usage:
        # - Matrix of input data with 1 as a first value: Use in prediction of training inputs and gradient.
        self.input_vectors = np.concatenate([np.ones((self.len_dataset, 1)), self.inputs], axis=1)
        # - Tranposed input vectors: used in gradient and normal equation
        self.trans_input = np.transpose(self.input_vectors)
        # - Flatten output: use in error.
        self.output_vector = self.outputs.flatten()
        # - Clone output vector to matrix with len(weights) rows
        self.cloned_output = np.tile(self.output_vector, (len(self.weights), 1))

    def hypothesis(self, vector):
        raise NotImplemented

    def calculate(self, vector):
        # proxy method for hypothesis.
        return self.hypothesis(vector)

    @property
    def error(self):
        raise NotImplemented

    def normal_equation(self):
        raise NotImplemented

    @property
    def accuracy(self):
        # Calculate accuracy based on error function.
        return round(100.00 - self.error * 100.00, 4)

    @property
    def predicted(self):
        # Calculate training set with weight vector.
        return np.array([self.hypothesis(x) for x in self.inputs])

    @property
    def cloned_predicted(self):
        # Clone predicted vector to matrix with len(weights) rows
        return np.tile(self.predicted, (len(self.weights), 1))

    @property
    def regularization(self, delta=0.1):
        return (delta / self.len_dataset) * np.power(self.weights, 2).sum()

    def gradient(self, speed):
        # Gradient Descent iteration function.
        permit = speed / self.len_dataset
        self.weights -= ((self.cloned_predicted - self.cloned_output) * self.trans_input).sum(axis=1) * permit
        self.epoch += 1

    def train_gradient(self, timeout=3000):
        # Gradient Descent method with automation decreasing speed rate.
        speed = 0.1
        iteration = 0
        latest_error = 1
        while iteration <= timeout:
            error = self.error
            if -0.0001 < error < 0.0001:
                break
            if error > latest_error:
                speed = speed * 0.5
            self.gradient(speed)

            latest_error = error
            iteration += 1

    def show_info(self, show_predicted_vs_output=False):
        predicted_vs_putput = ""
        if show_predicted_vs_output:
            predicted_vs_putput = [f"{p} - {o}\n" for p, o in zip(self.predicted, self.output_vector)]

        print(f"========== {self.__class__.__name__} ========= \n"
              f"Count of Features: {self.features_count} | Len of Dataset: {self.len_dataset} | Epoch: {self.epoch} \n"
              f"Weights: {self.weights}\n"
              f"Accuracy: {self.accuracy}% | Error: {self.error}\n"
              f"{''.join(predicted_vs_putput)}"
              f"=====================================\n"
              )

class LinearRegression(BaseRegression):

    @property
    def error(self):
        # Calculate squared error of training set. Scalar value.
        return (1 / (self.len_dataset * 2)) * np.power(self.predicted - self.output_vector, 2).sum()

    def hypothesis(self, vector):
        # Calculate value of input vector based on current weight
        return np.dot(self.weights, np.concatenate([np.ones(1), vector])).sum()

    def normal_equation(self):
        # Normal Equation method
        theta = np.linalg.inv(self.trans_input.dot(self.input_vectors)).dot(self.trans_input).dot(self.outputs)
        self.weights = theta.flatten()

class LogisticRegression(BaseRegression):

    def hypothesis(self, vector):
        # Sigmoid activation of calculated values of input vector based on current weight.
        doted = np.dot(self.weights, np.concatenate([np.ones(1), vector]))
        return 1.0 / (1 + np.exp(-doted))

    @property
    def error(self):
        # Calculate error of training set. Scalar value.
        cost = -self.output_vector * np.log(self.predicted) - (1 - self.output_vector) * np.log(1 - self.predicted)
        return cost.sum() / self.len_dataset

class SVM(LogisticRegression):

    def __init__(self, dataset):
        super().__init__(dataset)
        self.weights = np.zeros(self.features_count)
        self.weights = np.random.uniform(0, 1, self.features_count)

    def hypothesis(self, vector):
        return np.dot(self.weights, vector)

    def train_gradient(self, timeout=30000):
        # Gradient Descent method with automation decreasing speed rate.
        speed = 1
        for i in range(1, timeout):
            for x, y in zip(self.inputs, self.outputs):
                if y * self.hypothesis(x) < 1:
                    self.weights = self.weights + speed * ((y * x) - (2 * (1 / timeout) * self.weights))
                else:
                    self.weights = self.weights + speed * (-2 * (1 / timeout) * self.weights)


import numpy as np
from math import sqrt
import matplotlib.pyplot as plt
from matplotlib import style
import warnings
from collections import Counter
style.use('ggplot')

#euclidean_distance = sqrt( ((plot1[0] - plot2[0])**2) + ((plot1[1] - plot2[1])**2) )

dataset = {'k': [[1,2], [2,3], [3,1]], 'r' : [[6,5], [7,7], [8,6]]}

new_features1 = [5,7]

new_features2 = [1,1]

def k_nearest_neighbors(data, predict, k=3):
	if(len(data) >= k):
		warnings.warn('K is lesser than total data group')

	distances = []

	for group in data:
		for features in data[group]:
			#euclidean_distance = np.sqrt( ((features[0] - predict[0])**2) + ((features[1] - predict[1])**2) )
			euclidean_distance = np.linalg.norm(np.array(features) - np.array(predict) )
			distances.append([euclidean_distance, group])

	votes = [i[1] for i in sorted(distances)[:k]]
	#print(Counter(votes).most_common(1))
	vote_results = Counter(votes).most_common(1)[0][0]

	return vote_results

result = k_nearest_neighbors(dataset, new_features1, k=3)

print(result)

[[plt.scatter(ii[0], ii[1], s=100, color=i) for ii in dataset[i]] for i in dataset]
plt.scatter(new_features1[0], new_features1[1], s=200, color = result)
plt.scatter(new_features2[0], new_features2[1], s=200, color = result)
result = k_nearest_neighbors(dataset, new_features2, k=3)

print(result)

plt.scatter(new_features2[0], new_features2[1], s=200, color = result)
plt.show()


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

def read_data(file_path):
    data = pd.read_csv(file_path, header=None, names=["feature"])
    data = np.array(data)
    return data

def scatter(x, y):
    pos = np.where(y == 1)[0].tolist()
    neg = np.where(y == 0)[0].tolist()
    plt.plot(x[pos, 0], x[pos, 1], '+')
    plt.plot(x[neg, 0], x[neg, 1], 'o')
    plt.show()

def sigmoid(x, w, b):
    t = x.dot(w) + b
    t = 1 + np.exp(-t)
    t = 1 / t
    return t

def compute_acc(x, y, w, b):
    pre = sigmoid(x, w, b)
    pre = np.where(pre>0.5, 1, 0)
    res = pre == y
    acc = np.sum(res == True)
    return acc/len(x)

def GD(x, y, w, b, l_rate, epoches):
    loss = []
    for epoch in range(epoches):
        dl_db = (y - sigmoid(x, w, b))
        dl_dw = dl_db * x
        dl_db = np.mean(dl_db)
        dl_dw = np.mean(dl_dw, axis=0)
        dl_dw = np.expand_dims(dl_dw, axis=1)
        w = w + l_rate * dl_dw
        b = b + l_rate * dl_db
        loss.append(np.sum((y - sigmoid(x, w, b))**2))
        if epoch % 10 == 0:
            print("epoch {}: w={} , b={}, loss={}".format(epoch, w, b, loss[epoch]))
    return w, b, loss

def main():
    # 数据准备
    x = read_data("./ex4x.dat")
    y = read_data("./ex4y.dat")
    t = []
    for i in range(len(x)):
        temp = x[i, 0].split()
        temp[0] = float(temp[0])
        temp[1] = float(temp[1])
        t.append(temp)
    x = np.array(t)
    y = y.astype("int16")
    # -----------------------
    w, b, loss = GD(x, y, np.random.rand(2, 1), np.random.rand(), 0.0001, 1000)

    pos = np.where(y == 1)[0].tolist()
    neg = np.where(y == 0)[0].tolist()
    plt.plot(x[pos, 0], x[pos, 1], '+')
    plt.plot(x[neg, 0], x[neg, 1], 'o')
    plt.plot(x, (-b-w[0, 0]*x[:, 0])/w[1, 0], 'r')
    plt.show()
    print(compute_acc(x, y, w, b))

if __name__ == '__main__':
    main()


import numpy as np

def cov2d(std: np.ndarray, corr: np.ndarray):
    num_classes, dim_features = std.shape
    assert dim_features == 2
    assert corr.shape == (num_classes,)

    cov = np.zeros((num_classes, dim_features, dim_features))
    for i in range(num_classes):
        cov[i] = np.diag(std[i]) @ np.array([[1, corr[i]],
                                             [corr[i], 1]]) @ np.diag(std[i])
    return cov

def gaussian_mixture(mean: np.ndarray, cov: np.ndarray, n: int, p: np.ndarray = None):
    num_classes, dim_features = mean.shape
    if p is None:
        p = np.ones(num_classes) / num_classes
    assert cov.shape == (num_classes, dim_features, dim_features)
    assert p.shape == (num_classes,)

    # components [num_points]
    z = np.random.choice(num_classes, size=n, p=p)
    # features [num_points, dim_features]
    x = mean[z] + (np.linalg.cholesky(cov)[z] @ np.random.randn(n, dim_features, 1)).squeeze()
    return x, z


import numpy as np
import scipy.stats as st
import scipy
import scipy.optimize
import warnings
import bebi103
import pandas as pd

def log_like_gamma(params, t):

    """Log likelihood for a gamma distribution with
    input being alpha and beta parameters as well as counts.

    Parameters
    ----------
    params : array of the parameters alpha and beta.
    t : array array of counts.

    Returns
    -------
    output : float
        Log-likelihood.
    """

    alpha, beta = params

    if alpha <= 0 or beta <= 0:
        return -np.inf

    return st.gamma.logpdf(t, alpha, loc=0, scale=1/beta).sum()

def gamma_mle(t):

    """
    Perform maximum likelihood estimates for parameters for
    gamma measurements, parametrized by alpha and beta.

    Parameters
    ----------
    t : array array of counts.

    Returns
    -------
    output : float
         maximum likelihood estimates for alpha and beta.
    """

    # Initial guess
    t_bar = np.mean(t)
    beta_guess = t_bar / np.var(t)
    alpha_guess = t_bar * beta_guess

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")

        res = scipy.optimize.minimize(
            lambda params, t: -log_like_gamma(params, t),
            (alpha_guess, beta_guess),
            args=(t,),
            method="powell",
        )

    if res.success:
        return res.x
    else:
        raise RuntimeError('Convergence failed with message', res.message)

def gen_gamma(params, size, rg):
	"""
	Generate samples from the gamma distribution.

		Parameters
		----------
		params: parameterized alpha and beta
		size:s number of samples that are drawn.
		rg: numpy.random.Generator instance

		Returns
		-------
		output : numpy array
			Randon samples from the parameterized gamma distribution.
	"""
	alpha, beta = params
	return rg.gamma(alpha, 1 / beta, size=size)

def gamma_bs_MLE(conc_data):

	"""
	Generate parametric bootstrap replicates of maximum likelihood estimator
	from gamma distribution using bebi103.draw_bs_reps_mle.

		Parameters
		----------
		conc_data: MLEs data used for generating parametric bootstrap replicates

		Returns
		-------
		output : numpy array
		Bootstrap replicates of MLEs.

	"""

	bs_reps = bebi103.draw_bs_reps_mle(mle_fun=gamma_mle, gen_fun=gen_gamma, data=conc_data, size=5000, n_jobs=3)

	alpha_vals = bs_reps[:,0]
	beta_vals = bs_reps[:,1]
	return [np.mean(alpha_vals), np.mean(beta_vals)], np.percentile(bs_reps, [2.5, 97.5], axis=0)

def get_gamma_conf_intervals(concentrations, dataframe, conc_column, time_column):

	"""
	generate bootstrap replicates for gamma MLE estimation of catastrophe
	data and return a dataframe with all relevant information, along
	with arrays containing confidence intervals and MLE averages.

		Parameters
		----------
		concentrations: list conaining all tubulin concentrations of
		interest
		dataframe: dataframe with catastrophe times under colunns labeled
		with tubulin concentratiosn
		conc_column: the label used for the column with tubulin conc.
		in the dataframe
		time_column: the label used for the column with catastrophe
		times in the dataframe

		Returns
		-------
		output : dataframe, array, array
		dataframe with all relevant info
		array with confidence interavls
		array with MLE estimates

	"""

	#Make lists for both the MLE values and the confidence intervals
	MLE_vals = []
	conf_ints = []

	#Loop through the different tubulin concentrations
	for conc in concentrations:

		#Grab the relevant data for each different concentration
		data = dataframe[dataframe[conc_column] == conc][time_column]

		#Convert this data into an array for ease of analysis
		array = np.array(data)

		#Use our Gamma MLE funtion to pull out both MLE values and confidence intervals for our data
		mle_val, conf_int = gamma_bs_MLE(array)

		#Add the MLE values and confidence intervals to respective lists
		MLE_vals.append(mle_val)
		conf_ints.append(conf_int)

	#Convert our MLE values to an array for ease of use
	MLE_array = np.array(MLE_vals)

	#Make a dataframe containing these values and the relevant concentrations of tubulin that correspond to the measurements
	MLE_df = pd.DataFrame(MLE_array, columns=['alpha MLE', 'beta MLE'])
	MLE_df['Tubulin Concentration (uM)'] = concentrations

	alpha_low, alpha_high, beta_low, beta_high = [], [], [], []

	#Examine each confidence interval separately
	for piece in conf_ints:

		#Grab the alphas
		alphas = piece[:,0]

		#grab the beta values
		betas = piece[:,1]

		#append the high and lower bounds into separate lists
		alpha_low.append(alphas[0])
		alpha_high.append(alphas[1])
		beta_low.append(betas[0])
		beta_high.append(betas[1])

	MLE_df['low alpha'] = alpha_low
	MLE_df['high alpha'] = alpha_high
	MLE_df['low beta'] = beta_low
	MLE_df['high beta'] = beta_high

	return MLE_df, conf_ints, MLE_array


## import packages
import numpy as np
from PIL import Image
from scipy.signal import convolve2d as conv2
import matplotlib.pyplot as plt

import gauss_module

def rgb2gray(rgb):

    r, g, b = rgb[:,:,0], rgb[:,:,1], rgb[:,:,2]
    gray = 0.2989 * r + 0.5870 * g + 0.1140 * b

    return gray

## function gauss (Question 1.a)

sigma = 4.0
[Gx, x] = gauss_module.gauss(sigma)

plt.figure(1)
plt.plot(x, Gx, '.-')
plt.show()

## function gaussianfilter (Question 1.b)

img = rgb2gray(np.array(Image.open('graf.png')))
smooth_img = gauss_module.gaussianfilter(img, sigma)

plt.figure(2)
ax1 = plt.subplot(1,2,1)
ax2 = plt.subplot(1,2,2)
plt.sca(ax1)
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.sca(ax2)
plt.imshow(smooth_img, cmap='gray', vmin=0, vmax=255)
plt.show()

## function gaussdx (Question 1.c)

sigma = 4.0
[Gx, x] = gauss_module.gauss(sigma)
[Dx, x] = gauss_module.gaussdx(sigma)

plt.figure(5)
plt.plot(x, Gx, 'b.-')
plt.plot(x, Dx, 'r-')
plt.legend( ('gauss', 'gaussdx'))
plt.show()

## function gaussdx (Question 1.d)

img_imp = np.zeros([27,27])
img_imp[13, 13] = 1.0
plt.figure(6), plt.imshow(img_imp, cmap='gray')

sigma = 7.0
[Gx, x] = gauss_module.gauss(sigma)
[Dx, x] = gauss_module.gaussdx(sigma)

Gx = Gx.reshape(1, Gx.size)
Dx = Dx.reshape(1, Dx.size)

plt.figure(7)
plt.subplot(2,3,1)
plt.imshow(conv2(conv2(img_imp, Gx, 'same'), Gx.T, 'same') , cmap='gray')
plt.subplot(2,3,2)
plt.imshow(conv2(conv2(img_imp, Gx, 'same'), Dx.T, 'same') , cmap='gray')
plt.subplot(2,3,3)
plt.imshow(conv2(conv2(img_imp, Dx.T, 'same'), Gx, 'same') , cmap='gray')
plt.subplot(2,3,4)
plt.imshow(conv2(conv2(img_imp, Dx, 'same'), Dx.T, 'same') , cmap='gray')
plt.subplot(2,3,5)
plt.imshow(conv2(conv2(img_imp, Dx, 'same'), Gx.T, 'same') , cmap='gray')
plt.subplot(2,3,6)
plt.imshow(conv2(conv2(img_imp, Gx.T, 'same'), Dx, 'same') , cmap='gray')
plt.show()

## function gaussderiv (Question 1.e)

img_c = np.array(Image.open('graf.png')).astype('double')
img = rgb2gray(img_c)
[imgDx, imgDy] = gauss_module.gaussderiv(img, 7.0)

plt.figure(8)
ax1 = plt.subplot(1,3,1)
ax2 = plt.subplot(1,3,2)
ax3 = plt.subplot(1,3,3)
plt.sca(ax1)
plt.imshow(imgDx, cmap='gray')
plt.sca(ax2)
plt.imshow(imgDy, cmap='gray')
plt.sca(ax3)
imgmag = np.sqrt(imgDx**2 + imgDy**2)
plt.imshow(imgmag, cmap='gray')
plt.show()


# -*- coding: utf-8 -*-
"""
SEIR_model.py
Created on 2020/4/8

@author: yiqing
"""

import scipy.integrate
import numpy as np

class SEIR:
    def model(data, t, N, beta, gamma, sigma):
        """
        :param data:
        :param t:
        :param N:
        :param beta:
        :param gamma:
        :param sigma:
        :return:
        """

        S, E, I, R = data

        dS_t = - (beta * S * I)/N
        dE_t = beta * S * I/N - sigma * E
        dI_t = sigma * E - gamma * I
        dR_t = gamma * I

        return [dS_t, dE_t, dI_t, dR_t]

    def solve(init_value, t, N, beta, gamma, sigma):
        """
        :param model: SEIR model
        :param init_value: S,E,I,R = population - E0, E0, 0, 0
        :param t:
        :param beta: The parameter controlling how often a susceptible-infected contact results in a new infection.
        :param gamma: The rate an infected recovers and moves into the resistant phase.
        :param sigma: The rate at which an exposed person becomes infective.
        :return:
        """

        result = scipy.integrate.odeint(SEIR.model, init_value, t, args=(N, beta, gamma, sigma))
        result = np.array(result)
        return result


import numpy as np

def l2(x1, x2):
    distance = np.mean((x1-x2)**2)

    return distance


import numpy as np
from scipy import linalg
from scipy.stats import norm, t, levy_stable, logser
from scipy.special import gamma, comb

def SimuGaussian(n, m, corrMatrix):
    """
    # Gaussian Copula simulations with a given correlation matrix
    Requires:
        n = number of variables
        m = sample size
        corrMatrix = correlation matrix
    """

    # Generate n independent standard Gaussian random variables V = (v1 ,..., vn):
    v = [np.random.normal(0,1,m) for i in range(0,n)]

    # Compute the lower triangular Cholesky factorization of the correlation matrix:
    L = linalg.cholesky(corrMatrix, lower=True)
    y = np.dot(L, v)
    u = norm.cdf(y, 0, 1 )

    return u

def SimuStudent(n, m, corrMatrix, k):
    """
    # Student Copula with k degrees of freedom and a given correlation matrix
    Requires:
        n = number of variables
        m = sample size
        corrMatrix = correlation matrix
        k = degree of freedom
    """

    # Generate n independent standard Gaussian random variables  V = (v1 ,..., vn):
    v = [np.random.normal(0,1,m) for i in range(0,n)]

    # Compute the lower triangular Cholesky factorization of rho:
    L = linalg.cholesky(corrMatrix, lower=True)
    z = np.dot(L, v)

    # generate a random variable r, following a chi2-distribution with nu degrees of freedom
    r = np.random.chisquare(df=k,size=m)

    y = np.sqrt(k/ r)*z
    u = t.cdf(y, df=k, loc=0, scale=1)

    return u

def SimuClayton(n, m, theta):
    """
    # Clayton copula
    Requires:
        n = number of variables
        m = sample size
        theta = Clayton copula parameter
    """

    # Generate n independent standard uniform random variables  V = (v1 ,..., vn):
    v = [np.random.uniform(0,1,m) for i in range(0,n)]

    # generate a random variable x following the gamma distribution gamma(theta**(-1), 1)
    X = np.array([np.random.gamma(theta**(-1), scale=1.0) for i in range(0,m)])

    phi_t = lambda t:  (1+t)**(-1/theta)

    u = [phi_t(-np.log(v[i])/X) for i in range(0,n)]

    return u

def SimuGumbel(n, m, theta):
    """
    # Gumbel copula
    Requires:
        n = number of variables to generate
        m = sample size
        theta = Gumbel copula parameter
    """

    v = [np.random.uniform(0,1,m) for i in range(0,n)]
    X = levy_stable.rvs(alpha=1/theta, beta=1,scale=(np.cos(np.pi/(2*theta)))**theta,loc=0, size=m)

    phi_t = lambda t:  np.exp(-t**(1/theta))

    u = [phi_t(-np.log(v[i])/X) for i in range(0,n)]
    return u

def SimuFrank(n, m, theta):
    """
    # Frank copula
    Requires:
        n = number of variables to generate
        m = sample size
        theta = Frank copula parameter
    """

    v = [np.random.uniform(0,1,m) for i in range(0,n)]
    p = 1-np.exp(-theta)
    X = logser.rvs(p, loc=0, size=m, random_state=None)

    phi_t = lambda t:  -np.log(1-np.exp(-t)*(1-np.exp(-theta)))/theta
    u = [phi_t(-np.log(v[i])/X) for i in range(0,n)]
    return u

def SimuSibuya(alpha, m):
    """
        Sibuya distribution Sibuya(α)
        Used for sampling F=Sibuya(α) for Joe copula
        The algorithm in given in Proposition 3.2 in Hofert (2011) "Efficiently sampling nested Archimedean copulas"
    """

    G_1 = lambda y: ((1-y)*gamma(1-alpha) )**(-1/alpha)
    F = lambda n: 1- ((-1)**n)*comb(n,alpha-1)

    X = np.random.uniform(0,1,m)

    for i in range(0,len(X)):
        if X[i] <= alpha:
            X[i] = 1

        if F(np.floor(G_1(X[i]))) < X[i]:
            X[i] = np.ceil(G_1(X[i]))
        else:
            X[i] = np.floor(G_1(X[i]))
    return X

def SimuJoe(n, m, theta):
    """
    # Joe copula
    Requires:
        n = number of variables to generate
        m = sample size
        theta = Joe copula parameter
    """

    alpha = 1/theta
    X = SimuSibuya(alpha, m)

    v = [np.random.uniform(0,1,m) for i in range(0,n)]

    phi_t = lambda t: (1-(1-np.exp(-t))**(1/theta))

    u = [phi_t(-np.log(v[i])/X) for i in range(0,n)]

    return u

def SimuAMH(n, m, theta):
    """
    # Ali-Mikhail-Haq copula
    Requires:
        n = number of variables
        m = sample size
        theta = Ali-Mikhail-Haq copula parameter
    """

    v = [np.random.uniform(0,1,m) for i in range(0,n)]

    X = np.random.geometric(p=1-theta, size=m)

    phi_t = lambda t:  (1-theta)/(np.exp(t)-theta)

    u = [phi_t(-np.log(v[i])/X) for i in range(0,n)]
    return u

from scipy.stats import bernoulli

combination = [
    {"type": "clayton", "weight": 0.33, "theta": 3},
    {"type": "student", "weight": 0.33, "corrMatrix": 1, "k": 2},
    {"type": "gumbel", "weight": 0.33, "theta": 3}
]

def SimuMx(n, m, combination):
    v = [np.random.uniform(0,1,m) for i in range(0,n)]

    weights = [comb["weight"] for comb in combination]

    #Generate m random sample of category labels
    y = np.array([np.where(ls==1)[0][0] for ls in np.random.multinomial(n=1, pvals=weights, size=m)])

    for i in range(0,len(combination)):

        combinationsize = len(v[0][y==i])
        if combination[i]["type"] == "clayton":
            theta = combination[i]["theta"]
            X = np.array([np.random.gamma(theta**(-1), scale=1.0) for i in range(0,combinationsize)])
            phi_t = lambda t:  (1+t)**(-1/theta)
            for j in range(0,len(v)):
                v[j][y==i] = phi_t(-np.log(v[j][y==i])/X)

        elif combination[i]["type"] == "gumbel":
            theta = combination[i]["theta"]
            X = levy_stable.rvs(alpha=1/theta, beta=1,scale=(np.cos(np.pi/(2*theta)))**theta,loc=0, size=combinationsize)
            phi_t = lambda t:  np.exp(-t**(1/theta))
            for j in range(0,len(v)):
                v[j][y==i] = phi_t(-np.log(v[j][y==i])/X)

        elif combination[i]["type"] == "gaussian":
            corrMatrix = combination[i]["corrMatrix"]

            v2 = np.random.uniform(0,1,combinationsize)

            L = linalg.cholesky(corrMatrix, lower=True)

            for j in range(0,len(v)):
                v[j][y==i] = np.sqrt(-2*np.log(v[j][y==i]))*np.cos(2*np.pi*v2)

            y = np.dot(L, [vk[y==i] for vk in v])
            Y = norm.cdf(y, loc=0, scale=1)

            for j in range(0,len(v)):
                v[j][y==i] = np.array(Y[j])

        elif combination[i]["type"] == "student":
            corrMatrix = combination[i]["corrMatrix"]
            k = combination[i]["k"]

            v2 = np.random.uniform(0,1,combinationsize)
            L = linalg.cholesky(corrMatrix, lower=True)
            r = np.random.chisquare(df=k,size=combinationsize)

            for j in range(0,len(v)):
                v[j][y==i] = np.sqrt(-2*np.log(v[j][y==i]))*np.cos(2*np.pi*v2)

            z = np.dot(L, [vk[y==i] for vk in v])
            Y = t.cdf(np.sqrt(k/ r)*z, df=k, loc=0, scale=1)

            for j in range(0,len(v)):
                v[j][y==i] = np.array(Y[j])

    return v