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

from scipy import signal
import numpy as np
import matplotlib.pyplot as plt

fig_path = "/Users/gabriel/Documents/Research/USGS_Work/gmprocess/figs/spectra/"

#%%

def get_fft(series, fs, nfft):
    ft = np.fft.fft(series,fs)
    freq = np.fft.fftfreq(nfft)

    return freq, ft

def get_ifft(series, fs, nfft, real=True):
    if real:
        ift = np.fft.ifft(series,fs).real
    else:
        ift = np.fft.ifft(series,fs)

    return ift

def ps_psd_difference(ps,psd):
    diff = []
    if len(ps) == len(psd):
        diff = np.zeros(len(ps))
        for i in range(len(ps)):
            diff[i] = psd[i]/ps[i]
    else:
        print("Spectra must be of the same size")

    return diff

#%%

# Make a test signal
np.random.seed(0)
delta = .01
fs = 1/ delta
time_vec = np.arange(0, 70, delta)

#%% Sine wave

delta = .01
fs = 1/ delta
t = np.arange(0,256,delta)
wndw_factor=500
overlap_factor=2
nfft = len(t)
nperseg=len(t)/wndw_factor
noverlap=nperseg/overlap_factor

# filename = "sine_wave_input-del_.01-nfft_256k"
# plt.plot(t,np.sin(t))
# plt.title("Test sine wave, ∆=0.01, N=256000")
# plt.savefig(fname=fig_path + filename + ".png", dpi=500)
# plt.show()

#%% Calculate PSD of test signal with Welch's Method
freqs_psd, psd = signal.welch(np.sin(t),fs=fs, nfft=nfft, nperseg=nperseg, noverlap=noverlap, scaling="density")
# freqs_psd, psd = signal.welch(np.sin(t),fs=fs, nfft=nfft, nperseg=nperseg, scaling="density")
# freqs_psd, psd = signal.welch(np.sin(t),fs=fs, nfft=nfft, scaling="density")
# freqs_psd, psd = signal.welch(np.sin(t),fs=fs, scaling="density")
# freqs_psd, psd = signal.welch(np.sin(t), scaling="density")

freqs_ps, ps = signal.welch(np.sin(t),fs=fs, nfft=nfft, nperseg=nperseg, noverlap=noverlap, scaling="spectrum")
# freqs_ps, ps = signal.welch(np.sin(t),fs=fs, nfft=nfft, nperseg=nperseg, scaling="spectrum")
# freqs_ps, ps = signal.welch(np.sin(t),fs=fs, nfft=nfft, scaling="spectrum")
# freqs_ps, ps = signal.welch(np.sin(t),fs=fs,scaling="spectrum")
# freqs_ps, ps = signal.welch(np.sin(t),scaling="spectrum")

diff = ps_psd_difference(ps,psd)

# Note: freqs are the same for both psd and ps

# filename = "sine_wave-default_fs_and_nfft"
# filename = "sine_wave-default_fs_and_nfft_nperseg"
# filename = "sine_wave-set_fs_and_default_nfft_nperseg"
filename = "sine_wave-using_fs_and_nfft_nperseg->" + str(wndw_factor) + "->" + str(100/overlap_factor) + "perc_overlap"

# No Scaling
plt.plot(freqs_psd, psd, label="PSD")
plt.plot(freqs_ps, ps, "--", label="PS")
plt.title("Parameter Testing for Welch's Method")
plt.legend()
plt.savefig(fname=fig_path + filename + "-no_scaling.png", dpi=500)
plt.show()

# Log x
plt.semilogx(freqs_psd, psd, label="PSD")
plt.semilogx(freqs_ps, ps, "--", label="PS")
plt.title("Parameter Testing for Welch's Method")
plt.legend()
plt.savefig(fname=fig_path + filename + "-logx.png", dpi=500)
plt.show()

# Log Y
plt.semilogy(freqs_psd, psd, label="PSD")
plt.semilogy(freqs_ps, ps, "--", label="PS")
plt.title("Parameter Testing for Welch's Method")
plt.legend()
plt.savefig(fname=fig_path + filename + "-logy.png", dpi=500)
plt.show()

#%% Scaling differences

# PSD / PS scaling ratios
# plt.figure(figsize=(4, 6))
plt.semilogy(freqs_psd, diff, label="PSD/PS ratio")
ax = plt.gca()
# plt.annotate("Variation due to rounding error", xy=(2, 1), xytext=(3, 1.5))
plt.title("Differencing PSD and PS")
plt.legend()
plt.savefig(fname=fig_path + "diff-" + filename + "-logy.png", dpi=500)
plt.show()

#%% Calculate PSD of test signal with just a periodogram

# freqs_ps, ps = signal.periodogram(np.sin(t),fs)
# freqs_psd, psd = signal.periodogram(np.sin(t),fs,scaling="density")

# # No Scaling
# plt.plot(freqs_psd, psd, label="PSD")
# plt.plot(freqs_ps, ps, "--", label="PS")
# plt.legend()
# plt.show()
# # Log x
# plt.semilogx(freqs_psd, psd, label="PSD")
# plt.semilogx(freqs_ps, ps, "--", label="PS")
# plt.legend()
# plt.show()
# # Log Y
# plt.semilogy(freqs_psd, psd, label="PSD")
# plt.semilogy(freqs_ps, ps, "--", label="PS")
# plt.legend()
# plt.show()

#%% Forward FFT

# # Forward transform
# t = np.arange(256)
# sp = np.fft.fft(np.sin(t))
# freq = np.fft.fftfreq(t.shape[-1])
# # plt.plot(freq, sp.real, freq, sp.imag)
# plt.plot(freq, sp.real)
# plt.show()

# # Forward transform, ortho normalization
# t = np.arange(256)
# sp = np.fft.fft(np.sin(t),norm='ortho')
# freq = np.fft.fftfreq(t.shape[-1])
# # plt.plot(freq, sp.real, freq, sp.imag)
# plt.plot(freq, sp.real)
# plt.show()

# Forward transform finer spacing (larger NFFT)
t = np.arange(0,256,0.1)
sp = np.fft.fft(np.sin(t))
freq = np.fft.fftfreq(t.shape[-1],0.1)
# plt.plot(freq, sp.real, freq, sp.imag)
# plt.plot(freq, sp.real)
# plt.show()

# # Forward transform, finer spacing, ortho normalization
# t = np.arange(0,256,0.1)
# sp = np.fft.fft(np.sin(t),norm='ortho')
# freq = np.fft.fftfreq(t.shape[-1],0.1)
# # plt.plot(freq, sp.real, freq, sp.imag)
# plt.plot(freq, sp.real)
# plt.show()

#
# Inverse FFT
#

# # Inverse transform
# t = np.arange(256)
# sig = np.fft.ifft(sp)
# plt.plot(t, sig)
# # plt.show()

# # Inverse transform, ortho normalization
# t = np.arange(256)
# sig = np.fft.ifft(sp, norm='ortho')
# plt.plot(t, sig)
# plt.show()

# Inverse transform, finer spacing (larger NFFT)
t = np.arange(0,256,0.1)
sig = np.fft.ifft(sp)
plt.plot(t, sig)
plt.show()

# Inverse transform, finer spacing, ortho normalization
# t = np.arange(0,256,0.1)
# sig = np.fft.ifft(sp, norm='ortho')
# plt.plot(t, sig)
# plt.show()


#coding: utf-8
import time
import timeit
import numpy as np
from random import randint, uniform
from csv import writer

def iniciar_matriz_randomicamente(tamanho):
	M = []
	for i in range(tamanho):
		#for (j=0;j<N;j++){
		linha=[]
		for j in range(tamanho):
			#x=rand()%10;
			x = randint(0,10)
			if x<5:
				linha.append(0)
			elif x<8:
				linha.append(1)
			else:
				linha.append(2)
		M.append(linha)

	return M

def dividir(matriz):
	linha, coluna = matriz.shape #retorna o tamanho de linhas e coluna
	linha_metade, coluna_metade = linha//2, coluna//2 #prof. a barra simples dupla, faz uma divisao desconsiderando fracao
	return matriz[:linha_metade, :coluna_metade], matriz[:linha_metade, coluna_metade:], matriz[linha_metade:, :coluna_metade], matriz[linha_metade:, coluna_metade:]

def conquistar_mult(x, y):
	#multiplicando matriz AxB de forma recursiva, dividindo e conquistando
	if len(x) == 1:
		return x * y

	a, b, c, d = dividir(x)
	e, f, g, h = dividir(y)

	p1 = conquistar_mult(a, f - h)
	p2 = conquistar_mult(a + b, h)
	p3 = conquistar_mult(c + d, e)
	p4 = conquistar_mult(d, g - e)
	p5 = conquistar_mult(a + d, e + h)
	p6 = conquistar_mult(b - d, g + h)
	p7 = conquistar_mult(a - c, e + f)

	c11 = p5 + p4 - p2 + p6
	c12 = p1 + p2
	c21 = p3 + p4
	c22 = p1 + p5 - p3 - p7

	c = np.vstack((np.hstack((c11, c12)), np.hstack((c21,c22))))

	return c

if __name__ == "__main__":

	grade = lambda: round(uniform(0.0, 10.0), 2)
	data = ((i + 1, grade(), grade()) for i in range(10))

	with open("Tmp_Exe.csv", "w") as f:
		w = writer(f)
		w.writerow([" - ", "N", "Divide_Conquer_T_Exec"])
		N = [32, 64, 128, 256, 512, 1024]

		for i in range(len(N)):
			print N[i]

			A = np.array(iniciar_matriz_randomicamente(32))
			B = np.array(iniciar_matriz_randomicamente(32))
			inicio = timeit.default_timer()
			c = conquistar_mult(A,B)
			fim = timeit.default_timer()
			w.writerow([i, N[i], (fim - inicio)])

			if N[i] == 64:
				print("Matriz A")
				print(A)
				print("\n")
				print("Matriz B")
				print(B)
				print("\n")
				print("Matriz C")
				print(c)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Feb 25 22:12:44 2018

@author: miaortizma
"""
import random
import numpy as np
import itertools as it
import matplotlib.pyplot as plt

def bubbleSort(A):
    n = len(A)
    finished = False
    comparations = 0
    swaps = 0
    others = 0
    while(not finished):
        comparations = comparations + 1
        finished = True
        others = others + 1
        for i in range(1, n):
            others = others + 1
            comparations = comparations + 1
            if(A[i-1] > A[i]):
                finished = False
                A[i-1], A[i] = A[i], A[i-1]
                swaps = swaps + 1
        n = n - 1
        others = others + 1
    comparations = comparations + 1
    return (comparations, swaps, others)

def graph(comparations, swaps, others):
    N = len(comparations)
    print("Average:")
    print("Comparations:", sum(comparations)/N)
    print("Swaps:", sum(swaps)/N)
    print("Others:", sum(others)/N)
    print("Distribucion:")
    plt.hist(comparations,bins='auto')
    plt.title("Histogram of Comparations")
    plt.show()
    plt.hist(swaps,bins='auto')
    plt.title("Histogram of Swaps")
    plt.show()
    plt.hist(others,bins='auto')
    plt.title("Histogram of Others")
    plt.show()
    allOps = comparations + swaps + others
    plt.title("Histogram of all operations")
    plt.hist(allOps, bins='auto')
    plt.show()

'''
Referencia Heap's Algorithm - wikipedia
'''

def generate(n):
    A = list(range(1,n+1))
    c = [0]*n
    yield A
    i = 0
    while i < n:
        if  c[i] < i:
            if i%2 == 0:
                A[0],A[i] = A[i], A[0]
            else:
                A[c[i]],A[i] = A[i], A[c[i]]
            yield A
            c[i] = c[i] + 1
            i = 0
        else:
            c[i] = 0
            i = i + 1

def shuffle(A):
    A = list(A)
    n = len(A)
    for i in range(n-1):
        j = random.randint(i,n-1)
        A[j],A[i] = A[i], A[j]
    return A

def allPerms(n, perms):
    comparations = []
    swaps = []
    others = []
    for perm in perms:
        temp = bubbleSort(list(perm))
        comparations = comparations + [temp[0]]
        swaps = swaps + [temp[1]]
        others = others + [temp[2]]
    graph(comparations, swaps, others)

def samplePerms(n, m, rnd):
    comparations = []
    swaps = []
    others = []
    rng = range(n)
    for i in range(m):
        nxt = rnd(rng)
        temp = bubbleSort(nxt)
        comparations = comparations + [temp[0]]
        swaps = swaps + [temp[1]]
        others = others + [temp[2]]
    graph(comparations, swaps, others)

n = 5
allPerms(n,it.permutations(range(n)))
allPerms(n,generate(n))

n = 20
samples = 10000
samplePerms(n, samples, shuffle)
#samplePerms(n, samples, np.random.permutation)


from functools import lru_cache
from typing import Dict, List, Optional, Tuple

import numpy as np

def solve_tsp_dynamic_programming(
    distance_matrix: np.ndarray,
    maxsize: Optional[int] = None,
) -> Tuple[List, float]:
    """
    Solve TSP to optimality with dynamic programming.

    Parameters
    ----------
    distance_matrix
        Distance matrix of shape (n x n) with the (i, j) entry indicating the
        distance from node i to j. It does not need to be symmetric

    maxsize
        Parameter passed to ``lru_cache`` decorator. Used to define the maximum
        size for the recursion tree. Defaults to `None`, which essentially
        means "take as much space as needed".

    Returns
    -------
    permutation
        A permutation of nodes from 0 to n that produces the least total
        distance

    distance
        The total distance the optimal permutation produces

    Notes
    -----
    Algorithm: cost of the optimal path
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Consider a TSP instance with 3 nodes: {0, 1, 2}. Let dist(0, {1, 2}) be the
    distance from 0, visiting all nodes in {1, 2} and going back to 0. This can
    be computed recursively as:

        dist(0, {1, 2}) = min(
            c_{0, 1} + dist(1, {2}),
            c_{0, 2} + dist(2, {1}),
        )

    wherein c_{0, 1} is the cost from going from 0 to 1 in the distance matrix.
    The inner dist(1, {2}) is computed as:

        dist(1, {2}) = min(
            c_{1, 2} + dist(2, {}),
        )

    and similarly for dist(2, {1}). The stopping point in the recursion is:

        dist(2, {}) = c_{2, 0}.

    This process can be generalized as:

        dist(ni, N) =   min   ( c_{ni, nj} + dist(nj, N - {nj}) )
                      nj in N

    and

        dist(ni, {}) = c_{ni, 0}

    With starting point as dist(0, {1, 2, ..., tsp_size}). The notation
    N - {nj} is the difference operator, meaning set N without node nj.

    Algorithm: compute the optimal path
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The previous process returns the distance of the optimal path. To find the
    actual path, we need to store in a memory the following key/values:

        memo[(ni, N)] = nj_min

    with nj_min the node in N that provided the smallest value of dist(ni, N).
    Then, the process goes backwards starting from
    memo[(0, {1, 2, ..., tsp_size})].

    In the previous example, suppose memo[(0, {1, 2})] = 1.
    Then, look for memo[(1, {2})] = 2.
    Then, since the next step would be memo[2, {}], stop there. The optimal
    path would be 0 -> 1 -> 2 -> 0.

    Reference
    ---------
    https://en.wikipedia.org/wiki/Held%E2%80%93Karp_algorithm#cite_note-5
    """
    # Get initial set {1, 2, ..., tsp_size} as a frozenset because @lru_cache
    # requires a hashable type
    N = frozenset(range(1, distance_matrix.shape[0]))
    memo: Dict[Tuple, int] = {}

    # Step 1: get minimum distance
    @lru_cache(maxsize=maxsize)
    def dist(ni: int, N: frozenset) -> float:
        if not N:
            return distance_matrix[ni, 0]

        # Store the costs in the form (nj, dist(nj, N))
        costs = [
            (nj, distance_matrix[ni, nj] + dist(nj, N.difference({nj})))
            for nj in N
        ]
        nmin, min_cost = min(costs, key=lambda x: x[1])
        memo[(ni, N)] = nmin
        return min_cost

    best_distance = dist(0, N)

    # Step 2: get path with the minimum distance
    ni = 0  # start at the origin
    solution = [0]
    while N:
        ni = memo[(ni, N)]
        solution.append(ni)
        N = N.difference({ni})

    return solution, best_distance


"""Detects outliers for list or array of values"""

import numpy as np

def detect_outlier(data_1):
    """
    Detects outliers
    :params data_1 array:
    :returns list of outliers:
    """
    outliers = []
    threshold = 3
    mean_1 = np.mean(data_1)
    std_1 = np.std(data_1)

    for y_var in data_1:
        z_score = (y_var - mean_1)/std_1
        if np.abs(z_score) > threshold:
            outliers.append(y_var)
    return outliers


import numpy as np

class Markowitz:
    """Solver of Markowitz optimization problem
    """

    def __init__(self, expected_returns, cov_matrix):
        self._n_assets = len(expected_returns)
        self._cov_matrix = cov_matrix
        self._expected_returns = expected_returns.reshape((self._n_assets, 1))

        A, B, C, D, We, Wm = self._build_magic_numbers()

        self._A = A
        self._B = B
        self._C = C
        self._D = D
        self._We = We
        self._Wm = Wm

    def optimal_risk(self, target_risk):
        """Calculate optimization solution given target risk
        Args:
            - target_risk (float): risk tolerance
        Returns:
            - (np.array) optimal weights
        """
        x_min, z = self._solve()

        weights = x_min + (z * target_risk / 2)

        return weights

    def optimal_return(self, target_return):
        """Calculate optimization solution given target return
        Args:
            - target_return (float): target return
        Returns:
            - (np.array) optimal weights
        """

        target_risk = 2 * (target_return - self._A /
                           self._C) * self._C / self._D

        return self.optimal_risk(target_risk)

    def get_efficient_curve(self, n_points):
        """Generates risk return curve with optimal weights solution
        Args:
            - n_points (int): number of points
        Return:
            - Tuple(np.array, np.array, np.array) returns, risks and optimal weights, respectively
        """

        start_return = self._A / self._C
        end_return = self._expected_returns.max()
        step_size = (end_return - start_return)/n_points

        returns = np.arange(start_return, end_return, step_size)
        weights = np.array([self.optimal_return(target_return) for target_return in returns])
        weights = weights.squeeze()

        risks = np.sqrt(np.array([np.dot(w.T, np.dot(self._cov_matrix, w)) for w in weights]))

        return (returns, risks, weights)

    def get_start_return(self):
        """Get initial return value of efficient curve
        """

        return self._A / self._C

    def _build_useful_matrices(self):
        W = np.linalg.inv(self._cov_matrix)
        e = np.ones((self._n_assets, 1))

        We = np.dot(W, e)
        Wm = np.dot(W, self._expected_returns)

        return e, We, Wm

    def _build_magic_numbers(self):
        e, We, Wm = self._build_useful_matrices()

        A = np.dot(e.T, Wm)
        B = np.dot(self._expected_returns.T, Wm)
        C = np.dot(e.T, We)
        D = B * C - A**2

        return A, B, C, D, We, Wm

    def _solve(self):

        x_min = self._We / self._C
        z = self._Wm - (self._A/self._C) * self._We

        return x_min, z

    def _optimal_curve(self, target_return):

        hyperbola = self._C * target_return ** 2 - 2 * self._A * target_return + self._B

        risk = np.sqrt((1 / self._D) * hyperbola)

        return float(risk)


import numpy as np

class KMeans:
    '''Consiste à trouver n_clusters partitions qui minimisent la variance au sein d'une même partition pour un ensemble de points donnés
    '''
    def __init__(self, n_clusters):
        self.n_clusters = n_clusters
        self._cluster_centroids = None
        self._labels = None
        self._score = np.inf

    def _init_centroids(self, lower, upper, n_features):
        '''Initialisation naive: les barycentres des clusters sont tirés d'une distribution uniforme définie par lower et upper
        '''
        return (upper - lower) * np.random.random((self.n_clusters, n_features)) + lower

    def fit(self, X, max_iter=300, tol=1e-4, n_trials=10):
        '''Assigne un unique cluster à chaque point de X:

        Initialise les barycentres aléatoirement,
        Jusqu'à convergence ou que le nombre maximal d'itérations soit atteint:
            1 - assigne le cluster avec le barycentre le plus proche
            2 - recalcule les barycentres en prenant la moyenne des points qui sont assigné au cluster correspondant

        Repète l'opération n_trials fois car l'agorithme est heuristique et ne garantit pas de trouver une solution optimale globale.
        '''
        for _ in range(n_trials):
            cluster_centroids = self._init_centroids(np.min(X), np.max(X), X.shape[1])
            labels = np.zeros(X.shape[0])
            score = np.inf

            for _ in range(max_iter):
                labels, score = self._cluster_assignement(X, cluster_centroids)
                new_centroids = self._compute_centroids(X, cluster_centroids, labels)

                if  np.sum((new_centroids - cluster_centroids)**2) < tol:
                    break

                cluster_centroids = new_centroids

            if score < self._score:
                self._cluster_centroids = cluster_centroids
                self._labels = labels
                self._score = score

        return self._labels

    def _cluster_assignement(self, X, cluster_centroids):
        '''Calcule les distances euclidiennes au carré entre chaque point et les barycentres: matrice de dimensions (n_points, n_clusters) et retourne
        le cluster avec le barycentre le plus proche: vecteur de dimension (n_points,) ainsi que le score: somme des distances au carré au cluster le plus proche

        L'utilisation de la distance euclidienne permet de calculer la matrice de façon efficiente en utilisant les fonctions optimisées de numpy (pas de boucle)
        '''
        squarred_distances = -2 * X @ cluster_centroids.T + np.sum(cluster_centroids**2, axis=1) + np.sum(X**2, axis=1)[:, None]
        labels = squarred_distances.argmin(axis=1)
        score = squarred_distances.min(axis=1).sum()

        return labels, score

    def _compute_centroids(self, X, old_cluster_centroids, labels):
        '''Calcule les nouveaux barycentres en prenant la moyenne des points appartenant au cluster du barycentre, pour chaque barycentre
        '''
        new_cluster_centroids = old_cluster_centroids.copy()

        for i in range(self.n_clusters):
            label_mask = (labels == i)

            if X[label_mask].shape[0] > 0:
                new_cluster_centroids[i] = X[label_mask].mean(axis=0)

        return new_cluster_centroids


import numpy as np

from prml.linear._classifier import Classifier
from prml.preprocess.label_transformer import LabelTransformer

class SoftmaxRegression(Classifier):
    """Softmax regression model.

    aka
    multinomial logistic regression,
    multiclass logistic regression,
    maximum entropy classifier.

    y = softmax(X @ W)
    t ~ Categorical(t|y)
    """

    @staticmethod
    def _softmax(a):
        a_max = np.max(a, axis=-1, keepdims=True)
        exp_a = np.exp(a - a_max)
        return exp_a / np.sum(exp_a, axis=-1, keepdims=True)

    def fit(
        self,
        x_train: np.ndarray,
        y_train: np.ndarray,
        max_iter: int = 100,
        learning_rate: float = 0.1,
    ):
        """Maximum likelihood estimation of the parameter.

        Parameters
        ----------
        X : (N, D) np.ndarray
            training independent variable
        t : (N,) or (N, K) np.ndarray
            training dependent variable
            in class index or one-of-k encoding
        max_iter : int, optional
            maximum number of iteration (the default is 100)
        learning_rate : float, optional
            learning rate of gradient descent (the default is 0.1)
        """
        if y_train.ndim == 1:
            y_train = LabelTransformer().encode(y_train)
        self.n_classes = np.size(y_train, 1)
        w = np.zeros((np.size(x_train, 1), self.n_classes))
        for _ in range(max_iter):
            w_prev = np.copy(w)
            y = self._softmax(x_train @ w)
            grad = x_train.T @ (y - y_train)
            w -= learning_rate * grad
            if np.allclose(w, w_prev):
                break
        self.w = w

    def proba(self, x: np.ndarray):
        """Return probability of input belonging each class.

        Parameters
        ----------
        x : np.ndarray
            Input independent variable (N, D)

        Returns
        -------
        np.ndarray
            probability of each class (N, K)
        """
        return self._softmax(x @ self.w)

    def classify(self, x: np.ndarray):
        """Classify input data.

        Parameters
        ----------
        x : np.ndarray
            independent variable to be classified (N, D)

        Returns
        -------
        np.ndarray
            class index for each input (N,)
        """
        return np.argmax(self.proba(x), axis=-1)


import numpy as np

from deepy.autograd import Autograd

class ArcTan(Autograd):
    """ Applies the arctan function element-wise. """
    def forward(self, ctx: Autograd.Context, tensor: np.array):
        ctx.save_for_back(tensor)
        return np.arctan(tensor)

    def backward(self, ctx: Autograd.Context, grad: np.array):
        tensor = ctx.data_for_back
        return grad / (tensor * tensor + 1)

class ReLU(Autograd):
    def forward(self, ctx: Autograd.Context, tensor: np.array):
        ctx.save_for_back(tensor)
        return np.clip(tensor, a_min=0, a_max=None)

    def backward(self, ctx: Autograd.Context, grad: np.array):
        t = ctx.data_for_back
        return np.where(t < 0, 0, grad)

class Sigmoid(Autograd):
    def forward(self, ctx: Autograd.Context, tensor: np.array) -> np.array:
        sig = 1 / (1 + np.exp(-tensor))
        ctx.save_for_back(sig)
        return sig

    def backward(self, ctx: Autograd.Context, grad: np.array = None):
        sig = ctx.data_for_back
        return sig * (1 - sig) * grad

class Softmax(Autograd):
    def forward(self, ctx: Autograd.Context, x: np.array) -> np.array:
        e_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
        res = e_x / np.sum(e_x, axis=-1, keepdims=True)
        ctx.save_for_back(res)
        return res

    def backward(self, ctx: Autograd.Context, grad: np.array = None):
        res = ctx.data_for_back
        return grad * res * (1 - res)

class Softplus(Autograd):
    """ Applies the softplus function element-wise:

    Softplus(x) = ln(1 + e^x)
    Softplus'(x) = 1 / (1 + e^-x)
    """
    def forward(self, ctx: Autograd.Context, tensor: np.array) -> np.array:
        ctx.save_for_back(1 + np.exp(-tensor))
        return np.log(1 + np.exp(tensor))

    def backward(self, ctx: Autograd.Context, grad: np.array = None):
        denominator = ctx.data_for_back
        return grad / denominator

class Softsign(Autograd):
    """ Applies the softsign function element-wise:

    Softsign(x) = 1 / (1 + |x|)
    Softsign'(x) = 1 / (1 + |x|)^2
    """
    def forward(self, ctx: Autograd.Context, tensor: np.array) -> np.array:
        denominator = 1 + np.abs(tensor)
        ctx.save_for_back(denominator)
        return tensor / denominator

    def backward(self, ctx: Autograd.Context, grad: np.array = None):
        denominator = ctx.data_for_back
        return grad / (denominator * denominator)

class Tanh(Autograd):
    """ Applies the tanh function element-wise. """
    def forward(self, ctx: Autograd.Context, tensor: np.array) -> np.array:
        tanh = np.tanh(tensor)
        ctx.save_for_back(tanh)
        return tanh

    def backward(self, ctx: Autograd.Context, grad: np.array = None):
        tanh = ctx.data_for_back
        return (1 - tanh * tanh) * grad


import numpy as np

A = np.array([1, 1, 1])
B = np.array([2, 2, 2])

# 上下合并
C = np.vstack((A, B))
print(C)
print(C.shape)

# 左右合并
D = np.hstack((A, B))
print(D)
print(D.shape)

# 使用坐标轴合并(纵向合并)
print(np.concatenate((A[:, np.newaxis], B[:, np.newaxis]), axis=1))

# 添加一个行维度
print(A[np.newaxis, :])

# 添加一个列维度
print(A[:, np.newaxis])


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Perceptron
Original Source: https://github.com/Honghe/perceptron/tree/master/perceptron
Author: Honghe, modified by JVS.
"""

import matplotlib.pyplot as plt
import numpy as np

# set random seed so get same sequence of random numbers each time prog is run.
# np.random.seed(20)

class Perceptron(object):
    """docstring for Perceptron"""
    def __init__(self):
        super(Perceptron, self).__init__()
        self.w = [np.random.rand() * 2 - 1 for _ in range(2)] # weights
        self.learningRate = 0.001

    def response(self, x):
        # perceptron output
        y = x[0] * self.w[0] + x[1] * self.w[1] # dot product between w and x
        # y = sum([i * j for i, j in zip(self.w, x)]) # more pythonic
        #y = np.dot(x[0:1],self.w)
        y=y*1.0
        if y >= 0:
            res = 1.0
        else:
            res = -1.0
        return res

    def updateWeights(self, x, iterError):
        """
        upates the wights status, w at time t+1 is
        w(t+1) = w(t) + learningRate * (d - r) * x
        iterError is (d - r)
        """
        self.w[0] += self.learningRate * iterError * x[0]
        self.w[1] += self.learningRate * iterError * x[1]
        #self.w = \
            #[i + self.learningRate * iterError * j for i, j in zip(self.w, x)]

    def train(self, data):
        """
        Trains all the vector in data.
        Every vector in data must three elements.
        The third element of x (ie x[2]) is the label(desired output)
        """
        learned = False
        iteration = 0
        while not learned:
            numcorrect = 0
            globalError = 0.0
            for x in data: # for each input vector
                r = self.response(x)
                if x[2] != r: # if have a wrong response
                    iterError = x[2] - r # desired response - actual response
                    self.updateWeights(x, iterError)
                    globalError += abs(iterError)
                else:
                    numcorrect += 1
            print('num correctly classified = %s' % numcorrect)
            iteration += 1
            if globalError == 0.0 or iteration >= 100: # stop criteria
                print('iterations = %s' % iteration)
                learned = True # stop learning

            ########## Plot ##########
            plotinterval = 2
            if (iteration % plotinterval == 0):
                plotData(data,self.w)
                plt.pause(0.001)

def generateData(n):
    """
    generates a 2D linearly separable dataset with 2n samples.
    The third element of the sample is the correct response.
    """
    # class A=blue dots has all y values above 0
    xb = (np.random.rand(n) * 2 -1)
    yb = (np.random.rand(n) * 2 -1) / 2 + 0.55

    # class B=red dots has all y values below 0
    xr = (np.random.rand(n) * 2 -1)
    yr = (np.random.rand(n) * 2 -1) / 2 - 0.55

    inputs = []
    inputs.extend([[xb[i], yb[i], 1] for i in range(n)])
    inputs.extend([[xr[i], yr[i], -1] for i in range(n)])
    return inputs

def plotData(data,w):
    plt.clf()
    for x in data:
        if x[1] < 0:
            plt.plot(x[0], x[1], 'ob')
        else:
            plt.plot(x[0], x[1], 'or')
    # plot the decision boundary.
    # The decision boundary is orthogonal to w.
    n = np.linalg.norm(w) # aka the length of p.w vector
    ww = w / n # a unit vector
    ww1 = [ww[1], -ww[0]]
    ww2 = [-ww[1], ww[0]]
    plt.ion()
    plt.plot([ww1[0], ww2[0]], [ww1[1], ww2[1]], '--k')
    plt.title('Two classes separated by a line orthogonal to the weight vector')
    plt.show()

trainset = generateData(80) # train set generation
# testset = generateData(20) # test set generation

p = Perceptron()

plotData(trainset,p.w)
p.train(trainset)
plotData(trainset,p.w)

########## The End ##########


# coding: utf-8

# In[1]:

import numpy as np

# In[2]:

from scipy.stats import norm

def rnorm(n,mean,sd):
    """
    same functions as rnorm in r
    r: rnorm(n, mean=0, sd=1)
    py: rvs(loc=0, scale=1, size=1, random_state=None)
    """
    return norm.rvs(loc=mean,scale=sd,size=n)

def dnorm(x,mean,sd, log=False):
    """
    same functions as dnorm in r
    dnorm(x, mean=0, sd=1, log=FALSE)
    pdf(x, loc=0, scale=1)
    """
    if log:
        return np.log(norm.pdf(x=x,loc=mean,scale=sd))
    else:
        return norm.pdf(x=x,loc=mean,scale=sd)

def runif(n,min=0, max=1):
    """
    r: runif(n, min = 0, max = 1)
    py: random.uniform(low=0.0, high=1.0, size=None)
    """
    return np.random.uniform(min,max,size=n)

# In[3]:

s2 = 1
t2 = 10
mu = 5
n = 5

# In[4]:

y = rnorm(n,10,1)
y

# In[5]:

# mean of the normal posterior
mu_n = (np.mean(y)*n/s2 + mu/float(t2))/(n/float(s2)+1/float(t2))
mu_n

# In[6]:

# variance of the normal posterior
# t2.n<-1/(n/s2+1/t2)

t2_n = 1.0/(n/float(s2)+1.0/t2)
t2_n

# In[7]:

# defining the data
# y<-c(9.37, 10.18, 9.16, 11.60, 10.33)

y = [9.37, 10.18, 9.16, 11.60, 10.33]

# In[8]:

mu_n = (np.mean(y)*n/s2 + mu/float(t2))/(n/float(s2)+1/float(t2))
mu_n

# In[9]:

####metropolis part####
##S = total num of simulations
# theta<-0 ; delta<-2 ; S<-10000 ; THETA<-NULL ; set.seed(1)

theta = 0
delta = 2

S = 10000

theta_v = []

# In[ ]:

for s in range(S):
    theta_star = norm.rvs(theta,np.sqrt(delta),1)
    logr = (sum(dnorm(y,theta_star,np.sqrt(s2),log=True)) +
            sum(dnorm(theta_star,mu,np.sqrt(t2),log=True)))-
            (sum(dnorm(y,theta,np.sqrt(s2),log=True)) +
             sum(dnorm([theta],mu,np.sqrt(t2),log=True)))
    #print(logr)
    if np.log(runif(1))<logr:
        theta = theta_star
    #print(theta)
    theta_v.append(theta)

# In[ ]:

import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

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

plt.subplot(1, 2, 1)
plt.plot(theta_v,'b-.')

plt.subplot(1, 2, 2)
#bins = np.arange(0, S, 10)
plt.hist(theta_v, density=True,bins='auto')
x = np.linspace(min(theta_v),max(theta_v),100)
y = norm.pdf(x,mu_n,np.sqrt(t2_n))
plt.plot(x,y,'y-.')
plt.xlim(right=12)  # adjust the right leaving left unchanged
plt.xlim(left=8)  # adjust the left leaving right unchanged
plt.show()

# In[ ]:


import unittest

import numpy as np
import sympy as sym

import opt_mo

p = (0.1, 0.5, 0.6, 0.7)

q_1, q_2, q_3, q_4 = sym.symbols("q_1, q_2, q_3, q_4")
q = (q_1, q_2, q_3, q_4)

def test_markov_chain():
    M = opt_mo.mem_one_match_markov_chain(p, q)

    assert type(M) is np.ndarray
    assert M.item(0) == 0.1 * q_1
    assert M.item(0) == 0.1 * q_1
    assert M.item(1) == -0.1 * q_1 + 0.1
    assert M.item(2) == 0.9 * q_1
    assert M.item(3) == -0.9 * q_1 + 0.9
    assert M.item(4) == 0.5 * q_3
    assert M.item(5) == -0.5 * q_3 + 0.5
    assert M.item(6) == 0.5 * q_3
    assert M.item(7) == -0.5 * q_3 + 0.5
    assert M.item(8) == 0.6 * q_2
    assert M.item(9) == -0.6 * q_2 + 0.6
    assert M.item(10) == 0.4 * q_2
    assert M.item(11) == -0.4 * q_2 + 0.4
    assert M.item(12) == 0.7 * q_4
    assert M.item(13) == -0.7 * q_4 + 0.7
    assert M.item(14) == (1 - 0.7) * q_4
    assert M.item(15) == (1 - 0.7) * (1 - q_4)

def test_steady_states():
    pi_1, pi_2, pi_3 = sym.symbols("pi_1, pi_2, pi_3")
    pi = (pi_1, pi_2, pi_3)

    matrix = np.array(
        [[0.9, 0.075, 0.025], [0.15, 0.8, 0.05], [0.25, 0.25, 0.5]]
    )
    v = opt_mo.steady_states(matrix, pi)

    assert v[pi_1] == 0.6250
    assert v[pi_2] == 0.3125
    assert v[pi_3] == 0.0625

def test_make_B():
    q_1, q_2, q_3, q_4 = sym.symbols("q_1, q_2, q_3, q_4")
    p_1, p_2, p_3, p_4 = sym.symbols("q_1, q_2, q_3, q_4")

    p = (p_1, p_2, p_3, p_4)
    q = (q_1, q_2, q_3, q_4)
    S = (3, 0, 5, 1)

    B = opt_mo.make_B(S, p, q)

    assert type(B) is np.ndarray
    assert B.item(0) == q_1 ** 2 - 1
    assert B.item(1) == q_1 - 1
    assert B.item(2) == q_1 - 1
    assert B.item(3) == 3
    assert B.item(4) == q_2 * q_3
    assert B.item(5) == q_2 - 1
    assert B.item(6) == q_3
    assert B.item(7) == 0
    assert B.item(8) == q_2 * q_3
    assert B.item(9) == q_3
    assert B.item(10) == q_2 - 1
    assert B.item(11) == 5
    assert B.item(12) == q_4 ** 2
    assert B.item(13) == q_4
    assert B.item(14) == q_4
    assert B.item(15) == 1

def test_is_ZD():
    tit_for_tat = (1, 0, 1, 0)
    assert opt_mo.tools.is_ZD(tit_for_tat) == False

    extort_two = (8 / 9, 1 / 2, 1 / 3, 0)
    assert opt_mo.tools.is_ZD(extort_two) is True

def test_get_least_squares():
    vector = (1, 0, 0, 1)
    assert np.isclose(opt_mo.tools.get_least_squares(vector), 1.23, 10 ** -2)

    extort_two = (8 / 9, 1 / 2, 1 / 3, 0)
    assert np.isclose(opt_mo.tools.get_least_squares(extort_two), 0)


from utils import calculate_variance
import numpy as np
from math import sqrt

def display_as_percentage(val):
  return '{:.1f}%'.format(val * 100)

returns_disney = [0.10, 0.12, 0.15, 0.05, 0.04]
returns_cbs = [-0.80, -0.15, 0.31, -0.06, -0.29]

stddev_disney = np.std(returns_disney)
stddev_cbs = np.std(returns_cbs)

dataset = [10, 8, 9, 10, 12]

def calculate_stddev(dataset):
  variance = calculate_variance(dataset)
  stddev = sqrt(variance)
  return stddev

stddev_disney = calculate_stddev(returns_disney)
stddev_cbs = calculate_stddev(returns_cbs)

print('The standard deviation of Disney stock returns is', display_as_percentage(stddev_disney))
print('The standard deviation of CBS stock returns is', display_as_percentage(stddev_cbs))


from sympy import symbols, sin, exp, log, cos
from sympy.tensor.array import Array

from sympy.tensor.array.arrayop import tensorproduct, tensorcontraction, derive_by_array

def test_tensorproduct():
    x,y,z,t = symbols('x y z t')
    from sympy.abc import a,b,c,d
    assert tensorproduct() == 1
    assert tensorproduct([x]) == Array([x])
    assert tensorproduct([x], [y]) == Array([[x*y]])
    assert tensorproduct([x], [y], [z]) == Array([[[x*y*z]]])
    assert tensorproduct([x], [y], [z], [t]) == Array([[[[x*y*z*t]]]])

    assert tensorproduct(x) == x
    assert tensorproduct(x, y) == x*y
    assert tensorproduct(x, y, z) == x*y*z
    assert tensorproduct(x, y, z, t) == x*y*z*t

    A = Array([x, y])
    B = Array([1, 2, 3])
    C = Array([a, b, c, d])

    assert tensorproduct(A, B, C) == Array([[[a*x, b*x, c*x, d*x], [2*a*x, 2*b*x, 2*c*x, 2*d*x], [3*a*x, 3*b*x, 3*c*x, 3*d*x]],
                                            [[a*y, b*y, c*y, d*y], [2*a*y, 2*b*y, 2*c*y, 2*d*y], [3*a*y, 3*b*y, 3*c*y, 3*d*y]]])

    assert tensorproduct([x, y], [1, 2, 3]) == tensorproduct(A, B)

    assert tensorproduct(A, 2) == Array([2*x, 2*y])
    assert tensorproduct(A, [2]) == Array([[2*x], [2*y]])
    assert tensorproduct([2], A) == Array([[2*x, 2*y]])
    assert tensorproduct(a, A) == Array([a*x, a*y])
    assert tensorproduct(a, A, B) == Array([[a*x, 2*a*x, 3*a*x], [a*y, 2*a*y, 3*a*y]])
    assert tensorproduct(A, B, a) == Array([[a*x, 2*a*x, 3*a*x], [a*y, 2*a*y, 3*a*y]])
    assert tensorproduct(B, a, A) == Array([[a*x, a*y], [2*a*x, 2*a*y], [3*a*x, 3*a*y]])

def test_tensorcontraction():
    from sympy.abc import a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x
    B = Array(range(18), (2, 3, 3))
    assert tensorcontraction(B, (1, 2)) == Array([12, 39])
    C1 = Array([a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x], (2, 3, 2, 2))

    assert tensorcontraction(C1, (0, 2)) == Array([[a + o, b + p], [e + s, f + t], [i + w, j + x]])
    assert tensorcontraction(C1, (0, 2, 3)) == Array([a + p, e + t, i + x])
    assert tensorcontraction(C1, (2, 3)) == Array([[a + d, e + h, i + l], [m + p, q + t, u + x]])

def test_derivative_by_array():
    from sympy.abc import a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z

    bexpr = x*y**2*exp(z)*log(t)
    sexpr = sin(bexpr)
    cexpr = cos(bexpr)

    a = Array([sexpr])

    assert derive_by_array(sexpr, t) == x*y**2*exp(z)*cos(x*y**2*exp(z)*log(t))/t
    assert derive_by_array(sexpr, [x, y, z]) == Array([bexpr/x*cexpr, 2*y*bexpr/y**2*cexpr, bexpr*cexpr])
    assert derive_by_array(a, [x, y, z]) == Array([[bexpr/x*cexpr], [2*y*bexpr/y**2*cexpr], [bexpr*cexpr]])

    assert derive_by_array(sexpr, [[x, y], [z, t]]) == Array([[bexpr/x*cexpr, 2*y*bexpr/y**2*cexpr], [bexpr*cexpr, bexpr/log(t)/t*cexpr]])
    assert derive_by_array(a, [[x, y], [z, t]]) == Array([[[bexpr/x*cexpr], [2*y*bexpr/y**2*cexpr]], [[bexpr*cexpr], [bexpr/log(t)/t*cexpr]]])
    assert derive_by_array([[x, y], [z, t]], [x, y]) == Array([[[1, 0], [0, 0]], [[0, 1], [0, 0]]])
    assert derive_by_array([[x, y], [z, t]], [[x, y], [z, t]]) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]],
                                                                         [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]])

def test_issue_emerged_while_discussing_10972():
    ua = Array([-1,0])
    Fa = Array([[0, 1], [-1, 0]])
    po = tensorproduct(Fa, ua, Fa, ua)
    assert tensorcontraction(po, (1, 2), (4, 5)) == Array([[0, 0], [0, 1]])

    sa = symbols('a0:144')
    po = Array(sa, [2, 2, 3, 3, 2, 2])
    assert tensorcontraction(po, (0, 1), (2, 3), (4, 5)) == sa[0] + sa[108] + sa[111] + sa[124] + sa[127] + sa[140] + sa[143] + sa[16] + sa[19] + sa[3] + sa[32] + sa[35]
    assert tensorcontraction(po, (0, 1, 4, 5), (2, 3)) == sa[0] + sa[111] + sa[127] + sa[143] + sa[16] + sa[32]
    assert tensorcontraction(po, (0, 1), (4, 5)) == Array([[sa[0] + sa[108] + sa[111] + sa[3], sa[112] + sa[115] + sa[4] + sa[7],
                                                             sa[11] + sa[116] + sa[119] + sa[8]], [sa[12] + sa[120] + sa[123] + sa[15],
                                                             sa[124] + sa[127] + sa[16] + sa[19], sa[128] + sa[131] + sa[20] + sa[23]],
                                                            [sa[132] + sa[135] + sa[24] + sa[27], sa[136] + sa[139] + sa[28] + sa[31],
                                                             sa[140] + sa[143] + sa[32] + sa[35]]])
    assert tensorcontraction(po, (0, 1), (2, 3)) == Array([[sa[0] + sa[108] + sa[124] + sa[140] + sa[16] + sa[32], sa[1] + sa[109] + sa[125] + sa[141] + sa[17] + sa[33]],
                                                           [sa[110] + sa[126] + sa[142] + sa[18] + sa[2] + sa[34], sa[111] + sa[127] + sa[143] + sa[19] + sa[3] + sa[35]]])


#!/usr/bin/python3.7
# UTF8
# Date:Thu 19 Mar 2020 22:24:29 CET
# Author: Nicolas Flandrois
# Create a sudoku solver in python, using recursion.

import numpy as np

# Please Change this matrix according to the sudoku to solve.

# Exemple With only 1 solution
grid = [
    [5, 3, 0, 0, 7, 0, 0, 0, 0],
    [6, 0, 0, 1, 9, 5, 0, 0, 0],
    [0, 9, 8, 0, 0, 0, 0, 6, 0],
    [8, 0, 0, 0, 6, 0, 0, 0, 3],
    [4, 0, 0, 8, 0, 3, 0, 0, 1],
    [7, 0, 0, 0, 2, 0, 0, 0, 6],
    [0, 6, 0, 0, 0, 0, 2, 8, 0],
    [0, 0, 0, 4, 1, 9, 0, 0, 5],
    [0, 0, 0, 0, 8, 0, 0, 7, 9]
]

# Exemple With 2 solutions
# grid = [
#     [5, 3, 0, 0, 7, 0, 0, 0, 0],
#     [6, 0, 0, 1, 9, 5, 0, 0, 0],
#     [0, 9, 8, 0, 0, 0, 0, 6, 0],
#     [8, 0, 0, 0, 6, 0, 0, 0, 3],
#     [4, 0, 0, 8, 0, 3, 0, 0, 1],
#     [7, 0, 0, 0, 2, 0, 0, 0, 6],
#     [0, 6, 0, 0, 0, 0, 2, 8, 0],
#     [0, 0, 0, 4, 1, 9, 0, 0, 5],
#     [0, 0, 0, 0, 8, 0, 0, 7, 9]
# ]

print('Initial Grid:\n', np.matrix(grid))

def possible(y, x, n):
    global grid

    for i in range(0, 9):
        if grid[y][i] == n:
            return False

    for i in range(0, 9):
        if grid[i][x] == n:
            return False

    x0 = (x // 3) * 3
    y0 = (y // 3) * 3

    for i in range(0, 3):
        for j in range(0, 3):
            if grid[y0 + i][x0 + j] == n:
                return False

    return True

def solve():
    global grid

    for y in range(9):
        for x in range(9):
            if grid[y][x] == 0:
                for n in range(1, 10):
                    if possible(y, x, n):
                        grid[y][x] = n
                        solve()
                        grid[y][x] = 0 # Backtracking
                return
    print('\nA possible Solution is:\n', np.matrix(grid))
    input("\nMore?")
    # If the grid is open to multiple solution, this input() command will
    # relaunch the solve() function to find other possible solutions.
    # If only 1 solution exist to your grid, then the script stop.

solve()


#!/usr/bin/python
import argparse

import numpy as np
import sklearn.datasets
import sklearn.linear_model
import sklearn.model_selection
from sklearn.metrics import mean_squared_error

def rms(y_true, y_pred):
    return np.sqrt(mean_squared_error(y_true, y_pred))

def get_val_set_rmse(X_train, X_test, y_train, y_test, alpha):
    ridge = sklearn.linear_model.Ridge(alpha=alpha)
    ridge.fit(X_train, y_train)
    y_pred = ridge.predict(X_test)
    rmse = rms(y_test, y_pred)
    return [alpha, rmse]

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--plot", default=False, action="store_true", help="Plot the results"
    )
    parser.add_argument("--seed", default=42, type=int, help="Random seed")
    parser.add_argument("--test_size", default=50, type=int, help="Test size to use")
    args = parser.parse_args()

    # Load Boston housing dataset
    dataset = sklearn.datasets.load_boston()
    X = dataset.data
    y = dataset.target

    # TODO: Split the dataset randomly to train and test using
    # `sklearn.model_selection.train_test_split`, with
    # `test_size=args.test_size` and `random_state=args.seed`.
    X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(
        X, y, test_size=args.test_size, random_state=args.seed
    )
    # TODO: Using sklearn.linear_model.Ridge, fit the train set using
    # L2 regularization, employing lambdas from 0 to 100 with a step size 0.1.
    # For every model, compute the root mean squared error
    # (sklearn.metrics.mean_squared_error may come handy) and print out
    # the lambda producing lowest test error.
    alpha_space = np.linspace(start = 0.0, stop = 100.0, num = 1001)
    results = np.array([get_val_set_rmse(X_train, X_test, y_train, y_test, alpha) for alpha in alpha_space])
    best_alpha_id = np.argmin(results[:,1])
    best_lambda = results[best_alpha_id,0]
    best_rmse = results[best_alpha_id,1]

    with open("linear_regression_l2.out", "w") as output_file:
        print("{:.1f}, {:.2f}".format(best_lambda, best_rmse), file=output_file)

    if args.plot:
        # TODO: This block is not part of ReCodEx submission, so you
        # will get points even without it. However, it is useful to
        # learn to visualize the results.

        # If you collect used lambdas to `lambdas` and their respective
        # results to `rmses`, the following lines will plot the result
        # if you add `--plot` argument.
        import matplotlib.pyplot as plt

        plt.plot(lambdas, rmses)
        plt.show()


import numpy as np
from sklearn.metrics import log_loss, confusion_matrix, accuracy_score

def stable_softmax(X, axis=None):
    exps = np.exp(X - np.max(X, axis=axis).reshape(-1, 1))
    return exps / np.sum(exps, axis=axis).reshape(-1, 1)

def CE_loss(y_true, y_pred, labels=None):
    """Cross entropy loss.

    Parameters
    ----------
    y_true : vector
        Ground truth (correct) labels for n_samples samples
    y_pred : vector
        Predicted probabilities, as returned by a classifier’s
        ``predict_proba`` method.
    labels : vector, optional
        If not provided, labels will be inferred from `y_true`.

    Returns
    -------
    float
        Loss value.
    """
    # TODO: verify advantage of penalizing missing probabilities
    # Add remaining probabilities as unrepresented class
    # if labels is None:
    #     labels = np.unique(y_pred)
    # labels=np.concatenate((labels, [len(labels)]))
    # _y = np.hstack((y_pred, (1 - y_pred.sum(axis=1)).reshape(-1,1)))

    return log_loss(y_true, stable_softmax(y_pred, axis=1), labels=labels)

def CE_grad(y_true, y_pred):
    """Cross entropy loss gradient, w.r.t. y_pred columns.

    Parameters
    ----------
    y_true : vector
        Ground truth (correct) labels for n_samples samples
    y_pred : vector
        Predicted probabilities, as returned by a classifier’s
        ``predict_proba`` method.

    Returns
    -------
    float
        Loss value.
    """

    n = len(y_pred)

    sigma = stable_softmax(y_pred, axis=1)
    sigma[range(n), y_true] -= 1
    return sigma.sum(axis=0) / n

def print_results(target, pred, name=None, output=None):
    """Print confusion matrix and accuracy of predicted labels vs actual
    target.

    Parameters
    ----------
    target : vector
        Actual classes
    pred : vector
        Predicted labels
    name : str, optional
        Which name to print, required if output is not None. By default None.
    output : str, optional
        Output type, if None then results are printed to std.Out. By default
        ``None``
        - `dict` : return the scores in a nested dictionary
        ( `{name : {'confusion_matrix' : ..., 'accuracy' : ...})

    Returns
    -------
    [output]
        If `output` is not ``None``, the results are returned in desired
        structure.
    """
    if output is None:
        if name is None:
            name = "input"
        print(
            '\n' + 30*'#',
            "Confusion matrix on {}:".format(name),
            confusion_matrix(target, pred),
            "Accuracy : " + str(accuracy_score(target, pred)),
            sep='\n'
        )
        return None
    elif output == 'dict':
        if name is None:
            raise ValueError("Cannot output dict if `name` is not given")
        out = {name: {"confusion_matrix":
                      confusion_matrix(target, pred).tolist(),
                      "accuracy": accuracy_score(target, pred).item()
                      }
               }
        return out


import numpy as np
import matplotlib.pyplot as plt

class Regression():
    def __init__(self, x, y, add_constant=True, theta=None):
        self.x, self.y, self.theta = _pretreatment_params(x, y, add_constant, theta)

    def _hypothesis(self, x, theta):
        pass

    def _cost_function(self, theta):
        return _square_cost_function(self._hypothesis, self.y, self.x, theta)

    def gradient_descent(self, learning_rate=0.1, max_iteration=2000, delta_theta_rel=1e-6):
        print('starting gradient descent...')
        last_cost = self._cost_function(self.theta)
        current_iteration = 0
        while current_iteration < max_iteration:
            current_iteration += 1
            current_theta = []
            for i, theta_i in enumerate(self.theta):
                theta_i -= learning_rate * _partial_derivative(self._cost_function, self.theta, i, learning_rate)
                current_theta.append(theta_i)
            last_theta = self.theta
            current_theta = np.array(current_theta)
            self.theta = current_theta

            current_cost = self._cost_function(self.theta)
            yield current_cost

            delta_cost_actual = last_cost - current_cost
            if delta_cost_actual < 0:
                print("warning: on iteration {0} cost function increased".format(current_iteration))
            last_cost = current_cost

            if np.max(np.abs((current_theta - last_theta) / last_theta)) < delta_theta_rel:
                break
        print("complete on iteration {0}".format(current_iteration))
        print("theta: {0}".format(self.theta))

    def predict(self, x):
        x = np.array(x)
        if x.size + 1 == self.theta.size:
            x = np.insert(x, 0, [1])
        return self._hypothesis(x, self.theta)

class LinearRegression(Regression):
    def _hypothesis(self, x, theta):
        return linear_hypothesis(x, theta)

    def normal_equation(self):
        self.theta = np.dot(np.dot(np.linalg.pinv(np.dot(self.x.T, self.x)), self.x.T), self.y)
        return self.theta

class LogisticRegression(Regression):
    def _hypothesis(self, x, theta):
        return logistic_hypothesis(x, theta)

def linear_hypothesis(x, theta):
    return np.dot(x, theta)

def logistic_hypothesis(x, theta):
    return 1 / (1 + np.exp(-np.dot(x, theta)))

def _pretreatment_params(x, y, add_constant=True, theta=None):
    if not isinstance(x, np.ndarray):
        x = np.array(x)
    if x.ndim == 1:
        x = x.reshape(x.size, 1)
    if add_constant:
        x = _add_constant(x)
    if y and y.ndim != 1:
        y = y.reshape(y.size)
    if not theta:
        theta = np.random.randn(x.shape[1])
    return x, y, theta

def _add_constant(x):
    return np.concatenate((np.ones((x.shape[0], 1)), x), axis=1)

def _partial_derivative(cost_function, theta, i, learing_rate):
    theta_pos_delta = theta.copy()
    theta_pos_delta[i] += learing_rate
    theta_neg_delta = theta.copy()
    theta_neg_delta[i] -= learing_rate
    return (cost_function(theta_pos_delta) - cost_function(theta_neg_delta)) / 2 / learing_rate

def _square_cost_function(hypothesis, y, x, theta):
    return np.sum((hypothesis(x, theta) - y) ** 2) / 2 / y.size

if __name__ == '__main__':
    x = np.array([1.1, 2.1, 2.9, 3.9, 5.2])
    y = np.array([3, 5, 7, 9, 11])
    reg = LinearRegression(x, y)
    fig = plt.subplot(111)

    for it in reg.gradient_descent():
        print(it)

    print(reg.normal_equation())
    print(reg.predict(1))


#!/usr/bin/env/python3
import numpy as np
from sklearn.metrics import pairwise as pw
from math import sqrt as sq

'''This script computes sample distance covariance for a set of paired samples. See pg 8 of https://arxiv.org/pdf/1903.01051.pdf'''

def paired_sample_covar(a, b):
    #a,b pairwise distance matrices of equal size
    npoints = len(a[0])
    #Compute means
    a_row_means = np.mean(a, axis=1)
    a_col_means = np.mean(a, axis=0)
    b_row_means = np.mean(b, axis=1)
    b_col_means = np.mean(b, axis=0)
    a_tot_mean = np.mean(a)
    b_tot_mean = np.mean(b)

    #Compure dcov (and double centred matrix entries)
    products = []
    for k in range(npoints):
        for l in range(npoints):
            products.append((a.item((k,l)) - a_row_means.item(k) - a_col_means.item(l) + a_tot_mean)*(b.item((k,l)) - b_row_means.item(k) - b_col_means.item(l) + b_tot_mean))
    dcov = np.mean(np.array(products))
    return(sq(dcov))

def d_cor(a, b):
    #a,b pairwise distance matrices of equal size
    dvar_a =  paired_sample_covar(a,a)
    dvar_b = paired_sample_covar(b,b)
    if dvar_a*dvar_b == 0:
        return(0)
    dcor = (paired_sample_covar(a, b))/sq(dvar_a*dvar_b)
    return(dcor)

if __name__ == "__main__":
    npoints=3
    X = np.random.rand(npoints,2)
    Y = np.random.rand(npoints,2)
    #Pairwise distance matrices
    a = pw.euclidean_distances(X)
    b = pw.euclidean_distances(Y)
    dcov = paired_sample_covar(a,b)
    print(dcov)


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

def draw_plot():

    # Read data from file
    df = pd.read_csv('epa-sea-level.csv')

    # Create scatter plot
    years = df['Year']
    seaLevel = df['CSIRO Adjusted Sea Level']
    fig, ax = plt.subplots(figsize=(16, 12))
    plt.scatter(years, seaLevel, s=50, alpha=0.8)

    # Create first line of best fit
    lineReg1 = linregress(years, seaLevel)
    slope = lineReg1.slope
    intercept = lineReg1.intercept
    lineFunc = lambda x: slope * x + intercept
    years1 = [y for y in range(1880, 2051)]
    line1 = list(map(lineFunc, years1))
    plt.plot(years1,line1, 'b')

    # Create second line of best fit
    df2 = df.loc[df['Year'] >= 2000]
    yearsRecent = df2['Year']
    seaLevelRecent = df2['CSIRO Adjusted Sea Level']
    lineReg2 = linregress(yearsRecent, seaLevelRecent)
    slope = lineReg2.slope
    intercept = lineReg2.intercept
    years2 = [y for y in range(2000, 2051)]
    line2 = list(map(lineFunc, years2))
    plt.plot(years2, line2, 'r')

    # Add labels and title
    ax.set_xlabel('Year')
    ax.set_ylabel('Sea Level (inches)')
    ax.set_title('Rise in Sea Level')

    # Save plot and return data for testing (DO NOT MODIFY)
    plt.savefig('sea_level_plot.png')
    return plt.gca()


import math
from klampt import vectorops
from klampt import so3
#import numpy as np

def solve_2R_inverse_kinematics(x,y,L1=1,L2=1):
    """For a 2R arm centered at the origin, solves for the joint angles
    (q1,q2) that places the end effector at (x,y).

    The result is a list of up to 2 solutions, e.g. [(q1,q2),(q1',q2')].
    """
    D = vectorops.norm((x,y))
    thetades = math.atan2(y,x)
    if D == 0:
        raise ValueError("(x,y) at origin, infinite # of solutions")
    c2 = (D**2-L1**2-L2**2)/(2.0*L1*L2)
    q2s = []
    if c2 < -1:
        print "solve_2R_inverse_kinematics: (x,y) inside inner circle"
        return []
    elif c2 > 1:
        print "solve_2R_inverse_kinematics: (x,y) out of reach"
        return []
    else:
        if c2 == 1:
            q2s = [math.acos(c2)]
        else:
            q2s = [math.acos(c2),-math.acos(c2)]
    res = []
    for q2 in q2s:
        thetaactual = math.atan2(math.sin(q2),L1+L2*math.cos(q2))
        q1 = thetades - thetaactual
        res.append((q1,q2))
    return res

def solve_3R_forward_kinematics(q1,q2,q3,L1=1,L2=1,L3=1):
    """Returns a list of (x,y,theta) triples for each link
    for a planar, 3R manipulator with link lengths L1, L2, L3.
    It also returns the end effector transform."""
    T1 = (0,0,q1)
    dx1 = (L1*math.cos(T1[2]),L1*math.sin(T1[2]))
    T2 = vectorops.add((T1[0],T1[1]),dx1)+[T1[2]+q2]
    dx2 = (L2*math.cos(T2[2]),L2*math.sin(T2[2]))
    T3 = vectorops.add((T2[0],T2[1]),dx2)+[T2[2]+q3]
    dx3 = (L3*math.cos(T3[2]),L2*math.sin(T3[2]))
    T4 = vectorops.add((T3[0],T3[1]),dx3)+[T3[2]]
    return [T1,T2,T3,T4]

def solve_3R_inverse_kinematics(x,y,theta,L1=1,L2=1,L3=1):
    """IMPLEMENT ME: for a planar, 3R manipulator with link lengths L1, L2, L3,
    solve for the joint angles (q1,q2,q3) such that the end effector
    is placed at x,y and is oriented along the angle theta.

    The current implementation is incorrect, and only tries to reach x,y
    with the second and third joint angle, using 2R manipulator routine
    presented in class.  Your implementation should correctly place the end
    effector to be oriented at the angle theta (which will require using all
    three joint angles).

    In general there will be up to two solutions.  The result is a list of
    solutions.  Your implementation should correctly return 0 solutions
    if the request is infeasible.
    """
    q1,q2,q3 = 0,0,0
    (x1,y1) = (L1*math.cos(q1),L1*math.sin(q1))
    q23s = solve_2R_inverse_kinematics(x-x1,y-y1,L2,L3)
    res = []
    for q2,q3 in q23s:
        res.append((q1,q2,q3))
    return res

def run_ex1():
    print solve_3R_forward_kinematics(0,0,0)

    #test 1
    xdes = (3,0,0)
    qs = solve_3R_inverse_kinematics(*xdes)
    print "xdes =",xdes,
    if len(qs)==0:
        print "failed"
    else:
        print len(qs),"solutions:"
    for q in qs:
        print "    q =",q,"fk =",solve_3R_forward_kinematics(*q)[3]

    #note the orientation error
    xdes = (2.0,0.5,0)
    qs = solve_3R_inverse_kinematics(*xdes)
    print "xdes =",xdes,
    if len(qs)==0:
        print "failed"
    else:
        print len(qs),"solutions:"
    for q in qs:
        print "    q =",q,"fk =",solve_3R_forward_kinematics(*q)[3]

    #note the orientation error
    xdes = (2.0,0.0,math.pi*0.5)
    qs = solve_3R_inverse_kinematics(*xdes)
    print "xdes =",xdes,
    if len(qs)==0:
        print "failed"
    else:
        print len(qs),"solutions:"
    for q in qs:
        print "    q =",q,"fk =",solve_3R_forward_kinematics(*q)[3]

    #this one is feasible, but the current implementation fails
    xdes = (-3.0,0.0,0)
    qs = solve_3R_inverse_kinematics(*xdes)
    print "xdes =",xdes,
    if len(qs)==0:
        print "failed"
    else:
        print len(qs),"solutions:"
    for q in qs:
        print "    q =",q,"fk =",solve_3R_forward_kinematics(*q)[3]

    #this one is infeasible
    xdes = (-2.0,0.0,-math.pi*0.5)
    qs = solve_3R_inverse_kinematics(*xdes)
    print "xdes =",xdes,
    if len(qs)==0:
        print "failed"
    else:
        print len(qs),"solutions:"
    for q in qs:
        print "    q =",q,"fk =",solve_3R_forward_kinematics(*q)[3]

if __name__ == "__main__":
    run_ex1()


import numpy as np

def eigenvalues_2d_symmetric(a, b, d):
    """This function returns the eigenvalues of a 2x2 symmetric matrix given by:
    | a  b |
    | b  d |

    Note that this a special case of a 2x2 symmetric matrix where every element of the matrix is passed as an image.
    This allows the evaluation of eigenvalues to be vectorized over the entire image. This is much more efficient
    than calling the numpy functions for computing the eigenvalues for each pixel of the image.

    Parameters
    ----------
    a, b, d: array_like
        2D images containing the values of the matrix elements a b and d.
    """
    t = a + d
    bsq4 = 4 * b ** 2
    amdsq = (a - d) ** 2
    ht = 0.5 * t
    half_sqrt_discriminant = 0.5 * np.sqrt(bsq4 + amdsq)
    eig1 = ht + half_sqrt_discriminant
    eig2 = ht - half_sqrt_discriminant

    return np.stack((eig1, eig2), axis=len(eig1.shape))

def eigenvector_2d_symmetric(a, b, d, eig, eps=1e-8):
    """Returns normalized eigenvector corresponding to the provided eigenvalue.

    Note that this a special case of a 2x2 symmetric matrix where every element of the matrix is passed as an image.
    This allows the evaluation of eigenvalues to be vectorized over the entire image. This is much more efficient
    than calling the numpy function for computing the eigenvectors for each pixel of the image.

    This function solves:
    | a-lambda  b        |
    | b         d-lambda | [x, y] = 0

    Which means that:
      bx = (lambda - d) y
    or
      y = (lambda - a)/b x

    This solution is invalid for b == 0. Here we expect orthogonal vectors [1 0] and [0 1].
        ax + by = l x
        bx + dy = l y

    so x = 1 iff b = 0 and l = a
    and y = 1 iff b = 0 and l = d
    """
    ex = np.zeros(a.shape)
    ey = np.zeros(a.shape)
    ex[np.abs(a - eig) < eps] = 1
    ey[np.abs(d - eig) < eps] = 1

    mask = np.abs(b) > eps
    tx = b[mask]
    ty = eig[mask] - a[mask]

    length = np.sqrt(tx * tx + ty * ty)
    tx = tx / length
    ty = ty / length

    ex[mask] = tx
    ey[mask] = ty

    return ex, ey


import pandas as pd
import numpy as np
from sklearn.decomposition import PCA
from sklearn import preprocessing
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

#Scale the data to be appropriate for PCA
def scale_data(angle_data):
    scaled = preprocessing.scale(angle_data)
    return scaled

#Perform PCA on the data
def pca(angles, name, dir_name, graph_type):
    #Get all the PCA components from the data
    pca = PCA()
    pc_angles = angles.drop(angles.index[0.0])
    data = scale_data(pc_angles)
    pca.fit(data)
    pca_data = pca.transform(data)
    per_var = np.round(pca.explained_variance_ratio_ * 100, decimals = 1)
    labels = ['PC' + str(x) for x in range(1, len(per_var) + 1)]

    #Create a Scree Plot of the components
    plt.close()
    plt.bar(x = range(1, len(per_var) + 1), height = per_var, tick_label = labels)
    plt.ylabel('Percentage of Explained Variance')
    plt.xlabel('Principal Component')
    plt.title('Scree Plot')
    plt.savefig(dir_name + 'Scree Plot - ' + name + '.png')
    plt.show()
    plt.close()

    pca_df = pd.DataFrame(pca_data, columns = labels)

    #Generate the PCA Graph based on PC1 and PC2
    if graph_type == '2d':
        plt.scatter(pca_df.PC1, pca_df.PC2, s = 0.01)
        plt.title('Torsion Angle PCA Graph')
        plt.xlabel('PC1 - {0}%'.format(per_var[0]))
        plt.ylabel('PC2 - {0}%'.format(per_var[1]))
        plt.savefig(dir_name + '2D PCA - ' + name + '.png')
        plt.close()

    #Generate the PCA Graph Based on PC1, PC2, and PC3
    elif graph_type == '3d':
        ax = plt.axes(projection = '3d')
        ax.scatter3D(pca_df.PC1, pca_df.PC2, pca_df.PC3, s = 0.01)
        plt.xlabel('PC1 - {0}%'.format(per_var[0]))
        plt.ylabel('PC2 - {0}%'.format(per_var[1]))
        plt.ylabel('PC3 - {0}%'.format(per_var[2]))
        plt.savefig(dir_name + '3D PCA - ' + name + '.png')
        plt.close()

    else:
        raise Exception('Graph Type must be either "2d" or "3d".')

    return pca_df, pca

def load_score(pca, PC, n):
    # loading scores
    if PC.lower() == "all":
        all_scores = map(lambda x: pd.Series(pca.components_[x]), range(len(pca.components_)))
        all_sorted_scores = list(map(lambda x: x.abs().sort_values(ascending = False), all_scores))
        all_top_n = list(map(lambda x: x[0:n].index.values, all_sorted_scores))
        all_top_n_scores = list(map(lambda x: x[0:n].values, all_sorted_scores))
        return all_top_n, all_top_n_scores

    else:
        PC = int(PC)
        loading_scores = pd.Series(pca.components_[PC])

        # sort loading scores by magnitude
        sorted_loading_scores = loading_scores.abs().sort_values(ascending=False)

        # get names
        top_n = sorted_loading_scores[0:n].index.values
        top_n_scores = sorted_loading_scores[0:n].values
        return top_n, top_n_scores


import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns

sns.set()

raw_data = pd.read_csv('Bank-data.csv')

data = raw_data.copy()
data = data.drop(['Unnamed: 0'], axis=1)
data['y'] = data['y'].map({'yes': 1, 'no': 0})
data.describe()

# ## Model: Simple Classification
y = data['y']
x1 = data['duration']

x = sm.add_constant(x1)
reg_log = sm.Logit(y, x)
results_log = reg_log.fit()
results_log.summary()

plt.scatter(x1, y, color='C0')
plt.xlabel('Duration', fontsize=20)
plt.ylabel('Subscription', fontsize=20)
plt.show()

# ## Expanded model: Multivariate Classification
estimators = ['interest_rate', 'credit', 'march', 'previous', 'duration']
X1_all = data[estimators]
y = data['y']

X_all = sm.add_constant(X1_all)
reg_logit = sm.Logit(y, X_all)
results_logit = reg_logit.fit()
results_logit.summary2()

# ### Confusion Matrix

def confusion_matrix(data_array, actual_values, model):
    pred_values = model.predict(data_array)
    bins = np.array([0, 0.5, 1])
    cm = np.histogram2d(actual_values, pred_values, bins=bins)[0]
    accuracy = (cm[0, 0] + cm[1, 1]) / cm.sum()
    return cm, accuracy

confusion_matrix(X_all, y, results_logit)

# ## Testing the accuracy of the model
raw_data2 = pd.read_csv('Bank-data-testing.csv')
data_test = raw_data2.copy()
data_test = data_test.drop(['Unnamed: 0'], axis=1)

data_test['y'] = data_test['y'].map({'yes': 1, 'no': 0})

y_test = data_test['y']
X1_test = data_test[estimators]
X_test = sm.add_constant(X1_test)

confusion_matrix(X_test, y_test, results_logit)
confusion_matrix(X_all, y, results_logit)


import numpy as np
def dcg_at_k(r, k):
    r = np.asfarray(r)[:k]
    return np.sum(r / np.log2(np.arange(2, r.size + 2)))

def ndcg_at_k(r, k):
    dcg_max = dcg_at_k(sorted(r, reverse=True), k)
    if not dcg_max:
        return 0.
    return dcg_at_k(r, k) / dcg_max


from src.sdia_python.lab2.window import BallWindow, BoxWindow, UnitBoxWindow
import numpy as np

def calcul_pi(n):
    """compute a simple estimation of pi with the Monte Carlo method
    generates a square and a quadrant inscribed within it
    random points are generated uniformly inside the square
    the proportion of point which are in the circle is an estimation of pi/4

    Args:
        n (int): numbers of random points to be generated

    Returns:
        [float]: estimation of pi
    """
    unitBox = UnitBoxWindow(np.array([0.5, 0.5]))
    unitBall = BallWindow(np.array([0, 0]), 1)
    pointsAlea = unitBox.rand(n)
    piEstim = 0
    for point in pointsAlea:
        if point in unitBall:
            piEstim += 1
    return 4 * piEstim / n


import numpy as np

def circumference_circle(radius: float):
    """Calculate for a given radius the circumference of a circle

    :param radius: radius of circle
    :type radius: float in cm
    """
    if radius < 0.:
        raise ValueError("The radius must be >=0")
    circumference = 2 * np.pi * radius
    print("the circumference is C = %fcm" % circumference)
    return circumference

def euclidean_distance(list_ref, list_comp, vectors):
    """Calculates the Euclidean distance (L2 norm) between pairs of vectors.

    Args:
        list_ref (integer list): A list with the indices of the reference vectors.
        list_comp (integer list): A list with the indices of the vectors to\
        compare to.
        data (numpy array): The data object.

    Returns:
        numpy array: The Euclidean distance (L2 norm) for comparison vs. reference\
        vectors."""
    distances = np.zeros(len(list_ref))
    for i in range(len(list_ref)):
        distances[i] = np.linalg.norm(vectors[list_comp[i]] - vectors[list_ref[i]])
    return distances


import cvxpy as cp
import fire
import numpy as np

def rep(u1, u2):
    x = cp.Variable(shape=(2,))
    P = np.array([
        [1., -0.5],
        [-0.5, 2],
    ])

    x1 = x[0]
    x2 = x[1]

    objective = cp.Minimize(
        cp.quad_form(x, P) - x1
    )
    constraints = [
        x1 + 2 * x2 <= u1,
        x1 - 4 * x2 <= u2,
        5 * x1 + 76 * x2 <= 1,
    ]
    prob = cp.Problem(objective, constraints)
    result = prob.solve()
    return result

def main(
    u1=-2, u2=-3,
):
    grad1 = 2.747741246681633
    grad2 = 2.885233448461934
    base = 8.222222222222221
    for d1 in (0, -0.1, 0.1,):
        for d2 in (0, -0.1, 0.1,):
            result = rep(
                u1=u1 + d1,
                u2=u2 + d2,
            )
            print(d1, d2,)
            print('actual', result)
            pred = base - grad1 * d1 - grad2 * d2
            print('pred', pred)
            import pdb; pdb.set_trace()

if __name__ == "__main__":
    fire.Fire(main)


import math
import numpy as np
from numba import jit, njit

@njit
def SinalBasico(Tempo, Frequencia, Amplitude):
    return Amplitude*np.sin(Frequencia*2*np.pi*Tempo)

@jit
def EnergiaWale(arrayWavelet):
    return np.trapz((arrayWavelet)**2)

@jit
def WaleNormaliza(funcWavelet,tempo,dilat,posic):
    wavelet = funcWavelet(tempo,dilat,posic)
    Energia = EnergiaWale(wavelet)
    return 1/(Energia**(1/2))*(wavelet)

@njit
def WaleNotNormaliza(funcWavelet,tempo,dilat,posic):
    wavelet = funcWavelet(tempo,dilat,posic)
    return wavelet

@jit
def HermitianHat (tempo,dilat,posic ):
    """Retornar um array das posições de uma OndaLet(Chápeu de Hermitian) em relação ao tempo

    Argumentos:
        tempo: um Numpy Array com os pontos do sinal que serão exibido
        dilat: O valor de dilatação da Wavelet
        posic: O valor da posição em relação ao tempo da Wavelet

    Retorno:
        Retorna um Array 2D com os valores de Amplitude em relação ao tempo."""

    t = ((tempo-posic)/dilat)
    return 2/(5**(1/2))*math.pi**-(1/4)*t*(1+t)*math.e**((-1/2)*t**2)

@njit
def MexicanHat (tempo,dilat,posic):
    """Retornar um array das posições de uma OndaLet(Chápeu de mexicano) em relação ao tempo

    Argumentos:
        tempo: um Numpy Array com os pontos do sinal que serão exibido
        dilat: O valor de dilatação da Wavelet
        posic: O valor da posição em relação ao tempo da Wavelet

    Retorno:
        Retorna um Array 2D com os valores de Amplitude em relação ao tempo."""
    t = ((tempo-posic)/dilat)
    return (1-t**2)*math.e**((t**2/2)*-1)

@njit
def MeyerWale (tempo,dilat,posic ):
    """Retornar um array das posições de uma OndaLet(Meyer) em relação ao tempo

    Argumentos:
        tempo: um Numpy Array com os pontos do sinal que serão exibido
        dilat: O valor de dilatação da Wavelet
        posic: O valor da posição em relação ao tempo da Wavelet

    Retorno:
        Retorna um Array 2D com os valores de Amplitude em relação ao tempo.

        Formando a imagem correta(provavelmente), mas com problemas no deslocamento do eixo do tempo, indo da direita pra esquerda"""

    t = ((tempo-posic)/dilat)
    outputArray = np.array([])
    for x in t:
        if x == 0:
            output = 2/3 + 4/(3*math.pi)
        else:
            output = ((np.sin((2*math.pi)/(3)*x)+(4/3)*x*np.cos(((4*math.pi)/3)*x))/(math.pi*x-(16*math.pi/9)*(x**3)))
            output = output
        outputArray = np.append(output, outputArray)
    return outputArray

@njit
def HermitianWale1(tempo,dilat,posic):

    t = ((tempo-posic)/dilat)
    return (2**(1/2))*math.pi**(-1/4)*t*math.e**((-t**2)/2)

@njit
def MorletWavelet(tempo,dilat,posic):

    t = ((tempo-posic)/dilat)
    return math.e**((-t**2)/2)*math.e**(1j*6*t)


'''Author: Bryce Trabucco, Copyright 2019'''

import numpy as np
from numpy import random, dot, array

inputs = np.array([
    [0,0],
    [0,1],
    [1,0],
    [1,1]])

labels = np.array([
    [0],
    [1],
    [1],
    [0]])

# This is the activation function
def sigmoid(a):
    return 1 / (1 + np.exp(-a))

# This is the derivative of the activation function.
def dsigmoid_dx(a):
    return a * (1 - a)

class Layer(object):

    # This function initializes all of the values that will be used repeatedly in the class.
    def __init__(self, inputs, outputs, learning_rate = 0.1):

        self.weights = np.random.uniform(size = (outputs, inputs))
        self.bias = np.zeros(outputs)
        self.learning_rate = learning_rate

    # The forward function takes the weighted sum of the weights and inputs at each neuron. Then,
    # the weighted sum is passed through the Sigmoid activation function.
    def forward(self, inputs):
        self.last_inputs = inputs
        w_sum_bias = (np.dot(self.weights, inputs) + self.bias)
        activation = sigmoid(w_sum_bias)
        self.last_activation = activation
        return activation

    # The backward function takes the derivative of the output from the forward function. Then, it
    # updates the weights and biases.
    def backward(self, grad_out):
        grad = grad_out * dsigmoid_dx(self.last_activation)
        self.bias = self.bias - self.learning_rate * grad
        self.weights = self.weights - self.learning_rate * np.array(np.matrix(grad).T @ np.matrix(self.last_inputs))
        grad = np.matrix(grad) @ self.weights
        grad = np.array(grad)[0, :]
        return grad

# This is setting up the two layers of neurons.
first_neuron_layer = Layer(2, 2, learning_rate = 0.1)
second_neuron_layer = Layer(2, 1, learning_rate = 0.1)

# This loop is the training loop
for i in range(40000):

    k = random.randint(len(inputs))
    x = inputs[k]
    desired_response = labels[k]

    # This block is running through forward and backpropagation once
    hidden_layer = first_neuron_layer.forward(x)
    output_layer = second_neuron_layer.forward(hidden_layer)
    loss = (desired_response - output_layer) ** 2
    dloss_doutput_layer = - 2 * (desired_response - output_layer)
    back_output = second_neuron_layer.backward(dloss_doutput_layer)
    back_hidden = first_neuron_layer.backward(back_output)

# This is printing off the results
print(" Network output ")
for i in range(len(inputs)):
    x = inputs[i]
    response = labels[i]
    final_hidden = first_neuron_layer.forward(x)
    final_output = second_neuron_layer.forward(final_hidden)
    print("{} -> {} = {}".format(x, response, final_output))


# call scipy package
import numpy as np
from scipy import stats

# input data
x = [77, 50, 99, 60, 90, 82, 93, 75, 86, 99, 55, 79]

# numpy.std method
get_sample_std = np.std(x, ddof=1)
get_population_mean = np.sum(x) / (len(x))

# calculate coefficient of variation
get_cv = (get_sample_std * 100) / get_population_mean

# output
print("Sample of mean of x : ", get_population_mean)
print("Coeefficient of variation: {0}".format(get_cv))


import numpy as np

def quaternion(v):
	# Take 3d input and turn into quaternion.
	x,y,z = v
	return np.array(([0,x,y,z]))

def rotation(theta,axis=None):
	# Rotation quaternion of angle theta by axis x,y,z.
	# Axis input should be of type [1,0,0].
	if axis is None:
		axis = np.array(([1,1,1]))

	theta = np.deg2rad(theta)
	i,j,k = np.sin(theta/2)*axis

	return np.array([np.cos(theta/2),i,j,k])

def magnitude(q):
	# Calculate magnitude of quaternion.
	return np.sqrt(q[0]**2 + q[1]**2 + q[2]**2 + q[3]**2)

def normalise(q):
	# Normalise a quaternion.
	q /= magnitude(q)
	return q

def multiply(a,b):
	# Product of two quarternions, b operating on a.
	a0,a1,a2,a3 = a
	b0,b1,b2,b3 = b

	q0 = b0*a0 - b1*a1 - b2*a2 - b3*a3
	q1 = b0*a1 + b1*a0 - b2*a3 + b3*a2
	q2 = b0*a2 + b1*a3 + b2*a0 - b3*a1
	q3 = b0*a3 - b1*a2 + b2*a1 + b3*a0

	q = np.array(([q0,q1,q2,q3]))

	return q

def product(q):
	''' q as list'''
	qout = multiply(q[0],q[1])
	for i in range(2,len(q)):
		qout = multiply(qout,q[i])

	return qout

def intrinsicRotation(q):
	''' q as list'''
	return product(q)

def globalRotation(q):
	''' q as list'''
	e = len(q)-1
	qout = multiply(q[e],q[e-1])
	for i in range(e-2,-1,-1):
		qout = multiply(qout,q[i])

	return qout

def inverse(a):
	# Inverse of quaternion a
	a0,a1,a2,a3 = a
	q = (np.array(([a0,-a1,-a2,-a3])) / (a0**2 + a1**2 + a2**2 + a3**2))

	return q

def euler(q):
	R = np.array([[(q[0]**2+q[1]**2-q[2]**2-q[3]**2), 2*(q[1]*q[2]-q[0]*q[3]), 2*(q[1]*q[3]+q[0]*q[2])],
		[2*(q[2]*q[1]+q[0]*q[3]), (q[0]**2-q[1]**2+q[2]**2-q[3]**2), 2*(q[2]*q[3]-q[0]*q[1])],
		[2*(q[3]*q[1]-q[0]*q[2]), 2*(q[3]*q[2]+q[0]*q[1]), (q[0]**2-q[1]**2-q[2]**2+q[3]**2)]])

	return R

def rotate(a,r):
	# Rotate quaternion a, by quaternion r.
	ri = inverse(r)
	b = product(product(r,a),ri)

	return b


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

# Initial setup
xx0 = np.array([.25,1.5])
mu_ =[-.5,0,.07,1]
xmin,xmax = -2,2
ymin,ymax = -2,2
lw = 1.5
plt.close()
fig,([ax0,ax1],[ax2,ax3]) = plt.subplots(2,2,
                                                            figsize=(12,8),
                                                            sharex=True,
                                                            sharey=True)
ax0.set_facecolor(plt.cm.gray(.95))
ax1.set_facecolor(plt.cm.gray(.95))
ax2.set_facecolor(plt.cm.gray(.95))
ax3.set_facecolor(plt.cm.gray(.95))
#ax.axis('equal')

#Vector field
x1,y1 = np.linspace(xmin,xmax,200),np.linspace(ymin,ymax,200)
X,Y = np.meshgrid(x1,y1 )
#Plot1
#====================================
mu=mu_[0]
U = mu*X - Y +X*Y**2
V = X + mu*Y + Y**3
start = [[0.3,0],[1.4,-.35]]

#Plotting
strm = ax0.streamplot( X,Y,U, V,linewidth=.2)
try:
    strmS = ax0.streamplot(x1,y1, U, V, start_points=start, color="crimson", linewidth=.5)
except: # IndexError:
    print('Unable to plot initial value trajectories')
fig.suptitle('Hopf Bifurcation /n Strogatz 8.2.1, p.256', size=16)
ax0.set_title( 'a) Stable Spiral', size=12)
ax0.text(xmin+.25,ymax-.25, r'$\mu = {0}$'.format(mu),size=14)
ax0.plot(y1/(mu+y1**2),x1, 'k-.',lw=lw, label=r'x-nullcline: $x = \frac{y}{(\mu+y^2)}$')
ax0.plot(-mu*y1+y1**3,x1, 'k:', lw=lw, label=r'y-nullcline: $x =  -\mu y + y^3}$')
ax0.set_xlim([xmin,xmax])
ax0.set_ylim([ymin,ymax])
ax0.set_xlabel(r"$ x$",size=14)
ax0.set_ylabel(r"$ y$",size=14)
plt.grid(True)

#Plot 2
#===================================
mu= mu_[1]
U = mu*X - Y +X*Y**2
V = X + mu*Y + Y**3
start = [[0.3,0],[.6,.5]]

#Plotting
strm = ax1.streamplot( X,Y,U, V,linewidth=.2)
try:
    strmS = ax1.streamplot(x1,y1, U, V, start_points=start, color="crimson", linewidth=.5)
except: # IndexError:
    print('Unable to plot initial value trajectories')
ax1.set_title( 'b) Critical Point', size=12)
ax1.text(xmin+.25,ymax-.25, r'$\mu = {0}$'.format(mu),size=14)
ax1.plot(y1/(mu+y1**2),x1, 'k-.',lw=lw, label=r'x-nullcline: $x = \frac{y}{(\mu+y^2)}$')
ax1.plot(-mu*y1+y1**3,x1, 'k:', lw=lw, label=r'y-nullcline: $x =  -\mu y + y^3}$')
ax1.set_xlim([xmin,xmax])
ax1.set_ylim([ymin,ymax])
ax1.set_xlabel(r"$ x$",size=14)
ax1.set_ylabel(r"$ y$",size=14)
plt.grid(True)
#Plot 3
#===================================
mu= mu_[2]
U = mu*X - Y +X*Y**2
V = X + mu*Y + Y**3
start = [[0.3,0],[.6,.5]]

#Plotting
strm = ax2.streamplot( X,Y,U, V,linewidth=.2)
try:
    strmS = ax2.streamplot(x1,y1, U, V, start_points=start, color="crimson", linewidth=.5)
except: # IndexError:
    print('Unable to plot initial value trajectories')
ax2.set_title( 'c) Unstable Spiral', size=12)
ax2.text(xmin+.25,ymax-.25, r'$\mu = {0}$'.format(mu),size=14)
ax2.plot(y1/(mu+y1**2),x1, 'k-.',lw=lw, label=r'x-nullcline: $x = \frac{y}{(\mu+y^2)}$')
ax2.plot(-mu*y1+y1**3,x1, 'k:', lw=lw, label=r'y-nullcline: $x =  -\mu y + y^3}$')
ax2.set_xlim([xmin,xmax])
ax2.set_ylim([ymin,ymax])
ax2.set_xlabel(r"$ x$",size=14)
ax2.set_ylabel(r"$ y$",size=14)
plt.grid(True)
#Plot 4
#===================================
mu= mu_[3]
U = mu*X - Y +X*Y**2
V = X + mu*Y + Y**3
start = [[0.3,0],[.6,.5]]

#Plotting
strm = ax3.streamplot( X,Y,U, V,linewidth=.2)
try:
    strmS = ax3.streamplot(x1,y1, U, V, start_points=start, color="crimson", linewidth=.5)
except: # IndexError:
    print('Unable to plot initial value trajectories')
ax3.set_title( 'd) Unstable Spiral', size=12)
ax3.text(xmin+.25,ymax-.25, r'$\mu = {0}$'.format(mu),size=14)
ax3.plot(y1/(mu+y1**2),x1, 'k-.',lw=lw, label=r'x-nullcline: $x = \frac{y}{(\mu+y^2)}$')
ax3.plot(-mu*y1+y1**3,x1, 'k:', lw=lw, label=r'y-nullcline: $x =  -\mu y + y^3}$')
ax3.set_xlim([xmin,xmax])
ax3.set_ylim([ymin,ymax])
ax3.set_xlabel(r"$ x$",size=14)
ax3.set_ylabel(r"$ y$",size=14)
ax3.legend()
plt.grid(True)
plt.show()


import cv2
import numpy as np
from matplotlib import pyplot as plt
from pyplot_template import plt_arch

img = cv2.imread('../res/lenna.bmp', cv2.IMREAD_GRAYSCALE)

""" 고속 푸리에 변환(FFT) """
fft = np.fft.fft2(img)  # 고속 푸리에 변환을 한다.
fft_shift = np.fft.fftshift(fft)  # 셔플링을 한다.
# 스펙트럼 영상을 구한다. D(u, v) = c x log(1 + |F(u, v)| )
spectrum = 20 * np.log(1 + np.abs(fft_shift))

""" 역 고속 푸리에 변환(IFFT) """
hpf_ishift = np.fft.ifftshift(fft_shift)  # 셔플링 되었던 것을 역셔플링한다.
ifft = np.fft.ifft2(hpf_ishift)  # 역 고속 푸리에 변환을 한다.
ifft = np.abs(ifft)  # 절대값 적용, 복소수를 실수로 변환

""" 저주파 통과 필터링(LPF) """
rows, cols = img.shape
center_row, center_col = rows // 2, cols // 2  # 이미지의 중심 좌표
size = 30  # 통과시킬 저주파 영역의 크기 (n x n)
# 가운데 = 1, 외곽 = 0
lpf_mask = np.zeros((rows, cols), np.uint8)
cv2.circle(lpf_mask, (center_row, center_col), size, (255, 255, 255), cv2.FILLED)
lpf = fft_shift * lpf_mask  # 마스크를 적용한다. (요소별 곱셈: n x 1 = n, n x 0 = 0)
lpf_spectrum = 20 * np.log(1 + np.abs(lpf))

""" 고주파 통과 필터링(HPF) """
rows, cols = img.shape
center_row, center_col = rows // 2, cols // 2  # 이미지의 중심 좌표
size = 30  # 제거시킬 저주파 영역의 크기 (n x n)
# 가운데 = 0, 외곽 = 1
hpf_mask = np.ones((rows, cols), np.uint8)
cv2.circle(hpf_mask, (center_row, center_col), size, (0, 0, 0), cv2.FILLED)
hpf = fft_shift * hpf_mask  # 마스크를 적용한다. (요소별 곱셈: n x 1 = n, n x 0 = 0)
hpf_spectrum = 20 * np.log(1 + np.abs(hpf))

""" LPF가 적용된 역 고속 푸리에 변환(HPF with IFFT) """
lpf_ishift = np.fft.ifftshift(lpf)  # 셔플링 되었던 것을 역셔플링한다.
lpf_ifft = np.fft.ifft2(lpf_ishift)  # 역 고속 푸리에 변환을 한다.
lpf_ifft = np.abs(lpf_ifft)  # 절대값 적용, 복소수를 실수로 변환

""" HPF가 적용된 역 고속 푸리에 변환(HPF with IFFT) """
hpf_ishift = np.fft.ifftshift(hpf)  # 셔플링 되었던 것을 역셔플링한다.
hpf_ifft = np.fft.ifft2(hpf_ishift)  # 역 고속 푸리에 변환을 한다.
hpf_ifft = np.abs(hpf_ifft)  # 절대값 적용, 복소수를 실수로 변환

# 결과물을 출력한다.
plt_arch(331, 'Input Image', img)
plt_arch(332, 'FFT', spectrum)
plt_arch(333, 'IFFT', ifft)
plt_arch(334, 'IFFT(LPF apply)', lpf_ifft)
plt_arch(335, 'FFT(LPF apply)', lpf_spectrum)
plt_arch(336, 'LPF Mask', lpf_mask)
plt_arch(337, 'IFFT(HPF apply)', hpf_ifft)
plt_arch(338, 'FFT(HPF apply)', hpf_spectrum)
plt_arch(339, 'HPF Mask', hpf_mask)
plt.show()


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

def unimodal_func(x):
    return math.cos(x) * math.tanh(x)

def multymodal_func(x):
    return unimodal_func(x) * math.sin(5 * x)

x_ = np.linspace(-2, 0, 100)
y1 = [unimodal_func(i) for i in x_]
y2 = [multymodal_func(i) for i in x_]

def show_graphic(name, x=None, y=None):
    fig = plt.figure(figsize=(7, 7))
    plt.plot(x, y)
    plt.title(name, fontsize=15)  # заголовок
    plt.xlabel("x", fontsize=14)  # ось абсцисс
    plt.ylabel("y", fontsize=14)  # ось ординат
    plt.grid(True)  # включение отображение сетки
    plt.show()
    fig.savefig(name)

show_graphic("Унимодальная функция", x_, y1)
show_graphic("Мультимодальная функция", x_, y2)

def is_transition(delta, t_i, iteration):
    if delta <= 0:
        iteration.append(1.)
        iteration.append(True)
        return True
    else:
        value = random.uniform(0, 1)
        p = math.exp(-delta / t_i)
        iteration.append(p)
        iteration.append(value <= p)
        return value <= p

def print_data(dataset):
    print(' N      T      x    f(x)      P     Transition')
    for i in dataset:
        print(f'{i[0]}  {i[1]:.3f}   {i[2]:.3f}   {i[3]:.3f}  {i[4]:.3f} {i[5]}')

def annealing(f, t_max, t_min, begin, end):
    t_cur = t_max
    all_iters = []
    counter = 1
    x = random.uniform(begin, end)
    while t_cur > t_min:
        one_iter = [counter, t_cur, x, f(x)]
        new_x = random.uniform(begin, end)
        delta = f(new_x) - f(x)
        if is_transition(delta, t_cur, one_iter):
            x = new_x
        counter += 1
        t_cur *= 0.95
        all_iters.append(one_iter)
    print(f'Result: x_min = {x:.3f} F_min = {f(x):.3f}')
    return all_iters

unimodal_results = annealing(unimodal_func, 10000, 0.01, -2, 0)
print_data(unimodal_results)
print('_________________________________________')
multymodal_results = annealing(multymodal_func, 10000, 0.01, -2, 0)
print_data(multymodal_results)


import numpy as np

def f_ackley(x, a, b, c):
    """
    Define the benchmark Ackley function.

    :param numpy.ndarray x:
        The function's argument array.

    :param float a:
        Function's constant.

    :param float b:
        Function's constant.

    :param float c:
        Function's constant.

    :return:
        The evaluated function at the given input array.
    :rtype: float
    """
    d = len(x)
    f = - a * np.exp(-b * np.sqrt((1.0 / d) * np.sum(x * x))) \
        - np.exp((1.0 / d) * np.sum(np.cos(c * x))) + a + np.exp(1)
    return f

def f_rosenbrock(x):
    """
    Define the benchmark Rosenbrock function.

    :param numpy.ndarray x:
        The function's argument array.

    :return:
        The evaluated function at the given input array.
    :rtype: float
    """
    dim = len(x)
    f = 0.0
    for i in range(dim-1):
        left_term = 100. * (x[i + 1] - x[i] * x[i]) * (x[i + 1] - x[i] * x[i])
        right_term = (1. - x[i]) * (1. - x[i])
        f += left_term + right_term
    return f


import math
import numpy as np

#
# line segment intersection using vectors
# see Computer Graphics by F.S. Hill
#
def segPerp(a) :
    b = np.empty_like(a)
    b[0] = -a[1]
    b[1] = a[0]
    return b

# line segment a given by endpoints a1, a2
# line segment b given by endpoints b1, b2
# return
def seg_intersect(a1,a2, b1,b2):
    da = a2-a1
    db = b2-b1
    dp = a1-b1
    dap = segPerp(da)
    denom = np.dot( dap, db)
    num = np.dot( dap, dp )
    if denom == 0:
        return (False, (0,0))
    return (True, (num / denom.astype(float))*db + b1)

# Find if two lines are more or less orthogonal - can't be too precise as the
# image may be warped by perspective etc
def isOrthogonal(l1, l2):
    ang = (l1["theta"] - l2["theta"] + np.pi * 2) % np.pi
    return abs(ang - np.pi/2) < np.pi/4

# Calculate square of distance from a point to a line (for sorting)
def distSqPtToLineXY(x1, y1, x2, y2, xPt, yPt):
    dx = x2-x1
    dy = y2-y1
    sqdiff = dx*dx + dy*dy
    u = ((xPt - x1) * dx + (yPt - y1) * dy) / float(sqdiff)
    u = 0 if u < 0 else (1 if u > 1 else u)
    x = x1 + u * dx
    y = y1 + u * dy
    ddx = x - xPt
    ddy = y - yPt
    distSq = ddx*ddx + ddy*ddy
    return distSq

def distSqPtToLine(linePt1, linePt2, pt):
    return distSqPtToLineXY(linePt1[0], linePt1[1], linePt2[0], linePt2[1], pt[0], pt[1])

# Find the mid point of a line
def lineMidPt(line):
    return (((line["p1"][0]+line["p2"][0])/2, (line["p1"][1]+line["p2"][1])/2))

# Distance from pt to pt
def distPtToPt(p1, p2):
    dx = p1[0]-p2[0]
    dy = p1[1]-p2[1]
    return math.sqrt(dx*dx+dy*dy)

# Find separation distance of the mid-points of two lines
def lineSeparation(l1, l2):
    mid1 = lineMidPt(l1)
    mid2 = lineMidPt(l2)
#	print("Mids", l1, l2, mid1, mid2)
    return distPtToPt(mid1, mid2)


import numpy as np

X = [[0, 1, 3], [1, 2, 3], [4, 5, 6], [1, 4, 5]]
y = [11, 14, 31, 24]

def fun(x1, x2, x3):
    return x1 + 2 * x2 + 3 * x3

X = np.asmatrix(X)
y = np.asmatrix(y).T

# Normal Equation: (XT * X)**-1  * XT * y
ne = (X.T.dot(X) ** -1) * X.T * y
print(ne)

print(fun(1, 2, 3))
print(1 * ne[0][0] + 2 * ne[1][0] + 3 * ne[2][0])


import sys, getopt
import random
from array import array
import sympy

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

def multiplicative_inverse(a, b):
    mult_inv = 3

    while (a * mult_inv) % b != 1:
        mult_inv += 1

    return mult_inv

def generate_keypair(p, q):
    if not (sympy.isprime(p) and sympy.isprime(q)):
        raise ValueError('Both numbers must be prime.')
    elif p == q:
        raise ValueError('p and q cannot be equal')
    n = p * q

    phi = (p-1) * (q-1)

    e = sympy.randprime(3, phi)

    g = gcd(e, phi)
    while g != 1:
        e = sympy.randprime(3, phi)
        g = gcd(e, phi)

    d = multiplicative_inverse(e, phi)

    return ((e, n), (d, n))

def encrypt(pk, plaintext):
    key, n = pk
    cipher = [pow(ord(char), key, n) for char in plaintext]
    return cipher

def decrypt(pk, ciphertext):
    key, n = pk
    plain = [chr(pow(char, key, n)) for char in ciphertext]
    return ''.join(plain)

def bytes_from_file(filename, chunksize=8192):
    with open(filename, "rb") as f:
        return f.read()

def writeToBinaryFile(path, text):
    try:
        with open(path, "wb") as file_handler:
            file_handler.write(text)
            return True
    except IOError:
        print("Some error")
        return False

def encrypt_and_write(inputfile, outputfile, key):
    some_str = bytes_from_file(inputfile)
    decode_str = some_str.decode("latin-1")
    encrypted_msg = encrypt(key, decode_str)
    encrypted_msg_str = ','.join([str(x) for x in encrypted_msg])
    encode_result = encrypted_msg_str.encode('latin-1')
    writeToBinaryFile(outputfile, encode_result)

def decrypt_and_write(inputfile, outputfile, key):
    some_str = bytes_from_file(inputfile)
    decode_str = some_str.decode("latin-1").split(',')
    decode_str = [int(x) for x in decode_str]
    encrypted_msg = decrypt(key, decode_str)
    encode_result = encrypted_msg.encode('latin-1')
    writeToBinaryFile(outputfile, encode_result)

def generate_primes(a, b):
    prime1 = prime2 = 0
    while prime1 == prime2:
        prime1 = sympy.randprime(a, b)
        prime2 = sympy.randprime(a, b)

    if prime2 < prime1:
        return prime2, prime1

    return prime1, prime2


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

my_dataset = pd.read_excel('Smith_glass_post_NYT_data.xlsx', sheet_name='Supp_traces')

q1 = np.percentile(my_dataset.Zr, 25, interpolation = 'midpoint')
q3 = np.percentile(my_dataset.Zr, 75, interpolation = 'midpoint')

iqr = q3 - q1 # Interquaritle range (IQR)

print ('-------')
print ('Interquaritle range (IQR): {0:.0f} [ppm]'.format(iqr))
print ('-------')

fig, ax = plt.subplots()
ax.hist(my_dataset.Zr, bins='auto', density=True, edgecolor='k', label='Measurements Hist')
ax.axvline(q1, color='purple', label='Q1', linewidth=2)
ax.axvline(q3, color='green', label='Q3', linewidth=2)
ax.axvspan(q1, q3, alpha=0.1, color='orange', label='Interquaritle range (IQR)')
ax.set_xlabel('Zr [ppm]')
ax.set_ylabel('Probability density')
ax.legend()

'''
Output:
-------
Interquaritle range (IQR): 164 [ppm]
-------
'''


# QR decomposition
from numpy import array
from numpy.linalg import qr
# define a 3x2 matrix
A = array([[1, 2], [3, 4], [5, 6]])
print(A)
# QR decomposition
Q, R = qr(A, 'complete')
print(Q)
print(R)
# reconstruct
B = Q.dot(R)
print(B)


# %% [markdown]
# # Histogram equalization
# [![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_02a_basic_image_processing/histogram_equalization.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_02a_basic_image_processing/Unequalized_Hawkes_Bay_NZ.jpg'.split())

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

figsize = (10,10)
# %% [markdown]
# First, read the image as grayscale

# %%
# read as grayscale
I = cv2.imread("Unequalized_Hawkes_Bay_NZ.jpg",0)

plt.figure(figsize=figsize)
plt.imshow(I, cmap='gray', vmin=0, vmax=255)
plt.title("Original image")
# %% [markdown]
# Let's start by calculating and showing the original histogram
# %%
bins_edges_min_max = [0,256]
num_bins=256
bin_count,bins_edges = np.histogram(I,num_bins,bins_edges_min_max)
bins_start = bins_edges[:-1]
# %%
def draw_hist(x_axis,input):
    fig,ax = plt.subplots(figsize=figsize)
    # why not using plt.hist? because we want to plot also some derivations of this hist, so this is easier
    plt.bar(x_axis, input, width=input.shape[0]/(x_axis[-1]-x_axis[0]+1))
    return fig,ax

draw_hist(bins_start,bin_count)
plt.title("Original histogram")

# %% [markdown]
# Normalize the histogram to gat a discrete PDF
# %%
pdf = bin_count/np.sum(bin_count)

draw_hist(bins_start,pdf)
plt.title("Original PDF")

# %% [markdown]
# Get the CDF by calculating the cumulative sum of the pdf data
# %%
cdf = np.cumsum(pdf)

plt.figure(figsize=figsize)
plt.plot(cdf)
plt.title("Original CDF")

# %%
fig,ax = draw_hist(bins_start,pdf)
ax.plot(cdf*np.max(pdf),'r')
plt.title("Original PDF+ const*CDF to show the connection between the two")

# %% [markdown]
# The final step is to un-normalize the CDF to become the equalization function
# %%
f_eq = np.round(cdf*255).astype(int)

f_eq
# %% [markdown]
# Use the equalization function to get the equalized image
# %%
I_eq = f_eq[I]

plt.figure(figsize=figsize)
plt.imshow(I_eq, cmap='gray', vmin=0, vmax=255)
plt.title("equalized image")
# %% [markdown]
# Plot the equalized histogram, PDF and CDF
# %%
bin_count,bins_edges = np.histogram(I_eq,num_bins,bins_edges_min_max)
bins_start = bins_edges[:-1]

draw_hist(bins_start,bin_count)
plt.title("equalized histogram")
# %%
pdf = bin_count/np.sum(bin_count)
cdf = np.cumsum(pdf)

fig,ax = draw_hist(bins_start,pdf)
ax.plot(cdf*np.max(pdf),'r')
plt.title("equalized PDF and const*CDF")
# %% [markdown]
# ## cv2 histogram equalization function
# %%
I_eq_cv2 = cv2.equalizeHist(I)

plt.figure(figsize=figsize)
plt.imshow(I_eq_cv2, cmap='gray', vmin=0, vmax=255)
plt.title("cv2.equalizeHist() result")

# %%


from sympycore import *
from sympycore.calculus.relational import *
x = Symbol('x')

A = Assumptions

def test_inequalities():

    assert A().check(2 < 3) is True
    assert A().check(Rational(2,3) < Rational(7,2)) is True
    assert A().check(pi**2 > 0) is True
    assert A().check(pi**2 < 0) is False
    assert A().check(3+4*pi > 0) is True
    assert A().check(3-pi > 0) is None
    assert A().check(-4*pi < 0) is True
    assert A().check(-4*pi > 0) is False
    assert A().check(-4*pi**Rational(1,2) < 0) is True
    assert A().check(-4*pi**Rational(1,2) > 0) is False
    assert A().check(-4*pi**2 - 1 < 0) is True
    assert A([x > 3]).check(x > 2) is True
    assert A([x > 3]).check(x > 3) is True
    assert A([x > 3]).check(x > 4) is None
    #assert A([x > 3]).check(x < 3) is False
    assert A([x > 3]).check(x > 2) is True

def XXXtest_double_inequalities():
    assert A([x>0, x<1]).check(x < 1) is True
    assert A([x>0, x<1]).check(x > 0) is True
    assert A([x>0, x<1]).check(x > 2) is False
    assert A([x>0, x<1]).check(x < -1) is False


'''
Classifier        :   Linear Regression with User Defined Algorithm
Dataset           :   Head Brain Dataset
Features          :   Gender, Age, Head Size, Brain Weight
Labels            :   ----
Training Dataset  :   237
Testing Dataset   :   ----
Author            :   Prasad Dangare
Function Name     :   MarvellousHeadBrainPredictor

'''

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

def MarvellousHeadBrainPredictor():

    # Load data
    data = pd.read_csv('HeadBrain.csv')
    print("Size Of Dataset", data.shape)

    X = data['Head Size(cm^3)'].values
    Y = data['Brain Weight(grams)'].values

    # Least Square Method
    mean_x = np.mean(X)
    mean_y = np.mean(Y)

    n = len(X)

    numerator = 0
    denomenator = 0

    # Equation of line is y = mx + c

    for i in range(n):
        numerator += (X[i] - mean_x) * (Y[i] - mean_y)
        denomenator += (X[i] - mean_x) ** 2

    m = numerator / denomenator

    c = mean_y - (m * mean_x)

    print("slope of Regression Line is ", m)
    print("Y Intercept of Regression Line is ", c)

    max_x = np.max(X) + 100
    min_x = np.min(X) - 100

    # Display Plotting Of Above points

    x = np.linspace(min_x, max_x, n)
    y = c + m * x

    plt.plot(x, y, color = '#58b970', label = 'Regression Line')
    plt.scatter(X,Y, color = '#ef5423', label = 'Scatter Plot')

    plt.xlabel('Head size in cm3')
    plt.ylabel('Brain Weight in gram')

    plt.legend()
    plt.show()

    # findout goodness of fit ie R Square

    ss_t = 0
    ss_r = 0

    for i in range(n):
        y_pred = c + m * X[i]
        ss_t += (Y[i] - mean_y) ** 2
        ss_r += (Y[i] - y_pred) ** 2

    r2 = 1 - (ss_r/ss_t)
    print(r2)

def main():

    print("------Supervised Machine Learning------")
    print("Linear Regression on Haead And Brain Size Dataset")

    MarvellousHeadBrainPredictor()

if __name__ == "__main__":
    main()


import networkx as nx
from BasicGraphOperations import readGraph

G1 = readGraph("../Q1weighted.txt",directed=False)
G2 = readGraph("../Q1unweighted.txt",directed=False)

def maxValKey(dictionary):
    values=list(dictionary.values())
    keys=list(dictionary.keys())
    return keys[values.index(max(values))]
node1 = maxValKey(nx.degree(G1))
node2 = maxValKey(nx.degree(G2))
print(node1,G1.degree(node1))
print(node2,G2.degree(node2))

import networkx as nx
from BasicGraphOperations import readGraph
import numpy

G1 = readGraph("Q2edgelist.txt",directed=True)

adjMat = nx.adjacency_matrix(G1)
print(adjMat.toarray())

"""
TODO Faster with just ccm = adj*adj.T
"""
def getCoCitationMatrix(G1):
    ccm = numpy.zeros([len(G1.nodes()),len(G1.nodes())])
    for i in range(1,len(G1.nodes())):
        ccm[i][i] = G1.in_degree(i)
        for j in range(i+1,len(G1.nodes())):
            ccm[i][j] = len(list(set(G1.predecessors(i)).intersection(set(G1.predecessors(j)))))
    ccm = ccm + ccm.T - numpy.diag(ccm.diagonal())
    return ccm

"""
TODO Faster with just bcm = adj.T*adj
"""
def getBibliographicCoupling(G1):
    bcm = numpy.zeros([len(G1.nodes()),len(G1.nodes())])
    for i in range(1,len(G1.nodes())):
        bcm[i][i] = G1.out_degree(i)
        for j in range(i+1,len(G1.nodes())):
            bcm[i][j] = len(list(set(G1.successors(i)).intersection(set(G1.successors(j)))))
    bcm = bcm + bcm.T - numpy.diag(bcm.diagonal())
    return bcm

print(getCoCitationMatrix(G1))
print(getBibliographicCoupling(G1))

import networkx as nx
from BasicGraphOperations import readGraph
import numpy
import operator
import matplotlib.pyplot as plt

G1 = readGraph("../citation.txt", directed=True, skip=1, delimiter='\t')

print(len(G1.nodes()))
print(len(G1.edges()))

degseq = list(G1.in_degree().values())
dmax = max(degseq)+1
freq = [ 0 for d in range(dmax) ]
for d in degseq:
    freq[d] += 1

plt.loglog(freq)
plt.show()
#plt.hist(freq)
#plt.show()

citations = G1.in_degree()
citations = sorted(citations.items(), key=operator.itemgetter(1),reverse=True)
print(citations[0])
print(citations[1])
print(citations[2])