"""
This file contains tests that determine whether the code for utility functions works as expected.
"""

from functools import reduce
from math import gcd
from random import randint
from typing import Any, List

import pytest
from sympy import isprime

from tno.mpc.encryption_schemes.utils._check_gmpy2 import USE_GMPY2
from tno.mpc.encryption_schemes.utils.utils import (
    extended_euclidean,
    is_prime,
    lcm,
    mod_inv,
    pow_mod,
    randprime,
)

if USE_GMPY2:
    from gmpy2 import mpz

def prod(list_: List[Any]) -> Any:
    """
    Multiply all elements in a list

    :param list_: list of elements to be multiplied
    :return: the product of the elements in the input list
    """
    return reduce((lambda x, y: x * y), list_)

@pytest.mark.parametrize(
    "low, high",
    # random intervals
    [
        (rand_low, rand_low + randint(0, 2 ** 100))
        for rand_low in [randint(0, 2 ** 100) for _ in range(100)]
    ],
)
def test_randprime_regular_behaviour(low: int, high: int) -> None:
    """
    Test to check whether the randprime function from the utils module returns primes in the right
    interval and whether the result is of the correct type. The correct type depends on whether
    GMPY2 is installed.

    :param low: lower bound for the interval
    :param high: upper bound for the interval
    """
    prime = randprime(low, high)
    assert isprime(prime)
    assert low <= prime < high
    if USE_GMPY2:
        assert isinstance(prime, type(mpz(0)))
    else:
        assert isinstance(prime, int)

@pytest.mark.parametrize(
    "low, high",
    # random intervals
    [
        (rand_low, rand_low - randint(0, 2 ** 100))
        for rand_low in [randint(0, 2 ** 100) for _ in range(100)]
    ],
)
def test_randprime_wrong_input(low: int, high: int) -> None:
    """
    Test to check whether the randprime function from the utils module returns primes in the right
    interval and whether the result is of the correct type. The correct type depends on whether
    GMPY2 is installed.

    :param low: lower bound for the interval
    :param high: upper bound for the interval
    """
    with pytest.raises(ValueError):
        _ = randprime(low, high)

@pytest.mark.parametrize(
    "nr_of_primes",
    # 100 testentries, where the nr_of_primes is random between 3 and 100 and the respective powers
    # are random between 1 and 100
    list(range(3, 30)),
)
def test_lcm(nr_of_primes: int) -> None:
    """
    Test to determine whether the lcm function works properly. Artificial values are created through
    random prime numbers and random powers, such that we know the correct lcm by construction.
    This value is then checked against the result from the lcm function of the utils module.

    :param nr_of_primes: The number of primes to be generated
    """
    primes = []
    for i in range(nr_of_primes):
        new_prime = randprime(1, 2 ** 100)
        while new_prime in primes:
            new_prime = randprime(1, 2 ** 100)
        primes.append(new_prime)

    powers_1 = [randint(0, 100) for _ in range(nr_of_primes)]
    powers_2 = [randint(0, 100) for _ in range(nr_of_primes)]
    lcm_powers = [max(powers_1[i], powers_2[i]) for i in range(nr_of_primes)]
    value_1 = prod([primes[i] ** powers_1[i] for i in range(nr_of_primes)])
    value_2 = prod([primes[i] ** powers_2[i] for i in range(nr_of_primes)])
    correct_lcm = prod([primes[i] ** lcm_powers[i] for i in range(nr_of_primes)])
    if USE_GMPY2:
        utils_lcm_value = lcm(mpz(value_1), mpz(value_2))
    else:
        utils_lcm_value = lcm(value_1, value_2)
    assert correct_lcm == utils_lcm_value

@pytest.mark.parametrize(
    "value, inverse",
    [(randint(2, 2 ** 1024), randint(2, 2 ** 1024)) for _ in range(100)],
)
def test_mod_inv_invertible(value: int, inverse: int) -> None:
    """
    Test to check whether the mod_inv function works properly. Artificial pairs of value, inverse
    are created and the respective modulus is extracted from this input.

    :param value: value for which the inverse needs to be found
    :param inverse: correct inverse
    """
    # extract modulus such that inverse is the modulus inverse of value
    # modulus = value * inverse - 1 ->
    # value * inverse = modulus + 1 ->
    # value * inverse = 1 mod modulus
    modulus = value * inverse - 1
    utils_inverse = mod_inv(value, modulus)
    assert utils_inverse == inverse

@pytest.mark.parametrize(
    "value, modulus",
    [
        (prime, prime ** randint(3, 10))
        for prime in [randprime(3, 2 ** 100) for _ in range(100)]
    ]
    + [(0, prime) for prime in [randprime(3, 2 ** 100) for _ in range(100)]],
)
def test_mod_inv_not_invertible(value: int, modulus: int) -> None:
    """
    Test to check whether the mod_inv function correctly identifies when a value is not invertible
    in Z_modulus.

    :param value: value for which the inverse needs to be found
    :param modulus: modulus such that value is not invertible in Z_modulus
    """
    with pytest.raises(ZeroDivisionError):
        _ = mod_inv(value, modulus)

@pytest.mark.parametrize(
    "value, power, modulus",
    [
        (randint(1, mod - 1) * (randint(0, 1) * 2 - 1), randint(-mod, mod), mod)
        for mod in [randprime(3, 2 ** 20) for _ in range(100)]
    ],
)
def test_pow_mod_prime(value: int, power: int, modulus: int) -> None:
    """
    Test to check whether the pow_mod returns correct results for positive and negative values and
    powers if the modulus is prime (and thus each element is invertible).

    :param value: the base
    :param power: the exponent
    :param modulus: the modulus
    """
    correct_value = 1
    if power < 0:
        value = mod_inv(value, modulus)
        power = -power
    for _ in range(power):
        correct_value = (correct_value * value) % modulus
    utils_value = pow_mod(value, power, modulus)
    assert utils_value == correct_value

@pytest.mark.parametrize(
    "value, power, modulus",
    [
        (prime, randint(-prime + 1, -1), prime ** randint(2, 10))
        for prime in [randprime(3, 2 ** 20) for _ in range(100)]
    ],
)
def test_pow_mod_prime_power(value: int, power: int, modulus: int) -> None:
    """
    Test to check whether the pow_mod returns correctly identifies that negative powers are
    impossible to calculate when the base value is not invertible in Z_modulus

    :param value: the base
    :param power: the exponent
    :param modulus: the modulus
    """
    with pytest.raises(ValueError):
        _ = pow_mod(value, power, modulus)

@pytest.mark.parametrize(
    "value_1, value_2",
    [(randint(3, 2 ** 100), randint(3, 2 ** 100)) for _ in range(100)],
)
def test_extended_euclidean(value_1: int, value_2: int) -> None:
    """
    Test to determine whether the extended euclidean function works properly. The return value of
    the gcd is checked against the gcd result from the math library and the relation between the
    outputs and the inputs is verified.

    :param value_1: integer value
    :param value_2: integer value
    """
    gcd_inputs, value_1_mult, value_2_mult = extended_euclidean(value_1, value_2)
    assert gcd_inputs == gcd(value_1, value_2)
    assert value_1_mult * value_1 + value_2_mult * value_2 == gcd_inputs

@pytest.mark.parametrize(
    "low, high",
    # random intervals
    [
        (rand_low, rand_low + randint(0, 2 ** 100))
        for rand_low in [randint(0, 2 ** 100) for _ in range(100)]
    ],
)
def test_primality_check_primes(low: int, high: int) -> None:
    prime = randprime(low, high)
    assert is_prime(prime)

@pytest.mark.parametrize(
    "number",
    # random number
    list(randint(0, 2 ** 100) for _ in range(100)),
)
def test_primality_check_random_number(number: int) -> None:
    # compare the custom is_prime function with the sympy.isprime function
    assert isprime(number) == is_prime(number)


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

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

from collections import Counter
import math

def create_data():
    iris = load_iris()
    df = pd.DataFrame(iris.data, columns=iris.feature_names)
    df['label'] = iris.target
    df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
    data = np.array(df.iloc[:100, :])
    # print(data)
    return data[:,:-1], data[:,-1]

X, y = create_data()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

class NaiveBayes:
    def __init__(self):
        self.model = None

    # 数学期望
    @staticmethod
    def mean(x):
        return sum(x)/float(len(x))

    # 标准差
    def std(self,x):
        avg = self.mean(x)
        return math.sqrt(sum(math.pow(x_i-avg,2) for x_i in x)/float(len(x)))

    # 概率密度函数
    def gaussian_prob(self,x,mean,std):
        exp = math.pow(math.e, -1*(math.pow(x - mean,2))/(2*std))
        return (1/(math.sqrt(2*math.pi*std)))*exp

    # 计算训练的均值和方差
    def mean_and_std(self,x):
        mean_and_std=[(self.mean(i),self.std(i)) for i in zip(*x)]
        return mean_and_std

    # 分类别求出数学期望和标准差
    def fit(self,x,y):
        labels = list(set(y))
        data = {label:[] for label in labels}
        for f,label in zip(x,y):
            data[label].append(f)
        self.model = {label:self.mean_and_std(value) for label,value in data.items()}
        return "GaussianNB train Done!"

    # 计算概率
    def prob(self,data):
        probabillity = {}
        for label,value in self.model.items():
            probabillity[label] = 1
            for i in range(len(value)):
                mean,std = value[i]
                probabillity[label] *= self.gaussian_prob(data[i],mean,std)
        return probabillity

    # 类别
    def predict(self,x_test):
        label = sorted(self.prob(x_test).items(),key=lambda x:x[-1])[-1][0]
        return label

    def score(self,x_test,y_test):
        right = 0
        for x,y in zip(x_test,y_test):
            label = self.predict(x)
            if  label == y:
                right+=1
        return right / float(len(x_test))

model = NaiveBayes()
model.fit(X_train,y_train)
print(model.predict([4.4,3.2,1.3,0.2]))

# scikit-learn 实现

from sklearn.naive_bayes import  GaussianNB # 高斯模型
from sklearn.naive_bayes import BernoulliNB # 伯努利模型
from sklearn.naive_bayes import MultinomialNB # 多项式模型

clf = GaussianNB()
# clf = BernoulliNB()
# clf = MultinomialNB()

clf.fit(X_train,y_train)
print(clf.predict([[4.4,3.2,1.3,0.2]]))

lihang-reading_notes (with code)/第4章 朴素贝叶斯(NaiveBayes)/naive_bayes.py


import numpy as np

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


import tensorflow as tf
import numpy as np
from scipy import optimize
import scipy.spatial as spatial

def manhattan(x, y):
    # L1
    return tf.reduce_sum(tf.abs(x - y))

def euclidean(x, y):
    # L2
    return tf.sqrt(tf.reduce_sum((x - y) ** 2))

def minkowski(x, y, p):
    # Lp
    return tf.reduce_sum(tf.abs(x - y) ** p) ** (1 / p)

def chebyshev(x, y):
    # L-infinity
    return tf.reduce_max(tf.abs(x - y))

def hamming(x, y):
    return tf.reduce_sum(~tf.equal(x, y)) / tf.size(x)

def py_minkowski(x, y, p=2):
    return np.sum(np.abs(x-y)**p) ** (1 / p)

def mahalanobis_distance(obs, X, center="zero"):
    # mahalanobis distance of obs to X
    # wiki:
    # https://en.wikipedia.org/wiki/Mahalanobis_distance

    # 计算协方差矩阵
    cov = np.cov(X.T)

    # 计算数据集的中心
    if center == "zero":
        center = np.zeros(cov.shape[1])
    else:
        center = np.mean(X, axis=0)

    # 矩阵的逆不一定存在，这里使用矩阵的伪逆
    icov = np.linalg.pinv(cov)
    # 计算 obs 到 center 的 Mahalanobis distance
    d = spatial.distance.mahalanobis(obs, center, icov)
    return d

def wasserstein_distance(p, q, C):
    """Wasserstein距离计算方法，
    p.shape=(m,)
    q.shape=(n,)
    C.shape=(m,n)
    p q满足归一性概率化
    """
    p = np.array(p)
    q = np.array(q)
    A_eq = []
    for i in range(len(p)):
        A = np.zeros_like(C)
        A[i,:] = 1.0
        A_eq.append(A.reshape((-1,)))
    for i in range(len(q)):
        A = np.zeros_like(C)
        A[:,i] = 1.0
        A_eq.append(A.reshape((-1,)))
    A_eq = np.array(A_eq)
    b_eq = np.concatenate([p, q], axis=0)
    C = np.array(C).reshape((-1,))
    return optimize.linprog(
        c=C,
        A_eq=A_eq[:-1],
        b_eq=b_eq[:-1],
        method="interior-point",
        options={"cholesky":False, "sym_pos":True}
    ).fun


import numpy as np
from scipy import linalg as lin
from sklearn.preprocessing import StandardScaler

class RCCA:
    def __init__(self,n_comp=2,reg_param=0.1):
        self.n_comp = n_comp
        self.reg_param = reg_param

    def fit(self,data):
        if len(data) != 2: #RCCA works only for 2 views of data
            print('Use different variant of CCA.')
            print('For this variant use only 2 views of the data.')
        else:
            print('Training RCCA with regularization parameter = {} and {} components'.format(self.reg_param,self.n_comp))
            M = [d.T for d in data]
            D,F = 2,[m.shape[0] for m in M] # F stores number of features in both datasets
            n_comp = min([m.shape[1] for m in M])# stores minimum number of samples
            cross_cov = [np.dot(a,b.T)/n_comp for a in M for b in M] #Sxx,Syx,Sxy,Syy
            self.cross_cov = cross_cov

            #left = A, right = B for A*u = lambda*B*u <- generalized eigen problem
            left,right = np.zeros((sum(F),sum(F))), np.zeros((sum(F),sum(F)))
            for i in range(D):
                right[sum(F[:i]):sum(F[:i+1]), sum(F[:i]):sum(F[:i+1])] = (cross_cov[i*(D+1)] + self.reg_param*np.eye(F[i]))
                for j in range(D):
                    if i != j:
                        left[sum(F[:j]):sum(F[:j+1]), sum(F[:i]):sum(F[:i+1])] = cross_cov[D*j + i]

            left = (left + left.T)/2 # converted to symmetric matrix
            right = (right + right.T)/2 # converted to symmetric matrix

            e_value, e_vector = lin.eigh(left, right) #solved generalized eigenproblem
            e_value[np.isnan(e_value)] = 0
            eval_index = np.argsort(e_value)[::-1]
            self.weights = []
            e_vector = e_vector[:, eval_index]
            for i in range(D):
                self.weights.append(e_vector[sum(F[:i]):sum(F[:i+1]), :self.n_comp])
            self.weights = [w.real for w in self.weights]
            self.c_comp = [np.dot(i[0].T,i[1]) for i in zip(M,self.weights)] #canonical components

            #canonical variates
            k = len(self.c_comp)
            self.variates = np.zeros((self.c_comp[0].shape[1],k,k))
            for i in range(k):
                for j in range(k):
                    if j > i:
                        self.variates[:,i,j] = [np.nan_to_num(np.corrcoef(p,q)[0,1]) for (p,q) in zip(self.c_comp[i].T,self.c_comp[j].T)]
            self.variates = self.variates[np.nonzero(self.variates)]
            return self

    def transform(self,data):
        sc = StandardScaler()
        d_norm = [sc.fit_transform(d) for d in data]
        Ls = [np.dot(d,w) for d,w in zip(d_norm,self.weights)]
        return Ls


import codecademylib3_seaborn
from song_data import songs
import matplotlib.pyplot as plt
import numpy as np

q1 = np.quantile(songs, 0.25)
q2 = np.quantile(songs, 0.5)
q3 = np.quantile(songs, 0.75)

plt.subplot(3,1,1)
plt.hist(songs, bins = 200)
plt.axvline(x=q1, c = 'r')
plt.axvline(x=q2, c = 'r')
plt.axvline(x=q3, c = 'r')
plt.xlabel("Song Length (Seconds)")
plt.ylabel("Count")
plt.title("4-Quantiles")

plt.subplot(3,1,2)
plt.hist(songs, bins = 200)
plt.axvline(x=np.quantile(songs, 0.2), c = 'r')
plt.axvline(x=np.quantile(songs, 0.4), c = 'r')
plt.axvline(x=np.quantile(songs, 0.6), c = 'r')
plt.axvline(x=np.quantile(songs, 0.8), c = 'r')
plt.xlabel("Song Length (Seconds)")
plt.ylabel("Count")
plt.title("5-Quantiles")

plt.subplot(3,1,3)
plt.hist(songs, bins = 200)
for i in range(1, 10):
  plt.axvline(x=np.quantile(songs, i/10), c = 'r')
plt.xlabel("Song Length (Seconds)")
plt.ylabel("Count")
plt.title("10-Quantiles")

plt.tight_layout()
plt.show()

Data Scientist Career Path/7. Summary Statistics/5. Quartiles, Quantiles, Interquartile Range/2. Quantiles/1. intro.py


import numpy as np
import matplotlib.pyplot as plt

def vandermonde(x, d):
  # Expanding x in Vandermonde Matrix: f(x) = 1 + x + x^2 ... + x^d
  X = np.matrix(np.polynomial.polynomial.polyvander(x, d))
  return X

def polynomial_regression(x, y, d):
  # Expanding x in Vandermonde Matrix
  X = vandermonde(x, d)
  # Calculating model weights: W = Inv(X.T * X) * X.T * Y
  w = np.linalg.inv(np.transpose(X) * X) * np.transpose(X) * np.transpose(np.matrix(y))
  return w

# Importing dataset
## Dataset path
dataset_path = 'data/whData.dat'
## Column names
dt = np.dtype([('w', np.float), ('h', np.float), ('g', np.str_, 1)])
## Loading the dataset
dataset = np.loadtxt(dataset_path, dtype=dt, comments='#', delimiter=None)
## Loading dataset without outliers
dataset_without_outliers = dataset[np.where(dataset['w'] > 0)]
## Loading dataset outliers (w < 0)
dataset_outliers = dataset[np.where(dataset['w'] < 0)]

# Heights from the training data
train_data = dataset_without_outliers['h']
# Weights from the training data
train_labels = dataset_without_outliers['w']
# Heights to predict their corresponding weights
test_data = dataset_outliers['h']

# Regression line X points to draw the model fitted line
regressionX = np.linspace(np.amin(train_data)-5, np.amax(train_data)+5, 1000)

# Polynomial fitting for d = {1, 5, 10}
d = [1, 5, 10]
fig, ax = plt.subplots(1, len(d), sharey=True)
# Data mean(mu) and standard deviation (sigma)
mu = train_data.mean()
sigma = train_data.std()
for i in range(len(d)):
  # Standardize the data
  X_train = (train_data - mu) / sigma
  # Calculating the coefficients (weights) of the polynomial fitted line
  W = polynomial_regression(X_train, train_labels, d[i])
  # Standardize the regression line X points and expand them in Vandermonde Matrix
  X_regression = vandermonde((regressionX - mu) / sigma, d[i])
  # Calculating the fitted line Y points
  y = X_regression * W
  # Standardize the outlier height points and expand them in Vandermonde Matrix
  X_test = vandermonde((test_data - mu) / sigma, d[i])
  # Calculating the corresponding weights (prediction values)
  predictions = X_test * W
  # Plot the results
  ## Plot the data
  l1, = ax[i].plot(train_data, train_labels, 'k.')
  ## Plot the model line
  l2, = ax[i].plot(regressionX, y, 'b-')
  ## plot the predictions
  l3, = ax[i].plot(test_data, predictions, 'r.')
  ## Setting axes limits and title
  ax[i].set_xlim(np.amin(train_data)-5, np.amax(train_data)+5)
  ax[i].set_ylim(np.amin(train_labels)-5, np.amax(train_labels)+5)
  ax[i].set_title("d = " + str(d[i]))

fig.legend((l1, l2, l3), ('Data', 'Polynomial fitted line', 'Predictions'), 'lower right')
fig.text(0.5, 0.04, 'Height', ha='center')
fig.text(0.04, 0.5, 'Weight', va='center', rotation='vertical')
plt.savefig("out/regression/plots.png", bbox_inches="tight", pad_inches=0)
plt.show()


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

import numpy as np
import numpy.linalg as la

class Kernel(object):
    """
    Implemented following definitions at found at http://en.wikipedia.org/wiki/Support_vector_machine

    For these ones do I have to choose my kernel and pass arguments defined in the outer def,
    later passing x and y args to the  nested f function? How does this work?
    """
    @staticmethod
    def linear_kernel(**kwargs):
        def f(x1, x2):
            return np.inner(x1, x2) # inner is the dot product
        return f

    @staticmethod
    def gaussian(sigma):
        def f(x, y):
            left = la.norm(x-y) ** 2
            right = (2 * sigma ** 2)
            exponent = np.sqrt(left / right) * -1
            return np.exp(exponent)
        return f

    @staticmethod
    def polynomial_kernel(exponent, coef, **kwargs):
        def f(x1, x2):
            dotProduct = np.inner(x1, x2)
            return (dotProduct + coef)**exponent
        return f


import numpy as np

def areCospectral(A, B):
    """Input: 2 quadratic matrices of size n. Output: True/False depending if A and B are cospectral."""

    A_evals, _ = np.linalg.eig(A) # A_evecs
    B_evals, _ = np.linalg.eig(B) # B_evecs

    cospectral = validateEigenvalues(A_evals, B_evals)

    if cospectral:
        return True
    else:
        return False

def validateEigenvalues(A_evals, B_evals, err = 2 ** (-20)):
    """Input: 2 vectors containing the eigenvalues of 2 matrices.
    Output: True if the difference in all values is smaller then a given error."""

    evals = []

    for i in range(len(A_evals)):
        if A_evals[i] - B_evals[i] > err:
            return False
        evals.append(round(A_evals[i], 2))
    print(evals)

    return True

A = [
    [0,0,1,0,1],
    [0,0,0,0,0],
    [1,0,0,1,0],
    [0,0,1,0,1],
    [1,0,0,1,0]
]

B = [
    [0,1,0,0,0],
    [1,0,1,1,1],
    [0,1,0,0,0],
    [0,1,0,0,0],
    [0,1,0,0,0]
]

print(areCospectral(A, B))


import numpy as np

def AND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.7
    return int((np.sum(w*x) + b) > 0)

def NAND(x1, x2):
    x = np.array([x1, x2])
    w = np.array([-0.5, -0.5])
    b = 0.7
    return int((np.sum(w*x) + b) > 0)

def OR(x1, x2):
    x = np.array([x1, x2])
    w = np.array([0.5, 0.5])
    b = -0.2
    return int((np.sum(w*x) + b) > 0)

def XOR(x1, x2):
    return AND(NAND(x1, x2), OR(x1, x2))

print("AND")
print(AND(0, 0))
print(AND(1, 0))
print(AND(0, 1))
print(AND(1, 1))

print("NAND")
print(NAND(0, 0))
print(NAND(1, 0))
print(NAND(0, 1))
print(NAND(1, 1))

print("OR")
print(OR(0, 0))
print(OR(1, 0))
print(OR(0, 1))
print(OR(1, 1))

print("XOR")
print(XOR(0, 0))
print(XOR(1, 0))
print(XOR(0, 1))
print(XOR(1, 1))


import numpy as np

class MeanSquaredLogarithmicError:
    def __call__(self, y: np.ndarray, y_pred: np.ndarray) -> np.float64:
        return self.loss(y, y_pred)

    def loss(self, y: np.ndarray, y_pred: np.ndarray) -> np.float64:
        return np.sum(np.power(np.log(1 + y) - np.log(1 + y_pred), 2)) / y.shape[0]


import numpy as np
import matplotlib.pyplot as plt
import cvxpy as cvx

f = np.array( [1,1] )
A = np.array( [[2,1], [1,2]] )
b = np.array( [[29],[25]] )
lb = np.array( [[2],[5]] )

x = cvx.Variable(2,1)

objective = cvx.Minimize( -f*x )
constraints = [ A*x <=b, lb <=x ]

prob = cvx.Problem( objective, contraints )
result = prob.solve()

print(x.value)
print(result)

   # A = np.array( [2,1], [1,2] )
# => A = np.array( [[2,1], [1,2]] )
# Traceback (most recent call last):
  # File "cvxpy-example-linear_programming-01.py", line 6, in <module>
    # A = np.array( [2,1], [1,2] )
# TypeError: data type not understood


import numpy as np
from scipy.special import i0

def vonmises_kde(data, kappa, n_bins):
    """
    Generates a Vonmises kernel density estimate (KDE) for a given array
    of angles in radians.
    :param data: Angles in radians
    :param kappa: Vonmises kappa parameter
    :param n_bins: How many bins to generate the distribution over
    :return: Bins, Vonmises kDE
    """
    # from https: // stackoverflow.com / questions / 28839246 /
    # scipy - gaussian - kde - and -circular - data
    bins = np.linspace(-np.pi, np.pi, n_bins)
    x = np.linspace(-np.pi, np.pi, n_bins)
    # integrate vonmises kernels
    kde = np.exp(kappa * np.cos(x[:, None] - data[None, :])).sum(1) / (
        2 * np.pi * i0(kappa)
    )
    kde /= np.trapz(kde, x=bins)
    return bins, kde


from sympy.solvers import solve
from sympy import Symbol
from sympy import *
import matplotlib.pyplot as plt
import numpy as np
from scipy.sparse import *
from numpy.linalg import inv
from array import *
from scipy import linalg
x=Symbol('x')

# function to find k and f for linear elements
def kfmatixLin(nEle,domainLen,a,c,f):
    xb=[]
    xa=[]
    for i in range(1,nEle+1):
        xb.append(i*(domainLen/nEle))
        xa.append((i-1)*(domainLen/nEle))
    k=[]
    Ftemp=[]
    # for ith element  # NOTE: [[element 1 k's],[element 2 k's], ...]
    for i in range(nEle):
        psi_1 = (xb[i]-x)/(xb[i]-xa[i])
        psi_2 = (x-xa[i])/(xb[i]-xa[i])
        # print(psi_1)
        # print(psi_2)
        k.append([])
        Ftemp.append(integrate(f*psi_1 ,(x, xa[i], xb[i])))
        Ftemp.append(integrate(f*psi_2 ,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_1,x)*diff(psi_1,x)+c*psi_1*psi_1,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_1,x)*diff(psi_2,x)+c*psi_1*psi_2,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_2,x)*diff(psi_1,x)+c*psi_2*psi_1,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_2,x)*diff(psi_2,x)+c*psi_2*psi_2,(x, xa[i], xb[i])))

    F=[]
    F.append(Ftemp[0])
    for i in range(0,len(Ftemp)-2,2):
        F.append(Ftemp[i+1]+Ftemp[i+2])
    F.append(Ftemp[len(Ftemp)-1])

    # print('k = ',k)
    # print('Ftemp',Ftemp)
    # print('F = ',F)
    # two diagonals of the tridiagonal matrix
    diagA=[]
    diagB=[]
    # for three element 4*4 k matrix
    for i in range(nEle):
        diagA.append(k[i][1])
    # print('diagA',diagA)
    # NOTE: no need for diagC as it will always be same as diagA

    diagB.append(k[0][0])
    for i in range(nEle-1):
        diagB.append(k[i][3]+k[i+1][0])
    diagB.append(k[nEle-1][3])
    # print('diagB',diagB)
    diagA=np.array(diagA, dtype=np.float64)
    diagB=np.array(diagB, dtype=np.float64)

    K = np.array( diags([diagB,diagA,diagA], [0,-1, 1]).todense() )
    return(K,F)
# function to find k and f for Quadratic elements
def kfmatixQad(nEle,domainLen,a,c,f):
    xb=[]
    xa=[]
    xc=[]
    for i in range(1,nEle+1):
        xb.append(i*(domainLen/nEle))
        xa.append((i-1)*(domainLen/nEle))
    for i in range(nEle):
        xc.append(0.5*xa[i]+0.5*xb[i])
    # print('xa',xa)
    # print('xb',xb)
    # print('xc',xc)
    k=[]
    Ftemp=[]
    # for ith element  # NOTE: [[element 1 k's],[element 2 k's], ...]
    for i in range(nEle):
        psi_1 = ((x-xc[i])*(x-xb[i]))/((xa[i]-xc[i])*(xa[i]-xb[i]))
        psi_2 = ((x-xa[i])*(x-xb[i]))/((xc[i]-xa[i])*(xc[i]-xb[i]))
        psi_3 = ((x-xa[i])*(x-xc[i]))/((xb[i]-xa[i])*(xb[i]-xc[i]))
        # print(psi_1)
        # print(psi_2)
        k.append([])
        Ftemp.append(integrate(f*psi_1 ,(x, xa[i], xb[i])))
        Ftemp.append(integrate(f*psi_2 ,(x, xa[i], xb[i])))
        Ftemp.append(integrate(f*psi_3 ,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_1,x)*diff(psi_1,x)+c*psi_1*psi_1,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_1,x)*diff(psi_2,x)+c*psi_1*psi_2,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_1,x)*diff(psi_3,x)+c*psi_1*psi_3,(x, xa[i], xb[i])))

        k[i].append(integrate( a*diff(psi_2,x)*diff(psi_1,x)+c*psi_2*psi_1,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_2,x)*diff(psi_2,x)+c*psi_2*psi_2,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_2,x)*diff(psi_3,x)+c*psi_2*psi_3,(x, xa[i], xb[i])))

        k[i].append(integrate( a*diff(psi_3,x)*diff(psi_1,x)+c*psi_3*psi_1,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_3,x)*diff(psi_2,x)+c*psi_3*psi_2,(x, xa[i], xb[i])))
        k[i].append(integrate( a*diff(psi_3,x)*diff(psi_3,x)+c*psi_3*psi_3,(x, xa[i], xb[i])))

    F=[]
    F.append(Ftemp[0])
    F.append(Ftemp[1])
    t=0
    i=0
    while t<nEle-1:
        F.append(Ftemp[i+2]+Ftemp[i+3])
        F.append(Ftemp[i+4])
        i=i+3
        t=t+1
    F.append(Ftemp[len(Ftemp)-1])

    # print('k = ',k)
    # print('Ftemp',Ftemp)
    # print('F = ',F)
    # print('len f',len(F))
    # three diagonals of the quadiagonal matrix
    diagA=[]
    diagB=[]
    diagC=[]
    # for three element 4*4 k matrix
    for i in range(nEle):
        diagA.append(k[i][1])
        diagA.append(k[i][5])
    # print('diagA',diagA)

    for i in range(nEle):
        diagC.append(k[i][2])
        if i!=nEle-1:
            diagC.append(0.0)
    # print('diagC',diagC)

    diagB.append(k[0][0])
    diagB.append(k[0][4])
    for i in range(nEle-1):
        diagB.append(k[i][8]+k[i+1][0])
        diagB.append(k[i+1][4])
    diagB.append(k[nEle-1][8])

    # print('diagB',diagB)
    diagA=np.array(diagA, dtype=np.float64)
    diagB=np.array(diagB, dtype=np.float64)
    diagC=np.array(diagC, dtype=np.float64)

    K = np.array(diags([diagB,diagA,diagA,diagC,diagC], [0,-1, 1,-2, 2]).todense() )
    return(K,F)
# function to find Q at the left and right ends
def solQ(k,f,nEle,bcs,method):
    bc1=Symbol('bc1')
    bc2=Symbol('bc2')
    q1=Symbol('q1')
    q2=Symbol('q2')
    c1=0
    c2=0
    if method=='linear':
        for i in range(nEle+1):
            c1=c1+k[0][i]
            c2=c2+k[nEle][i]
        q1_eqn = c1*bc1-f[0]+q1
        q2_eqn = c2*bc2-f[nEle]-q2
    elif method=='Quadratic':
        for i in range(2*nEle+1):
            c1=c1+k[0][i]
            c2=c2+k[nEle][i]
        q1_eqn = c1*bc1-f[0]+q1
        q2_eqn = c2*bc2-f[2*nEle]-q2
    if len(bcs)==0:
        return(solve(q1_eqn,q1),solve(q2_eqn,q2))
    elif len(bcs)==2:
        return(solve(q1_eqn,q1)[0].subs(bc1,bcs[0]),solve(q2_eqn,q2)[0].subs(bc2,bcs[1]))

# user inputs
domainLen=1
# number of elements
nEle=3
# problem data
a=1
c=-1
f=-x*x
method='Both' # accepts 'Quadratic','linear','Both'
# dirchlet boundary conditions values at left and right end
bcs=[2,3] # assumed boundary values [left end,right end]

if method=='Quadratic':
    kq,fq=kfmatixQad(nEle,domainLen,a,c,f)
    q1q,q2q=solQ(kq,fq,nEle,bcs,'Quadratic')
    fq[0]=fq[0]+q1q
    fq[len(fq)-1]=fq[len(fq)-1]+q2q
    sq=linalg.inv(kq).dot(fq)
    print('Quadratic Solution, U : \n',sq)

elif method=='linear':
    k,f=kfmatixLin(nEle,domainLen,a,c,f)
    q1,q2 = solQ(k,f,nEle,bcs,'linear')
    f[0]=f[0]+q1
    f[nEle]=f[nEle]+q2
    sl=linalg.inv(k).dot(f)
    print('Linear Solution, U : \n',sl)

elif method=='Both':
    kq,fq=kfmatixQad(nEle,domainLen,a,c,f)
    q1q,q2q=solQ(kq,fq,nEle,bcs,'Quadratic')
    fq[0]=fq[0]+q1q
    fq[len(fq)-1]=fq[len(fq)-1]+q2q
    sq=linalg.inv(kq).dot(fq)
    print('Quadratic Solution, U : \n',sq)
    k,f=kfmatixLin(nEle,domainLen,a,c,f)
    q1,q2 = solQ(k,f,nEle,bcs,'linear')
    f[0]=f[0]+q1
    f[nEle]=f[nEle]+q2
    sl=linalg.inv(k).dot(f)
    print('\nLinear Solution, U : \n',sl)

import numpy,from numpy,from scipy,from sympy


import numpy as np
from scipy.optimize import leastsq

def gaussian_func(x, args):
    a, b, c, d = args
    return a * np.exp(-(x - b) ** 2 / (2 * c ** 2)) + d

def gaussian_fit_init_args(points):
    xs, ys = np.array(points).transpose()
    dx = xs[1] - xs[0]
    peak_index = np.argmax(ys)
    a = ys[peak_index]
    b = xs[peak_index]
    d = np.min(ys)
    c = dx * np.sum(ys - d) / np.sqrt(2.0 * np.pi) / a
    return np.array((a, b, c, d), np.float)

def gaussian_fit(points):
    init_args = gaussian_fit_init_args(points)
    result = leastsq(
        lambda args, xs, ys: gaussian_func(xs, args) - ys,
        init_args, (points[:, 0], points[:, 1]))
    return result[0]

def gaussian_fwhm(args):
    return 2 * args[2] * np.sqrt(2 * np.log(2))


import numpy as np
from matplotlib.pyplot import plot
from matplotlib.pyplot import show

bhp = np.loadtxt('BHP.csv', delimiter=',', usecols=(6,), unpack=True)

bhp_returns = np.diff(bhp) / bhp[ : -1]

vale = np.loadtxt('VALE.csv', delimiter=',', usecols=(6,), unpack=True)

vale_returns = np.diff(vale) / vale[ : -1]

covariance = np.cov(bhp_returns, vale_returns)
print "Covariance", covariance

print "Covariance diagonal", covariance.diagonal()
print "Covariance trace", covariance.trace()

print covariance/ (bhp_returns.std() * vale_returns.std())

print "Correlation coefficient", np.corrcoef(bhp_returns, vale_returns)

difference = bhp - vale
avg = np.mean(difference)
dev = np.std(difference)

print "Out of sync", np.abs(difference[-1] - avg) > 2 * dev

t = np.arange(len(bhp_returns))
plot(t, bhp_returns, lw=1)
plot(t, vale_returns, lw=2)
show()


"""
Designed to calculate the linear regression of any data passed in.
Must take in at least two sets of data (x, y) axis in order for a
linear regression line to be calculated.

Author: Ashton Foulger
Version: 0.01, 11/3/21
Python-Version: 3.10.0
"""

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

"""
Takes in two sets of data to compute the sum of X times Y
variables from both sets of data. Returning an int value of
the sum of the two data arrays.
"""
def Compute_SumXY(data1, data2):
    data_XY = []

    for n1, n2 in zip(data1, data2):
        data_XY.append(n1 * n2)

    return sum(data_XY)

"""
Takes in a data set, an alpha and beta values to compute points
on the linear regression line. To then be used to plot the line of
regression.
"""
def Compute_Regression_Slope_Points(data, a, b):
    y = 0
    squarePoints = []

    for i in range(len(data)):
        y = a + b * data[i]
        squarePoints.append(y)

    return squarePoints

"""
Computes the Sum of Squares Error used in calculating the
coefficient of determination. Taking in a data array, points
(found on line of regression), and an n value to act as a count
for how may points we need to sum. Returning an int value of the sum
of squares error.
"""
def Compute_SSE(data, squares, n):
    temp = []

    for i in range(n):
        data[i] - squares[i]
        temp.append((data[i] - squares[i])**2)

    return sum(temp)

"""
Computes the Sum of Squares Total used in calculating the coefficent
of determination. Taking in a data array, Mean of Y axis points, and an
n value to act as a count for how many points we need to sum. Returning
an int value of the sum of squares total.
"""
def Compute_SST(Y_data, Y_mean, n):
    temp = []
    for i in range(n):
        temp.append((Y_data[i] - Y_mean)**2)

    return sum(temp)

"""
Computes the Coefficent of Determination for linear regression line from the data.
Taking in a Sum of Squares Error int value, and Sum of Squares Total in value.
Returning an int value of R squared.
"""
def Compute_R_Squared(SSE, SST):
    R = 1 - (SSE / SST)
    return R

#---------------LINE_OF_BEST_FIT_CALCULATION---------------#

#Data Arrays
data_X = [1,2,3,4,5,6]
data_Y = [0,7,6,14,11,10]

#Data Sample Means
mean_X = np.mean(data_X)
mean_Y = np.mean(data_Y)

#Data Sample Variances
variance_X = np.var(data_X)
variance_Y = np.var(data_Y)

#Data Linear Regression Equation Variables
n = 6
sumX = sum(data_X)
sumXX = sum(np.power(data_X, 2))
sumY = sum(data_Y)
sumXY = Compute_SumXY(data_X, data_Y)
a = ((sumY * sumXX) - (sumX * sumXY)) / ((n * sumXX) - (sumX)**2)
b = ((n * sumXY) - (sumX * sumY)) / ((n * sumXX) - (sumX)**2)

#Data Coefficent of Determination Variable
lineOfBestFitSquares = Compute_Regression_Slope_Points(data_X, a, b)
SSE = Compute_SSE(data_Y, lineOfBestFitSquares, n)
SST = Compute_SST(data_Y, mean_Y, n)
R = Compute_R_Squared(SSE, SST)

#Print Linear Regression Values & Coefficent of Determination
print("\n")
print("Mean X : " + str(mean_X))
print("Mean Y : " + str(mean_Y))
print("Variance X : " + str(round(variance_X , 2)))
print("Variance Y : " + str(round(variance_Y, 2)))
print("Sum X : " + str(sumX))
print("Sum XX : " + str(sumXX))
print("Sum Y : " + str(sumY))
print("Sum XY : " + str(sumXY))
print("Var a : " + str(a))
print("Var b ; " + str(b))
print("SSE : " + str(SSE))
print("SST : " + str(SST))
print("R^2 : " + str(R))
print("\n")

#Display Linear Regression Graph
plt.scatter(data_X,data_Y, marker = 'd', color = 'blue')
plt.plot(data_X, data_Y, color = 'blue')
plt.scatter(data_X, lineOfBestFitSquares, marker = 's', color = 'red')
plt.plot(data_X, lineOfBestFitSquares, color = 'red')
plt.show()


import numpy as np
from functools import partial
from pyspark import SparkContext
from pyspark.sql import SparkSession

sc = SparkSession.builder.appName("AdvDat").getOrCreate()

def haversine(p,q):
    """
    Calculate haversine distance based on coordinates p,q
    """
    lng1, lat1 = p
    lng2, lat2 = q
    dlng = abs(lng2-lng1)
    dlat = abs(lat2-lat1)

    a = np.sin(0.5*dlng)**2 + np.cos(lng1)*np.cos(lng2)*np.sin(0.5*dlat)**2
    c = 2 * np.arctan2(np.sqrt(a),np.sqrt(1-a))
    return c*6371 # earth radius

def coordinates(line):
    """
    Produces coordinates tuples
    line: CSV string from RDD
    """
    contents = line.split(",")
    lng, lat = map(float,contents[3:5])
    return lng, lat

def closest(centroids,coordinates):
    """
    Computes the minimum haversine distance and saves centroid
    centroids: contains the centroids as tuples (id,coordinates)
    coordinates: tuple of floats

    Returns id_coords: tuple (int,tuple)
    Tuple containing the id of the closest centroid
    and the tuple of coordinates of this point
    """
    tup = [(cen[0], haversine(coordinates,cen[1])) for cen in centroids]
    distance = min(tup, key = lambda x:x[1])
    return (distance[0],coordinates)

def sum_by_elem(p,q):
    """
    Reduce Function, sums each coordinate of 2 items
    p,q: tuples of (tuple of floats: coordinates,int)
    Returns tuple of (tuple of summed floats, summed int)
    """
    p, num1 = p
    q, num2 = q
    tup = map(sum,zip(p,q))
    return (tuple(tup),num1+num2)

def avg_by_elem(p):
    """
    Averages the coordinates assigned to centroid
    p: tuple returned by sum_by_elem
    Returns tuple of floats: mean of coordinates
    """
    p, num = p
    avg = map(lambda x:x/num, p)
    return tuple(avg)

data = sc.textFile('yellow_tripdata_1m.csv')
# get all coordinates as tuples and filter outliers
population = data.map(coordinates).filter(lambda line: line[0] and line[1]).cache()

# take first 5 as initial centroids with id >= 1
centroids = list(enumerate(population.take(5),1))

for _ in range(3):
    # assign current centroids to closest() function
    p_closest = partial(closest,centroids)
    # find closest centroid for each pair of coordinates
    cen_coords = population.map(p_closest)
    # find new centroids by map-reduce-map
    new_centroids = cen_coords.mapValues(lambda label:(label,1))\
                              .reduceByKey(sum_by_elem)\
                              .mapValues(avg_by_elem)
    centroids = new_centroids.collect()

# save results in csv file
centroids = new_centroids.toDF(["id","centroid"])
centroids.withColumn("centroid", centroids.centroid.cast("string"))\
         .coalesce(1).write\
         .csv("/Centroids",header="true",mode="overwrite",quote="")


from numpy import zeros, array

def gauss_seidel(A,b,x10,x20,x30,n):
    x1 = zeros(n)
    x2 = zeros(n)
    x3 = zeros(n)
    x1[0] = x10
    x2[0] = x20
    x3[0] = x30
    print('%7s %9s %9s %9s' % ('k','x1','x2','x3'))
    print('%7d %9.5f %9.5f %9.5f' % (0,x1[0],x2[0],x3[0]))
    for k in range(n-1):
        x1[k+1] = (b[0] - A[0,1] * x2[k] - A[0,2] * x3[k])/A[0,0]
        x2[k+1] = (b[1] - A[1,0] * x1[k+1] - A[1,2] * x3[k])/A[1,1]
        x3[k+1] = (b[2] - A[2,0] * x1[k+1] - A[2,1] * x2[k+1])/A[2,2]
        print('%7d %9.5f %9.5f %9.5f' % (k+1,x1[k+1],x2[k+1],x3[k+1]))
    return x1,x2,x3

A = array([[5,-1,1],[-1,3,-1],[1,-1,4]])
b = array([6,2,11])
x10 = 0.0
x20 = 0.0
x30 = 0.0
n = 10
x1, x2, x3 = gauss_seidel(A,b,x10,x20,x30,n)


import numpy as np
from math import sqrt

def RMSE(y,y_hat):
    '''
    args
    ----
        y: true values (np array)
        y_hat: predicted values (np array)

     returns
     ----
        the root mean swquared error

    '''
    return sqrt(np.mean(np.square(y-y_hat)))


# Author: OMKAR PATHAK

import numpy as np

angles = np.array([0, 30, 45, 60, 90, 180, 360])

# Convert to radians by multiplying with pi/180
# for getting sine of angles
print(np.sin(angles * np.pi/180))

# for getting cosine of angles
print(np.cos(angles * np.pi/180))

# for getting tangent of angles
print(np.tan(angles * np.pi/180))

# for computing inverse of trigonometric functions
sine = np.sin(angles * np.pi/180)
sineinv = np.arcsin(sine)
# computing angle from inverse
print(np.degrees(sineinv))

# for rounding the values
print(np.around(sine, 4))       # [ 0.      0.5     0.7071  0.866   1.      0.     -0.    ]

# for rounding to previous integer
print(np.floor(sine))           # [ 0.  0.  0.  0.  1.  0. -1.]

# for rounding to next integer
print(np.ceil(sine))            # [ 0.  1.  1.  1.  1.  1. -0.]


# %% [markdown]
# # Gradient filters
# [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/YoniChechik/AI_is_Math/blob/master/c_03_edge_detection/gradient_filters.ipynb)

# %%
# to run in google colab
import sys
if 'google.colab' in sys.modules:
    import subprocess
    subprocess.call('apt-get install subversion'.split())
    subprocess.call('svn export https://github.com/YoniChechik/AI_is_Math/trunk/c_03_edge_detection/Bikesgray.jpg'.split())

# %%
import numpy as np
import cv2
from matplotlib import pyplot as plt

figsize = (10,10)

# %% [markdown]
# ## Original image
# %%
img = cv2.imread("Bikesgray.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.figure(figsize=figsize)
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.title('Original image')

# %% [markdown]
# ## X absolute grad filter
# %%
img = img.astype(float)  # 'uint8' doesn't work with minus sign - for filtering

# 1. cv2.filter2D is working with corelation rether than convolution
#    no need to flip the kernel
# 2. Notice that kernel is 2D array - if 1d than we will get a column vector convolution
kernel = np.array([[-1, 0, +1]])
dst = cv2.filter2D(img, -1, kernel)

plt.figure(figsize=figsize)
plt.imshow(np.abs(dst), cmap='gray')
plt.colorbar()
plt.title('$f\'_x$: image filtered with '+str(kernel))

print("kernel shape is "+str(kernel.shape))

# %% [markdown]
# ## Y grad filter (no abs)
# %%
kernel = np.array([[-1, 0, +1]]).T
dst = cv2.filter2D(img, -1, kernel)

plt.figure(figsize=figsize)
plt.imshow(dst, cmap='gray')
plt.colorbar()
plt.title('$f\'_y$: image filtered with\n '+str(kernel))

# %% [markdown]
# ## Comparison of x gradient filters
# %%
plt.rcParams['figure.figsize'] = [20, 20]

plt.subplot(4, 2, 1)
plt.imshow(img, cmap='gray', vmin=0, vmax=255)
plt.title('original image')

#######################################
kernel = 1/2*np.array([[-1, 0, +1]])
dst_sym = cv2.filter2D(img, -1, kernel)

plt.subplot(4, 2, 2)
plt.imshow(dst_sym, cmap='gray')
plt.title('$f\'_x$: image filtered with symmetric derivative')

#######################################
kernel = 1/6*np.array([
    [-1, 0, +1],
    [-1, 0, +1],
    [-1, 0, +1]])
dst_prewitt = cv2.filter2D(img, -1, kernel)

plt.subplot(4, 2, 3)
plt.imshow(dst_prewitt, cmap='gray')
plt.title('$f\'_x$: image filtered with Prewitt')

#######################################
# cv2.Sobel() also exist
kernel = 1/8*np.array([
    [-1, 0, +1],
    [-2, 0, +2],
    [-1, 0, +1]])
dst_sobel = cv2.filter2D(img, -1, kernel)

plt.subplot(4, 2, 4)
plt.imshow(dst_sobel, cmap='gray')
plt.title('$f\'_x$: image filtered with Sobel')

#######################################
dst_cv2_sobel = cv2.Sobel(img, -1, 1, 0)  #cv2.Sobel(img,ddepth,x_size,y_size)

plt.subplot(4, 2, 5)
plt.imshow(dst_cv2_sobel, cmap='gray')
plt.colorbar()
plt.title('cv2.Sobel X')

#######################################
plt.subplot(4, 2, 6)
plt.imshow(np.abs(dst_sobel-dst_sym))
plt.colorbar()
plt.title('|sobel-symmetric|')

#######################################
plt.subplot(4, 2, 7)
plt.imshow(np.abs(dst_sobel-dst_prewitt))
plt.colorbar()
plt.title('|sobel-prewitt|')

#######################################
plt.subplot(4, 2, 8)
plt.imshow(np.abs(dst_sym-dst_prewitt))
plt.colorbar()
plt.title('|symmetric-prewitt|')
# %% [markdown]
# ## Filtering common errors
# ### kernel dimension error
# Note that you need to use a 2D array for a horizontal kernel!
# %%

kernel = np.array([-1, 0, +1])
dst = cv2.filter2D(img, -1, kernel)

plt.figure(figsize=figsize)
plt.imshow(np.abs(dst), cmap='gray')
plt.colorbar()
plt.title('wrong kernel dim: '+str(kernel))

print("kernel shape is "+str(kernel.shape))

# %% [markdown]
# ### uint8 errors
# Wrong filtering when keeping uint8 instead of float, because uint8 doesn't have negative numbers...
# %%
uint8_img = np.zeros((500, 500), dtype=np.uint8)
uint8_img[200:300, 200:300] = 1

kernel = np.array([[-1, 0, +1]])
dst = cv2.filter2D(uint8_img, -1, kernel)

fig, axs = plt.subplots(1, 2, figsize=(20,20))
axs[0].imshow(uint8_img, cmap='gray')
axs[0].title.set_text('original image')
axs[1].imshow(dst, cmap='gray')
axs[1].title.set_text('uint8 WRONG filtering')


import numpy as np
print(f'np.__version__ {np.__version__}')
a = np.random.randint(0,100,20)
print(f'a => {a}')

print(f'a % 2 == 0 => {a % 2 == 0}')
print(f'a[ a % 2 == 0] => {a[a%2 == 0]}')
print(f'(a %  2 == 0) & (a > 50) => {(a %  2 == 0) & (a > 50)}')
print(f'a[(a %  2 == 0) & (a > 50)] => {a[(a %  2 == 0) & (a > 50)]}')
print(f'(a%2 == 0 | (a > 50)) => {a%2 == 0 | (a > 50)}')
print(f'a[(a%2 == 0) | (a > 50)] => {a[(a % 2 == 0)| (a > 50)]}')

p = np.random.randint(1, 9999, 100)
print(f'p => {p}')
print(f'p[p%10 == 9] => {p[p%10 == 9]}')

print(f'np.where(p%10 == 9) => {np.where(p%10 == 9)}')

d = np.loadtxt('displ_cty_hwy.csv', delimiter=',')
print(f'd => {d}')
print(f'd[d == 28] => {d[d==28]}')
print(f'np.where(d == 28) => {np.where(d == 28)}')
print(f'd[0, d > 3] => {d[(d[:, 0] > 3) & (d[:,1] > 15)]}')


a=[]
a=range(1,10)
print(list(a))

# we can have mixed data types in a list
b=[1,2,3,'vivek',True,4,5]
print(list(b))

# index of list start with 0, 1, 2 ..
# so vivek is present at index 3
print(b[3])

# list can have a list as one of its elements

# slicing - [start:stop:step]
# slicing - [stop:start:-step]
# end (stop) is not inclusive
a=[1,2,3,4,5,6,7,8,9]
a[1:6:2]

# reversing a list
L[::-1]

# tuples - immutable list, cant be changed
t = (1,2,3) # use () instead of []

# module - group of functions
# packages - group of modules

# conda install package-name
# pip install package-name

# scrapy is a good web crawling package

# arrays
# python has inbuilt arrays and well as numpy arrays
# we just use numpy array as the inbuilt ones are less flexible
l=[546,375,254,651,781,569,454,564]

import numpy as np
a=np.array(l)
# if we convert a list with multiple data types (such as int, string, boolean, etc.)
# the numpy.array() function will convery all elements into a string, so it becomes an array of strings
# so data type of all elements in an array are same

print(a)

# when you slice an array you dont create a copy of an array
# so any modification to the slice of an array will be reflected in the actual array
a=[1,2,3,4]
a=np.array(a) # array([1, 2, 3, 4])
b=a[0:2]
b[:]=111 # array([1, 2])
# now, b becomes array([111, 111])
# but c also becomes array([111, 111,   3,   4])

# https://datatofish.com/
# Convert Strings to Integers in a Python List
# Using map
mylist = ['value1','value2','value3',...]
mylist = list(map(int, mylist))

# Using list comprehension
mylist = ['value1','value2','value3',...]
mylist = [int(i) for i in mylist]

# matrics
import numpy as np # we need to import the numpy libabry which provides tools for numerical computing.
m=np.array([[1,2,3],[4,5,6],[7,8,9]])
print(m)

# Arrays - while matrices are confined to two dimensions, arrays can be of any number of dimensions.
import numpy as np # we need to import the numpy libabry which provides tools for numerical computing.
m=np.array([1,2,3])
print(type(m))

# Matrices - A matrix is a two-dimensional rectangular data set. It can be created using .array() function.
import numpy as np # we need to import the numpy libabry which provides tools for numerical computing.
m=np.array([[1,2,3],[4,5,6],[7,8,9]])
print(type(m))


import numpy
from numpy import sin, arange
import matplotlib.pyplot
from matplotlib.pyplot import *
from sympy import Limit

def g( x ):
    g = x ** 2
    return g

# An example will be used to show right and left convergence to a value.
# Convergence at x = 0 will be shown graphically using g(x).

n = 5  # This determines the number of values calculated on each side of x=0.

powers = arange( 0, n+1 )

denominator = 2.0 ** powers  # denominator contains exponentiated values of 2.0.

delta = 1           # This is the interval used on either side of the origin.

# The following are values of x and f(x) trending to the limit.
# Delta is being divided by powers of 2 to reduce the distance from the limit.
# The letter "r" denotes from the right, and "l" denotes from the left.

x_r = delta / denominator
y_r = g( x_r )
x_l = -x_r   # The negative sign generates a symmetric point on the left.
y_l = g( x_l )

# The following determines the vertical boundaries of the resulting plot.

ymax = max( abs( y_r ) ) + 0.5
ymin = -ymax

figure()
xlim( -delta - 0.5 , delta + 0.5 )
ylim( ymin, ymax )

# Plotting is being done in layers.  First the line plot then the points.

plot( x_r,y_r, color = 'b' )
plot( x_l,y_l, color = 'r' )

# The black points were computed.  The yellow point marks the limit.

scatter( x_r,y_r, color = 'k', s= 30 )
scatter( x_l,y_l, color = 'k', s= 30 )
scatter( 0.0, g(0.0), c = 'y', s = 40 )

title( 'Example of Convergence to a Functional Value' )
xlabel( 'x-axis' )
ylabel( 'y-axis' )
show()


""" Utilities """

import torch
import numpy as np
import random

def set_seed(seed=None):
	"""Set random seed, or reset if None.
	"""
	random.seed(seed)
	np.random.seed(seed)
	if seed is None:
		torch.manual_seed(random.randint(1,1e6))
	else:
		torch.manual_seed(seed)

def spectral_radius(A: torch.Tensor, eps=None, n_iter=1000):
	"""Differentiable procedure for computing spectral radius (magnitude of largest eigenvalue)

	Args:
		A: square matrix
		eps: (optional) if provided, uses convergence-based power iteration method
		n_iter: (optional) if provided, uses power iterations with this many steps (default; 1000 steps)

	For 2x2 systems, performs direct computation.
	"""
	if A.shape[0] == A.shape[1] == 2:
		tr, det = A.trace(), A.det()
		disc = tr**2 - 4*det
		if disc >= 0:
			return torch.max(
				torch.abs(tr + torch.sqrt(disc)) / 2,
				torch.abs(tr - torch.sqrt(disc)) / 2
			)
		else:
			return torch.sqrt((tr/2)**2 - disc/4)
	elif eps is not None:
		return _sp_radius_conv(A, eps)
	else:
		return _sp_radius_niter(A, n_iter)

def _sp_radius_conv(A: torch.Tensor, eps: float):
	v = torch.ones((A.shape[0], 1), device=A.device)
	v_new = v.clone()
	ev = v.t()@A@v
	ev_new = ev.clone()
	while (A@v_new - ev_new*v_new).norm() > eps:
		v = v_new
		ev = ev_new
		v_new = A@v
		v_new = v_new / v_new.norm()
		ev_new = v_new.t()@A@v_new
	return ev_new

def _sp_radius_niter(A: torch.Tensor, n_iter: int):
	v = torch.ones((A.shape[0], 1), device=A.device)
	for _ in range(n_iter):
		v = A@v
		v = v / v.norm()
	ev = v.t()@A@v
	return ev

def is_semistable(P: torch.Tensor, eps=1e-2):
	"""Semistability test for transfer operator using spectral radius """
	return spectral_radius(P).item() <= 1.0 + eps

def rmse(X: torch.Tensor, Y: torch.Tensor):
	assert X.shape == Y.shape
	return torch.sqrt(torch.mean((X - Y)**2)).item()

""" Tests """

if __name__ == '__main__':
	set_seed(9001)
	device = 'cuda' if torch.cuda.is_available() else 'cpu'

	prec = 1e-2

	# 2d spectral radius test
	for _ in range(100):
		d = 2
		A = torch.randn((d, d), device=device)
		e = np.random.uniform(0.1, 2.00)
		L = torch.linspace(e, 0.01, d, device=device)
		P = torch.mm(torch.mm(A, torch.diag(L)), torch.pinverse(A))

		np_e_max = np.abs(np.linalg.eigvals(P.cpu().numpy())).max()
		pwr_e_max = spectral_radius(P).item()
		print('True:', e, 'numpy:', np_e_max, 'pwr_iter:', pwr_e_max)
		assert np.abs(e - pwr_e_max) < prec

	# Nd Power iteration test
	for _ in range(100):
		d = 100
		A = torch.randn((d, d), device=device)
		e = np.random.uniform(0.1, 1.10)
		L = torch.linspace(e, 0.01, d, device=device)
		P = torch.mm(torch.mm(A, torch.diag(L)), torch.pinverse(A))

		np_e_max = np.abs(np.linalg.eigvals(P.cpu().numpy())).max()
		pwr_e_max = spectral_radius(P).item()
		print('True:', e, 'numpy:', np_e_max, 'pwr_iter:', pwr_e_max)
		assert np.abs(e - pwr_e_max) < prec


# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# Importing the dataset
dataset = pd.read_csv('50_Startups.csv')
X = dataset.iloc[:, :-1].values
y = dataset.iloc[:, 4].values

# Encoding categorical data
# Encoding the Independent Variable
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder_X = LabelEncoder()
X[:, 3] = labelencoder_X.fit_transform(X[:, 3])
onehotencoder = OneHotEncoder(categorical_features = [3])
X = onehotencoder.fit_transform(X).toarray()

# Avoiding the dummy variable trap
X= X[:,1:]

# Splitting the dataset into the Training set and Test set
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

# Feature Scaling
"""from sklearn.preprocessing import StandardScaler
sc_X = StandardScaler()
X_train = sc_X.fit_transform(X_train)
X_test = sc_X.transform(X_test)
sc_y = StandardScaler()
y_train = sc_y.fit_transform(y_train)"""

# Fitting multiple linear regression to training set
from sklearn.linear_model import LinearRegression
regressor= LinearRegression()
regressor.fit(X_train, y_train)

# Predicting the test set results
y_pred= regressor.predict(X_test)

#Building optimal model using Backward Elimination
import statsmodels.formula.api as sm
X =np.append(arr=np.ones((50,1)).astype(int), values=X, axis=1)
X_opt= X[:,[0,1,2,3,4,5]]
regressor_OLS= sm.OLS(endog=y, exog=X_opt).fit()
# print(regressor_OLS.summary())

X_opt= X[:,[0,1,3,4,5]]
regressor_OLS= sm.OLS(endog=y, exog=X_opt).fit()
# print(regressor_OLS.summary())

X_opt= X[:,[0,3,4,5]]
regressor_OLS= sm.OLS(endog=y, exog=X_opt).fit()
# print(regressor_OLS.summary())

X_opt= X[:,[0,3,5]]
regressor_OLS= sm.OLS(endog=y, exog=X_opt).fit()
print(regressor_OLS.summary())

# X_opt= X[:,[0,3,4,5]]
# regressor_OLS= sm.OLS(endog=y, exog=X_opt).fit()
# print(regressor_OLS.summary())

print("Debug Stop")


import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
def load_data():
    iris = load_iris()
    data = pd.DataFrame(iris.data, columns=iris.feature_names)
    data['label'] = iris.target
    print(data)
    print("data loaded finished")
    return data
def set_data_frame(data):
    data.columns = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'label']
    print(data.label.value_counts())
    return data

def data_show(data):
    plt.scatter(data[:50]['sepal_length'], data[:50]['sepal_width'],label = '0')
    plt.scatter(data[50:100]['sepal_length'], data[50:100]['sepal_width'],label='1')
    plt.xlabel('sepal_length')
    plt.ylabel('sepal_width')
    plt.show()
def get_train_data(data):
    data = np.array(data.iloc[:100,[0,1,-1]])
    train_features = data[:, :2]
    y = data[:, -1]
    train_label = np.array([1 if i == 1 else -1 for i in y]) # label = 0 --> label = -1
    feature_dim = len(train_features[0])
    print(train_features)
    print(train_label)
    print("特征维数为：",feature_dim)
    return train_features, train_label,feature_dim

"""
def main():
    data = load_data()
    train_data = set_data_frame(data)
    data_show(train_data)
    features, labels = get_train_data(train_data)
    print(features, labels)
if __name__ == '__main__':
    main()
"""


"""

 logistic_regression_GD.py  (author: Anson Wong / git: ankonzoid)

"""
import os, random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import log_loss

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

def split(fracs, N, seed):
    def is_intersect(arr1, arr2):
        n_intersect = len(np.intersect1d(arr1, arr2))
        if n_intersect == 0: return False
        else: return True
    fracs = [round(frac, 2) for frac in fracs]
    if sum(fracs) != 1.00:
        raise Exception("fracs do not sum to one!")
    indices = list(range(N))
    random.Random(seed).shuffle(indices)
    indices = np.array(indices, dtype=int)
    n_fracs = []
    for i in range(len(fracs) - 1):
        n_fracs.append(int(max(fracs[i] * N, 0)))
    n_fracs.append(int(max(N - sum(n_fracs), 0)))
    if sum(n_fracs) != N:
        raise Exception("n_fracs do not sum to N!")
    n_selected = 0
    indices_fracs = []
    for n_frac in n_fracs:
        indices_frac = indices[n_selected:n_selected + n_frac]
        indices_fracs.append(indices_frac)
        n_selected += n_frac
    for a, indices_frac_A in enumerate(indices_fracs):
        for b, indices_frac_B in enumerate(indices_fracs):
            if a == b:
                continue
            if is_intersect(indices_frac_A, indices_frac_B):
                raise Exception("there are intersections!")
    return indices_fracs

class LogisticRegressorGD():

    def __init__(self):
        pass

    def fit(self, X, y, X_tune, y_tune):
        #
        # Use binary cross-entropy loss instead of MSE
        #
        # L = -(1/N) * sum[i=1, N] (y*log(y_hat) + (1-y)*log(1-y_hat))
        #   = -(1/N) * sum[i=1, N] (y*log(sigma(a*x + a0)) + (1-y)*log(1-sigma(a*x + a0)))
        #
        # y_hat = sigma(x)
        #
        # dL/daj = -(1/N) * sum[i=1, N] * y * xj for j=1,2,...,d
        # dL/daj = -(1/N) * sum[i=1, N] * y for j=0
        #
        # GD: a{i+1} <- a{i} - \eta * dL/dxj
        #
        print("Fitting...")

        # Initialize fit parameters [a0, a1, a2, ..., ad] where a0 is y-intercept
        N, d = X.shape
        a_fit = np.random.normal(size=d+1)

        # Make gradient descent updates
        loss_tolerance = 1E-4
        fit_tolerance = 1E-4
        eta = 10  # learning rate
        converge = False
        loss = 9E99
        while not converge:

            # Compute gradient
            gradient = np.zeros(d+1)
            for i in range(N):
                y_pred_i = sigmoid(a_fit[0] + np.dot(a_fit[1:], X[i]))
                gradient[0] += (y_pred_i - y[i])
                gradient[1:] += (y_pred_i - y[i]) * X[i, 0:]
            gradient /= N

            # Perform gradient descent step
            a_fit_new = a_fit - eta * gradient

            # Compute loss (to keep track)
            y_pred = np.array([sigmoid(a_fit_new[0] + np.dot(a_fit_new[1:], x)) for x in X_tune])
            loss_new = log_loss(y_tune, y_pred)
            print("loss = {}".format(loss))

            # See if loss and fit parameters have converged
            if np.abs(loss_new - loss) < loss_tolerance and loss_new > loss_tolerance:
                converge = True

            # Update fit parameters
            a_fit = a_fit_new
            loss = loss_new

        # Save fit parameters
        self.a_fit = a_fit

    def predict(self, X):
        y_pred = np.array([sigmoid(self.a_fit[0] + np.dot(self.a_fit[1:], x)) for x in X])
        return y_pred

def plot_sorted(X_train, y_pred_train, X_valid, y_pred_valid):
    idx_train_sorted = np.argsort(X_train.flatten())
    idx_valid_sorted = np.argsort(X_valid.flatten())
    plt.plot(X_train[idx_train_sorted].flatten(), y_pred_train[idx_train_sorted], 'r--')
    plt.plot(X_valid[idx_valid_sorted].flatten(), y_pred_valid[idx_valid_sorted], 'k-')

# Main Driver
if __name__ == "__main__":

    random.seed(10)
    N0, N1 = 400, 400
    N = N0 + N1
    X = np.array([random.uniform(0, 0.6) for _ in range(N0)] + [random.uniform(0.4, 1) for _ in range(N1)]).reshape(-1, 1)
    y = np.array([0 for _ in range(N0)] + [1 for _ in range(N1)], dtype=int)
    assert len(X) == len(y)

    indices_valid, indices_train = split(fracs=[0.2, 0.8], N=N, seed=1)
    X_train, y_train = X[indices_train], y[indices_train]
    X_valid, y_valid = X[indices_valid], y[indices_valid]

    model = LogisticRegressorGD()
    model.fit(X, y, X_tune=X_valid, y_tune=y_valid)
    y_pred_train = model.predict(X_train)
    y_pred_valid = model.predict(X_valid)
    bce_train = log_loss(y_train, y_pred_train)
    bce_valid = log_loss(y_valid, y_pred_valid)
    print("bce_train =", bce_train)
    print("bce_valid =", bce_valid)

    plt.figure(1)
    plt.plot(X.flatten(), y, 'o')
    plot_sorted(X_train, y_pred_train, X_valid, y_pred_valid)
    plt.show()


#1-Dimensional Data:

#Import required libraries:
from scipy import stats

#Dataset:
d = [1,2,3,4,5]

#Finding 0th moment:
print("0th Moment = ",stats.moment(d,moment=0))

#Finding 1st moment:
print("1st Moment = ",stats.moment(d,moment=1))

#Finding 2nd moment:
print("2nd Moment = ",stats.moment(d,moment=2))

#Finding 3nd moment:
print("3nd Moment = ",stats.moment(d,moment=3))

#Finding 4th moment:
print("4th Moment = ",stats.moment(d,moment=4))

#============================================================

#2-Dimensional Data:

#Import required libraries:
from scipy import stats

#Dataset:
d = [[5,6,9,11,3],[21,4,8,15,2]]

#Finding 0th moment:
print("0th Moment = ",stats.moment(d,moment=0))

#Finding 1st moment:
print("1st Moment = ",stats.moment(d,moment=1))

#Finding 2nd moment:
print("2nd Moment = ",stats.moment(d,moment=2))

#Finding 3nd moment:
print("3nd Moment = ",stats.moment(d,moment=3))

#Finding 4th moment:
print("4th Moment = ",stats.moment(d,moment=4))

#============================================================

#2-Dimensional Data:
#Set axis=1 (Horizonatal):

#Import required libraries:
from scipy import stats

#Dataset:
d = [[5,6,9,11,3],[21,4,8,15,2]]

#Finding 0th moment:
print("0th Moment = ",stats.moment(d,moment=0,axis=1))

#Finding 1st moment:
print("1st Moment = ",stats.moment(d,moment=1,axis=1))

#Finding 2nd moment:
print("2nd Moment = ",stats.moment(d,moment=2,axis=1))

#Finding 3nd moment:
print("3nd Moment = ",stats.moment(d,moment=3,axis=1))

#Finding 4th moment:
print("4th Moment = ",stats.moment(d,moment=4,axis=1))

#============================================================

#Multi-Dimensional Data:

#Import required libraries:
from scipy import stats

#Dataset:
d = [[5,6,9,11,3],
     [21,4,8,15,2],
    [15,23,42,1,36]]

#Finding 0th moment:
print("0th Moment = ",stats.moment(d,moment=0))

#Finding 1st moment:
print("1st Moment = ",stats.moment(d,moment=1))

#Finding 2nd moment:
print("2nd Moment = ",stats.moment(d,moment=2))

#Finding 3nd moment:
print("3nd Moment = ",stats.moment(d,moment=3))

#Finding 4th moment:
print("4th Moment = ",stats.moment(d,moment=4))

#============================================================

#2-Dimensional Data:
#Set axis=1 (Horizonatal):
#Higher Order Moments:

#Import required libraries:
from scipy import stats

#Dataset:
d = [[5,6,9,11,3],[21,4,8,15,2]]

#Finding 10th moment:
print("10th Moment = ",stats.moment(d,moment=10,axis=1))

#Finding 12th moment:
print("12th Moment = ",stats.moment(d,moment=12,axis=1))


import numpy as np, os, sys
import scipy
import matplotlib as mpl #patch-wise similarities, droi images

def datagen2d(w1,w2,eps,num):

  # your implementation here
  # 2d features

  x = np.arange(num)

  low, high = w1, w2
  if w1>w2:
    low, high = w2, w1

  delta = np.random.uniform(low, high, size=(num,))

  y = w1 * x + 3 + delta

  #x.shape=(numdata,dims) dims=2 here
  #y.shape=(numdata)
  print(x.shape,y.shape)

  return x,y

def rndsplit(x,y,numtr):

  inds=np.arange(y.size)
  np.random.shuffle(inds)

  xtr=x[inds[0:numtr],:]
  ytr=y[inds[0:numtr]]

  xv=x[inds[numtr:],:]
  yv=y[inds[numtr:]]

  return xtr,ytr,xv,yv

def gendata(numtotal):

  w1=0.5
  w2=-2
  xtr,ytr = datagen2d(w1=w1,w2=w2,eps=0.8,num= int( numtotal) ) #numtotal
  xv,yv = datagen2d(w1=w1,w2=w2,eps=0.8,num= 3000 ) #fix 3k test samples
  #xtr,ytr,xv,yv = rndsplit(x,y,numtr=int( 0.7*numtotal))
  return xtr,ytr,xv,yv,w1,w2

def gendata2(numtotal):
  w1=0.5
  w2=-2
  xtr,ytr = datagen2d(w1=w1,w2=w2,eps=0.8,num= int( 0.7*numtotal) ) #70% of numtotal
  xv,yv = datagen2d(w1=w1,w2=w2,eps=0.8,num= int( 0.3*numtotal) ) #30 % of numtotal
  #xtr,ytr,xv,yv = rndsplit(x,y,numtr=int( 0.7*numtotal))
  return xtr,ytr,xv,yv,w1,w2

def linreg_train(xtr,ytr,C):
  w = ''
  # your implementation here
  return w

def linreg_apply(xv,w):
  return np.dot(xv,w)

def mse(ypred,ytrue):
  e=np.mean( (ypred-ytrue)**2 )
  return e

def run1(xtr,ytr,xv,yv,w1,w2,C):

  w=linreg_train(xtr,ytr,C=C) # 0.1

  wtrue=np.asarray([w1,w2])

  print('w',w, 'true w', [w1,w2], 'diff', np.dot((w-wtrue).T,w-wtrue))

  ypred=linreg_apply(xv,w)
  e=mse(ypred,yv)

  print('mse',e)

if __name__ == '__main__':
  x, y = datagen2d(0.5, 2, 0.8, 50)
  print(x.shape)
  print(y.shape)
  # xtr,ytr,xv,yv,w1,w2=gendata(50)
  # run1(xtr,ytr,xv,yv,w1,w2,1e-3)
  #
  # xtr,ytr,xv,yv,w1,w2=gendata(1000)
  # run1(xtr,ytr,xv,yv,w1,w2,1e-3)


#################################################################
# Name:     Gauss-Seidel.py                                     #
# Authors:  Michael Battaglia                                   #
# Function: Program calculates PDE solution using Gauss-Seidel  #
#           relaxation method.                                  #
#################################################################

#essential imports
import numpy as np
import matplotlib.pyplot as plt

#function: Gauss-Seidel relaxation method
def GaussSeidel(image, delta, relax, flag=-99, plot=False):
    #assume image full of flags except at boundaries
    im1 = np.copy(image)
    #calculate boundary mean
    bdy = []
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            if abs(image[i][j]-flag) > 1e-10:
                #point is on boundary
                bdy.append(image[i][j])
    bdy = np.mean(bdy)
    #change flags to boundary mean
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            if abs(image[i][j]-flag) < 1e-10:
                #point is in interior
                im1[i][j] = bdy
    #plot initial state if parameter give
    if plot:
        plt.imshow(im1.T, interpolation='nearest', cmap='gray')
        plt.title("Gauss-Seidel Solving PDE")
        plt.colorbar()
        plt.draw()
        plt.pause(0.01)

    #initialize error
    error = 2*delta
    #relax until error within tolerance
    while error > delta:
        im2 = np.copy(im1)
        #for each row
        for i in range(image.shape[0]):
            #for each column
            for j in range(image.shape[1]):
                #leave boundary untouched (mark non-bnd by -99)
                if abs(image[i][j]-flag) < 1e-10:
                    #Gauss Seidel relaxation
                    im2[i][j] = 0.25*(1+relax)*(im2[i+1,j]+im2[i-1,j]
                                    +im2[i,j+1]+im2[i,j-1])-relax*im2[i][j]
        #calculate error
        error = np.amax(np.absolute(im2-im1))
        im1 = np.copy(im2)
        #plot if parameter give
        if plot:
            plt.cla()
            plt.imshow(im1.T, interpolation='nearest', cmap='gray')
            plt.draw()
            plt.pause(0.01)
    #close plots
    if plot:
        plt.close()
    return im1, error

#function: main
if __name__ == '__main__':
    #construct grid 8cm x 20cm at 0.1cm resolution
    length = 8.0
    width = 20.0
    dx = 0.1
    T = -99*np.ones([int(width/dx),int(length/dx)],float)
    #initialize boundary values
    T[:,0].fill(10.0)  #top row
    T[0,:] = np.linspace(10.0,0,T.shape[1],endpoint=True) #left column
    T[-1,:] = np.linspace(10.0,0,T.shape[1],endpoint=True) #right column
    #bottom row with indent
    T[0:int(5.0/dx),-1] = np.linspace(0,5.0,int(5.0/dx),endpoint=True) #lrow
    T[T.shape[0]-int(5.0/dx):T.shape[0],-1] = np.linspace(5.0,0,int(5.0/dx),endpoint=True) #rrow
    T[int(5.0/dx)-1,T.shape[1]-int(3.0/dx):T.shape[1]] = np.linspace(7.0,5.0,int(3.0/dx),endpoint=True) #left indent
    T[T.shape[0]-int(5.0/dx),T.shape[1]-int(3.0/dx):T.shape[1]] = np.linspace(7.0,5.0,int(3.0/dx),endpoint=True) #right indent
    T[int(5.0/dx)-1:T.shape[0]-int(5.0/dx)+1,T.shape[1]-int(3.0/dx)].fill(7.0) #top indent
    #fill out indent area
    T[int(5.0/dx):T.shape[0]-int(5.0/dx),T.shape[1]-int(3.0/dx)+1:T.shape[1]].fill(0.0)

    #PDE solution accuracy
    delta = 1.0e-6
    #Gauss-Seidel relaxation parameter w
    relax = 0.9
    #solve PDE using Gauss-Seidel relaxation
    T,error = GaussSeidel(T, delta=delta, relax=relax, flag=-99, plot=True)

    #plot final solution
    plt.title("Gauss-Seidel Relaxation for Laplace's Eqn")
    plt.imshow(T.T, interpolation='nearest', cmap='gray')
    plt.colorbar()
    plt.show()


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

import numpy as np

def estimate_kaiser_bessel_beta(W):
    r"""
    Estimate the kaiser bessel beta using the following heuristic:

    .. math::

        \beta = 2.34 \times W

    Derived from `Nonuniform fast Fourier transforms
    using min-max interpolation
    <nufft-min-max-ref_>`_.

    .. _nufft-min-max-ref: https://ieeexplore.ieee.org/document/1166689/

    Parameters
    ----------
    W : int
        Width of the filter

    Returns
    -------
    float
        Kaiser Bessel beta shape parameter
    """
    return 2.34*W

def kaiser_bessel(u, W, beta):
    r"""
    Compute a 1D Kaiser Bessel filter as defined
    in `Selection of a Convolution Function
    for Fourier Inversion Using Gridding
    <kbref_>`_.

    .. _kbref: https://ieeexplore.ieee.org/document/97598/

    Parameters
    ----------
    u : :class:`numpy.ndarray`
        Filter positions
    W : int
        Width of the filter
    beta : float, optional
        Kaiser Bessel shape parameter

    Returns
    -------
    :class:`numpy.ndarray`
        Kaiser Bessel filter with the same shape as `u`
    """

    # Sanity check
    hW = W // 2
    assert np.all(-hW <= u) & np.all(u <= hW)

    param = 1 - (2 * u / W)**2
    param[param < 0] = 0  # Zero negative numbers
    return np.i0(beta * np.sqrt(param)) / np.i0(beta)

def kaiser_bessel_with_sinc(u, W, oversample, beta, normalise=True):
    """
    Produces a filter composed of Kaiser Bessel multiplied by a sinc.

    Accounts for the oversampling factor, as well as normalising the filter.

    Parameters
    ----------
    u : :class:`numpy.ndarray`
        Filter positions
    W : int
        Width of the filter
    oversample : int
        Oversampling factor
    beta : float
        Kaiser Bessel shape parameter
    normalise : optional, {True, False}
        True if the filter should be normalised

    Returns
    -------
    :class:`numpy.ndarray`
        Filter with the same shape as `u`
    """
    kb = kaiser_bessel(u, W, beta)
    kb *= oversample
    kb *= np.sinc(u / oversample)

    if normalise:
        kb /= np.trapz(kb, u)

    return kb

def kaiser_bessel_fourier(x, W, beta):
    r"""
    Computes the Fourier Transform of a 1D Kaiser Bessel filter.
    as defined in `Selection of a Convolution Function
    for Fourier Inversion Using Gridding
    <kbref_>`_.

    .. _kbref: https://ieeexplore.ieee.org/document/97598/

    Parameters
    ----------
    x : :class:`numpy.ndarray`
        Filter positions
    W : int
        Width of the filter.
    beta : float
        Kaiser bessel shape parameter

    Returns
    -------
    :class:`numpy.ndarray`
        Fourier Transform of the Kaiser Bessel,
        with the same shape as `x`.
    """
    term = (np.pi*W*x)**2 - beta**2
    val = np.lib.scimath.sqrt(term).real
    return np.sin(val)/val


import numpy as np

class AutoDiff():
    '''
    Class to use for automatic differentiation, forward mode

    Addresses the following need.

    1) The user has some function which maps some number of input variables, for example x and y, to a single
    output value, f(x,y).

    2) The user would like to calculate f(x,y) at a point (x,y) that they specify, as well as the partial
    derivatives df/dx and df/dy at that same point (x, y).

    By first defining their input variables as AutoDiff objects, and then using these objects in
    standard python calculations, including with numpy functions, the user is returned a AutoDiff object
    whose val attribute is the value of the function, and whose derv attribute is the derivative of the function.

    Which partial derivative is stored in the derv attribute of the final AutoDiff object depends on which
    input variable's derv attribute is initially set to 1, while the derv attributes of the other input variables
    are set to 0.

    Example:
    x = AutoDiff(3,1)
    y = AutoDiff(2,0)
    f = x**2 + y**2 + 4
    print(f.val, f.dev)
    (17, 6)
    '''

    def __init__(self, val, derv=1):
        self.val = float(val)
        self.derv = float(derv)

    # -----------Overloading Urnary functions ---------------------------------------------

    def __pos__(self):
        return AutoDiff(self.val, self.derv)

    def __neg__(self):
        return AutoDiff(-1*self.val, -1*self.derv)

    # -----------Add, Subtract, Multiple, Divide functions --------------------------------

    def __mul__(self, other):
        try:
            return AutoDiff(self.val * other.val, self.derv * other.val + other.derv*self.val)
        except:
            return AutoDiff(self.val * other, self.derv * other)

    def __rmul__(self, other):
        return AutoDiff(self.val * other, self.derv * other)

    def __truediv__(self, other):
        try:
            return AutoDiff(self.val/other.val, self.derv/other.val + ( -1*self.val/(other.val**2) ) *other.derv)
        except:
            return AutoDiff(self.val/other, self.derv/other)

    def __rtruediv__(self, other):
        return AutoDiff(other/self.val,  -1*other/(self.val**2) )

    def __add__(self, other):
        try:
            return AutoDiff(self.val + other.val, self.derv + other.derv)
        except:
            return AutoDiff(self.val + other, self.derv + 0)

    def __radd__(self, other):
        return AutoDiff(self.val + other, self.derv + 0)

    def __sub__(self, other):
        try:
            return AutoDiff(self.val - other.val, self.derv + -1*other.derv)
        except:
            return AutoDiff(self.val - other, self.derv + 0)

    def __rsub__(self, other):
        return AutoDiff(other - self.val, -1*self.derv + 0)

    # -----------Overloading Trigonometric functions ---------------------------------------------

    def sin(self):
        return AutoDiff(np.sin(self.val), np.cos(self.val)*self.derv)

    def cos(self):
        return AutoDiff(np.cos(self.val), -1*np.sin(self.val)*self.derv)

    def tan(self):
        return AutoDiff(np.tan(self.val), (1/(np.cos(self.val)**2))*self.derv)

    def arcsin(self):
        if (self.val < -1) or (self.val > 1):
            raise ValueError(' Input to arcsin() must be between -1 and 1 inclusive.')
        else:
            return AutoDiff(np.arcsin(self.val), 1/np.sqrt(1 - (self.val)**2)*self.derv)

    def arccos(self):
        if (self.val < -1) or (self.val > 1):
            raise ValueError(' Input to arccos() must be between -1 and 1 inclusive.')
        else:
            return AutoDiff(np.arccos(self.val), -1/np.sqrt(1 - (self.val)**2)*self.derv)

    def arctan(self):
        return AutoDiff(np.arctan(self.val), 1/(1 + (self.val)**2)*self.derv)

    # -----------Overloading Hyperbolic functions ---------------------------------------------

    def sinh(self):
        return AutoDiff(np.sinh(self.val), np.cosh(self.val)*self.derv)

    def cosh(self):
        return AutoDiff(np.cosh(self.val), np.sinh(self.val)*self.derv)

    def tanh(self):
        return AutoDiff(np.tanh(self.val), (1/np.cosh(self.val))**2*self.derv)

    def arcsinh(self):
        return AutoDiff(np.arcsinh(self.val), 1/np.sqrt(1 +(self.val)**2)*self.derv)

    def arccosh(self):
        return AutoDiff(np.arccosh(self.val), 1/np.sqrt((self.val)**2 - 1) *self.derv)

    def arctanh(self):
        return AutoDiff(np.arctanh(self.val), 1/(1 - (self.val)**2) *self.derv)

    # -----------Overloading Power functions ---------------------------------------------

    def __pow__(self, other):
        try:
            return AutoDiff(self.val**other.val, other.val*self.val**(other.val - 1)*self.derv  +  self.val**other.val*np.log(self.val)*other.derv )
        except:
            return AutoDiff(self.val**other, other*self.val**(other - 1)*self.derv)

    def __rpow__(self, other):
        return AutoDiff(other**self.val, other**self.val*np.log(other)*self.derv)

    def exp(self):
        return AutoDiff(np.exp(self.val), np.exp(self.val)*self.derv)

    # -----------Overloading log functions ---------------------------------------------

    def log(self):
        return AutoDiff(np.log(self.val), (1/self.val)*self.derv)

    def log10(self):
        return AutoDiff(np.log10(self.val), (1/(np.log(10)*self.val))*self.derv)

    def log2(self):
        return AutoDiff(np.log2(self.val), (1 / (np.log(2) * self.val)) * self.derv)

    # -----------Overloading the Square Root function ------------------------------------------

    def sqrt(self):
        if self.val < 0:
            print('negative number has been input to the sqaure root function')
            return 0
        else:
            return AutoDiff(np.sqrt(self.val), (1/(2*np.sqrt(self.val) )*self.derv) )

    #-----------Overloading the Comparison Operators >, <, >=, <=, ==. != -------------------------

    def __lt__(self, other):
        try:
            if self.val < other.val:
                return True
            else:
                return False
        except:
            if self.val < other:
                return True
            else:
                return False

    def __gt__(self, other):
        try:
            if self.val > other.val:
                return True
            else:
                return False
        except:
            if self.val > other:
                return True
            else:
                return False

    def __le__(self, other):
        try:
            if self.val <= other.val:
                return True
            else:
                return False
        except:
            if self.val <= other:
                return True
            else:
                return False

    def __ge__(self, other):
        try:
            if self.val >= other.val:
                return True
            else:
                return False
        except:
            if self.val >= other:
                return True
            else:
                return False

    def __eq__(self, other):
        try:
            if self.val == other.val:
                return True
            else:
                return False
        except:
            if self.val == other:
                return True
            else:
                return False

    def __ne__(self, other):
        try:
            if self.val != other.val:
                return True
            else:
                return False
        except:
            if self.val != other:
                return True
            else:
                return False

def logist(x):
    '''
    Function to evaluate the logistic function at the input x, and if the input is
    an AutoDiff object, then also the derivative of the logistic function with
    respect to x

    Inputs:
        x (either a python float object or AutoDiff object)

    Returns:
        If x is a python float object, it returns the value of the logistic function evaluated at x (float).
        If x is an AutoDiff object, it returns another AutoDiff object whose val attribute contains the
        logistic function evaluated at x, and whose derv attribute contains the derivative of the
        logistic function with respect to x evaluated at x.
    '''
    if isinstance(x, AutoDiff):
        return AutoDiff(1 / (1 + np.exp(-1 * (x.val))),
                        (1 / (1 + np.exp(-1 * (x.val)))) * (1 - (1 / (1 + np.exp(-1 * (x.val))))) * x.derv)
    else:
        return 1/(1+np.exp(-1*x))

def logN(x, N):
    '''
    Function to evaluate the logarithm of the input x using the base N, and if the input is
    an AutoDiff object, then also the derivative of the logarithm function with repsect to
    x at x

    Inputs:
        x (either a python float object or AutoDiff object)
        N (int) the base of the logarithm function

    Returns:
        If x is a python float object, it returns the value of the logarithm base N function evaluated at x (float).
        If x is an AutoDiff object, it returns another AutoDiff object whose val attribute contains the
        logarithm base N function  evaluated at x, and whose derv attribute contains the derivative of the
        logarithm base N function with respect to x evaluated at x.
    '''
    if isinstance(x, AutoDiff):
        return AutoDiff(np.log(x.val)/np.log(N), (1/(x.val*np.log(N)) *x.derv))
    else:
        return np.log(x)/np.log(N)


#!/usr/bin/env python3
import argparse

import numpy as np

import matplotlib.pyplot as plt
import sklearn.datasets

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--clusters", default=3, type=int, help="Number of clusters")
    parser.add_argument("--examples", default=200, type=int, help="Number of examples")
    parser.add_argument(
        "--iterations",
        default=20,
        type=int,
        help="Number of kmeans iterations to perfom",
    )
    parser.add_argument(
        "--plot", default=False, action="store_true", help="Plot the results"
    )
    parser.add_argument("--seed", default=42, type=int, help="Random seed")
    args = parser.parse_args()

    # Set random seed
    np.random.seed(args.seed)

    # Generate artificial data
    data, target = sklearn.datasets.make_blobs(
        n_samples=args.examples,
        centers=args.clusters,
        n_features=2,
        random_state=args.seed,
    )

    # Start by using the first `args.clusters` samples as the cluster representations.
    centers = data[: args.clusters].copy()

    # TODO: Run `args.iterations` of the kmeans algorithm, storing zero-based cluster assignment
    # to `clusters`.
    clusters = np.zeros(data.shape[0], dtype=np.int8)
    for i in range(args.iterations):
        for row in range(data.shape[0]):
            observation = data[row, :]
            clusters[row] = np.argmin(
                [np.sum((center - observation) ** 2) for center in centers]
            )
        for center_index in range(args.clusters):
            centers[center_index] = np.mean(data[clusters == center_index, :], axis=0)

    if args.plot:
        plt.gca().set_aspect(1)
        plt.scatter(data[:, 0], data[:, 1], c=clusters)
        plt.scatter(centers[:, 0], centers[:, 1], marker="P", s=200, c="#ff0000")
        plt.scatter(
            centers[:, 0], centers[:, 1], marker="P", s=50, c=range(args.clusters)
        )
        plt.show()

    # Print the zero-based cluster assignments, one input example per line
    for cluster in clusters:
        print(cluster)


print ("[0/5] Importing libraries")
import struct
import wave
import numpy as np
import matplotlib.pyplot as plt

#VARIABLES
frequency = 261.63
frame_rate = 44100
duration = 5
channels = 1
sample_width = 2
amplitude = 1

print ('[1/5] Creating the values for the waves')
vals_nor = []
vals_inv = []
vals_mer = []
nor = wave.open('waves/normals/'+str(frequency)+'.wav', 'wb')
inv = wave.open('waves/inverses/'+str(frequency)+'.wav', 'wb')
mer = wave.open('waves/merges/'+str(frequency)+'.wav', 'wb')
for i in range (int(frame_rate*duration)):
	vals_nor.append(amplitude*np.sin(2*np.pi*frequency*(i/frame_rate)))
	vals_inv.append(amplitude*np.sin(2*np.pi*frequency*(i/frame_rate))*(-1))
	vals_mer.append(vals_nor[i]+vals_inv[i])

print ("[2/5] Defining waves' parameters")
nor.setnchannels(channels)
inv.setnchannels(channels)
mer.setnchannels(channels)
nor.setsampwidth(sample_width)
inv.setsampwidth(sample_width)
mer.setsampwidth(sample_width)
nor.setframerate(frame_rate)
inv.setframerate(frame_rate)
mer.setframerate(frame_rate)
nor.setnframes(len(vals_nor))
inv.setnframes(len(vals_inv))
mer.setnframes(len(vals_mer))
nor.setcomptype('NONE', 'not compressed')
inv.setcomptype('NONE', 'not compressed')
mer.setcomptype('NONE', 'not compressed')

print ("[3/5] Exporting the waves' raws")
raw_nor = open('raws/normals/'+str(frequency)+'.txt', 'w+')
raw_inv = open('raws/inverses/'+str(frequency)+'.txt', 'w+')
raw_mer = open('raws/merges/'+str(frequency)+'.txt', 'w+')
for i in range (int(frame_rate*duration)):
	raw_nor.write(str(vals_nor[i])+'\n')
	raw_inv.write(str(vals_inv[i])+'\n')
	raw_mer.write(str(vals_mer[i])+'\n')
raw_nor.close()
raw_inv.close()
raw_mer.close()

print ("[4/5] Writing the wav files")
for i in range (int(frame_rate*duration)):
	nor.writeframes(struct.pack('h', int(vals_nor[i]*32767)))
	inv.writeframes(struct.pack('h', int(vals_inv[i]*32767)))
	mer.writeframes(struct.pack('h', int(vals_mer[i]*32767)))
nor.close()
inv.close()
mer.close()

print ("[5/5] Plotting")
x = np.linspace(0, duration, num=int(frame_rate*duration))
plt.plot(x, vals_nor[:], 'b')
plt.plot(x, vals_inv[:], 'r')
plt.plot(x, vals_mer[:], 'g')
plt.title('Wave representation')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.show()


import convolution as cf
import numpy as np

from PIL import Image
import matplotlib.pyplot as plt

def grey_scale_convolution():
    image = np.array(Image.open('5.1.09.tiff'))
    plt.imshow(image, cmap='gray')
    plt.show()

    kernel = np.array([
        [0, -1, 0],
        [-1, 5, -1],
        [0, -1, 0]])

    convolved_image = cf.convolve_greyscale(image, kernel)
    plt.imshow(convolved_image, cmap='gray')
    plt.show()

def rgb_convolution():
    image = np.array(Image.open('4.1.07.tiff'))
    plt.imshow(image)
    plt.show()

    kernel = np.ones((11, 11))
    kernel /= np.sum(kernel)

    convolved_image = cf.convolve_rgb(image, kernel)
    plt.imshow(convolved_image.astype('uint8'))
    plt.show()

def max_pooling_shrink():
    image = np.array(Image.open('5.1.09.tiff'))
    plt.imshow(image, cmap='gray')
    plt.show()

    kernel_size = (2, 2)
    stride = (2, 2)

    output = cf.max_pooling(image, kernel_size, stride)
    plt.imshow(output, cmap='gray')
    plt.show()

def max_pooling_blur():
    image = np.array(Image.open('5.1.09.tiff'))
    plt.imshow(image, cmap='gray')
    plt.show()

    kernel_size = (3, 3)
    stride = (1, 1)

    output = cf.max_pooling(image, kernel_size, stride)
    plt.imshow(output, cmap='gray')
    plt.show()

def max_pooling_stretch():
    image = np.array(Image.open('5.1.09.tiff'))
    plt.imshow(image, cmap='gray')
    plt.show()

    kernel_size = (3, 3)
    stride = (1, 3)

    output = cf.max_pooling(image, kernel_size, stride)
    plt.imshow(output, cmap='gray')
    plt.show()

def average_pooling_shrink():
    image = np.array(Image.open('5.1.09.tiff'))
    plt.imshow(image, cmap='gray')
    plt.show()

    kernel_size = (2, 2)
    stride = (2, 2)

    output = cf.average_pooling(image, kernel_size, stride)
    plt.imshow(output, cmap='gray')
    plt.show()

def average_pooling_blur():
    image = np.array(Image.open('5.1.09.tiff'))
    plt.imshow(image, cmap='gray')
    plt.show()

    kernel_size = (3, 3)
    stride = (1, 1)

    output = cf.average_pooling(image, kernel_size, stride)
    plt.imshow(output, cmap='gray')
    plt.show()

def average_pooling_stretch():
    image = np.array(Image.open('5.1.09.tiff'))
    plt.imshow(image, cmap='gray')
    plt.show()

    kernel_size = (3, 3)
    stride = (1, 3)

    output = cf.average_pooling(image, kernel_size, stride)
    plt.imshow(output, cmap='gray')
    plt.show()

if __name__ == "__main__":
    grey_scale_convolution()
    rgb_convolution()

    max_pooling_shrink()
    max_pooling_blur()
    max_pooling_stretch()

    average_pooling_shrink()
    average_pooling_blur()
    average_pooling_stretch()


from typing import Iterable

import numpy as np
import scipy.stats

def compute_correlation(X: Iterable[float],
                        Y: Iterable[float],
                        ):
    """
    Compute the Pearson correlation coefficient from a sequence of samples of a joint variables (X_i, Y_i)

    :param X: (Iterable[float]) List of samples drawn from the first variable
    :param Y: (Iterable[float]) List of samples drawn from the second variable

    :return: Pearson coefficient of the joint variable (X, Y)

    """

    # Normalize the two variables
    X_normalized = (X - np.mean(X))/np.std(X)
    Y_normalized = (Y - np.mean(Y))/np.std(Y)

    # Compute the covariance of the normalized variables
    r = np.mean(X_normalized * Y_normalized)

    return r

def compute_pearson_correlation_p_value(X: Iterable[float],
                                        Y: Iterable[float],
                                        n: int = 10000.,
                                        ):
    """
    Compute the Pearson correlation p-value by permutation

    :param X: (Iterable[float]) List of samples drawn from the first variable
    :param Y: (Iterable[float]) List of samples drawn from the second variable
    :param n: (int) Number of times we simulate a correlation coefficient by permutation

    :return: p-values of the Pearson correlation test by permutation

    """

    # Compute the correlation coefficient on (X, Y)
    r = compute_correlation(X, Y)

    # Initialize the list of values comparisons
    r_list = []

    # MC
    for i in range(n):

        # Randomly permute X and Y to make the draws independent
        X = np.random.permutation(X)
        Y = np.random.permutation(Y)

        # Compute correlation on permuted variables and compare with r
        r_list.append(float(compute_correlation(X, Y) > r))

    # Compute the p-value of the Pearson correlation test
    p_value = np.mean(r_list)

    return p_value

if __name__ == '__main__':
    X = np.random.randn(1000)
    Y = np.random.randn(1000)
    print(scipy.stats.pearsonr(X, Y))
    print(compute_correlation(X, Y))
    print(compute_pearson_correlation_p_value(X, Y))

    X = np.arange(1000)
    Y = 7*np.arange(1000) + 4
    print(scipy.stats.pearsonr(X, Y))
    print(compute_correlation(X, Y))
    print(compute_pearson_correlation_p_value(X, Y))


import numpy as np
from pyai import Tensor
from pyai.nn.activations.base import ActivationFunction

class Tanh(ActivationFunction):
    def __init__(self):
        super().__init__(self.tahn, self.tanh_prime)

    def tahn(self, x: Tensor) -> Tensor:
        return np.tanh(x)

    def tanh_prime(self, x: Tensor) -> Tensor:
        y = self.tahn(x)
        return 1 - y ** 2


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

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression

#
# Download and convert the MNIST data set
# see the program: mnist2csv.py (converts idx3 data to csv)

# Load the dataset

df = pd.read_csv('data/mnist_train.csv')
#print( df.head() )

# Plot a couple of images

pixel_colnames = df.columns[1:]

# Get all columns except the label column for the first image

image_values = df.loc[0, pixel_colnames].values

# Plot up the first two images just for fun:

plt.figure(figsize=(8,4))

for index in range(0, 2):

    plt.subplot(1, 2, 1 + index )
    image_values = df.loc[index, pixel_colnames].values
    image_label = df.loc[index, 'label']
    plt.imshow(image_values.reshape(28,28), cmap ='gray')
    plt.title('Label: ' + str(image_label), fontsize = 18)

# Split data into Training and Test Sets

X_train, X_test, y_train, y_test = train_test_split(df[pixel_colnames], df['label'], random_state=0)

# Standardize the data:
# PCA and logisitic regression are sensitive to the scale of your features.
# set the data onto unit scale (mean = 0 and variance = 1) by using StandardScaler

scaler = StandardScaler()

# Fit on training set only.

scaler.fit(X_train)

# Apply transform to both the training set and the test set.

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

# for the plot at the bottom
scaledTrainImages = X_train.copy()

# Perform PCA
# n_components = .90 means that scikit-learn will choose the minimum number
# of principal components such that 90% of the variance is retained.

pca = PCA(n_components = .90)

# Fit PCA on training set only

pca.fit(X_train)

# Apply the mapping (transform) to both the training set and the test set.

X_train = pca.transform(X_train)
X_test = pca.transform(X_test)

# Logistic Regression
# - If you turn PCA off, you obtain a very similar accuracy as to using the
#   complete data set

clf = LogisticRegression()
clf.fit(X_train, y_train)

print('Number of dimensions before PCA: ' + str(len(pixel_colnames)))
print('Number of dimensions after PCA: ' + str(pca.n_components_))
print('Classification accuracy: ' + str(clf.score(X_test, y_test)))

#==========================================================================
# A Plot to demonstrate the cumulative explained variance and the
# number of principal components

# if n_components is not set, all components are kept (784 in this case)
pca = PCA()

pca.fit(scaledTrainImages)

# Summing explained variance
tot = sum(pca.explained_variance_)

var_exp = [(i/tot)*100 for i in sorted(pca.explained_variance_, reverse=True)]

# Cumulative explained variance
cum_var_exp = np.cumsum(var_exp)

# PLOT OUT THE EXPLAINED VARIANCES SUPERIMPOSED
fig, ax = plt.subplots(nrows = 1, ncols = 1, figsize = (10,7));
ax.tick_params(labelsize = 18)
ax.plot(range(1, 785), cum_var_exp, label='cumulative explained variance')
ax.set_ylabel('Cumulative Explained variance', fontsize = 16)
ax.set_xlabel('Principal components', fontsize = 16)
ax.axhline(y = 95, color='k', linestyle='--', label = '95% Explained Variance')
ax.axhline(y = 90, color='c', linestyle='--', label = '90% Explained Variance')
ax.axhline(y = 85, color='r', linestyle='--', label = '85% Explained Variance')
ax.legend(loc='best', markerscale = 1.0, fontsize = 12)

plt.show()


import superimport

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from pathlib import Path

import os
import scipy.io

# Get Data
data_dir = Path('.').absolute().parent / 'data' / 'heightWeight'
data = scipy.io.loadmat(data_dir / "heightWeight.mat")['heightWeightData']
data = pd.DataFrame(data).rename(columns = {0:'gender', 1: 'height', 2: 'weight'})

# Function for plotting categorical scatter plot with 1D PCA line
def make_pca_plot(data):

    pca = PCA(1)
    X_reconstr = pca.inverse_transform(pca.fit_transform(data[['height','weight']].values))
    X_reconstr = np.sort(X_reconstr,axis=0)

    fig, ax = plt.subplots(figsize=(6, 6))

    for i, (name, group) in enumerate(data.groupby('gender')):
        color = 'red' if i==1 else 'blue'
        marker = 'o' if i==1 else 'x'
        fc = 'none' if i==1 else 'blue'
        ax.scatter(x=group['height'], y=group['weight'], color=color, marker=marker, facecolor=fc, s=100)
        ax.set_ylabel('weight')
        ax.set_xlabel('height')
        ax.plot(X_reconstr[:,0], X_reconstr[:,1], color='black',linewidth=2)

    return fig, ax

# Save figure function
figdir = "../figures"
def save_fig(fname):
    plt.savefig(os.path.join(figdir, fname))

# Create and save figures
fig, ax = make_pca_plot(data)
ax.set_title('heightWeightPCA')
save_fig('heightWeightPCA.pdf')

data_std = (data - data.mean())/data.std()
fig, ax = make_pca_plot(data_std)
ax.set_title('heightWeightPCAstnd')
save_fig('heightWeightPCAstnd.pdf')


import numpy as np
import os
from os.path import dirname
import sys
import matplotlib.pyplot as plt
import tensorflow as tf

# hide Tensorflow GPU warnings
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

def generate_dummy_data(is_display_graph=False):
    total = 100
    x = np.arange(total)                                  # x is an array of 100 items: [0, 1, 2, ..., 99]
    y = 2.0 * x + np.random.uniform(-30, 30, size=total)  # y = 2 * x + random number -> linear form
    dummy_data = np.stack([x, y], axis=1)

    # draw the graph of input data
    if is_display_graph:
        plt.plot(x, y, 'o', alpha=0.5)
        plt.title('Input data')
        plt.show()

    return dummy_data

# define flags
tf.app.flags.DEFINE_integer('training_epochs', 10000, 'Total training epochs')
tf.app.flags.DEFINE_integer('display_step', 1000, 'Step to display the loss value')
tf.app.flags.DEFINE_float('learning_rate', 1e-9, 'The learning rate')
# tf.app.flags.DEFINE_float('expected_loss_minimum', 1e-10, 'The expected loss minimum value')
FLAGS = tf.app.flags.FLAGS

# init data
data = generate_dummy_data(True)
losses = []

# init the hypothesis model
X = tf.placeholder(tf.float32, name='X')
Y = tf.placeholder(tf.float32, name='Y')
w = tf.Variable(0.0, name='weight')
b = tf.Variable(0.0, name='bias')
hypothesis = w * X + b

# minimize the loss value using gradient descent
loss = tf.reduce_sum(tf.squared_difference(hypothesis, Y)) / 2 * data.shape[0]
optimizer = tf.train.GradientDescentOptimizer(FLAGS.learning_rate)
train = optimizer.minimize(loss)
training_data = {X: data[:, 0], Y: data[:, 1]}

# calculate score of the model
unexplained_loss = tf.reduce_sum(tf.squared_difference(hypothesis, Y), name='unexplained_loss')
R_squared = tf.subtract(1.0, tf.divide(unexplained_loss, loss))

# running the computation in Tensorflow
with tf.Session() as session:
    session.run(tf.global_variables_initializer())

    # previous_loss = 0.0
    print('\nModel training...')
    for epoch in range(FLAGS.training_epochs):
        _train, _loss = session.run([train, loss], feed_dict=training_data)
        losses.append(_loss)

        if epoch % FLAGS.display_step == 0:
            print('Epoch={}, loss value={}'.format(epoch, _loss))

        # we will quit the training process if we have reached our expected loss minimum value
        # if np.abs(previous_loss - _loss) < FLAGS.expected_loss_minimum:
        #     break
        # previous_loss = _loss

    _w, _b, _r_squared = session.run([w, b, R_squared], feed_dict=training_data)
    print('\nFinished!!!')
    print('y = {0:.4f} * x + {1:.4f}'.format(_w, _b))
    print('score = {0:.4f}\n'.format(_r_squared))

    # export model graph to Tensorboard
    # you can run this command to see the graph: tensorboard --logdir="./tensorboard/simple-linear"
    writer = tf.summary.FileWriter(dirname(__file__) + 'tensorboard/simple-linear', session.graph)
    writer.close()

    # display the fitted line
    plt.plot(data[:, 0], data[:, 1], "o", alpha=0.5)
    plt.plot(data[:, 0], _w * data[:, 0] + _b, alpha=0.5, label='Fitted line')
    plt.legend()
    plt.title('After predicted')
    plt.show()

    # draw the loss diagram
    plt.title('The loss diagram after trained')
    plt.plot(losses[:])
    plt.show()


"""
test_numpy.hamming_example_01.py
This is an example code for numpy.hamming
https://docs.scipy.org/doc/numpy/reference/generated/numpy.hamming.html
"""

from numpy.fft import fft, fftshift
import numpy as np
import matplotlib.pyplot as plt

window = np.hamming(51)
plt.plot(window)
#[<matplotlib.lines.Line2D object at 0x7f199c027630>]
plt.title("Hamming Window")
plt.xlabel("Sample")
plt.ylabel("Amplitude")
plt.show()