import scipy.stats as ss
import numpy as np
import statsmodels.stats.api as sms
from math import sqrt

# import data

def getdata(path):
    datalist =[]
    data = open(path, "r")
    for line in data:
        line = line.rstrip()
        line = float(line)
        datalist.append(line)
    data.close()
    return datalist

#inputs für data

path_a = input("Data A? (Example: data_A.txt): ")
path_b = input("Data B? (Example: data_B.txt): ")

#hardcoded für tests zum zeitsparen
#path_a = "data_A.txt"
#path_b = "data_B.txt"

data_a = getdata(path_a)
data_b = getdata(path_b)

#data_a = [0.03,0.91,0.64,0.99,0.64,0.16,0.16,0.91,0.16,0.27]
#data_b = [0.64,0.08,0.16,0.27,0.02,0.01,0.16,0.03,0.03,0.64]
#alpha = 0.05
check = False
while check == False:
    alpha = float(input("Which Alpha? (Value between 0 and 1): "))
    if alpha >0 and alpha < 1:
        check = True
    else:
        print("Alpha out of bounds. Please try again.")

#print(path_a)
#print(path_b)

#print(alpha)

#######################################################################
#sort data:
data_a_sorted = sorted(data_a)
data_b_sorted = sorted(data_b)

#print data:
print("*****************Data*****************")
print("Datapoints A:", data_a)
print("Datapoints B:", data_b)
print("")

#print sorted data:
print("*****************Sorted Data*****************")
print("Sorted Data A:", data_a_sorted)
print("Sorted Data B:", data_b_sorted)
print("")

#######################################################################

def ranks(a, b):
    ranks_a = []
    ranks_b = []

    sequence_a = sorted(a)
    sequence_b = sorted(b)

    sequence_both = sorted(a+b)
    ranks_both = ss.rankdata(sequence_both)

    for i in range(len(sequence_a)):
        for j in range(len(sequence_both)):
            if sequence_a[i] == sequence_both[j]:
                ranks_a.append(ranks_both[j])
                break
        continue

    for i in range(len(sequence_b)):
        for j in range(len(sequence_both)):
            if sequence_b[i] == sequence_both[j]:
                ranks_b.append(ranks_both[j])
                break
        continue

    return ranks_a, ranks_b

ranksA, ranksB = ranks(data_a,data_b)
print("***************Ranks per datalist***************")
print("a:", data_a_sorted)
print("ranks a:", list(ss.rankdata(sorted(data_a))))
print("")
print("b:", data_b_sorted)
print("ranks b:", list(ss.rankdata(sorted(data_b))))
print("")
print("*****************Ranks combined*****************")
print("a:", data_a_sorted)
print("ranks a:", ranksA)
print("")
print("b:", data_b_sorted)
print("ranks b:", ranksB)
print("")

#######################################################################
#Tests:

def test_all(a, b, alpha = 0.05):
    mean_a = np.mean(a)
    mean_b = np.mean(b)

    std_dev_a = np.std(a, ddof=1)
    std_dev_b = np.std(b, ddof=1)

    percentile2_5_a = np.percentile(a,2.5)
    if len(a)*0.025 < 1:
        percentile2_5_a = sorted(a)[0]
    percentile25_a = np.percentile(a,25)
    percentile50_a = np.percentile(a,50)
    percentile75_a = np.percentile(a,75)
    percentile97_5_a = np.percentile(a,97.5)
    if len(a)*0.975 > len(a)-1:
        percentile97_5_a = sorted(a)[len(a)-1]

    percentile2_5_b = np.percentile(b,2.5)
    if len(b)*0.025 < 1:
        percentile2_5_b = sorted(b)[0]
    percentile25_b = np.percentile(b ,25)
    percentile50_b = np.percentile(b,50)
    percentile75_b = np.percentile(b,75)
    percentile97_5_b = np.percentile(b,97.5)
    if len(b)*0.975 > len(b)-1:
        percentile97_5_b = sorted(b)[len(b)-1]

    ci_lower_a, ci_upper_a = sms.DescrStatsW(a).tconfint_mean(alpha)
    ci_lower_b, ci_upper_b = sms.DescrStatsW(b).tconfint_mean(alpha)

    #ts ci intervalls:
    rankedA = list(ss.rankdata(sorted(a)))
    rankedB = list(ss.rankdata(sorted(b)))
    ci_lower_a_rank, ci_upper_a_rank = sms.DescrStatsW(rankedA).tconfint_mean(alpha)
    ci_upper_a_rank = int(round(ci_upper_a_rank))
    ci_lower_a_rank = int(round(ci_lower_a_rank))
    ci_lower_a_rank_value = sorted(a)[ci_lower_a_rank-1]
    ci_upper_a_rank_value = sorted(a)[ci_upper_a_rank-1]
    ci_lower_b_rank, ci_upper_b_rank = sms.DescrStatsW(rankedB).tconfint_mean(alpha)
    ci_upper_b_rank = int(round(ci_upper_b_rank))
    ci_lower_b_rank = int(round(ci_lower_b_rank))
    ci_lower_b_rank_value = sorted(b)[ci_lower_b_rank-1]
    ci_upper_b_rank_value = sorted(b)[ci_upper_b_rank-1]

    #sharpio-wilk-test:
    w_value_a, w_p_value_a = ss.shapiro(a)
    w_value_b, w_p_value_b = ss.shapiro(b)
    #Kolmogorov–Smirnov-Test(normality):
    ksscore_a, ks_p_value_a = ss.kstest(a,"norm")
    ksscore_b, ks_p_value_b = ss.kstest(b, "norm")
    #Anderson–Darling-Test:
    anderson_a ,_, _ = ss.anderson(a)
    anderson_b, _, _ = ss.anderson(b)

    ###interset tests

    #ttest norm same sigma:
    tscore_norm_same, pvalue_norm_same = ss.ttest_ind(a,b)
    tscore_norm_diff, pvalue_norm_diff = ss.ttest_ind(a, b,equal_var=False)

    #manwhitneyu test
    u_value, pvalue_mwu = ss.mannwhitneyu(a,b)
    pvalue_mwu = pvalue_mwu*2

    #Kolmogorov–Smirnov-Test:
    ksscore, ks_p_value = ss.ks_2samp(a,b)

    #cohens d:
    cohens_d = (mean_a - mean_b) / (sqrt((std_dev_a ** 2 + std_dev_b ** 2) / 2))

    #hedges g:
    hedges_g = cohens_d*(1-(3/(4*(len(a)+len(b))-9)))

    #glass's delta:
    if len(a) > len(b):
        glass_delta = (mean_b-mean_a)/(std_dev_a)
    else:
        glass_delta = (mean_a-mean_b)/(std_dev_b)

    return (mean_a, mean_b, std_dev_a, std_dev_b, percentile2_5_a, percentile25_a, percentile50_a,
            percentile75_a, percentile97_5_a, percentile2_5_b, percentile25_b, percentile50_b,
            percentile75_b, percentile97_5_b, ci_lower_a, ci_upper_a, ci_lower_b, ci_upper_b,
            tscore_norm_same,pvalue_norm_same,tscore_norm_diff,pvalue_norm_diff, u_value,pvalue_mwu,
            w_value_a, w_p_value_a, w_value_b, w_p_value_b,ksscore,ks_p_value,ksscore_a,ksscore_b,
            ks_p_value_a,ks_p_value_b,anderson_a,anderson_b,cohens_d,hedges_g, glass_delta,
            ci_lower_a_rank, ci_upper_a_rank, ci_lower_b_rank, ci_upper_b_rank, ci_lower_a_rank_value,
            ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value)

#Rankedbased Tests:

def test_all2(a, b, alpha = 0.05):
    rankA, rankB = ranks(a,b)

    mean_a = np.mean(rankA)
    mean_b = np.mean(rankB)

    std_dev_a = np.std(rankA, ddof=1)
    std_dev_b = np.std(rankB, ddof=1)

    percentile2_5_a = np.percentile(rankA,2.5)
    if len(rankA)*0.025 < 1:
        percentile2_5_a = rankA[0]
    percentile25_a = np.percentile(rankA,25)
    percentile50_a = np.percentile(rankA,50)
    percentile75_a = np.percentile(rankA,75)
    percentile97_5_a = np.percentile(rankA,97.5)
    if len(rankA)*0.975 > len(rankA)-1:
        percentile97_5_a = rankA[len(rankA)-1]

    percentile2_5_b = np.percentile(rankB,2.5)
    if len(rankB)*0.025 < 1:
        percentile2_5_b = rankB[0]
    percentile25_b = np.percentile(rankB,25)
    percentile50_b = np.percentile(rankB,50)
    percentile75_b = np.percentile(rankB,75)
    percentile97_5_b = np.percentile(rankB,97.5)
    if len(rankB)*0.975 > len(rankB)-1:
        percentile97_5_b = rankB[len(rankB)-1]

    ci_lower_a, ci_upper_a = sms.DescrStatsW(rankA).tconfint_mean(alpha)
    ci_lower_b, ci_upper_b = sms.DescrStatsW(rankB).tconfint_mean(alpha)

    #ts ci intervalls:
    rankedA = list(ss.rankdata(sorted(rankA)))
    rankedB = list(ss.rankdata(sorted(rankB)))
    ci_lower_a_rank, ci_upper_a_rank = sms.DescrStatsW(rankedA).tconfint_mean(alpha)
    ci_upper_a_rank = int(round(ci_upper_a_rank))
    ci_lower_a_rank = int(round(ci_lower_a_rank))
    ci_lower_a_rank_value = sorted(rankA)[ci_lower_a_rank-1]
    ci_upper_a_rank_value = sorted(rankA)[ci_upper_a_rank-1]
    ci_lower_b_rank, ci_upper_b_rank = sms.DescrStatsW(rankedB).tconfint_mean(alpha)
    ci_upper_b_rank = int(round(ci_upper_b_rank))
    ci_lower_b_rank = int(round(ci_lower_b_rank))
    ci_lower_b_rank_value = sorted(rankB)[ci_lower_b_rank-1]
    ci_upper_b_rank_value = sorted(rankB)[ci_upper_b_rank-1]

    #sharpio-wilk-test:
    w_value_a, w_p_value_a = ss.shapiro(rankA)
    w_value_b, w_p_value_b = ss.shapiro(rankB)
    #Kolmogorov–Smirnov-Test(normality):
    ksscore_a, ks_p_value_a = ss.kstest(rankA,"norm")
    ksscore_b, ks_p_value_b = ss.kstest(rankB, "norm")
    #Anderson–Darling-Test:
    anderson_a ,_, _ = ss.anderson(a)
    anderson_b, _, _ = ss.anderson(b)

    ###interset tests:

    #ttest norm same sigma:
    tscore_norm_same, pvalue_norm_same = ss.ttest_ind(rankA,rankB)
    tscore_norm_diff, pvalue_norm_diff = ss.ttest_ind(rankA, rankB, equal_var=False)

    #manwhitneyu test
    u_value, pvalue_mwu = ss.mannwhitneyu(rankA,rankB)
    pvalue_mwu = pvalue_mwu*2

    #Kolmogorov–Smirnov-Test:
    ksscore, ks_p_value = ss.ks_2samp(rankA,rankB)

    #cohens d:
    cohens_d = (mean_a - mean_b) / (sqrt((std_dev_a ** 2 + std_dev_b ** 2) / 2))

    #hedges g:
    hedges_g = cohens_d*(1-(3/(4*(len(rankA)+len(rankB))-9)))

    #glass's delta:
    if len(a) > len(b):
        glass_delta = (mean_b-mean_a)/(std_dev_a)
    else:
        glass_delta = (mean_a-mean_b)/(std_dev_b)

    return (mean_a, mean_b, std_dev_a, std_dev_b, percentile2_5_a, percentile25_a, percentile50_a,
            percentile75_a, percentile97_5_a, percentile2_5_b, percentile25_b, percentile50_b,
            percentile75_b, percentile97_5_b, ci_lower_a, ci_upper_a, ci_lower_b, ci_upper_b,
            tscore_norm_same,pvalue_norm_same,tscore_norm_diff,pvalue_norm_diff, u_value,pvalue_mwu,
            w_value_a,w_p_value_a,w_value_b,w_p_value_b,ksscore,ks_p_value,ksscore_a,ksscore_b,
            ks_p_value_a,ks_p_value_b,anderson_a,anderson_b,cohens_d,hedges_g, glass_delta,
            ci_lower_a_rank, ci_upper_a_rank, ci_lower_b_rank, ci_upper_b_rank, ci_lower_a_rank_value,
            ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value)

#print results

def print_results_raw(alpha,mean_a,mean_b,std_dev_a, std_dev_b, percentile2_5_a, percentile25_a,
                      percentile50_a, percentile75_a, percentile97_5_a, percentile2_5_b,
                      percentile25_b, percentile50_b, percentile75_b, percentile97_5_b, ci_lower_a,
                      ci_upper_a, ci_lower_b, ci_upper_b, tscore_norm_same,pvalue_norm_same,
                      tscore_norm_diff, pvalue_norm_diff, u_value,pvalue_mwu,w_value_a,w_p_value_a,
                      w_value_b,w_p_value_b,ksscore,ks_p_value,ksscore_a,ksscore_b,
                      ks_p_value_a,ks_p_value_b,anderson_a,anderson_b,cohens_d,hedges_g, glass_delta,
                      ci_lower_a_rank, ci_upper_a_rank, ci_lower_b_rank, ci_upper_b_rank, ci_lower_a_rank_value,
                      ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value):
    print("*****************Full analysis of raw data*****************")
    print("Alpha:\t\t\t\t\t\t\t", alpha)
    # Sequence A:
    print("")
    print("***Sequence A:")
    print("")
    print("Mean:\t\t\t\t\t\t\t", round(mean_a, 4))
    print("Std. Deviation:\t\t\t\t\t\t", round(std_dev_a, 4))
    print("2.5th Percentile:\t\t\t\t\t", round(percentile2_5_a,4))
    print("25th Percentile 25%:\t\t\t\t\t", round(percentile25_a,4))
    print("50th Percentile 50%:\t\t\t\t\t", round(percentile50_a,4))
    print("75th Percentile 75%:\t\t\t\t\t", round(percentile75_a,4))
    print("97.5th Percentile 97,5%:\t\t\t\t", round(percentile97_5_a,4))
    print("CI Lower:\t\t\t\t\t\t", round(ci_lower_a,4))
    print("CI Upper:\t\t\t\t\t\t", round(ci_upper_a,4))
    print("CI Thompson Savur Lower Rank:\t\t\t\t", ci_lower_a_rank)
    print("CI Thompson Savur Lower Value:\t\t\t\t", round(ci_lower_a_rank_value,4))
    print("CI Thompson Savur Upper Rank:\t\t\t\t", ci_upper_a_rank)
    print("CI Thompson Savur Upper Value:\t\t\t\t", round(ci_upper_a_rank_value,4))
    print("")
    print("###Normality Tests:")
    print("#sharpio-wilk-test:")
    print("p-value:\t\t\t\t\t\t", round(w_p_value_a,4))
    print("W:\t\t\t\t\t\t\t", round(w_value_a,4))
    print("#Kolmogorov Smirnov Test:")
    print("p-value:\t\t\t\t\t\t",round(ks_p_value_a,4))
    print("ksscore:\t\t\t\t\t\t",round(ksscore_a,4))
    print("#Anderson–Darling-Test:")
    print("A:\t\t\t\t\t\t\t", round(anderson_a,4))

    # Sequence B:
    print("")
    print("***Sequence B:")
    print("")
    print("Mean:\t\t\t\t\t\t\t", round(mean_b, 4))
    print("Std. Deviation:\t\t\t\t\t\t", round(std_dev_b, 4))
    print("2.5th Percentile:\t\t\t\t\t",round(percentile2_5_b,4))
    print("25th Percentile 25%:\t\t\t\t\t", round(percentile25_b,4))
    print("50th Percentile 50%:\t\t\t\t\t", round(percentile50_b,4))
    print("75th Percentile 75%:\t\t\t\t\t", round(percentile75_b,4))
    print("97.5th Percentile 97,5%:\t\t\t\t",round(percentile97_5_b,4))
    print("CI Lower:\t\t\t\t\t\t", round(ci_lower_b,4))
    print("CI Upper:\t\t\t\t\t\t", round(ci_upper_b,4))
    print("CI Thompson Savur Lower Rank:\t\t\t\t", ci_lower_b_rank)
    print("CI Thompson Savur Lower Value:\t\t\t\t", round(ci_lower_b_rank_value,4))
    print("CI Thompson Savur Upper Rank:\t\t\t\t", ci_upper_b_rank)
    print("CI Thompson Savur Upper Value:\t\t\t\t", round(ci_upper_b_rank_value,4))
    print("")
    print("###Normality Tests:")
    print("#sharpio-wilk-test:")
    print("p-value:\t\t\t\t\t\t", round(w_p_value_b,4))
    print("W:\t\t\t\t\t\t\t", round(w_value_b,4))
    print("#Kolmogorov Smirnov Test:")
    print("p-value:\t\t\t\t\t\t",round(ks_p_value_b,4))
    print("ksscore:\t\t\t\t\t\t",round(ksscore_b,4))
    print("#Anderson–Darling-Test:")
    print("A:\t\t\t\t\t\t\t", round(anderson_b,4))

    print("")
    print("***Interset Tests")

    print("")
    print("T-test und p-Value:")
    print("asume same sigma:")
    print("t-score:\t\t\t\t\t\t", round(tscore_norm_same,4))
    print("p-value:\t\t\t\t\t\t", round(pvalue_norm_same,4))
    print("asume diffrent sigma:")
    print("t-score:\t\t\t\t\t\t", round(tscore_norm_diff,4))
    print("p-value:\t\t\t\t\t\t", round(pvalue_norm_diff,4))

    print("")
    print("Manwhitney-U-Test:")
    print("p-value:\t\t\t\t\t\t",round(pvalue_mwu,4))
    print("U:\t\t\t\t\t\t\t",round(u_value,4))

    print("")
    print("Kolmogorov Smirnov Test:")
    print("p-value:\t\t\t\t\t\t", round(ks_p_value,4))
    print("ks score:\t\t\t\t\t\t", round(ksscore,4))

    print("")
    print("Cohens-D:")
    print("d measure:\t\t\t\t\t\t", round(cohens_d,4))

    print("")
    print("Hedge's g:")
    print("g measure:\t\t\t\t\t\t", round(hedges_g,4))

    print("")
    print("Glass's delta:")
    print("delta:\t\t\t\t\t\t\t", round(glass_delta,4))

    print("")
    print("***************Full analysis of raw data done***************")
    print("")
    print("")

def print_results_ranks(alpha, mean_a, mean_b, std_dev_a, std_dev_b, percentile2_5_a, percentile25_a,
                        percentile50_a, percentile75_a, percentile97_5_a, percentile2_5_b,
                        percentile25_b, percentile50_b, percentile75_b, percentile97_5_b,
                        ci_lower_a, ci_upper_a, ci_lower_b, ci_upper_b, tscore_norm_same,
                        pvalue_norm_same,tscore_norm_diff,pvalue_norm_diff, u_value,pvalue_mwu,
                        w_value_a,w_p_value_a,w_value_b,w_p_value_b,ksscore,ks_p_value,
                        ksscore_a, ksscore_b, ks_p_value_a, ks_p_value_b,anderson_a,anderson_b,
                        cohens_d,hedges_g, glass_delta,ci_lower_a_rank, ci_upper_a_rank,
                        ci_lower_b_rank, ci_upper_b_rank, ci_lower_a_rank_value,
                        ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value):
    print("*****************Full analysis of rank data*****************")
    print("Alpha:\t\t\t\t\t\t\t", alpha)

    #Sequence A:
    print("")
    print("***Sequence A:")
    print("")
    print("Mean:\t\t\t\t\t\t\t",round(mean_a, 4))
    print("Std. Deviation:\t\t\t\t\t\t", round(std_dev_a, 4))
    print("2.5th Percentile:\t\t\t\t\t", round(percentile2_5_a,4))
    print("25th Percentile 25%:\t\t\t\t\t", round(percentile25_a,4))
    print("50th Percentile 50%:\t\t\t\t\t", round(percentile50_a,4))
    print("75th Percentile 75%:\t\t\t\t\t", round(percentile75_a,4))
    print("97.5th Percentile 97,5%:\t\t\t\t", round(percentile97_5_a,4))
    print("CI Lower:\t\t\t\t\t\t", round(ci_lower_a,4))
    print("CI Upper:\t\t\t\t\t\t", round(ci_upper_a,4))
    print("CI Thompson Savur Lower Rank:\t\t\t\t", ci_lower_a_rank)
    print("CI Thompson Savur Lower Value:\t\t\t\t", round(ci_lower_a_rank_value,4))
    print("CI Thompson Savur Upper Rank:\t\t\t\t", ci_upper_a_rank)
    print("CI Thompson Savur Upper Value:\t\t\t\t", round(ci_upper_a_rank_value,4))
    print("")
    print("###Normality Tests:")
    print("#sharpio-wilk-test:")
    print("p-value:\t\t\t\t\t\t", round(w_p_value_a,4))
    print("W:\t\t\t\t\t\t\t", round(w_value_a,4))
    print("#Kolmogorov Smirnov Test:")
    print("p-value:\t\t\t\t\t\t",round(ks_p_value_a,4))
    print("ksscore:\t\t\t\t\t\t",round(ksscore_a,4))
    print("#Anderson–Darling-Test:")
    print("A:\t\t\t\t\t\t\t", round(anderson_a,4))

    #Sequence B:
    print("")
    print("***Sequence B:")
    print("")
    print("Mean:\t\t\t\t\t\t\t",round(mean_b, 4))
    print("Std. Deviation:\t\t\t\t\t\t", round(std_dev_b, 4))
    print("2.5th Percentile:\t\t\t\t\t", round(percentile2_5_b,4))
    print("25th Percentile 25%:\t\t\t\t\t", round(percentile25_b,4))
    print("50th Percentile 50%:\t\t\t\t\t", round(percentile50_b,4))
    print("75th Percentile 75%:\t\t\t\t\t", round(percentile75_b,4))
    print("97.5th Percentile 97,5%:\t\t\t\t", round(percentile97_5_b,4))
    print("CI Lower:\t\t\t\t\t\t", round(ci_lower_b,4))
    print("CI Upper:\t\t\t\t\t\t", round(ci_upper_b,4))
    print("CI Thompson Savur Lower Rank:\t\t\t\t", ci_lower_b_rank)
    print("CI Thompson Savur Lower Value:\t\t\t\t", round(ci_lower_b_rank_value,4))
    print("CI Thompson Savur Upper Rank:\t\t\t\t", ci_upper_b_rank)
    print("CI Thompson Savur Upper Value:\t\t\t\t", round(ci_upper_b_rank_value,4))
    print("")
    print("###Normality Tests:")
    print("#sharpio-wilk-test:")
    print("p-value:\t\t\t\t\t\t", round(w_p_value_b,4))
    print("W:\t\t\t\t\t\t\t", round(w_value_b,4))
    print("#Kolmogorov Smirnov Test:")
    print("p-value:\t\t\t\t\t\t",round(ks_p_value_b,4))
    print("ksscore:\t\t\t\t\t\t",round(ksscore_b,4))
    print("#Anderson–Darling-Test:")
    print("A:\t\t\t\t\t\t\t", round(anderson_b,4))

    print("")
    print("***Interset Tests")

    print("")
    print("T-test und p-Value:")
    print("asume same sigma:")
    print("t-score:\t\t\t\t\t\t", round(tscore_norm_same,4))
    print("p-value:\t\t\t\t\t\t", round(pvalue_norm_same,4))
    print("asume diffrent sigma:")
    print("t-score:\t\t\t\t\t\t", round(tscore_norm_diff,4))
    print("p-value:\t\t\t\t\t\t", round(pvalue_norm_diff,4))

    print("")
    print("Manwhitney-U-Test:")
    print("p-value:\t\t\t\t\t\t",round(pvalue_mwu,4))
    print("U:\t\t\t\t\t\t\t",round(u_value,4))

    print("")
    print("Kolmogorov Smirnov Test:")
    print("p-value:\t\t\t\t\t\t", round(ks_p_value, 4))
    print("ks score:\t\t\t\t\t\t", round(ksscore, 4))

    print("")
    print("Cohens-D:")
    print("d measure:\t\t\t\t\t\t", round(cohens_d,4))

    print("")
    print("Hedge's g:")
    print("g measure:\t\t\t\t\t\t", round(hedges_g,4))

    print("")
    print("Glass's delta:")
    print("delta:\t\t\t\t\t\t\t", round(glass_delta,4))

    print("")
    print("***************Full analysis of rank data done***************")
    print("")
    print("")

(mean_a, mean_b, std_dev_a, std_dev_b, percentile2_5_a, percentile25_a, percentile50_a,
 percentile75_a, percentile97_5_a, percentile2_5_b, percentile25_b, percentile50_b,
 percentile75_b, percentile97_5_b, ci_lower_a, ci_upper_a, ci_lower_b, ci_upper_b,
 tscore_norm_same,pvalue_norm_same,tscore_norm_diff,pvalue_norm_diff, u_value,
 pvalue_mwu,w_value_a,w_p_value_a,w_value_b,w_p_value_b,ksscore,ks_p_value,ksscore_a,
 ksscore_b,ks_p_value_a,ks_p_value_b,anderson_a,anderson_b,cohens_d,hedges_g, glass_delta,
 ci_lower_a_rank, ci_upper_a_rank, ci_lower_b_rank, ci_upper_b_rank, ci_lower_a_rank_value,
 ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value) = test_all(data_a, data_b, alpha)

print_results_raw(alpha, mean_a, mean_b, std_dev_a, std_dev_b, percentile2_5_a, percentile25_a,
                  percentile50_a, percentile75_a, percentile97_5_a, percentile2_5_b,
                  percentile25_b, percentile50_b, percentile75_b, percentile97_5_b,
                  ci_lower_a, ci_upper_a, ci_lower_b, ci_upper_b, tscore_norm_same,
                  pvalue_norm_same,tscore_norm_diff,pvalue_norm_diff, u_value,pvalue_mwu,
                  w_value_a, w_p_value_a, w_value_b, w_p_value_b,ksscore,ks_p_value,ksscore_a,
                  ksscore_b,ks_p_value_a,ks_p_value_b,anderson_a,anderson_b,cohens_d,hedges_g,
                  glass_delta, ci_lower_a_rank, ci_upper_a_rank, ci_lower_b_rank, ci_upper_b_rank,
                  ci_lower_a_rank_value,ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value)

(mean_a, mean_b, std_dev_a, std_dev_b, percentile2_5_a, percentile25_a, percentile50_a,
 percentile75_a, percentile97_5_a, percentile2_5_b, percentile25_b, percentile50_b,
 percentile75_b, percentile97_5_b, ci_lower_a, ci_upper_a, ci_lower_b, ci_upper_b,
 tscore_norm_same,pvalue_norm_same,tscore_norm_diff,pvalue_norm_diff, u_value,
 pvalue_mwu,w_value_a,w_p_value_a,w_value_b,w_p_value_b,ksscore,ks_p_value,ksscore_a,
 ksscore_b,ks_p_value_a,ks_p_value_b,anderson_a,anderson_b,cohens_d,hedges_g, glass_delta,
 ci_lower_a_rank, ci_upper_a_rank, ci_lower_b_rank, ci_upper_b_rank, ci_lower_a_rank_value,
 ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value) = test_all2(data_a, data_b, alpha)

print_results_ranks(alpha, mean_a, mean_b, std_dev_a, std_dev_b, percentile2_5_a, percentile25_a,
                    percentile50_a, percentile75_a, percentile97_5_a, percentile2_5_b,
                    percentile25_b, percentile50_b, percentile75_b, percentile97_5_b,
                    ci_lower_a, ci_upper_a, ci_lower_b, ci_upper_b, tscore_norm_same,
                    pvalue_norm_same,tscore_norm_diff,pvalue_norm_diff, u_value,pvalue_mwu,
                    w_value_a, w_p_value_a, w_value_b, w_p_value_b,ksscore,ks_p_value,ksscore_a,
                    ksscore_b,ks_p_value_a,ks_p_value_b,anderson_a,anderson_b,cohens_d,hedges_g,
                    glass_delta,ci_lower_a_rank, ci_upper_a_rank, ci_lower_b_rank, ci_upper_b_rank,
                    ci_lower_a_rank_value,ci_upper_a_rank_value, ci_lower_b_rank_value, ci_upper_b_rank_value)

import numpy,import scipy,import statsmodels


import numpy
from bblr.models.Model import Model

class HopfieldModel(Model):
    def __init__(self, properties, seedAddition):
        self.trainingRule = properties.get('trainingRule')

        # Validating the configuration.

        if self.trainingRule not in ('hebbian', 'storkey'):
            raise Exception('Unknown training rule "' + self.trainingRule + '". Only "hebbian" and "storkey" are supported')

    # Public methods. A model must implement these methods in order to use it in Main.py

    def train(self, patternDataSet, patternDataSetProperties):
        self.patternSize = len(patternDataSet[0])
        hopfieldDomainPatternDataSet = map(lambda pattern: self.toHopfieldDomain(pattern), patternDataSet)

        if self.trainingRule == 'hebbian':
            self.trainHebbian(hopfieldDomainPatternDataSet)
        else:
            self.trainStorkey(hopfieldDomainPatternDataSet)

        return {'trainingEpochs': 1}

    def recall(self, inputVector):
        result = self.toHopfieldDomain(inputVector)
        iterations = 0
        changed = True

        while (changed):
            changed = self.updateNeurons(result)
            iterations += 1

        return self.toStandardDomain(result), iterations

    # Private methods.

    def toHopfieldDomain(self, vector):
        return numpy.array(map(lambda x: 1.0 if x == 1 else -1.0, vector))

    def toStandardDomain(self, vector):
        return tuple(map(lambda x: int(x != -1.0), vector))

    def trainHebbian(self, patternDataSet):
        self.weights = numpy.zeros((self.patternSize, self.patternSize))

        for pattern in patternDataSet:
            self.weights += numpy.outer(pattern, pattern)

        self.weights[numpy.diag_indices(self.patternSize)] = 0
        self.weights /= self.patternSize

    def trainStorkey(self, patternDataSet):
        self.weights = numpy.zeros((self.patternSize, self.patternSize))
        n = self.patternSize

        for v in xrange(len(patternDataSet)):
            lastWeights = self.weights.copy()

            for i in range(0, self.patternSize):
                for j in range(i + 1, self.patternSize):
                    weight = lastWeights[i][j]
                    weight += patternDataSet[v][i] * patternDataSet[v][j] / n
                    weight -= patternDataSet[v][i] * self.h(v, j, i, lastWeights, patternDataSet) / n
                    weight -= patternDataSet[v][j] * self.h(v, i, j, lastWeights, patternDataSet) / n

                    self.weights[i][j] = weight
                    self.weights[j][i] = weight

    def h(self, v, i, j, lastWeights, patternDataSet):
        s = 0.0

        for k in xrange(self.patternSize):
            if k != i and k != j:
                s += lastWeights[i][k] * patternDataSet[v][k]

        return s

    def updateNeurons(self, inputVector):
        changed = False

        for neuron in xrange(self.patternSize):
            neuronOutput = self.calculateNeuronOutput(neuron, inputVector)

            if neuronOutput != inputVector[neuron]:
                inputVector[neuron] = neuronOutput
                changed = True

        return changed

    def calculateNeuronOutput(self, neuron, inputVector):
        return 1.0 if numpy.sum(numpy.multiply(self.weights[neuron,:], inputVector)) > 0.0 else -1.0


#  /* Copyright 2018 kunming.xie
#   *
#   * Licensed under the Apache License, Version 2.0 (the "License");
#   * you may not use this file except in compliance with the License.
#   * You may obtain a copy of the License at
#   *
#   *    http://www.apache.org/licenses/LICENSE-2.0
#   *
#   * Unless required by applicable law or agreed to in writing, software
#   * distributed under the License is distributed on an "AS IS" BASIS,
#   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   * See the License for the specific language governing permissions and
#   * limitations under the License.
#   */
import numpy as np

# numpy.linspace(start, stop, num = 50, endpoint = True, retstep = False, dtype = None) : Returns number spaces evenly w.r.t interval. Similiar to arange but instead of step it uses sample number.

x = np.linspace(0, 1, 5)
x2 = np.linspace(0, 1, 5)[:, np.newaxis]

print(x) # [0.   0.25 0.5  0.75 1.  ]
print(x.shape) # (5,)

print(x2)
#  [[0.  ]
#   [0.25]
#   [0.5 ]
#   [0.75]
#   [1.  ]]
print(x2.shape) # (5,1)

#  newaxis
#  Simply put, the newaxis is used to increase the dimension of the existing array
#  by one more dimension, when used once. Thus,
#
#  1D array will become 2D array
#  2D array will become 3D array
#  3D array will become 4D array

# 1x1
a = np.arange(3)
print(a) # [0 1 2]
print(a.shape) #(3,)

# 2x2
row_vec = a[np.newaxis, :]
print(row_vec) # [[0 1 2]]
print(row_vec.shape) # (1, 3)

# 2x2
col_vec = a[:, np.newaxis]
print(col_vec)
#  [[0]
#   [1]
#   [2]]

print(col_vec.shape) # (3, 1)


#
#	plot-data-4.py
#	Plot data using Mathplotlib to PNG as simple as possible
#
#	Sparisoma Viridi | https://github.com/dudung
#
#	20210408
#	0411 Continue from plot-data-3.py program, try [1].
#	0419 Find that init(), animate() [2] not require return value.
#	0423 Add two series to the animated curve.
#
#	References
#	1. url https://stackoverflow.com/a/60580026 [20210408].
#	2. url https://matplotlib.org/gallery/animation
#	   /double_pendulum_animated_sgskip.html [20210205].
#

# Import required libraries
from numpy import sin, cos
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# Set parameters for plotting
p = ['0184.gif']

# Define wave parameters
A = 0.1
_lambda = 1
k = 2 * np.pi / _lambda
_phi = 0
v = 1
_omega = k * v
T = np.abs(2 * np.pi / _omega)

# Create array for x and showing two _lambda
dx = _lambda / 20
x = np.arange(0, 2 *_lambda + dx, dx)

#	Define wave
def wave(t):
	y = A * sin(k * x - _omega * t + _phi)
	return y

# Create array for time t from tbed to tend with step dt
tbeg = 0
tend = 4 * T
Nt = 10
dt = T / Nt
t = np.arange(tbeg, tend, dt)

# Get range of x and y
y = wave(0)
xmin = min(x)
xmax = max(x)
ymin = min(y)
ymax = max(y)
xmt = np.arange(xmin, xmax, 2.5 * dx)
ymt = np.arange(ymin, ymax, 0.05)

# Get figure for plotting and set it
fig = plt.figure(figsize=[5, 1.6])

# Configure axes
ax = fig.add_subplot()
ax.grid(which='both')
ax.set_xlabel('$x$')
ax.set_ylabel('$y$')
ax.set_xlim([xmin, xmax])
ax.set_ylim([ymin, ymax])
ax.set_xticks(xmt, minor=True)
ax.set_yticks(ymt, minor=True)

# It must be set after configuring axis to give the effect
fig.tight_layout(rect=[-0.03, -0.07, 1.01, 1.05])

# Prepare curve
line, = ax.plot([], [], 'or-', lw=2, ms=0)
time_template = '$t$ = %.1f s'
time_text = ax.text(0.04, 0.84, '', transform=ax.transAxes)

line2, = ax.plot([], [], 'sb-', lw=0, ms=10)
line3, = ax.plot([], [], 'sg-', lw=0, ms=10)

# Perform animation
def init():
	line.set_data([], [])
	time_text.set_text('')
	line2.set_data([], [])
	line3.set_data([], [])
	return line, time_text,

def animate(i):
	tt = i * dt / T
	y = wave(tt)
	thisx = [x]
	thisy = [y]

	line.set_data(thisx, thisy)
	time_text.set_text(time_template % tt)

	line2.set_data(x[20], y[20])
	line3.set_data(x[30], y[30])

	return line, time_text, line2

ani = animation.FuncAnimation(
	fig, animate, np.arange(1, len(t)),
	interval=70, blit=True, init_func=init
)

ani.save(p[0], fps=10)


"""
Basic Inner Products
====================

Inner products between two scalar or vector quantities represents the most
basic class of inner products. For this class of inner products, we demonstrate:

    - How to construct the inner product matrix
    - How to use inner product matricies to approximate the inner product
    - How to construct the inverse of the inner product matrix.

For scalar quantities :math:`\\psi` and :math:`\\phi`, the
inner product is given by:

.. math::
    (\\psi , \\phi ) = \\int_\\Omega \\psi \\, \\phi \\, dv

And for vector quantities :math:`\\vec{u}` and :math:`\\vec{v}`, the
inner product is given by:

.. math::
    (\\vec{u}, \\vec{v}) = \\int_\\Omega \\vec{u} \\cdot \\vec{v} \\, dv

In discretized form, we can approximate the aforementioned inner-products as:

.. math::
    (\\psi , \\phi) \\approx \\mathbf{\\psi^T \\, M \\, \\phi}

and

.. math::
    (\\vec{u}, \\vec{v}) \\approx \\mathbf{u^T \\, M \\, v}

where :math:`\\mathbf{M}` in either equation represents an
*inner-product matrix*. :math:`\\mathbf{\\psi}`, :math:`\\mathbf{\\phi}`,
:math:`\\mathbf{u}` and :math:`\\mathbf{v}` are discrete variables that live
on the mesh. It is important to note a few things about the
inner-product matrix in this case:

    1. It depends on the dimensions and discretization of the mesh
    2. It depends on where the discrete variables live; e.g. edges, faces, nodes, centers

For this simple class of inner products, the inner product matricies for
discrete quantities living on various parts of the mesh have the form:

.. math::
    \\textrm{Centers:} \\; \\mathbf{M_c} &= \\textrm{diag} (\\mathbf{v} ) \n
    \\textrm{Nodes:} \\; \\mathbf{M_n} &= \\frac{1}{2^{2k}} \\mathbf{P_n^T } \\textrm{diag} (\\mathbf{v} ) \\mathbf{P_n} \n
    \\textrm{Faces:} \\; \\mathbf{M_f} &= \\frac{1}{4} \\mathbf{P_f^T } \\textrm{diag} (\\mathbf{I_k \\otimes v} ) \\mathbf{P_f} \n
    \\textrm{Edges:} \\; \\mathbf{M_e} &= \\frac{1}{4^{k-1}} \\mathbf{P_e^T } \\textrm{diag} (\\mathbf{I_k \\otimes v}) \\mathbf{P_e}

where :math:`k = 1,2,3`, :math:`\\mathbf{I_k}` is the identity matrix and
:math:`\\otimes` is the kronecker product. :math:`\\mathbf{P}` are projection
matricies that map quantities from one part of the cell (nodes, faces, edges)
to cell centers.

"""

####################################################
#
# Import Packages
# ---------------
#
# Here we import the packages required for this tutorial
#

from discretize.utils import sdiag
from discretize import TensorMesh
import matplotlib.pyplot as plt
import numpy as np

# sphinx_gallery_thumbnail_number = 2

#####################################################
# Scalars
# -------
#
# It is natural for scalar quantities to live at cell centers or nodes. Here
# we will define a scalar function (a Gaussian distribution in this case):
#
# .. math::
#     \phi(x) = \frac{1}{\sqrt{2 \pi \sigma^2}} \, e^{- \frac{(x- \mu )^2}{2 \sigma^2}}
#
#
# We will then evaluate the following inner product:
#
# .. math::
#     (\phi , \phi) = \int_\Omega \phi^2 \, dx = \frac{1}{2\sigma \sqrt{\pi}}
#
#
# according to the mid-point rule using inner-product matricies. Next we
# compare the numerical approximation of the inner product with the analytic
# solution. *Note that the method for evaluating inner products here can be
# extended to variables in 2D and 3D*.
#

# Define the Gaussian function
def fcn_gaussian(x, mu, sig):

    return (1 / np.sqrt(2 * np.pi * sig ** 2)) * np.exp(-0.5 * (x - mu) ** 2 / sig ** 2)

# Create a tensor mesh that is sufficiently large
h = 0.1 * np.ones(100)
mesh = TensorMesh([h], "C")

# Define center point and standard deviation
mu = 0
sig = 1.5

# Evaluate at cell centers and nodes
phi_c = fcn_gaussian(mesh.gridCC, mu, sig)
phi_n = fcn_gaussian(mesh.gridN, mu, sig)

# Define inner-product matricies
Mc = sdiag(mesh.vol)  # cell-centered
# Mn = mesh.getNodalInnerProduct()  # on nodes (*functionality pending*)

# Compute the inner product
ipt = 1 / (2 * sig * np.sqrt(np.pi))  # true value of (f, f)
ipc = np.dot(phi_c, (Mc * phi_c))
# ipn = np.dot(phi_n, (Mn*phi_n)) (*functionality pending*)

fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111)
ax.plot(mesh.gridCC, phi_c)
ax.set_title("phi at cell centers")

# Verify accuracy
print("ACCURACY")
print("Analytic solution:    ", ipt)
print("Cell-centered approx.:", ipc)
# print('Nodal approx.:        ', ipn)

#####################################################
# Vectors
# -------
#
# To preserve the natural boundary conditions for each cell, it is standard
# practice to define fields on cell edges and fluxes on cell faces. Here we
# will define a 2D vector quantity:
#
# .. math::
#     \vec{v}(x,y) = \Bigg [ \frac{-y}{r} \hat{x} + \frac{x}{r} \hat{y} \Bigg ]
#     \, e^{-\frac{x^2+y^2}{2\sigma^2}}
#
# We will then evaluate the following inner product:
#
# .. math::
#     (\vec{v}, \vec{v}) = \int_\Omega \vec{v} \cdot \vec{v} \, da
#     = 2 \pi \sigma^2
#
# using inner-product matricies. Next we compare the numerical evaluation
# of the inner products with the analytic solution. *Note that the method for
# evaluating inner products here can be extended to variables in 3D*.
#

# Define components of the function
def fcn_x(xy, sig):
    return (-xy[:, 1] / np.sqrt(np.sum(xy ** 2, axis=1))) * np.exp(
        -0.5 * np.sum(xy ** 2, axis=1) / sig ** 2
    )

def fcn_y(xy, sig):
    return (xy[:, 0] / np.sqrt(np.sum(xy ** 2, axis=1))) * np.exp(
        -0.5 * np.sum(xy ** 2, axis=1) / sig ** 2
    )

# Create a tensor mesh that is sufficiently large
h = 0.1 * np.ones(100)
mesh = TensorMesh([h, h], "CC")

# Define center point and standard deviation
sig = 1.5

# Evaluate inner-product using edge-defined discrete variables
vx = fcn_x(mesh.gridEx, sig)
vy = fcn_y(mesh.gridEy, sig)
v = np.r_[vx, vy]

Me = mesh.getEdgeInnerProduct()  # Edge inner product matrix

ipe = np.dot(v, Me * v)

# Evaluate inner-product using face-defined discrete variables
vx = fcn_x(mesh.gridFx, sig)
vy = fcn_y(mesh.gridFy, sig)
v = np.r_[vx, vy]

Mf = mesh.getFaceInnerProduct()  # Edge inner product matrix

ipf = np.dot(v, Mf * v)

# The analytic solution of (v, v)
ipt = np.pi * sig ** 2

# Plot the vector function
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111)
mesh.plotImage(
    v, ax=ax, v_type="F", view="vec", stream_opts={"color": "w", "density": 1.0}
)
ax.set_title("v at cell faces")

fig.show()

# Verify accuracy
print("ACCURACY")
print("Analytic solution:    ", ipt)
print("Edge variable approx.:", ipe)
print("Face variable approx.:", ipf)

##############################################
# Inverse of Inner Product Matricies
# ----------------------------------
#
# The final discretized system using the finite volume method may contain
# the inverse of an inner-product matrix. Here we show how the inverse of
# the inner product matrix can be explicitly constructed. We validate its
# accuracy for cell-centers, nodes, edges and faces by computing the folling
# L2-norm for each:
#
# .. math::
#     \| \mathbf{v - M^{-1} M v} \|^2
#
#

# Create a tensor mesh
h = 0.1 * np.ones(100)
mesh = TensorMesh([h, h], "CC")

# Cell centered for scalar quantities
Mc = sdiag(mesh.vol)
Mc_inv = sdiag(1 / mesh.vol)

# Nodes for scalar quantities  (*functionality pending*)
# Mn = mesh.getNodalInnerProduct()
# Mn_inv = mesh.getNodalInnerProduct(invMat=True)

# Edges for vector quantities
Me = mesh.getEdgeInnerProduct()
Me_inv = mesh.getEdgeInnerProduct(invMat=True)

# Faces for vector quantities
Mf = mesh.getFaceInnerProduct()
Mf_inv = mesh.getFaceInnerProduct(invMat=True)

# Generate some random vectors
phi_c = np.random.rand(mesh.nC)
phi_n = np.random.rand(mesh.nN)
vec_e = np.random.rand(mesh.nE)
vec_f = np.random.rand(mesh.nF)

# Generate some random vectors
norm_c = np.linalg.norm(phi_c - Mc_inv.dot(Mc.dot(phi_c)))
# norm_n = np.linalg.norm(phi_n - Mn_inv*Mn*phi_n)
norm_e = np.linalg.norm(vec_e - Me_inv * Me * vec_e)
norm_f = np.linalg.norm(vec_f - Mf_inv * Mf * vec_f)

# Verify accuracy
print("ACCURACY")
print("Norm for centers:", norm_c)
# print('Norm for nodes:  ', norm_n)
print("Norm for edges:  ", norm_e)
print("Norm for faces:  ", norm_f)


## exercise 2.1.6
from ex2_1_1 import *
import matplotlib.pyplot as plt
from scipy.linalg import svd

r = np.arange(1,X.shape[1]+1)
plt.bar(r, np.std(X,0))
plt.xticks(r, attributeNames)
plt.ylabel('Standard deviation')
plt.xlabel('Attributes')
plt.title('NanoNose: attribute standard deviations')

## Investigate how standardization affects PCA

# Try this *later* (for last), and explain the effect
#X_s = X.copy() # Make a to be "scaled" version of X
#X_s[:, 2] = 100*X_s[:, 2] # Scale/multiply attribute C with a factor 100
# Use X_s instead of X to in the script below to see the difference.
# Does it affect the two columns in the plot equally?

# Subtract the mean from the data
Y1 = X - np.ones((N, 1))*X.mean(0)

# Subtract the mean from the data and divide by the attribute standard
# deviation to obtain a standardized dataset:
Y2 = X - np.ones((N, 1))*X.mean(0)
Y2 = Y2*(1/np.std(Y2,0))
# Here were utilizing the broadcasting of a row vector to fit the dimensions
# of Y2

# Store the two in a cell, so we can just loop over them:
Ys = [Y1, Y2]
titles = ['Zero-mean', 'Zero-mean and unit variance']
threshold = 0.9
# Choose two PCs to plot (the projection)
i = 0
j = 1

# Make the plot
plt.figure(figsize=(10,15))
plt.subplots_adjust(hspace=.4)
plt.title('NanoNose: Effect of standardization')
nrows=3
ncols=2
for k in range(2):
    # Obtain the PCA solution by calculate the SVD of either Y1 or Y2
    U,S,Vh = svd(Ys[k],full_matrices=False)
    V=Vh.T # For the direction of V to fit the convention in the course we transpose
    # For visualization purposes, we flip the directionality of the
    # principal directions such that the directions match for Y1 and Y2.
    if k==1: V = -V; U = -U;

    # Compute variance explained
    rho = (S*S) / (S*S).sum()

    # Compute the projection onto the principal components
    Z = U*S;

    # Plot projection
    plt.subplot(nrows, ncols, 1+k)
    C = len(classNames)
    for c in range(C):
        plt.plot(Z[y==c,i], Z[y==c,j], '.', alpha=.5)
    plt.xlabel('PC'+str(i+1))
    plt.xlabel('PC'+str(j+1))
    plt.title(titles[k] + '\n' + 'Projection' )
    plt.legend(classNames)
    plt.axis('equal')

    # Plot attribute coefficients in principal component space
    plt.subplot(nrows, ncols,  3+k)
    for att in range(V.shape[1]):
        plt.arrow(0,0, V[att,i], V[att,j])
        plt.text(V[att,i], V[att,j], attributeNames[att])
    plt.xlim([-1,1])
    plt.ylim([-1,1])
    plt.xlabel('PC'+str(i+1))
    plt.ylabel('PC'+str(j+1))
    plt.grid()
    # Add a unit circle
    plt.plot(np.cos(np.arange(0, 2*np.pi, 0.01)),
         np.sin(np.arange(0, 2*np.pi, 0.01)));
    plt.title(titles[k] +'\n'+'Attribute coefficients')
    plt.axis('equal')

    # Plot cumulative variance explained
    plt.subplot(nrows, ncols,  5+k);
    plt.plot(range(1,len(rho)+1),rho,'x-')
    plt.plot(range(1,len(rho)+1),np.cumsum(rho),'o-')
    plt.plot([1,len(rho)],[threshold, threshold],'k--')
    plt.title('Variance explained by principal components');
    plt.xlabel('Principal component');
    plt.ylabel('Variance explained');
    plt.legend(['Individual','Cumulative','Threshold'])
    plt.grid()
    plt.title(titles[k]+'\n'+'Variance explained')

plt.show()


import numpy as np
import math

def k_prac(x1,x2,l):
    '''
    Radial Basis Kernel

    args:
        x1: 1xd vector
        x2: 1xd vector
        l: lenghtscale
    return:
        int: Similarity measure
    '''
    exponent = - 1/(2*l**2) * np.linalg.norm(x1-x2)**2
    return np.exp(exponent)

def k_homework(x1, x2, l, P=3):
    exponent_1 = - 1/(2*l**2) * np.linalg.norm(x1-x2)**2
    exponent_2 = - 2/(l**2) * math.sin(math.pi * np.linalg.norm(x1-x2) / P )**2
    return np.exp(exponent_1) * np.exp(exponent_2)

def k_q2(x1,x2,c,d):
    return (x1*x2 +c)**d


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

iteration=45

#deal with a_0
a_0=math.pi/4

#deal with a_n,b_n
a_n=[]
b_n=[]
for i in range(1,iteration+1):
    a_n.append((1-(-1)**i)/(i**2)/math.pi)
    b_n.append(1/i)

print(a_n)
print(b_n)

def fourier(a_0,a_n,b_n,iteration,x):
    value=a_0
    for i in range(1,iteration):
        value+=a_n[i-1]*math.cos(i*x)+b_n[i-1]*math.sin(i*x)
    return value

#visualize the fourier transform
discrete_num=1000
x=np.linspace(-math.pi,math.pi,discrete_num)
y=[]
for j in range(discrete_num):
    y.append(fourier(a_0,a_n,b_n,iteration,x[j]))

plt.plot(x,y)
plt.title("realize the fourier transformation (number of summations: %d)" %(iteration))
plt.xlabel("x")
plt.ylabel("y")
plt.text(-3,1,"f(x)=0, for x=-π~0")
plt.text(-3,0.5,"f(x)=π-x, for x=0~π")
plt.show()


#Python3 Steven
#simualtion distrubutions for people's income
#https://en.wikipedia.org/wiki/Gini_coefficient
import numpy as np
import matplotlib.pyplot as plt
from genDistributions import *
from distributions import *
#from plotCommon import scatterSub

def calLineSlopAndBias(startPt,stopPt):
    slop = (stopPt[1]-startPt[1])/(stopPt[0]-startPt[0])
    b = stopPt[1]-slop*stopPt[0]
    return slop,b

def calDistribution(dis):
    dis = np.abs(dis)
    disOrdered = sorted(dis)
    #plot(range(len(dis)), dis)
    cumDis = np.cumsum(disOrdered)

    l = len(cumDis)
    slop,b = calLineSlopAndBias([0,cumDis[0]],[len(cumDis)-1,cumDis[len(cumDis)-1]])
    equalDis = [ slop*i+b for i in range(l)]

    # print('dis=',dis)
    # print('disOrdered=',disOrdered)
    # print('cumDis=',cumDis)
    # print('equalDis=',equalDis)

    gini = (np.sum(equalDis)-np.sum(cumDis))/np.sum(equalDis)
    return dis,disOrdered,cumDis,equalDis,gini

def plotAll(dis,name=''):
    dis,disOrdered,cumDis,equalDis,gini = calDistribution(dis)

    fmt = '{:24} | {:18}'
    print( fmt.format('Distribution:'+name,'Gini coefficient:' + str(round(gini,4))))

    #plotIncomeDistribution(name,dis,disOrdered)
    # plotLorenzCurve(cumDis,equalDis,gini)
    plotWhole(name,dis,disOrdered,cumDis,equalDis,gini)

gSaveBasePath=r'.\images\\'
def plotWhole(name,dis,disOrdered,cumDis,equalDis,gini):
    plt.figure(figsize=(9,4.2))

    ax = plt.subplot(1, 2, 1)
    ax.plot(dis,label='Income ' + name + ' distribution')
    ax.plot(disOrdered,label='Income ordered')
    ax.set_title("Income")
    ax.legend()

    ax = plt.subplot(1, 2, 2)
    z0 = np.zeros(len(cumDis))
    x = range(len(cumDis))
    c1 = tuple(ti/255 for ti in (176,196,214))
    c2 = tuple(ti/255 for ti in (128,179,255))
    ax.fill_between(x,equalDis,cumDis, color=c1)# where=x<=1, facecolor='green'
    ax.fill_between(x,z0,cumDis, color=c2)
    ax.plot(cumDis,label='Cumlative Income')
    ax.plot(equalDis,linestyle='dashed',label='Equal Income')
    ax.set_title('Income Lorenz Curve,Gini='+str(round(gini,4)))
    ax.legend()

    plt.subplots_adjust(left=0.07, bottom=0.07, right=0.97, top=0.90, wspace=None, hspace=None)
    plt.savefig(gSaveBasePath + name + '_simulationGini' + '.png')
    plt.show()

def plotIncomeDistribution(name,dis,disOrdered):
    ax = plt.subplot(1, 1, 1)
    #ax.plot(dis,label='Income distribution')
    #ax.plot(disOrdered,label='Income ordered')
    ax.hist(dis,bins=60, rwidth=0.72, label='Income',alpha=0.75)
    #plt.hist(x, 50, density=True, facecolor='g', alpha=0.75)

    ax.set_title("Income " + name + ' Distribution')
    ax.legend()
    plt.savefig(gSaveBasePath + name + '_simulationIncome' + '.png')
    plt.show()

def plotLorenzCurve(cumDis,equalDis,gini): #https://en.wikipedia.org/wiki/Lorenz_curve
    ax = plt.subplot(1, 1, 1)

    z0 = np.zeros(len(cumDis))
    x = range(len(cumDis))
    c1 = tuple(ti/255 for ti in (176,196,214))
    c2 = tuple(ti/255 for ti in (128,179,255))
    plt.fill_between(x,equalDis,cumDis, color=c1)# where=x<=1, facecolor='green'
    plt.fill_between(x,z0,cumDis, color=c2)
    ax.plot(cumDis,label='Cumlative Income')
    ax.plot(equalDis,linestyle='dashed',label='Equal Income')
    ax.set_title('Income Lorenz Curve,Gini='+str(round(gini,4)))
    ax.legend()
    plt.show()

def simulateDistribution():
    N=500
    start=0
    width=1
    dis = genUniform_distribution(N,start,width)
    #dis = Uniform_distribution(N,0,1)
    #print(dis,'sum=',np.sum(dis))
    #plot(np.linspace(0,1,N), dis)
    #plot(range(N), dis)
    plotAll(dis,name='Uniform')

    dis = genNormal_distribution(N,1)
    #print(dis,'sum=',np.sum(dis))
    plotAll(dis,name='Normal')

    dis = genGamma_distribution(N)
    plotAll(dis,name='Gamma')

    dis = genExp_distribution(N)
    plotAll(dis,name='Exponential')

    dis = genPoisson_distribution(N)
    plotAll(dis,name='Poisson')

    dis = genBinomial_distribution(N)
    plotAll(dis,name='Binomial')

    dis = genBernoulli_distribution(N)
    plotAll(dis,name='Bernoulli')

def standardDistribution():
    N=500
    plotAll(Uniform_distribution(N,0,1), name='S_Uniform')
    plotAll(Binomial_distribution(N, 0.8), name='S_Binomial')
    plotAll(Poisson_distribution(N,0.2), name='S_Poisson')
    plotAll(ZipfsLaw(N), name='S_ZipfsLaw')
    plotAll(NormalDistribution(np.linspace(0, N, N), u=N//2,delta=10), name='S_Normal')
    plotAll(Cauchy_pdf(np.linspace(0, N, N), x0=N//2, scaler=10), name='S_Cauchy')
    plotAll(Gumbel_distribution(np.linspace(0, N, N), u=N//2, belta=10), name='S_Gumbel')
    plotAll(Weibull_distribution(np.linspace(0, N, N),lamda=N//2,k=1.5), name='S_Weibull')
    plotAll(Pareto_distribution(np.linspace(0, N, N),alpha=.5,Xm=2), name='S_Pareto')
    plotAll(Logit_normal_distribution(np.linspace(0.001, 0.999, N), u=0,deta=1.5), name='S_Logit_normal')

def main():
    #simulateDistribution()
    standardDistribution()

if __name__=='__main__':
    main()


import numpy as np
import matplotlib.pyplot as plt

"""
	1. Membuat data
	2. Membuat plot
	3. Menampilkan plot
"""

# 1. Membuat data (sin(2wt + theta))
# camel case
def sinusGenerator(amplitudo,frekuensi,tAkhir,theta):
	t = np.arange(0,tAkhir,0.1)
	y = amplitudo * np.sin(2*frekuensi*t + np.deg2rad(theta))
	return t,y

# 2. Membuat plot
t1,y1 = sinusGenerator(1,1,4,0)
plt.plot(t1,y1)

t2,y2 = sinusGenerator(1,1,4,30)
plt.plot(t2,y2, 'r')

t3,y3 = sinusGenerator(1,1,4,60)
plt.plot(t3,y3, 'b--')

t4,y4 = sinusGenerator(1,1,4,90)
plt.plot(t4,y4, 'c-o')

# 3. Menampilkan plot
plt.show()

# "."	point
# ","	pixel
# "o"	circle
# "v"	triangle_down
# "^"	triangle_up
# "<"	triangle_left
# ">"	triangle_right
# "1"	tri_down
# "2"	tri_up
# "3"	tri_left
# "4"	tri_right
# "8"	octagon
# "s"	square
# "p"	pentagon
# "P"	plus (filled)
# "*"	star
# "h"	hexagon1
# "H"	hexagon2
# "+"	plus
# "x"	x
# "X"	x (filled)
# "D"	diamond
# "d"	thin_diamond
# "|"	vline
# "_"	hline


# %% importing the libraries

import numpy as np

# %% Defining the sudoku grid

grid = [
    [0,0,0,0,3,0,0,0,9],
    [0,0,0,0,0,5,0,6,0],
    [0,0,0,0,0,7,5,0,8],
    [0,0,6,0,0,0,0,0,0],
    [3,2,0,0,0,0,6,0,0],
    [0,0,0,0,8,0,0,5,4],
    [0,3,0,0,5,0,0,0,0],
    [8,1,0,9,4,3,0,0,0],
    [9,0,0,0,0,8,0,0,0]
]

# Converting the grid to matrix for better indexing
grid_matrix = np.matrix(grid)
# grid_matrix[0,2] == 3
# grid_matrix[3,0] == 6

# %%
# Validation methods

# Check if number can be inputted into row
def check_row(sudoku_grid, x, num):
    sol = np.sum(np.isin(num, sudoku_grid[x,:]))
    if(sol == 0):
        return True
    else:
        return False

# Check if number can be inputted into column
def check_column(sudoku_grid, y, num):
    sol = np.sum(np.isin(num, sudoku_grid[:,y]))
    if(sol == 0):
        return True
    else:
        return False

# Check if number can be inputted into the 3x3 grid
def check_3_3(sudoku_grid, x, y, num):
    x_pos = x//3
    y_pos = y//3
    grid_3x3 = sudoku_grid[ x_pos*3:(x_pos+1)*3, y_pos*3:(y_pos+1)*3 ]

    sol = np.sum(np.isin(num, grid_3x3))
    if(sol == 0):
        return True
    else:
        return False

def check_possible(sudoku_grid, x, y, num):
    row = check_row(sudoku_grid, x, num)
    column = check_column(sudoku_grid, y, num)
    small_grid = check_3_3(sudoku_grid, x, y, num)
    if(row and column and small_grid):
        return True
    else:
        return False

# %%
# Solver algorithm
def solve(sudoku_grid):
    for x in range(9):
        for y in range(9):
            if(sudoku_grid[x,y] == 0):
                for n in range(1, 10):
                    if (check_possible(sudoku_grid, x, y, n)):
                        sudoku_grid[x, y] = n
                        solve(sudoku_grid)
                        sudoku_grid[x, y] = 0
                return "Completed :D"
    print(sudoku_grid)
# %%
solve(grid_matrix)


from typing import Any, Union, List
import numpy as np
from causaldag.utils.ci_tests import kernels
from scipy.stats import gamma
from causaldag.utils.ci_tests._utils import residuals
from causaldag.utils.core_utils import to_list

def hsic_test_vector(x: np.ndarray, y: np.ndarray, sig: float=1/np.sqrt(2), alpha=0.05):
    if x.ndim == 1:
        x = x.reshape((len(x), 1))
    if y.ndim == 1:
        y = y.reshape((len(y), 1))
    n = x.shape[0]
    if y.shape[0] != n:
        raise ValueError("Y should have the same number of samples as X")

    n = x.shape[0]
    H = np.eye(n) - np.ones([n, n])/n
    kernel_precision = 1/(sig**2)

    # === COMPUTE CENTRALIZED KERNEL MATRICES
    kx = kernels.rbf_kernel(x, kernel_precision)
    ky = kernels.rbf_kernel(y, kernel_precision)
    kx_centered = kernels.center(kx)
    ky_centered = kernels.center(ky)

    # === COMPUTE STATISTIC
    statistic = 1/n**2 * np.sum(kx_centered * ky_centered.T)  # SAME AS trace(kx_centered @ ky_centered)

    mu_x = 1/(n*(n-1)) * np.sum(kx - np.diag(np.diag(kx)))  # SUM OFF-DIAGONALS
    mu_y = 1/(n*(n-1)) * np.sum(ky - np.diag(np.diag(ky)))
    mean_approx = 1/n * (1 + mu_x*mu_y - mu_x - mu_y)
    var_approx = 2*(n-4)*(n-5)/(n*(n-1)*(n-2)*(n-3)) * np.sum(kx_centered * kx_centered.T) * np.sum(ky_centered * ky_centered.T) / n**4

    k_approx = mean_approx ** 2 / var_approx
    prec_approx = var_approx / mean_approx

    critval = gamma.ppf(1-alpha, k_approx, scale=prec_approx)
    p_value = 1 - gamma.cdf(statistic, k_approx, scale=prec_approx)

    return dict(
        statistic=statistic,
        critval=critval,
        p_value=p_value,
        reject=statistic > critval,
        mean_approx=mean_approx,
        var_approx=var_approx
    )

def hsic_test(
        suffstat: Any,
        i: int,
        j: int,
        cond_set: Union[List[int], int]=None,
        alpha: float=0.05
):
    cond_set = to_list(cond_set)
    if len(cond_set) == 0:
        return hsic_test_vector(suffstat[:, i], suffstat[:, j], alpha=alpha)
    else:
        residuals_i, residuals_j = residuals(suffstat, i, j, cond_set)
        return hsic_test_vector(residuals_i, residuals_j, alpha=alpha)


import numpy as np
import torch
import torch.nn as nn

"""
The modules/function here implement custom versions of batch normalization in PyTorch.
In contrast to more advanced implementations no use of a running mean/variance is made.
You should fill in code into indicated sections.
"""

######################################################################################
# Code for Question 3.1
######################################################################################

class CustomBatchNormAutograd(nn.Module):
  """
  This nn.module implements a custom version of the batch norm operation for MLPs.
  The operations called in self.forward track the history if the input tensors have the
  flag requires_grad set to True. The backward pass does not need to be implemented, it
  is dealt with by the automatic differentiation provided by PyTorch.
  """

  def __init__(self, n_neurons, eps=1e-5):
    """
    Initializes CustomBatchNormAutograd object.

    Args:
      n_neurons: int specifying the number of neurons
      eps: small float to be added to the variance for stability

    TODO:
      Save parameters for the number of neurons and eps.
      Initialize parameters gamma and beta via nn.Parameter
    """
    super(CustomBatchNormAutograd, self).__init__()

    ########################
    # PUT YOUR CODE HERE  #
    #######################
    self.gamma = nn.Parameter(torch.ones(n_neurons))
    self.beta = nn.Parameter(torch.zeros(n_neurons))
    self.eps = eps
    ########################
    # END OF YOUR CODE    #
    #######################

  def forward(self, input):
    """
    Compute the batch normalization

    Args:
      input: input tensor of shape (n_batch, n_neurons)
    Returns:
      out: batch-normalized tensor

    TODO:
      Check for the correctness of the shape of the input tensor.
      Implement batch normalization forward pass as given in the assignment.
      For the case that you make use of torch.var be aware that the flag unbiased=False should be set.
    """

    ########################
    # PUT YOUR CODE HERE  #
    #######################
    shape = input.shape

    if len(shape) == 1:
        input = input.unsqueeze(0)
        shape = input.shape
    elif len(shape) > 2:
        raise ValueError(f"Expected 2D input. Instead, got {len(shape)}D input with shape of {shape}.")
    elif shape[1] != self.gamma.shape[0]:
        raise ValueError(f"Expected input of shape batch_size x {self.gamma.shape[0]}. Instead, got input with"
                         f"shape of {shape}.")

    mean = input.mean(0)
    var = input.var(0)

    x_hat = (input - mean)/torch.sqrt(var + self.eps)
    out = self.gamma * x_hat + self.beta
    ########################
    # END OF YOUR CODE    #
    #######################

    return out

######################################################################################
# Code for Question 3.2 b)
######################################################################################

class CustomBatchNormManualFunction(torch.autograd.Function):
  """
  This torch.autograd.Function implements a functional custom version of the batch norm operation for MLPs.
  Using torch.autograd.Function allows you to write a custom backward function.
  The function will be called from the nn.Module CustomBatchNormManualModule
  Inside forward the tensors are (automatically) not recorded for automatic differentiation since the backward
  pass is done via the backward method.
  The forward pass is not called directly but via the apply() method. This makes sure that the context objects
  are dealt with correctly. Example:
    my_bn_fct = CustomBatchNormManualFunction()
    normalized = fct.apply(input, gamma, beta, eps)
  """

  @staticmethod
  def forward(ctx, input, gamma, beta, eps=1e-5):
    """
    Compute the batch normalization

    Args:
      ctx: context object handling storing and retrival of tensors and constants and specifying
           whether tensors need gradients in backward pass
      input: input tensor of shape (n_batch, n_neurons)
      gamma: variance scaling tensor, applied per neuron, shpae (n_neurons)
      beta: mean bias tensor, applied per neuron, shpae (n_neurons)
      eps: small float added to the variance for stability
    Returns:
      out: batch-normalized tensor

    TODO:
      Implement the forward pass of batch normalization
      Store constant non-tensor objects via ctx.constant=myconstant
      Store tensors which you need in the backward pass via ctx.save_for_backward(tensor1, tensor2, ...)
      Intermediate results can be decided to be either recomputed in the backward pass or to be stored
      for the backward pass. Do not store tensors which are unnecessary for the backward pass to save memory!
      For the case that you make use of torch.var be aware that the flag unbiased=False should be set.
    """

    ########################
    # PUT YOUR CODE HERE  #
    #######################
    shape = input.shape

    if len(shape) == 1:
        input = input.unsqueeze(0)
        shape = input.shape
    elif len(shape) > 2:
        raise ValueError(
            f"Expected 2D input. Instead, got {len(shape)}D input with shape of {shape}.")
    elif shape[1] != gamma.shape[0]:
        raise ValueError(f"Expected input of shape batch_size x {gamma.shape[0]}. Instead, got input with"
                         f"shape of {shape}.")

    mean = input.mean(0)
    var = input.var(0, unbiased = False)
    inv_var = 1/torch.sqrt(var + eps)
    x_hat = (input - mean) * inv_var
    out = gamma * x_hat + beta

    ctx.save_for_backward(input, gamma, beta, mean, inv_var)
    ctx.eps = eps

    ########################
    # END OF YOUR CODE    #
    #######################

    return out

  @staticmethod
  def backward(ctx, grad_output):
    """
    Compute backward pass of the batch normalization.

    Args:
      ctx: context object handling storing and retrival of tensors and constants and specifying
           whether tensors need gradients in backward pass
    Returns:
      out: tuple containing gradients for all input arguments

    TODO:
      Retrieve saved tensors and constants via ctx.saved_tensors and ctx.constant
      Compute gradients for inputs where ctx.needs_input_grad[idx] is True. Set gradients for other
      inputs to None. This should be decided dynamically.
    """

    ########################
    # PUT YOUR CODE HERE  #
    #######################
    input, gamma, beta, mean, inv_var = ctx.saved_tensors
    input_needs_grad, gamma_needs_grad, beta_needs_grad = ctx.needs_input_grad
    batch_dim = input.shape[0]

    x_hat = (input - mean) * inv_var
    dx_hat = grad_output * gamma
    grad_gamma = (grad_output * x_hat).sum(0) if gamma_needs_grad else None
    grad_beta = grad_output.sum(0) if beta_needs_grad else None
    grad_input = 1./batch_dim * inv_var * \
                (batch_dim * dx_hat - dx_hat.sum(0) - \
                x_hat * (dx_hat * x_hat).sum(0)) if input_needs_grad else None
    ########################
    # END OF YOUR CODE    #
    #######################

    # return gradients of the three tensor inputs and None for the constant eps
    return grad_input, grad_gamma, grad_beta, None

######################################################################################
# Code for Question 3.2 c)
######################################################################################

class CustomBatchNormManualModule(nn.Module):
  """
  This nn.module implements a custom version of the batch norm operation for MLPs.
  In self.forward the functional version CustomBatchNormManualFunction.forward is called.
  The automatic differentiation of PyTorch calls the backward method of this function in the backward pass.
  """

  def __init__(self, n_neurons, eps=1e-5):
    """
    Initializes CustomBatchNormManualModule object.

    Args:
      n_neurons: int specifying the number of neurons
      eps: small float to be added to the variance for stability

    TODO:
      Save parameters for the number of neurons and eps.
      Initialize parameters gamma and beta via nn.Parameter
    """
    super(CustomBatchNormManualModule, self).__init__()

    ########################
    # PUT YOUR CODE HERE  #
    #######################
    self.gamma = nn.Parameter(torch.ones(n_neurons))
    self.beta = nn.Parameter(torch.zeros(n_neurons))
    self.eps = eps
    ########################
    # END OF YOUR CODE    #
    #######################

  def forward(self, input):
    """
    Compute the batch normalization via CustomBatchNormManualFunction

    Args:
      input: input tensor of shape (n_batch, n_neurons)
    Returns:
      out: batch-normalized tensor

    TODO:
      Check for the correctness of the shape of the input tensor.
      Instantiate a CustomBatchNormManualFunction.
      Call it via its .apply() method.
    """

    ########################
    # PUT YOUR CODE HERE  #
    #######################
    shape = input.shape

    if len(shape) == 1:
        input = input.unsqueeze(0)
        shape = input.shape
    elif len(shape) > 2:
        raise ValueError(
            f"Expected 2D input. Instead, got {len(shape)}D input with shape of {shape}.")
    elif shape[1] != self.gamma.shape[0]:
        raise ValueError(f"Expected input of shape batch_size x {self.gamma.shape[0]}. Instead, got input with"
                         f"shape of {shape}.")

    batchNormFunc = CustomBatchNormManualFunction()
    out = batchNormFunc.apply(input, self.gamma, self.beta, self.eps)
    ########################
    # END OF YOUR CODE    #
    #######################

    return out


""" Module for analytic expressions of option prices
"""

from scipy.stats import norm
import numpy as np

def black_scholes_call_price(spot,strike,expiry,interest_rate,volatility):
      """ Analytic Black schole price for a European call

      Args:
        - spot: current spot
        - strike: call option's strike
        - expiry: expiry/maturity of the option (in years)
        - interest_rate: annualized interest rate
        - volatility: annualized volatility

      Returns:
        - price: the price of the European call
      """
      k = strike
      factor_plus  = (interest_rate+0.5*volatility**2)
      factor_minus = (interest_rate-0.5*volatility**2)
      d1 = (np.log(spot/k) + factor_plus*expiry) \
           /volatility/np.sqrt(expiry)
      d2 = (np.log(spot/k) + factor_minus*expiry) \
           /volatility/np.sqrt(expiry)
      price  = spot*norm.cdf(d1) - \
               k*np.exp(-interest_rate*expiry)*norm.cdf(d2)
      return price

def margrabe_option_price(spots,expiry,covariance_matrix):
    """ Analytic Magrabe price for an exchange option

    """
    sigma = np.sqrt(np.trace(covariance_matrix) \
                    - np.trace(np.fliplr(covariance_matrix)))
    if len(np.shape(spots))>1:
        s_plus  = spots[:,0]
        s_minus = spots[:,1]
        d1 = (np.log(s_plus/s_minus)+sigma**2*expiry*0.5)/sigma/np.sqrt(expiry)
        d2 = d1 - sigma*np.sqrt(expiry)
        price  = s_plus*norm.cdf(d1) - s_minus*norm.cdf(d2)
    else:
        s_plus  = spots[0]
        s_minus = spots[1]
        d1 = (np.log(s_plus/s_minus)+sigma**2*expiry)*0.5/sigma/np.sqrt(expiry)
        d2 = d1 - sigma*np.sqrt(expiry)
        price  = s_plus*norm.cdf(d1) - s_minus*norm.cdf(d2)
    return price


import numpy as np

#Función que calcula la matriz resultante C después de aplicar la operación convolución de A*B
def convolucion(A,B):
	for row in range(len(A)-2):
		for column in range(len(A[0])-2):
			suma = 0
			for i_row in range(len(B)):
				for j_column in range(len(B[0])):
					suma = suma + A[row+i_row][column+j_column]*B[i_row][j_column]
			C[row][column] = suma
	return C

#Matriz del ejemplo de la página
Matriz1 = [[1,2,3,4,5,6],[7,8,9,10,11,12],[0,0,1,16,17,18],[0,1,0,7,23,24],[1,7,6,5,4,3]]
Filtro = [[1,1,1],[0,0,0],[2,10,3]]

#Matriz del ejercicio.
#Matriz1 =[[6,9,0,3],[8,4,9,1],[4,1,3,12],[3,2,1,100]]
#Filtro = [[1,0,2],[5,0,9],[6,2,1]]

A = np.array(Matriz1) #Me da una mejor representación al hacer el print.
B = np.array(Filtro)

C = np.zeros((len(A)-2,len(A[0])-2)) #Genera una matriz de ceros que me sirve para inicializar la matriz directamente.

print(np.array(C))
print(convolucion(A,B))


##### Графики на плоскости

### --- 1 Задание пункт:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-2*np.pi, 3*np.pi, 201)
plt.plot(x,  5*np.cos(x + 1) + 5)
plt.plot(x, -0.5*np.cos(x + 6))
plt.plot(x, 4*np.cos(x - 2)-5)
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()

### --- 3 Задание ---

## Напишите код, который будет переводить полярные координаты в декартовы.
a = np.linspace(0, 2*np.pi, 100)
r = 2
x = r*np.cos(a)
y = r*np.sin(a)
plt.plot(x, y)

## Напишите код, который будет рисовать график окружности в полярных координатах.
x = np.linspace(0, 2*np.pi, 100)
y = 4+0*np.cos(x)
plt.polar(x, y)

## Напишите код, который будет рисовать график отрезка прямой линии в полярных координатах.
#--- не сделано

### --- 4 Задание ---
## 1

from scipy.optimize import fsolve

def equations(p):
    x, y = p
    return (y - x**2 + 1, np.exp(x) + x - x*y - 1)

x1, y1 =  fsolve(equations, (-2, 3))

print (x1, y1)
x2, y2 =  fsolve(equations, (2, 3))

print (x2, y2)

## 2
#--- не сделано


"""
This file uses fourier transform from numpy module on data filemsl_rems.csv
which recorded surface air pressure measurements from the Mars over 2
Mars years. We will explore the how to extract information through
Fourier transfrom
"""
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks

#importing data from csv
marsData = np.genfromtxt('msl_rems.csv', delimiter=',',skip_header=1)
Time,L_S,A,B,C,D,E = marsData.T

def cosine_wave(time, amplitude, period, phase):
    """Generate a cosine wave with known amplitude, period, and phase"""
    return amplitude*np.cos((time/period + phase) *2*np.pi)

def fourierAnalysis(data,dt):
    """
    Perform Fourier Transform and return the fft coeffiecients,
    frequency, amplitude, and phase
    """
    fftData = np.fft.fft(data)
    fftData = fftData[1::]
    freqs = np.fft.fftfreq(len(data),dt)
    freqs = freqs[1::]
    amplitude = 2 * np.abs(fftData)/len(data)
    phase = np.arctan2(fftData.imag, fftData.real)

    ln = len(data)//2
    amplitude = amplitude[:ln]
    phase = phase[:ln]
    freqs = freqs[:ln]

    return fftData, freqs, amplitude, phase

def printAnswers(peaksIndices, amplitude, freqs, phase):
    """
    This function takes the indices of peaks and prints out the
    amplitude, period, and phase of the peaks.
    """
    for i in peaksIndices:
        print("Peak {}:".format(np.where(peaksIndices == i)[0]+1))
        print("amplitudes:", amplitude[i])
        print("period:", 1/freqs[i], "sol")
        print("phase:", phase[i], "rad")
        print()

def filterbyMinPeriod(peakIndices, freqs, amplitude, minimum, num):
    """
    This function takes the indices of peaks and filter out for peaks with
    periods over a minimum threshold. Then, it will print out the
    amplitude, period, and phase of the peaks.
    """
    temp = []
    for i in peakIndices:
        if 1/freqs[i] >= minimum:
            temp.append(i)
    result = sorted(temp, key=lambda x: amplitude[x], reverse=True)
    return result[:num]

def filterbyMaxPeriod(peakIndices, freqs, amplitude, maximum, num):
    """
    This function takes the indices of peaks and filter out for peaks with
    periods under a maximum threshold. Then, it will print out the
    amplitude, period, and phase of the peaks.
    """
    temp = []
    for i in peakIndices:
        if 1/freqs[i] <= maximum:
            temp.append(i)
    result = sorted(temp, key=lambda x: amplitude[x], reverse=True)
    return result[:num]

## PART A
#set arbituary time from 0s to 100s for testing
dt = 0.1
timeRange = np.arange(0,100,dt)
#construction of our test case with amplitude of 3, period of 20, and phase of 0.25
y = cosine_wave(timeRange, 3, 20, 0.25)
#fourier transformed data
fy, freqs, amplitude, phase = fourierAnalysis(y, dt)
#calculating amplitude, period, phase from fft data
print("fft amplitude:", np.max(amplitude), "original amplitude:",3)
print("fft period:", 1/freqs[np.argmax(amplitude)], "original period:",20)
print("fft phase:", phase[np.argmax(amplitude)]/(2*np.pi), "original phase:",np.pi/2)
#plotting the results
fig, graph = plt.subplots()
graph.plot(timeRange, y)
graph.set(xlabel='Time', ylabel='Amplitude',
      title='Frequency and amplitude')
graph.grid()
plt.show()

fig, graph = plt.subplots()
graph.plot(1/freqs, amplitude)
graph.set(xlabel='Frequency', ylabel='Amplitude',
      title='Frequency and amplitude')
graph.grid()
fig.savefig("q2a.png")
plt.show()

## PART B
#fourier transform data set A
fy, freqs, amplitude, phase = fourierAnalysis(A, 1/24)
#find the peaks in amplitude and printing respective informations:
peaksIndices = find_peaks(amplitude)[0][::-1]
printAnswers(peaksIndices, amplitude, freqs, phase)

#plotting amplitude and phase over period in log scale
fig, graph = plt.subplots()
graph.plot(1/freqs, amplitude)
graph.set(xlabel='Period in log scale (sols)', ylabel='Pressure Amplitude (Pa?)',
       title='Period and amplitude',xscale="log")
graph.grid()
fig.savefig("q2b_amplitude.png")
plt.show()

fig, graph = plt.subplots()
graph.plot(1/freqs, phase)
graph.set(xlabel='Period in log scale (sols)', ylabel='Phase (rad)',
       title='Period and phase',xscale="log")
graph.grid()
fig.savefig("q2b_phase.png")
plt.show()

## PART C
#fourier transform data set B
fy, freqs, amplitude, phase = fourierAnalysis(B, 1/24)
#find the peaks in amplitude and printing respective informations:
peaksIndices = find_peaks(amplitude)[0][::-1]
printAnswers(peaksIndices, amplitude, freqs, phase)

#plotting amplitude and phase over period in log scale
fig, graph = plt.subplots()
graph.plot(1/freqs, amplitude)
graph.set(xlabel='Period in log scale (sols)', ylabel='Pressure Amplitude',
       title='Period and amplitude', xscale="log")
graph.grid()
fig.savefig("q2c_amplitude.png")
plt.show()

fig, graph = plt.subplots()
graph.plot(1/freqs, phase)
graph.set(xlabel='Period in log scale (sols)', ylabel='Phase (rad)',
       title='Period and phase',xscale="log")
graph.grid()
fig.savefig("q2c_phase.png")
plt.show()

## PART D
#fourier transform data set C
fy, freqs, amplitude_C, phase = fourierAnalysis(C, 1/24)
#find the peaks in amplitude and printing respective informations:
peaksIndices_C = find_peaks(amplitude_C)[0][::-1]
printAnswers(peaksIndices_C, amplitude_C, freqs, phase)

#plotting amplitude and phase over period in log scale
fig, graph = plt.subplots()
graph.plot(1/freqs, amplitude_C)
graph.set(xlabel='Period in log scale (sols)', ylabel='Pressure Amplitude',
       title='Period and amplitude', xscale="log")
graph.grid()
fig.savefig("q2d_amplitude.png")
plt.show()

fig, graph = plt.subplots()
graph.plot(1/freqs, phase)
graph.set(xlabel='Period in log scale (sols)', ylabel='Phase (rad)',
       title='Period and phase',xscale="log")
graph.grid()
fig.savefig("q2d_phase.png")
plt.show()

## PART E
#fourier transform data set D
fy, freqs, amplitude_D, phase = fourierAnalysis(D, 1/24)
#find the peaks in amplitude and printing respective informations:
#using information from part d to kinda cheat
mask = []
for peak in peaksIndices_C:
    mask.append(np.where(np.logical_and(amplitude_D <= amplitude_C[peak]*1.1,
                               amplitude_D >= amplitude_C[peak]*0.9))[0])
mask = [item for sublist in mask for item in sublist]
peaksIndices = find_peaks(amplitude_D, distance=16047)[0][::-1]
printAnswers(mask, amplitude_D, freqs, phase)

#plotting amplitude and phase over period in log scale
fig, graph = plt.subplots()
graph.plot(1/freqs, amplitude_D)
graph.set(xlabel='Period in log scale (sols)', ylabel='Pressure Amplitude (Pa?)',
       title='Period and amplitude', xscale="log")
graph.grid()
fig.savefig("q2e_amplitude.png")
plt.show()

fig, graph = plt.subplots()
graph.plot(1/freqs, phase)
graph.set(xlabel='Period in log scale (sols)', ylabel='Phase (rad)',
       title='Period and phase',xscale="log")
graph.grid()
fig.savefig("q2e_phase.png")
plt.show()

fig, graph = plt.subplots()
graph.plot(Time, D)
graph.set(xlabel='time (s)', ylabel='Pressure (Pa)',
       title='Time series of D')
graph.grid()
fig.savefig("q2e_timeseries.png")
plt.show()

## PART F
#fourier transform data set E
fy, freqs, amplitude, phase = fourierAnalysis(E, 1/24)
#find the peaks in amplitude and printing respective informations:
peaksIndices = find_peaks(amplitude)[0][::-1]
#finding peaks over 100 sols and under 1 sol
filtered100 = filterbyMinPeriod(peaksIndices, freqs, amplitude, 100, 4)
filtered1 = filterbyMaxPeriod(peaksIndices, freqs, amplitude, 1.1, 4)
print("largest  waves  with periods longer than 100 sols:")
printAnswers(filtered100, amplitude, freqs, phase)
print("largest  waves  with periods shorted than 1 sols:")
printAnswers(filtered1, amplitude, freqs, phase)

#plotting amplitude and phase over period in log scale
fig, graph = plt.subplots()
graph.plot(1/freqs, amplitude)
graph.set(xlabel='Period in log scale (sols)', ylabel='Pressure Amplitude (Pa?)',
       title='Period and amplitude', xscale="log")
graph.grid()
fig.savefig("q2f_amplitude.png")
plt.show()

fig, graph = plt.subplots()
graph.plot(1/freqs, phase)
graph.set(xlabel='Period in log scale (sols)', ylabel='Phase (rad)',
       title='Period and phase',xscale="log")
graph.grid()
fig.savefig("q2f_phase.png")
plt.show()


'''
Is Temperature a Random Walk (with Drift)?

An ARMA model is a simplistic approach to forecasting climate changes, but it illustrates many of the topics covered in this class.

The DataFrame temp_NY contains the average annual temperature in Central Park, NY from 1870-2016 (the data was downloaded from the NOAA here). Plot the data and test whether it follows a random walk (with drift).

INSTRUCTIONS
100XP
Convert the index of years into a datetime object using pd.to_datetime(), and since the data is annual, pass the argument format='%Y'.
Plot the data using .plot()
Compute the p-value the Augmented Dickey Fuller test using the adfuller function.
Save the results of the ADF test in result, and print out the p-value in result[1].
'''
# Import the adfuller function from the statsmodels module
from statsmodels.tsa.stattools import adfuller

# Convert the index to a datetime object
temp_NY.index = pd.to_datetime(temp_NY.index, format='%Y')

# Plot average temperatures
temp_NY.plot()
plt.show()

# Compute and print ADF p-value
result = adfuller(temp_NY['TAVG'])
print("The p-value for the ADF test is ", result[1])


# Eric Robbins
# A quick test of scipy's solution to the assignment (cost-matrix) problem

import random
import numpy as np
from scipy.optimize import linear_sum_assignment
import math

X_RANGE = 100
Y_RANGE = 100

# randomize stations and centroids (workers and jobs, respectively, in the classic assignment problem)
# format is (index, x_coord, y_coord)
stations = [(i, random.randint(-X_RANGE, X_RANGE), random.randint(-Y_RANGE, Y_RANGE)) for i in range(15)]
centroids = [(i, random.randint(-X_RANGE, X_RANGE), random.randint(-Y_RANGE, Y_RANGE)) for i in range(15)]

# calculate pythagorean distance between two xy coords
def pyth_dist(pt1, pt2):

    return math.sqrt(math.pow((pt2[1] - pt1[1]), 2) + math.pow((pt2[2] - pt1[2]), 2))

# create empty numpy array
m = len(stations)
n = len(centroids)
cost_mat = np.empty(shape=(m,n))

newRow = []
temp_arr = []

# make matrix out of station->centroid distances
for j in range(n):
    for i in range(m):
        newRow.append(pyth_dist(stations[i], centroids[j]))
    temp_arr.append(newRow)
    newRow = []

# fill numpy array
cost_mat = np.array(temp_arr)

# find optimized pairings (hungarian method)
opt_row, opt_col = linear_sum_assignment(cost_mat)

# output ordered pairs
print_list = []
for i in range(len(opt_row)):
    print_list.append((stations[opt_row[i]], centroids[opt_col[i]]))

print(print_list)


import numpy as np
from sklearn.metrics import matthews_corrcoef

def sigmoid(x):
    return 1.0 / (1.0 + np.exp(- x))

def mcc(tp, tn, fp, fn):
    sup = tp * tn - fp * fn
    inf = (tp + fp) * (tp + fn) * (tn + fp) * (tn + fn)
    if inf == 0:
        return 0
    else:
        return sup / np.sqrt(inf)

def eval_mcc(y_true, y_prob, show=False):
    idx = np.argsort(y_prob)
    y_true = np.array(y_true, dtype=int)
    y_true_sort = y_true[idx]
    n = y_true.shape[0]
    nump = 1.0 * np.sum(y_true)  # number of positive
    numn = n - nump  # number of negative
    tp = nump
    tn = 0.0
    fp = numn
    fn = 0.0
    best_mcc = 0.0
    best_id = -1
    mccs = np.zeros(n)
    for i in range(n):
        if y_true_sort[i] == 1:
            tp -= 1.0
            fn += 1.0
        else:
            fp -= 1.0
            tn += 1.0
        new_mcc = mcc(tp, tn, fp, fn)
        mccs[i] = new_mcc
        if new_mcc >= best_mcc:
            best_mcc = new_mcc
            best_id = i
    best_proba = y_prob[idx[best_id]]
    y_pred = (y_prob > best_proba).astype(int)
    final_mcc = matthews_corrcoef(y_true, y_pred)
    if show:
        return best_proba, final_mcc, y_pred
    else:
        return final_mcc

def eval_mcc0(y_true, y_prob, show=False):
    return matthews_corrcoef(y_true, (y_prob > 0.005) * 1)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jul  9 11:57:54 2019

@author: fietekrutein

A script for solving an unconstrained single variable function using
the Golden Section method
"""
import numpy as np

# function as per example problem

def gsNext(a0, b0, p):
    return(a0 + p*(b0 - a0))

# method

def GoldenSection(a,b,fx,tol=0.001):
    aCurrent = a
    bCurrent = b

    N = int(np.ceil((np.log(2*tol) - np.log(np.abs(b-a)))/np.log(0.618)))

    aNext = gsNext(aCurrent, bCurrent, 0.382)
    bNext = gsNext(aCurrent, bCurrent, 0.618)
    fxa = fx(aNext)
    fxb = fx(bNext)

    for i in range(N):
        if fxa < fxb:
            bCurrent = bNext
            bNext = aNext
            fxb = fxa
            aNext = gsNext(aCurrent, bCurrent, 0.382)
            fxa = fx(aNext)
        else:
            aCurrent = aNext
            aNext = bNext
            fxa = fxb
            bNext = gsNext(aCurrent, bCurrent, 0.618)
            fxb = fx(bNext)

    return((aCurrent+bCurrent)/2)

# execute

GoldenSection(0,2,lambda x: 2*x**6 + 3*x**4 -12*x, 0.01)


from numpy import mat

'''
测试A的转置的逆与A的逆的转置是否相等
'''
m = mat([[2, 3, 1],
         [4, 5, 6],
         [7, 8, 9],
         ])

print(m.T.I)
print(m.I.T)


import numpy as np
import matplotlib.pyplot as plt

# mass, spring constant, initial position and velocity
m = 1
k = 1
x = 0
v = 1

# Creating first two data using Euler's method
t_max = 0.2
dt = 0.1
t_array = np.arange(0, t_max, dt)
x_list = []
v_list = []
for t in t_array:
    x_list.append(x)
    v_list.append(v)
    a = -k * x / m
    x = x + dt * v
    v = v + dt * a

# Verlet method
t_max = 10
dt = 0.1
t_array = np.arange(0.2, t_max, dt)

# initialise empty lists to record trajectories
counter = 1
# Euler integration
for t in t_array:
    # append current state to trajectories
    # calculate new position and velocity
    a = -k * x / m
    x = 2*x_list[counter]-x_list[counter-1]+(dt**2)*a
    v = (1/dt)*(x-x_list[counter])
    x_list.append(x)
    v_list.append(v)
    counter +=1
# convert trajectory lists into arrays, so they can be sliced (useful for Assignment 2)
x_array = np.array(x_list)
v_array = np.array(v_list)

t_array_plot = np.arange(0, t_max, dt)
# plot the position-time graph
plt.figure(1)
plt.clf()
plt.xlabel('time (s)')
plt.grid()
plt.plot(t_array_plot, x_array, label='x (m)')
plt.plot(t_array_plot, v_array, label='v (m/s)')
plt.legend()
plt.show()


import numpy as np
import matplotlib.pyplot as plt

def identity(x):
    return x

def d_identity(x):
    return np.ones(shape=x.shape)

def relu(x):
    y = np.copy(x)
    threshold = x < np.zeros(shape=x.shape)
    y[threshold] = 0
    return y

def d_relu(x):
    y = np.ones(shape=x.shape)
    threshold = x < np.zeros(shape=x.shape)
    y[threshold] = 0
    return y

def sigmoid(x):
    return 1/(1+np.exp(-x))

def d_sigmoid(x):
    return sigmoid(x)*(1-sigmoid(x))

if __name__ == '__main__':
    x = np.arange(-6, 6, 0.1)
    y = identity(x)
    plt.plot(x, y)
    y = d_identity(x)
    plt.plot(x, y)
    plt.show()

    y = relu(x)
    plt.plot(x, y)
    y = d_relu(x)
    plt.plot(x, y)
    plt.show()

    y = sigmoid(x)
    plt.plot(x, y)
    y = d_sigmoid(x)
    plt.plot(x, y)
    plt.show()


import numpy as np
from matplotlib import cm
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

def surface_curvature_3d(X, Y, Z):
  # Shape
  (lr,lb) = X.shape

  # First Derivatives
  Xv,Xu = np.gradient(X)
  Yv,Yu = np.gradient(Y)
  Zv,Zu = np.gradient(Z)

  # Second Derivatives
  Xuv,Xuu = np.gradient(Xu)
  Yuv,Yuu = np.gradient(Yu)
  Zuv,Zuu = np.gradient(Zu)

  Xvv,Xuv = np.gradient(Xv)
  Yvv,Yuv = np.gradient(Yv)
  Zvv,Zuv = np.gradient(Zv)

  # 2D to 1D conversion
  # Reshape to 1D vectors
  Xu = np.reshape(Xu,lr*lb)
  Yu = np.reshape(Yu,lr*lb)
  Zu = np.reshape(Zu,lr*lb)
  Xv = np.reshape(Xv,lr*lb)
  Yv = np.reshape(Yv,lr*lb)
  Zv = np.reshape(Zv,lr*lb)
  Xuu = np.reshape(Xuu,lr*lb)
  Yuu = np.reshape(Yuu,lr*lb)
  Zuu = np.reshape(Zuu,lr*lb)
  Xuv = np.reshape(Xuv,lr*lb)
  Yuv = np.reshape(Yuv,lr*lb)
  Zuv = np.reshape(Zuv,lr*lb)
  Xvv = np.reshape(Xvv,lr*lb)
  Yvv = np.reshape(Yvv,lr*lb)
  Zvv = np.reshape(Zvv,lr*lb)

  Xu = np.c_[Xu, Yu, Zu]
  Xv = np.c_[Xv, Yv, Zv]
  Xuu = np.c_[Xuu, Yuu, Zuu]
  Xuv = np.c_[Xuv, Yuv, Zuv]
  Xvv = np.c_[Xvv, Yvv, Zvv]

  # First fundamental Coeffecients of the surface (E,F,G)
  E = np.einsum('ij,ij->i', Xu, Xu)
  F = np.einsum('ij,ij->i', Xu, Xv)
  G = np.einsum('ij,ij->i', Xv, Xv)

  m = np.cross(Xu, Xv, axisa=1, axisb=1)
  p = np.sqrt(np.einsum('ij,ij->i', m, m))
  n = m / np.c_[p,p,p] # n is the normal

  # Second fundamental Coeffecients of the surface (L,M,N), (e,f,g)
  L = np.einsum('ij,ij->i', Xuu, n) #e
  M = np.einsum('ij,ij->i', Xuv, n) #f
  N = np.einsum('ij,ij->i', Xvv, n) #g

  # Gaussian Curvature
  # Alternative formula for gaussian curvature in wiki
  # K = det(second fundamental) / det(first fundamental)
  K = (L*N-M**2) / (E*G-F**2)
  K = np.reshape(K, lr*lb)
  # wiki trace of (second fundamental)(first fundamental inverse)

  # Mean Curvature
  H = ((E*N + G*L - 2*F*M) / ((E*G - F**2))) / 2
  H = np.reshape(H,lr*lb)

  # Principle Curvatures
  Pmax = H + np.sqrt(H**2 - K)
  Pmin = H - np.sqrt(H**2 - K)

  # Curvedness
  # 3D Shape Modeling for Cell Nuclear Morphological Analysis and Classification
  CV = np.sqrt((Pmin**2 + Pmax**2) / 2)

  # Shape Index
  # 3D Shape Modeling for Cell Nuclear Morphological Analysis and Classification
  SI = np.zeros(Pmax.shape)
  idx = (Pmax - Pmin) != 0
  SI[idx] = (2 / np.pi) * np.arctan((Pmin[idx] + Pmax[idx])/(Pmax[idx] - Pmin[idx]))

  # Reshape
  K = np.reshape(K,(lr,lb))
  H = np.reshape(H,(lr,lb))
  Pmax = np.reshape(Pmax,(lr,lb))
  Pmin = np.reshape(Pmin,(lr,lb))
  CV = np.reshape(CV,(lr,lb))
  SI = np.reshape(SI,(lr,lb))

  return K, H, Pmax, Pmin, CV, SI

if __name__ == '__main__':

  # Generate surface data
  X = np.arange(-5, 5, 0.25)
  Y = np.arange(-5, 5, 0.25)
  X, Y = np.meshgrid(X, Y)
  Z = np.exp(-0.1*X**2-0.1*Y**2)

  # Curvature 3D
  K, H, Pmax, Pmin, CV, SI = surface_curvature_3d(X, Y, Z)

  # Plot
  fig = plt.figure()
  ax = fig.gca(projection='3d')

  # Auto-adjust true radius into [0,1] for color mapping
  norm = Normalize()
  colors = norm(CV)
  cmap = cm.get_cmap("jet")

  # Surface
  ax.plot_surface(X, Y, Z, facecolors=cmap(colors),
                  linewidth=0, antialiased=False)

  # Add a color bar which maps values to colors
  # the surface is not mappable, we need to handle the colorbar manually
  mappable = cm.ScalarMappable(cmap=cmap)
  mappable.set_array(colors)
  fig.colorbar(mappable, shrink=0.9, aspect=5)

  # Save
  plt.savefig('./im/surface_curvature3d.png', bbox_inches = 'tight',
    pad_inches = 0)

  # Show
  plt.show()


import numpy as np

def centroide(k,data,cent):
    n = np.array(data.shape)[0]
    dataF = np.zeros(shape=(n,k),dtype=float)
    for counter in range(0,k):
        diff = cent[counter,:] - data
        diff2 = diff**2
        diffm = diff2[:,0] + diff2[:,1]
        distance = [ x**0.5 for x in diffm]
        dataF[:,counter] = distance
    dataC = np.zeros(shape=(k,2),dtype=float)
    indice = np.argmin(dataF,1)
    for counter in range(0,k):
        x = data[indice == counter][:,0].mean()
        y = data[indice == counter][:,1].mean()
        new_center = [x,y]
        dataC[counter,:] = new_center
    return(dataC)

def kmeans(data,k):
    center = np.random.rand(k,2)
    while True:
        new_center = centroide(k,data,center)
        comp = center - new_center
        if np.all(comp == 0):
            center = new_center
            break
        else:
            center = new_center
            new_center = centroide(k,data,center)
    return center


import numpy as np

d1 = np.array([1,2,3,4])
d2 = np.array([5,6,7,8])

result =np.add( d1, d2)

print("add\n",result)
result =np.subtract( d1, d2)

print("subtract\n",result)
result =np.multiply( d1, d2)

print("multiply\n",result)
result =np.divide( d2, d1)

print("divide\n",result)

result =np.floor_divide( d2, d1)

print("floor divide\n",result)

result =np.power( d1, d2)

print("power\n",result)

result =np.remainder( d1, d2)

print("remainder\n",result)

result =np.divmod( d2, d1)

print("divmod\n",result)

result =np.absolute( d1)*-1

print("-abs\n",result)

result =np.trunc(  d2/d1)

print("trunc\n",result)
result =np.around(  d2/d1,2)

print("around\n",result)
result =np.floor(  d2/d1)

print("floor\n",result)
result =np.ceil(  d2/d1)

print("ceil\n",result)
result =np.ceil(  d1/d2)
print("Original\n",d1/d2)
print("ceil\n",result)
result =np.log(  d1)

print("log\n",result)
result =np.log10(  d2/d1)

print("log10\n",result)


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

# importing the Iris dataset -- only use dataset with target value 0 and 1
iris = datasets.load_iris()
X = iris.data[:100,:]
X = np.insert(X, [4], [[1]]*100, axis=1)
y = iris.target[:100]

# split data
np.random.seed(1)
shuffle = np.insert(X, [5], np.reshape(y,(100,1)), axis=1)
np.random.shuffle(shuffle)
X = shuffle[:, :5]
y = shuffle[:, 5]

X_train = X[:80]
y_train = y[:80]
X_test = X[80:100]
y_test = y[80:100]

def cost(theta, X, y):
    sum = 0
    for i in range(len(X)):
        sum += y[i] * np.log(1/(1 + np.exp(-np.sum(X[i]*theta)))) + (1-y[i]) * np.log(1 - 1/(1 + np.exp(-np.sum(X[i]*theta))))
    return (-1/len(X)) * sum

def derivative(theta, X, y, j):
    sum = 0
    for i in range(len(X)):
        sum += (1/(1+np.exp(-np.sum(X[i]*theta))) - y[i])*X[i, j]
    return sum

def accuracy(theta, X_train, y_train, X_test, y_test):
    prediction = 1/(1+np.exp(-np.matmul(X_train, theta)))
    train_accuracy = 100 - np.sum(np.power(np.round(prediction)-y_train, 2)) / len(y_train) * 100
    prediction = 1/(1+np.exp(-np.matmul(X_test, theta)))
    test_accuracy = 100 - np.sum(np.power(np.round(prediction)-y_test, 2)) / len(y_test) * 100
    return np.round(train_accuracy, 2), np.round(test_accuracy, 2)

alpha = 0.1
np.random.seed(1)
theta = np.random.rand(5)

iter = 1
iter_cost = []
iter_accuracy = []
while True :
    temp = [0] * 5
    for j in range(len(theta)):
        temp[j] = theta[j] - alpha * (1/len(X)) * derivative(theta, X_train, y_train, j)
    theta = temp.copy()
    tr_a, te_a = accuracy(theta, X_train, y_train, X_test, y_test)
    print('iter', str(iter), ':', cost(theta, X_train, y_train), "/ train set Accuracy :", tr_a,"%","/ test set Accuracy :", te_a,"%")
    iter_cost.append([iter, cost(theta, X_train, y_train), cost(theta, X_test, y_test)])
    iter_accuracy.append([iter, tr_a, te_a])
    iter += 1
    if cost(theta, X_train, y_train) < 0.05 :
        if cost(theta, X_train, y_train) > 0.1 :
            print('The model may be overfitted.')
        print(theta)
        break

iter_cost = np.array(iter_cost)
j_train = iter_cost[:,[0,1]]
j_test = iter_cost[:,[0,2]]
plt.figure(0)
plt.plot(j_train[:,0], j_train[:,1], label='train-set')
plt.plot(j_test[:,0], j_test[:,1], label='test-set')
plt.title("Cost Curve for Logistic Regression")
plt.xlabel("number of iterations")
plt.ylabel("cost")
plt.ylim(0,3)
plt.legend()
plt.savefig('logistic_regression__cost_curve.png', bbox_inches='tight')

iter_accuracy = np.array(iter_accuracy)
acc_train = iter_accuracy[:,[0,1]]
acc_test = iter_accuracy[:,[0,2]]
plt.figure(1)
plt.plot(acc_train[:,0], acc_train[:,1], label='train-set')
plt.plot(acc_test[:,0], acc_test[:,1], label='test-set')
plt.title("Accuracy Curve for Logistic Regression")
plt.xlabel("number of iterations")
plt.ylabel("accuracy (%)")
plt.legend()
plt.savefig('logistic_regression__accuracy_curve.png', bbox_inches='tight')


import numpy as np
import scipy.linalg as sl

def gaussian_loglikelihood(z, th, sigsq):
  z = np.atleast_2d(z)
  x = z[:, :-1]
  y = z[:, -1]
  th = np.atleast_2d(th)
  XST = x.dot(th.T)
  return -1./2.*np.log(2.*np.pi*sigsq) - 1./(2.*sigsq)*(y[:,np.newaxis]**2 - 2*XST*y[:,np.newaxis] + XST**2)

def gaussian_grad_x_loglikelihood(z, th, sigsq):
  z = np.atleast_2d(z)
  x = z[:, :-1]
  y = z[:, -1]
  th = np.atleast_2d(th)
  return 1./sigsq*(y[:, np.newaxis] - x.dot(th.T))[:,:,np.newaxis]*np.hstack((th, np.ones(th.shape[0])[:,np.newaxis]))[np.newaxis, :, :]

def gaussian_KL(mu0, Sig0, mu1, Sig1inv):
  t1 = np.dot(Sig1inv, Sig0).trace()
  t2 = np.dot((mu1-mu0),np.dot(Sig1inv, mu1-mu0))
  t3 = -np.linalg.slogdet(Sig1inv)[1] - np.linalg.slogdet(Sig0)[1]
  return 0.5*(t1+t2+t3-mu0.shape[0])

def weighted_post(th0, Sig0inv, sigsq, z, w):
  z = np.atleast_2d(z)
  X = z[:, :-1]
  Y = z[:, -1]
  LSigpInv = np.linalg.cholesky(Sig0inv + (w[:, np.newaxis]*X).T.dot(X)/sigsq)
  LSigp = sl.solve_triangular(LSigpInv, np.eye(LSigpInv.shape[0]), lower=True, overwrite_b = True, check_finite = False)
  mup = np.dot(LSigp.dot(LSigp.T),  np.dot(Sig0inv,th0) + (w[:, np.newaxis]*Y[:,np.newaxis]*X).sum(axis=0)/sigsq )
  #Sigp = np.linalg.inv(Sig0inv + (w[:, np.newaxis]*X).T.dot(X)/sigsq)
  #mup = np.dot(Sigp,  np.dot(Sig0inv,th0) + (w[:, np.newaxis]*Y[:,np.newaxis]*X).sum(axis=0)/sigsq )
  return mup, LSigp, LSigpInv


import sympy as sp

x = sp.Symbol('x')
function = x**2 - 2

def bisection(f, xl, xr):
    fxl = f.evalf(subs={x : xl})
    xm = 0

    while True:
        xm = (xl + xr)/2
        fxl = f.evalf(subs={x : xl})
        fxm = f.evalf(subs={x : xm})
        if fxl * fxm < 0:
            xr = xm
        else:
            xl = xm

        if abs(fxm) < 10**(-4):
            break

    return xm

def newton(f, df, xVal):
    while True:
        fx = f.evalf(subs={x : xVal})
        xVal = xVal -  fx/ df.evalf(subs={x : xVal})

        if abs(fx) < 10**(-4):
            break

    return xVal

def secant(f, x1, x2):
    xNew = 0

    while True:
        fx1 = f.evalf(subs={x : x1})
        fx2 = f.evalf(subs={x : x2})
        denominator = fx2 - fx1
        if denominator != 0:
            xNew = x2 - ((x2-x1)/denominator) * fx2
            if abs(xNew - x2) < 10*(-4):
                break
            else:
                x1 = x2
                x2 = xNew
        else:
            break

    return xNew

print("Bisection:", bisection(function, 0, 4))
print("Newton:", newton(function, sp.diff(function), 4))
print("Secant:", secant(function, 0, 4))


import numpy as np

print("VEKTORAUFGABEN")
print()
print("a) Betrag des Vektors [[-6]")
print("                       [7]]")
print()
print('=', np.linalg.norm(np.array([[-6], [7]])))
print()
print("b) [[2]    [[-4]")
print("    [3]  +  [5]")
print("    [4]]    [-7]]")
print()
print('=', np.array([[2], [3], [4]]) + np.array([[-4], [5], [-7]]))
print()
print("c)     [[6]")
print("   5 *  [-7]")
print("        [8]]")
print()
print('=', 5 * np.array([[6], [-7], [8]]))
print()
print("d) [[2]    [[8]")
print("    [3]  *  [-1]")
print("    [4]]    [4]]")
print()
print('=', np.array([[2], [3], [4]]) * np.array([[8], [-1], [4]]))
print()
print("MATRIXAUFGABEN")
print()
print("                      [[2    1.5]")
print("A = [[3  -4  5] , B =  [-1.5   2]  , C = [[-3  1]")
print("     [-5  4  3]]       [0     -1]]        [2  -4]]")
print()
a = np.array([[3, -4, 5], [-5, 4, 3]])
b = np.array([[2, 1.5], [-1.5, 2], [0, -1]])
c = np.array([[-3, 1], [2, -4]])
print("a) A + B[T]")
print('=', a + b.transpose())
print()
print("b) A * B")
print('=', np.dot(a, b))
print()
print("c) B * A")
print('=', np.dot(b, a))
print()
print("d) det(C)")
print('=', np.linalg.det(c))
print()
print("e) C ** -1")
print('=', np.linalg.inv(c))
print()
print("f) Gleichungssysteme mit inverser Matrix lösen:")
print("f1) -3x + y = 0, 2x - 4y = -20")
print('=', np.linalg.solve(c, np.array([0, -20])))
print()
print("f2) -3x + y = -2, 2x - 4y = 16")
print('=', np.linalg.solve(c, np.array([-2, 16])))


import numpy as np
import matplotlib.pyplot as plt
from scipy.special import assoc_laguerre
import seaborn as sns

sns.set_theme()

def radial_wavefunction(x, n, l, z):
    prefac = (2.0 * z / n) ** 3 / 2.0 / n / np.prod(range(n - l, n + l + 1))
    return (
        -np.sqrt(prefac)
        * np.exp(-z * x / n)
        * (2.0 * z * x / n) ** l
        * assoc_laguerre(2.0 * z * x / n, n - l - 1, k=2.0 * l + 1.0)
    )

def integrate(x, y):
    return np.sum((y[1:] + y[:-1]) * (x[1:] - x[:-1])) / 2

def normalize(x, y):
    mask = x > 0
    prop_density = y[mask] ** 2
    N = integrate(x[mask], prop_density)
    if y[1] < 0:
        return y / x / np.sqrt(N)
    return -y / x / np.sqrt(N)

def plot_eigenfunction(
    basefilename, indices, savename, xmax=10, l=0, z=1, fakenorm=False, legend=True
):
    data = np.genfromtxt(f"build/output/{basefilename}_plot_points.npy").T
    eigvalues = np.genfromtxt(f"build/output/{basefilename}_eigenvalues.npy").T

    x, ys = data[0], data[1:]
    mask = x <= xmax

    iter = list(zip(ys, eigvalues))
    for idx in indices:
        y, eigvalue = iter[idx]
        y_ = normalize(x, y)

        ana = radial_wavefunction(x[mask], idx + 1 + l, l, z)

        if fakenorm:
            y_ = y_ / y_[mask][-10] * ana[-10]

        p = plt.plot(x[mask], y_[mask], label=f"$E_{{ {idx+1} }}={eigvalue}$")[0]

        if not legend:
            plt.text(x[mask][1] - 0.1, y_[mask][1] - 0.1, f"$E_{{ {idx+1} }}$")

        plt.plot(
            x[mask],
            ana,
            ".",
            alpha=0.5,
            color=p.get_color(),
        )

    plt.xlabel("$r/a_0$")
    plt.ylabel(r"$\psi_n(r) / a_0^{-3/2}$")

    if legend:
        plt.legend()

    plt.tight_layout()
    plt.savefig(f"build/plots/{savename}.pdf")
    plt.cla()

plot_eigenfunction("good_wideplot", [0, 1, 2], "eigenfunctions", legend=False)
plot_eigenfunction("good_wideplot", [10, 11, 12], "eigenfunctions_high", fakenorm=True)
plot_eigenfunction("good_wideplot_l1", [1, 2, 3], "eigenfunctions_l1", l=1)
plot_eigenfunction("good_wideplot_l2", [2, 3, 4], "eigenfunctions_l2", l=2)
plot_eigenfunction(
    "good_wideplot_l6", [6, 7, 8], "eigenfunctions_l6", fakenorm=True, l=6
)


import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sys
from math import sin, cos, sqrt, atan2, radians
from sklearn.metrics import confusion_matrix
from sklearn.metrics import roc_curve, auc

def computeGeoDistance(lat1, lon1, lat2, lon2):

    # approximate radius of earth in km
    R = 6373.0

    lat1 = radians(lat1)
    lon1 = radians(lon1)
    lat2 = radians(lat2)
    lon2 = radians(lon2)

    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))

    distance = R * c

    # print("Result:", distance)
    # print("Should be:", 278.546, "km")

    return round(distance,4)

def missing_data(data_frame):
    total = data_frame.isnull().sum().sort_values(ascending=False)
    percent = (data_frame.isnull().sum()/data_frame.isnull().count()).sort_values(ascending=False)
    missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])

    return missing_data

def deal_synonyms(i, dict_synonyms):
    if i.strip() in dict_synonyms:
        i = dict_synonyms[i.strip()]
    return i

#########################################################
#  evaluation

def confusionMatrix(y_test, y_pred, model_name):

    cm = confusion_matrix(y_true = y_test, y_pred = y_pred)

    fig, ax = plt.subplots(figsize = (5, 5))
    ax.matshow(cm, alpha = 0.3, cmap = plt.cm.Blues)
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            ax.text(x = j, y = i, s = cm[i,j], va = 'center', ha = 'center')
    plt.xlabel('predicted label')
    plt.ylabel('true label')
    plt.title(model_name)
    plt.show()

def rocCurcve(test_y, test_y_score):

    # Compute ROC curve and ROC area for each class
    fpr, tpr, threshold = roc_curve(test_y, test_y_score)
    roc_auc = auc(fpr, tpr)

    lw = 2
    plt.figure(figsize=(8, 5))
    plt.plot(fpr, tpr, color='darkorange',
            lw=lw, label='ROC curve (area = %0.2f)' % roc_auc)
    plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('False Positive Rate')
    plt.ylabel('True Positive Rate')
    plt.title('Receiver operating characteristic example')
    plt.legend(loc="lower right")
    plt.show()

if __name__ == "__main__":
    lat1 = 52.2296756
    lon1 = 21.0122287
    lat2 = 52.406374
    lon2 = 16.9251681
    computeGeoDistance(lat1, lon1, lat2, lon2)