#  Solving  linear systems

import numpy as np
from scipy import linalg
from itertools import combinations

def naive_solve(A, b):
    return np.linalg.inv(A.T @ A) @ A.T @ b

def qr_solve(A, b):
    m, n = np.shape(A)
    if m > n:
        return qr_solve_over(A, b)
    else:
        return qr_solve_under(A, b)

def qr_solve_over(A, b):
    Q, R = np.linalg.qr(A)
    Qb = np.dot(Q.T,b)
    return scipy.linalg.solve_triangular(R, Qb)

def qr_solve_under(A, b):
    Q, R = np.linalg.qr(A.T)
    c = scipy.linalg.solve_triangular(R, b)
    m, n = A.shape
    x = np.zeros(n)
    xx = np.dot(Q, c)
    xx = xx[:,0]
    K = xx.shape[0]
    x[:K] = xx # other components are zero
    return x

def run_demo(m, n):
    print('Solving linear system with {} constraints and {} unknowns'.format(m, n))
    np.random.seed(0)
    A = np.random.rand(m,n)
    b = np.random.rand(m,1)

    methods = list()
    solns = list()

    methods.append('naive')
    solns.append(naive_solve(A, b))

    methods.append('pinv')
    solns.append(np.dot(np.linalg.pinv(A), b))

    methods.append('lstsq')
    solns.append(np.linalg.lstsq(A, b, rcond=None)[0])

    methods.append('qr')
    solns.append(qr_solve(A, b))

    for (method, soln) in zip(methods, solns):
        residual = b -  np.dot(A, soln)
        print('method {}, norm {:0.5f}, residual {:0.5f}'.format(method, np.linalg.norm(soln), np.linalg.norm(residual)))
        print(soln.T)

    # https://stackoverflow.com/questions/33559946/numpy-vs-mldivide-matlab-operator
    if m < n: # underdetermined
        rank = np.linalg.matrix_rank(A)
        assert m==rank
        for nz in combinations(range(n), rank):    # the variables not set to zero
            soln = np.zeros((n,1))
            soln[nz, :] = np.asarray(np.linalg.solve(A[:, nz], b))
            residual = b -  np.dot(A, soln)
            print('sparse qr, norm {:0.5f}, residual {:0.5f}'.format(np.linalg.norm(soln), np.linalg.norm(residual)))
            print(soln.T)

m = 5; n = 3 # Overdetermined
run_demo(m, n)

m = 3; n = 5 # Underdetermined
run_demo(m, n)


import numpy as np
from numpy.linalg import norm

class KMeansClusterer:
    def __init__(self, data, nclusters, niters):
        # Note: niters could be changed to tolerance
        self.nsamples = data.shape[0]
        self.nfeatures =  data.shape[1]
        self.niters = niters
        self.nclusters = nclusters
        self.centroids = None
        self.data = data
        # labels: an array which will be filled by
        # corresponding cluster of each datapoint
        self.labels = None
        self.sse = None
        # Predict is unimplemented

    def initialize_centroids(self, rstate):
        np.random.seed(rstate)
        ids = np.random.permutation(self.nsamples)[:self.nclusters]
        self.centroids = self.data[ids]
        # centroids size = r: # features, c: # clusters

    def get_distances(self, centroids):
        # Compute the sum of the squared difference
        # between data point and centroid
        # for each datapoint (row) and centroid
        distance_matrix = np.zeros((self.nsamples, self.nclusters))
        # si = sample index, ci = centroid index
        for si in range(self.nsamples):
            for ci in range(self.nclusters):
                # Frobius Norm: ((x1-c1)^2 + (x2-c2)^2 + (x3-c3)^2)^0.5
                frobius = norm(self.data[si] - centroids[ci])
                distance_matrix[si, ci] = np.square(frobius)
        return distance_matrix

    def update_labels(self, distance_matrix):
        # Get a vector that contains the index
        # (index = current cluster/centroid id)
        # of the minimum distance for each sample (row)
        self.labels = np.argmin(distance_matrix, axis=1)

    def update_centroids(self, centroids):
        centroids = np.zeros((self.nclusters, self.nfeatures))
        for ci in range(self.nclusters):
            # Get all samples of the same cluster
            # by getting all the rows/samples that match the
            # centroid index, store at separate matrix
            cluster = self.data[self.labels==ci, :]
            # For each cluster, average each sample feature (col)
            # this is its new centroid
            if len(cluster) != 0:
                centroids[ci] = np.mean(cluster, axis=0)
            else:
                centroids[ci] = self.centroids[ci]
        self.centroids = centroids

    def compute_error(self):
        # error - sse - sum of square error/distance where
        # error between data samples corresponding centroid
        errs = np.zeros(self.nsamples)
        for k in range(self.nclusters):
            errs[self.labels == k] = norm(
                self.data[self.labels == k] - self.centroids[k], axis=1)

        self.sse = np.sum(np.square(errs))

    def fit(self, rstate):
        self.initialize_centroids(rstate)
        for i in range(self.niters):
            current_centroids = self.centroids
            distance_matrix = self.get_distances(current_centroids)
            self.update_labels(distance_matrix)
            self.update_centroids(current_centroids)
            # self.centroids is the updated centroids
            if np.allclose(current_centroids, self.centroids):
                break
        self.compute_error()

def preliminary_kmeans(data, nclusters, nr=10):
    km = KMeansClusterer(data, nclusters, niters=100)
    km.fit(rstate=0)
    err, r = km.sse, 0
    labels, centroids = km.labels, km.centroids

    # find the best r (random initialization of centroids)
    for i in range(1, nr):
        km.fit(rstate=i)
        if (err > km.sse ):
            err, r = km.sse, i
            labels, centroids = km.labels, km.centroids

    return labels, centroids, err

def get_angle_between_3points(x, y, z):
    a = np.array(x)
    b = np.array(y)
    c = np.array(z)
    ba = a - b
    bc = c - b
    cosine_angle = np.dot(ba, bc) / (norm(ba) * norm(bc))
    angle = np.arccos(cosine_angle)
    a = np.degrees(angle)
    return a

def find_best_k(ys, nk):
    # estimate angles between 3 points
    # the smallest angle wins!

    angles, nys = [], len(ys)
    n = max(ys) / nk # for normalizing the x

    for i in range(1, nys - 1):
        x = i + 1
        x1, x2, x3 = x - 1, x, x + 1
        y1, y2, y3 = ys[i - 1], ys[i], ys[i + 1]
        angle = get_angle_between_3points([n*x1, y1], [n*x2, y2], [n*x3, y3])
        angles.append(angle)

    k = np.argmin(np.array(angles)) + 2
    return k

def kmeans_more(data, nk=10, niter=100):
    errorset, labelset, centroidset = [], [], []

    for nclusters in range(1, nk + 1):
        labels, centroids, err = preliminary_kmeans(data, nclusters)
        errorset.append(err)
        labelset.append(labels)
        centroidset.append(centroids)
        print(">", end="")

    k = find_best_k(errorset, nk)
    i = k - 1
    return k, labelset[i], centroidset[i]

def kmeans(data, nk=10, niter=100):
    k, labels, _ = kmeans_more(data, nk, niter)
    return k, labels

def find_k_elbow(errors):
    nk = len(errors)
    x1, y1 = 1,  errors[0]
    x2, y2 = nk, errors[-1]
    m = (y1 - y2) / (x1 - x2)
    bias = (y1 + y2 - m * (x1 + x2)) / 2
    # y = mx + bias,  -mx + y - bias= 0
    # ax + by + c,
    a, b, c = -m, 1, -bias

    # get the shortest distance from point to line
    # let x, y be the point
    # d = abs( a * x + b  * y + c) / sqrt( a**2 + b**2)
    distances = []
    for x, y in enumerate(errors):
        x += 1
        d = np.abs(a*x + b*y + c) / np.sqrt(a**2 + b**2)
        distances.append(d)

    k = np.argmax(np.array(distances)) + 1
    return k

def kmeans_elbow(data, nk=10, niter=100):
    errorset = []

    for nclusters in range(1, nk + 1):
        _, _, err = preliminary_kmeans(data, nclusters)
        errorset.append(err)
        print(".", end="")

    k = find_k_elbow(errorset)
    return k, errorset


import numpy as np
from scipy import stats

def _two_sided_zstat_generic(value1, value2, std_diff, diff):
    zstat = (value1 - value2 - diff) / std_diff
    pvalue = stats.norm.sf(np.abs(zstat)) * 2
    return zstat, pvalue

def _two_sided_tstat_generic(value1, value2, std_diff, dof, diff):
    """The test statistic is :
        tstat = (value1 - value2 - diff) / std_diff
    and is assumed to be t-distributed with ``dof`` degrees of freedom.
    """
    tstat = (value1 - value2 - diff) / std_diff
    pvalue = stats.t.sf(np.abs(tstat), dof) * 2
    return tstat, pvalue

def two_sided_test(x1, x2, test='t_test', value=0):

    """two sample mean two-sided t-test based on normal distribution
        the samples are assumed to be independent.
        Parameters
        ----------
        x1 : array_like, 1-D or 2-D
            first of the two independent samples
        x2 : array_like, 1-D or 2-D
            second of the two independent samples
        value : float
            In the one sample case, value is the mean of x1 under the Null
            hypothesis.
            In the two sample case, value is the difference between mean of x1 and
            mean of x2 under the Null hypothesis. The test statistic is
            `x1_mean - x2_mean - value`
    """

    x1 = np.asarray(x1)
    nobs1 = x1.shape[0]
    x1_mean = x1.mean(0)
    x1_var = x1.var(0) # sample variance
    x2 = np.asarray(x2)
    nobs2 = x2.shape[0]
    x2_mean = x2.mean(0)
    x2_var = x2.var(0) # sample variance
    var_pooled = nobs1 * x1_var + nobs2 * x2_var

    if test == 't_test':
        dof = nobs1 + nobs2 - 2
    elif test == 'z_test':
        dof = nobs1 + nobs2
    else:
        raise ValueError('Either t_test or z_test!')

    var_pooled = var_pooled/dof
    var_pooled = var_pooled*(1.0 / nobs1 + 1.0 / nobs2)
    std_diff = np.sqrt(var_pooled)

    if test == 't_test:':
        stat, pval = _two_sided_tstat_generic(x1_mean, x2_mean, std_diff, dof, diff=value)
    else:
        stat, pval = _two_sided_zstat_generic(x1_mean, x2_mean, std_diff, diff=value)

    return stat, pval

if __name__ == '__main__':

    x1 = np.random.randn(500)
    x2 = np.random.randn(500)
    # testing for two proportions
    #x1 = np.random.binomial(n=1,p=0.4,size=100)
    #x2 = np.random.binomial(n=1,p=0.5,size=100)
    stat, p = two_sided_test(x1, x2, 'z_test')
    print(f'Performing Z-test, the statistic is {stat} and p-value is {p}')


import math
import numpy as np
#1-a
def function1():
    value=0
    for i in range(1,1000+1):
        value+=i
    return value

#1-b
def function2(m):
    value=0
    for i in range(1,m+1):
        value+=i
    return value

#2
def function3():
    value=0
    for i in range(1,100+1):
        value+=math.sqrt(i*math.pi/100)*math.sin(i*math.pi/100)
    return value

print(function1())
print(function2(1000))
print(function3())
# 500500
# 500500
# 77.51389798916512

#oriented object programming
class physic_calculation:
    def __init__(self):
        pass

    def function_a(self):
        value1=0
        for i in range(1,1000+1):
            value1+=i
        return value1

    def function_b(self,m):
        self.m=m
        value2=0
        for i in range(1,self.m+1):
            value2+=i
        return value2

    def function_c(self):
        value3=0
        for i in range(1,100+1):
            value3+=math.sqrt(i*math.pi/100)*math.sin(i*math.pi/100)
        return value3

pc=physic_calculation()
print("---------------OOP----------------")
print(pc.function_a())
print(pc.function_b(1000))
print(pc.function_c())
# 500500
# 500500
# 77.51389798916512

print("---------------numpy----------------")
a=np.arange(1,26).reshape(5,5)
print(a)
# [[ 1  2  3  4  5]
#  [ 6  7  8  9 10]
#  [11 12 13 14 15]
#  [16 17 18 19 20]
#  [21 22 23 24 25]]


import matplotlib.pyplot as plt
import numpy as np
from statistics import stdev
e1=[]
# função do circuito rl => I(t)=Io*e^-((r/l)*t), r=1, l=1, e Io=1
def dydx(x): # 1ª derivada da função
    return -1*(1*(1/2))*np.exp(-1*(1/2)*x)
def dydx2(x): # 2ª derivada da função
    return (1*(1/4))*np.exp(-1*(1/2)*x)
def f(x):
    return 1*np.exp(-1*(1/2)*x) # função original
def erro(y,y1):
    erro=0
    for i in range(len(y)):
        e=((y[i]-y1[i])/y[i])**2
        erro+=e
        e1.append(e)
    return erro

def rungeKutta1(x0, y0, x, h):
    n = int((x - x0)/h)
    X=np.zeros(n+1)
    Y=np.zeros(n+1)
    Y[0] = y0
    X[0] = x0
    for i in range(0, n):
     k1 = h * dydx(X[i])
     #k2 = h * dydx(X[i] + 0.5 * h, Y[i] + 0.5 * k1)
     #k3 = h * dydx(X[i] + 0.5 * h, Y[i] + 0.5 * k2)
     #k4 = h * dydx(X[i] + h, Y[i] + k3)
     #Y[i] = y[i] +(1.0/6)*(k1+2*k2+2*k3+k4)
     Y[i+1] = Y[i] +k1
     X[i+1] = X[i] + h
    Y1=f(X)
    soma=erro(Y1,Y)
    print("Erro=",soma," com h=0.001 soma dos erro=",soma/len(e1),"Desvio padrão=",stdev(e1))#Erro quadrático médio
    plt.plot(X,Y,'b-',X,Y1,'r-',X,e1,'g-')
    plt.legend(['Runge-Kutka 1ª ordem','Função Original','Função erro'])
    plt.axis([0,2,-0.2,2])
    plt.grid(True)
    plt.title("Solução da $I'=-1*(1*(1/2))*np.exp(-1*(1/2)*t) , I(0)=1$ r=1, l=2")
    plt.show()

def rungeKutta2(x0, y0, x, h):
    n = int((x - x0)/h)
    X=np.zeros(n+1)
    Y=np.zeros(n+1)
    Y[0] = y0
    X[0] = x0
    for i in range(0, n):
     k1 = h * dydx2(X[i])
     Y[i+1] = Y[i] +k1
     X[i+1] = X[i] + h
    Y1=dydx(X)
    soma=erro(Y1,Y)
    print("Erro=",soma," com h=0.001 soma dos erro=",soma/len(e1),"Desvio padrão=",stdev(e1))#Erro quadrático médio
    plt.plot(X,Y,'b-',X,Y1,'r-',X,e1,'g-')
    plt.legend(['Runge-Kutka 2ª ordem','Função da 1ª derivada(como a função exata)','Função erro'])
    plt.axis([0,2,-2,2])
    plt.grid(True)
    plt.title("Solução da $I''=(1*(1/4))*np.exp(-1*(1/2)*t) , I(0)=1$ r=1, l=2")
    plt.show()

x0 = 0
y = 1
x = 2
h = (2/21)
#rungeKutta1(x0, y, x, h)
rungeKutta2(x0,dydx(x0), x, h)

# This code is contributed by Prateek Bhindwar


import math

from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
from scipy.stats import skew, kurtosis, norm, uniform, kurtosistest

num_samples = 100000

# rvs (Random variates)
n = norm.rvs(loc=0.0, scale=1.0, size=num_samples)
print("for normal distribution N(0, 1),")
print("skew= ", round(skew(n), 4))
print("kurtosis= ", round(kurtosis(n), 4))

triangle = np.array([math.sqrt(u * 16 / num_samples)
                     for u in range(num_samples)])

v = n + triangle * 3.0
print("for incremental shape,")
print("skew= ", round(skew(v), 4))
print("kurtosis= ", round(kurtosis(v), 4))

plt.hist(v, bins=50, normed=True)
plt.show()


import numpy as np
from instprofile import *

def test_one_gaussian():
    """
    test the `peakdet` function with one gaussian.
    """
    gaussian = lambda x: peak*np.exp(-(mean-x)**2/(2*stdev**2))

    x_vector = np.arange(0, 100.5, 0.5)
    peak = 1
    stdev = 0.1

    # the peakdet function does not obtain the peak if it is located in the
    #last argument of the arrar. thus, we reject it.
    for x in np.arange(len(x_vector) - 1):
        mean = x_vector[x]

        #generate some data
        y_power = gaussian(x_vector)

        mean_found, peak_found = peakdet(y_power, 0.5, x_vector)[0][0]

        assert mean_found == mean
        assert peak_found == peak

def test_two_gaussians():
    """
    Test the `peakdet` function with two gaussians.
    """
    gaussians = lambda x: peak_1*np.exp(-(mean_1-x)**2/(2*stdev_1**2)) + \
                          peak_2*np.exp(-(mean_2-x)**2/(2*stdev_2**2))

    x_vector = np.arange(0, 100.5, 0.5)

    mean_1 = 25
    mean_2 = 75

    peak_1 = 1.5
    peak_2 = 2

    stdev_1 = 0.1
    stdev_2 = 0.05

    #generate some data
    y_power = gaussians(x_vector)

    values = peakdet(y_power, 0.5, x_vector)[0]

    assert mean_1 == values[0, 0] and peak_1 == values[0, 1]
    assert mean_2 == values[1, 0] and peak_2 == values[1, 1]

def test_fit_gauss():
    gaussian = lambda x: peak*(1/np.sqrt(2*np.pi*(stdev**2)))*\
                               np.exp(-(mean-x)**2/(2*stdev**2))

    x_vector = np.arange(0, 100.5, 0.01)
    mean = 50
    peak = 1
    stdev = 0.1

    y_power = gaussian(x_vector)

    assert np.allclose(fit_gauss(x_vector, y_power, [peak, mean, stdev]),
                       [peak, mean, stdev])

def test_find_fit():
    # We have a spectrum wih two gaussians and we need to detect it and fit each one of them.

    gauss = lambda p, x: p[0]*np.exp(-(p[1]-x)**2/(2*p[2]**2)) #1d Gaussian func

    x_vector = np.arange(0, 100, 0.1)
    peaks = [0.5, 1]
    means = [25, 75]
    stdevs = [2, 1.5]

    y_vector = gauss([peaks[0], means[0], stdevs[0]], x_vector) + \
               gauss([peaks[1], means[1], stdevs[1]], x_vector)

    values = find_fit(x_vector, y_vector, 0.05)

    assert np.allclose(peaks, values[:,0])
    assert np.allclose(means, values[:,1])
    assert np.allclose(stdevs, values[:,2])

def test_fwhm():
    assert isinstance(fwhm(1), float)
    assert isinstance(fwhm([1,1]), np.ndarray)
    assert len(fwhm([1,1])) == 2

def test_inst_profile():
    gauss = lambda p, x: p[0]*np.exp(-(p[1]-x)**2/(2*p[2]**2)) #1d Gaussian func

    x_vector = np.arange(0, 100, 0.1)
    peaks = [0.5, 1]
    means = [25.0, 75.0]
    stdevs = [0.5, 1.5]

    y_vector = gauss([peaks[0], means[0], stdevs[0]], x_vector) + \
               gauss([peaks[1], means[1], stdevs[1]], x_vector)

    ip = inst_profile(x_vector, y_vector, delta=0.05)

    assert len(ip) == 2     # Number of lines
    assert len(ip[0]) == 2  # Number of columns
    assert np.allclose(ip[:,0], means)
    assert np.all(ip[:,1]>0)


import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import pandas as pd
from scipy.optimize import minimize

# The SIR model differential equations.
def deriv(y, t, N, beta,gamma):
    S,I,R = y

    dSdt = -(beta*I/N)*S
    dIdt = (beta*S/N)*I - gamma*I
    dRdt = gamma*I

    return dSdt, dIdt, dRdt

def time_evo(N,beta,gamma,I0=1,R0=0,t=np.arange(0,365)):
    # Definition of the initial conditions
    # I0 and R0 denotes the number of initial infected people (I0)
    # and the number of people that recovered and are immunized (R0)

    # t ise the timegrid

    S0=N-I0-R0  # number of people that can still contract the virus

    # Initial conditions vector
    y0 = S0, I0, R0

    # Integrate the SIR equations over the time grid, t.
    ret = odeint(deriv, y0, t, args=(N,beta,gamma))
    S, I, R = np.transpose(ret)

    return (t,S,I,R)

# The SIR2 model differential equations.
def deriv2(y, t, N, gamma,beta1,beta2,t_tresh=22):
    S,I,R = y

    if t<=t_tresh:
        B=beta1
    elif t>t_tresh and t<=1000:
        B=beta1*np.exp(-(t-t_tresh)/beta2)
    elif t>1000:
        B=0.2*np.exp(-(t-1000)/beta2)

    dSdt = -(B*I/N)*S
    dIdt = (B*S/N)*I - gamma*I
    dRdt = gamma*I

    return dSdt, dIdt, dRdt

def time_evo2(N,beta1,beta2,gamma,death_rate,t_tresh=22,I0=1,R0=0,t=np.arange(0,365)):
    # Definition of the initial conditions
    # I0 and R0 denotes the number of initial infected people (I0)
    # and the number of people that recovered and are immunized (R0)

    # t ise the timegrid

    S0=N-I0-R0  # number of people that can still contract the virus

    # Initial conditions vector
    y0 = S0, I0, R0

    # Integrate the SIR equations over the time grid, t.
    ret = odeint(deriv2, y0, t, args=(N,gamma,beta1,beta2,t_tresh))
    S, I, R = np.transpose(ret)

    return (t,S,I,(1-death_rate/100)*R,R*death_rate/100)

vector_regions = ['nord', 'centro', 'sud', 'isole']
time_window    = 5
for r in range(len(vector_regions)):
    fit_region = vector_regions[r]

    if fit_region =='nord':
        region    = ['Lombardia','Veneto','Emilia-Romagna','Liguria','Piemonte','Valle d\'Aosta','P.A. Trento','P.A. Bolzano','Friuli Venezia Giulia']
        n_regions = len(region)
    elif fit_region =='centro':
        region    = ['Toscana','Marche','Umbria','Lazio','Abruzzo','Molise']
        n_regions = len(region)
    elif fit_region =='sud':
        region    = ['Puglia','Calabria','Basilicata','Campania']
        n_regions = len(region)
    elif fit_region =='isole':
        region    = ['Sicilia','Sardegna']
        n_regions = len(region)

    popolation_regions = np.array([  1304970,      559084,        533050,   1947131,   5801692,         4459477,                1215220,5879082, 1550640,    10060574,  1525271,  305617,    4356406, 4029053, 1639591,  4999891,  3729641,       541380,  882015,          125666, 4905854])
    name_regions       = np.array(['Abruzzo','Basilicata','P.A. Bolzano','Calabria','Campania','Emilia-Romagna','Friuli Venezia Giulia','Lazio','Liguria','Lombardia','Marche','Molise','Piemonte','Puglia','Sardegna','Sicilia','Toscana','P.A. Trento','Umbria','Valle d\'Aosta','Veneto'])
    regions            = np.vstack((name_regions,popolation_regions))

    mask_reg = []
    for i in range(n_regions):
        mask_reg.append(regions[0,:] == region[i])
    mask_reg = np.array(mask_reg)

    data = pd.read_csv('https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-regioni/dpc-covid19-ita-regioni.csv')
    N = 0
    xxx = []
    yyy = []
    zzz = []
    for i in range(n_regions):
        N += int(regions[1,mask_reg[i]])
        mask_REG=data['denominazione_regione']==region[i]
        xxx.append(data.loc[mask_REG,'totale_casi'])
        yyy.append(data.loc[mask_REG,'deceduti'])
        zzz.append(data.loc[mask_REG,'dimessi_guariti'])

    ydata       = np.array(np.sum(xxx,axis=0))
    ydata_death = np.array(np.sum(yyy,axis=0))
    ydata_rec   = np.array(np.sum(zzz,axis=0))
    ydata_inf   =ydata-ydata_rec-ydata_death
    xdata       = pd.to_numeric(range(ydata.shape[0]))
    today       = len(xdata)

    ### Macroregions model ###
    if fit_region =='nord':
        fin_result2=time_evo2(N,0.41,27.65,1/14,5.5,t_tresh=17,I0=2,t=np.arange(0,720)) # Nord + 0 giorni
        dt = 0
    elif fit_region =='centro':
        fin_result2=time_evo2(N,0.41,24.65,1/14,3.4,t_tresh=14.4,I0=2,t=np.arange(0,720)) # Centro + 12 giorni
        dt = 10
    elif fit_region =='sud':
        fin_result2=time_evo2(N,0.41,29.14,1/14,2.5,t_tresh=9,I0=2,t=np.arange(0,720))  # Sud + 12 giorni
        dt = 12
    elif fit_region =='isole':
        fin_result2=time_evo2(N,0.41,27.25,1/14,2,t_tresh=7.8,I0=2,t=np.arange(0,720)) # Isole + 16 giorni
        dt = 16

    tSIR2=fin_result2[0]
    s_vecSIR2=fin_result2[1]
    i_vecSIR2=fin_result2[2]
    r_vecSIR2=fin_result2[3]
    m_vecSIR2=fin_result2[4]

    # Starting time for the model according to each region
    if fit_region   ==   'nord':
        new_tSIR2  = pd.to_datetime(tSIR2,unit='D',origin='2020-02-07')
    elif fit_region == 'centro':
        new_tSIR2  = pd.to_datetime(tSIR2,unit='D',origin='2020-02-17')
    elif fit_region ==    'sud':
        new_tSIR2  = pd.to_datetime(tSIR2,unit='D',origin='2020-02-19')
    elif fit_region ==  'isole':
        new_tSIR2  = pd.to_datetime(tSIR2,unit='D',origin='2020-02-23')

    # Starting time for the data - All regions
    data_tSIR2        = pd.to_datetime(xdata,unit='D',origin='2020-02-24')

    # Model dataframe
    export = pd.DataFrame({'S':np.around(s_vecSIR2,0), 'I': np.around(i_vecSIR2,0), 'R':np.around(r_vecSIR2+m_vecSIR2,0), 'sintomatici_modello':np.around(i_vecSIR2/3,0)})
    export.index = new_tSIR2

    # Data dataframe
    new_ydata_infSIR2 = pd.DataFrame({'sintomatici_data':np.around(ydata_inf,0)})
    new_ydata_infSIR2.index = data_tSIR2

    # Join and export
    joint_frames = export.join(new_ydata_infSIR2,on=export.index)
    export2SIR2 = joint_frames.iloc[:200,:]
    export2SIR2.index.name='data'
    export2SIR2.to_csv('output/'+fit_region+'.csv',index=True)

    ### Macroregions R0 ###
    def minimizer(R0,t1=today-time_window,t2=today):

        #true data
        ydata_inf_2=np.array(ydata_inf[t1:t2])
        xdata_2=np.arange(0,len(ydata_inf_2))

        #model
        fin_result=time_evo(N,0.07*R0,0.07,I0=ydata_inf_2[0])
        i_vec=fin_result[2]
        i_vec_2=i_vec[0:len(xdata_2)]

        #average error
        error=np.sum(np.abs(ydata_inf_2-i_vec_2)/ydata_inf_2)*100

        return error

    minimizer_vec=np.vectorize(minimizer)

    xgrid    = np.arange(0.1,1.3,0.01)
    ygrid    = minimizer_vec(xgrid)
    r0_ideal = round(xgrid[np.argmin(ygrid)],2)

    ydata_inf_2 = np.array(ydata_inf[today-time_window:today])
    xdata_2     = np.arange(0,len(ydata_inf_2))

    fin_result  = time_evo(N,0.07*r0_ideal,0.07,I0=ydata_inf_2[0])

    t=fin_result[0]
    s_vec=fin_result[1]
    i_vec=fin_result[2]
    r_vec=fin_result[3]

    def minimizer_gen(t1,t2):

        xgrid=np.arange(0.1,7.2,0.01)
        ygrid=minimizer_vec(xgrid,t1=t1,t2=t2)
        r0_ideal=round(xgrid[np.argmin(ygrid)],2)

        return r0_ideal

    r0_time=[]

    for i in range(today-(time_window-1)):
        min_val=minimizer_gen(i,i+time_window)
        r0_time.append(min_val)

    if fit_region =='nord':
        r0_time_nord=np.array(r0_time)
    elif fit_region =='centro':
        r0_time_centro=np.array(r0_time)
    elif fit_region =='sud':
        r0_time_sud=np.array(r0_time)
    elif fit_region =='isole':
        r0_time_isole=np.array(r0_time)
    r0_time.clear()

df_r0=pd.DataFrame(pd.to_datetime(np.arange(len(r0_time_nord)),unit='D',origin='2020-02-28'))
df_r0['nord']   = r0_time_nord
df_r0['centro'] = r0_time_centro
df_r0['sud']    = r0_time_sud
df_r0['isole']  = r0_time_isole

df_r0.columns   = ['Data','nord','centro','sud','isole']#,'nolombardia','lombardia']

df_r0.to_csv('output/r0_regions.csv',index=False)


from networkx import minimum_spanning_tree, subgraph_view, eulerian_circuit
from graphilp.matching import perfect
from graphilp.imports import networkx as nximp
from gurobipy import GRB

def get_heuristic(G, weight='weight'):
    """ Approximation to TSP by `Christofides's algorithm <https://en.wikipedia.org/wiki/Christofides_algorithm>`__

    Creates a TSP tour from a minimum weight spanning tree by applying a minimum weight perfect matching
    to the nodes of odd degree in the spanning tree. This gives a low-weight Eulerian subgraph.
    An `Euler tour <https://en.wikipedia.org/wiki/Eulerian_path>`__ in it can be used to create
    a TSP tour by skipping over vertices that are visited more than once.

    This is a 3/2-approximation to the metric TSP and hence also gives a lower bound.

    :param G: a weighted :py:class:`~graphilp.imports.ilpgraph.ILPGraph`
    :param weight: name of the argument in the edge dictionary of the graph used to store edge cost

    :return: a list of edges forming the approximate solution and a lower bound on the optimal solution

    Example:
        .. code-block::

            warmstart, lower_bound = tsp_christofides.get_heuristic(G)

            m = create_model(G, warmstart=warmstart, lower_bound=lower_bound)

    """
    # compute minimum spanning tree
    T = minimum_spanning_tree(G.G, weight=weight)

    # get all vertices of odd degree
    odd_degree = [n[0] for n in T.degree() if n[1] % 2 != 0]

    # work on the subgraph of G induced by the nodes of odd degree in the spanning tree
    odd_sub = G.G.subgraph(odd_degree)

    # retain only those edges which are not part of the spanning tree
    odd_sub_min_T = subgraph_view(odd_sub,
                                  filter_edge=lambda u, v: ((u, v) not in T.edges()) and ((v, u) not in T.edges()))

    # find a minimum weight perfect matching on the resulting subgraph
    ilpG = nximp.read(odd_sub_min_T)
    m = perfect.create_model(ilpG, weight='weight', direction=GRB.MINIMIZE)
    m.optimize()

    matching = perfect.extract_solution(ilpG, m)

    # combine spanning tree and matching to get an Eulerian graph
    MT = T.copy()
    MT.add_edges_from(matching)

    # find an Euler circuit in MT
    euler = eulerian_circuit(MT)
    tour = list(euler)

    # short-cut by skipping vertices that would be visited twice
    # (this is where the metric property is used)
    visited = set([tour[0][0]])
    final_tour = []
    pos = 0

    while len(visited) < G.G.number_of_nodes():
        current_node = tour[pos][0]
        next_node = tour[pos][1]

        while next_node in visited:
            pos += 1
            next_node = tour[pos][1]

        final_tour.append((current_node, next_node))
        visited.add(next_node)
        pos += 1

    # close tour
    final_tour.append((final_tour[-1][1], 0))

    # We get a 3/2 approximation, so 2/3 of its value would be a lower bound
    # 19/30 is a somewhat careful version
    lower_bound = 19 * sum([G.G.edges()[e][weight] for e in final_tour]) / 30.0

    return final_tour, lower_bound


import numpy

def lu(A):
    n = len(A)
    L = numpy.zeros_like(A)
    U = numpy.zeros_like(A)
    for k in range(n):
        L[k, k] = 1.0
        U[k, k] = (A[k, k] - numpy.dot(L[k, :], U[:, k])) / L[k, k]
        for row in range(k+1, n):
            L[row, k] = (A[row,k] - numpy.dot(L[row,:],U[:,k])) / U[k, k]
        for col in range(k+1, n):
            U[k, col] = (A[k,col] - numpy.dot(L[k,:],U[:,col])) / L[k, k]
    return L, U

if __name__=="__main__":
    A = numpy.array([[1.0, 2.0, 3.0],
                     [4.0, 5.0, 6.0],
                     [7.0, 8.0, 0.0]])
    b = numpy.array([[1.0], [2.0], [3.0]])
    L, U = lu(A)
    print(A)
    print(L)
    print(U)
    print(numpy.dot(L, U))

    # Compare this against the result on the slides
    A = numpy.array([[2.0, 1.0,-1.0],
                     [4.0, 1.0, 0.0],
                     [-2.0,-3.0,8.0]])
    print(A)
    L, U = lu(A)
    print(L)
    print(U)
    print(numpy.dot(L, U))


import numpy as np

def rhs_heat_centered(T, dx, alpha, source):
    """Returns the right-hand side of the 1D heat
    equation based on centered finite differences

    Parameters
    ----------
    T : array of floats
        solution at the current time-step.
    dx : float
        grid spacing
    alpha : float
        heat conductivity
    source : array of floats
        source term for the heat equation

    Returns
    -------
    f : array of floats
        right-hand side of the heat equation with
        Dirichlet boundary conditions implemented
    """
    nx = T.shape[0]
    f = np.empty(nx)

    f[1:-1] = alpha/dx**2 * (T[:-2] - 2*T[1:-1] + T[2:]) + source[1:-1]
    f[0] = 0.
    f[-1] = 0.

    return f

def exact_solution(x, t, alpha):
    """Returns the exact solution of the 1D
    heat equation with heat source term sin(np.pi*x)
    and initial condition sin(2*np.pi*x)

    Parameters
    ----------
    x : array of floats
        grid points coordinates
    t: float
        time

    Returns
    -------
    f : array of floats
        exact solution
    """
    # Note the 'Pythonic' way to break the long line. You could
    # split a long line using a backlash (\) but the conventional
    # way is to embrace your code in parenthesis.
    #
    # For more info we refer you to PEP8:
    # https://www.python.org/dev/peps/pep-0008/#id19
    f = (np.exp(-4*np.pi**2*alpha*t) * np.sin(2*np.pi*x)
      + 2.0*(1-np.exp(-np.pi**2*alpha*t)) * np.sin(np.pi*x)
      / (np.pi**2*alpha))

    return f


import numpy.random as rng

num_trials = 10**6
r = 1.0
r2 = r * r

Ncirc = 0
for _ in range(num_trials):
    x = rng.random()
    y = rng.random()
    if ( x**2 + y**2 < r2 ):
	Ncirc +=1

pi = 4.0 * ( float(Ncirc) / float(num_trials) )

print("\n \t Computing pi in serial: \n")
print("\t For %d trials, pi = %f\n" % (num_trials,pi))


from math import ceil, pi
import numpy as np
import matplotlib.pyplot as plt

def lowess(x, y, f=2./3., iter=3):

    r = ceil(f*n)
    h = [np.sort(np.abs(x-xi))[r] for xi in x]

    w = np.clip(np.abs((x[:, None]-x[None, :])/h), 0.0, 1.0)
    w = (1 - w**3)**3

    yest = np.zeros(n)
    delta = np.ones(n)

    for j in range(iter):
        for i in range(n):
            weights = delta * w[:, i]
            b = np.array([np.sum(weights*y), np.sum(weights*y*x)])
            A = np.array([[np.sum(weights), np.sum(weights*x)],
                          [np.sum(weights*x), np.sum(weights*x*x)]])
            beta = np.linalg.solve(A, b)
            yest[i] = beta[0] + beta[1]*x[i]
        residuals = y - yest
        mid = np.median(np.abs(residuals))
        delta = np.clip(residuals/(6.0*mid), -1, 1)
        delta = (1-delta**2)**2
    return yest

if __name__=='__main__':
    n = 100
    x = np.linspace(0, 2*pi, n)
    print("=================value of x ===================")
    print(x)
    y = np.sin(x) + 0.3*np.random.randn(n)
    print("================vlaue of y ====================")
    print(y)
    yest = lowess(x, y, f = 0.25, iter=3)

    plt.plot(x, y, label='y noisy')
    plt.plot(x, yest, label='y pred')
    plt.legend()


import numpy as np
import pytest

from galois_field.core import inverse as inv
from galois_field.core.types import Fp

@pytest.mark.parametrize("el, p, expected", [
    (1, 2, 1),
    (-1, 7, 6),
    (123456789, 123456791, 61728395),
])
def test_inverse_el(el: Fp, p: int, expected: Fp):
    """el^{-1} = expected (mod p)"""
    result = inv.inverse_el(el, p)
    assert result == expected

@pytest.mark.parametrize("poly, p, mod_poly, expected", [
    (np.poly1d([4]), 11, np.poly1d([1, 0, 1]), np.poly1d([3])),
    (np.poly1d([1, 1]), 5, np.poly1d([1, 0, 2]), np.poly1d([3, 2])),
    (np.poly1d([1, 1]), 7, np.poly1d([1, 0, 0, 1, 1]), np.poly1d([6, 1, 6, 0]))
])
def test_inverse_poly(poly, p, mod_poly, expected):
    """poly^{-1} = expected (mod mod_poly)"""
    result = inv.inverse_poly(poly, p, mod_poly)

    assert result == expected


import numpy as np

def sine_min_max(frequency):
    """
    For a given frequency, return the minimum and maximum values that
    correspond to a single full peak (i.e. -1 to -1)
    :param frequency:
    :return: minimum and maximum values (in radians)
    """
    period = 2 * np.pi / frequency
    min_val = -period / 4
    max_val = 3 * period / 4
    return min_val, max_val

def get_scaled_sine(x, y_max, frequency):
    """
    For a given input (x), returns a sine function, scaled to a given maximum
    value.
    :param x: Array of x values
    :param y_max: Target maximum value of the function
    :param frequency:  Sine wave frequency
    :return: Sine function with a given max
    """
    y = np.sin(frequency * x) + 1
    y = y * (y_max / y.max())
    return y


# Plot the gamma distribution
# Based on https://github.com/probml/pmtk3/blob/master/demos/gammaPlotDemo.m

import numpy as np
import matplotlib.pyplot as plt
import os
figdir = os.path.join(os.environ["PYPROBML"], "figures")
def save_fig(fname): plt.savefig(os.path.join(figdir, fname))

from scipy.stats import gamma

x = np.linspace(0, 7, 100)
b = 1
plt.figure()
for a in [1, 1.5, 2]:
    y = gamma.pdf(x, a, scale=1/b, loc=0)
    plt.plot(x, y)
plt.legend(['a=%.1f, b=1' % a for a in [1, 1.5, 2]])
plt.title('Gamma(a,b) distributions')
save_fig('gammaDistb1.pdf')
plt.show()

x = np.linspace(0, 7, 100)
b = 1
a = 1
rv = gamma(a, scale=1/b, loc=0)
y = rv.pdf(x)
plt.plot(x, y)
plt.axvline(1, color='r')
plt.title('Gamma(1,1) distribution')
save_fig('gammaDist1.pdf')
plt.show()


import numpy as np
from q4 import plot_plane, get_average_distanace

def least_squares_fit(points):
    imh, imw = points.shape
    mean = np.average(points, axis=0)
    R = points - mean
    w,v = np.linalg.eig(np.matmul(R.T,R))
    idx = np.argmin(w)
    normal = v[:,idx]
    return normal, mean

def best_points(points, iterations = 2000, threshold = 0.003):
    """
        Takes in a set of points, performs ransac and finds the inliers
        smallest_num -> min number of points to form a plane
        iterations -> number of iterations to run ransac
        threshold -> error thresholding
        num_near -> number of nearby points required in the ransac
    """

    length_points = points.shape[0]
    maxInliers = -1
    bestInliers = np.zeros((1,1))
    for i in range(iterations):
        idx = np.random.permutation(length_points)
        sample_in = idx[0:3]
        p_in = points[sample_in,:]
        normal, mean = least_squares_fit(p_in)

        dist = abs(np.dot(points-mean, normal))
        inliers = dist < threshold
        numInliers = sum(inliers)

        if numInliers > maxInliers:
            maxInliers = numInliers
            bestInliers = inliers

    p_best = points[bestInliers,:]
    p_rest = points[~bestInliers,:]
    n_best, m_best = least_squares_fit(p_best)
    return p_best, n_best, m_best, p_rest

if __name__ == "__main__":
    points = np.loadtxt('cluttered_table.txt')
    final_points, final_normal, final_mean, p_rest = best_points(points)
    plot_plane(points, final_normal, final_mean)
    avg_distance = get_average_distanace(points, final_normal, final_mean)
    print (avg_distance, final_normal, np.dot(final_normal, final_mean))


from sympy import mod_inverse
import math
import numpy as np

d = 8891

def sieve_of_eratosthenes(n):
    prime = [True for i in range(n + 1)]
    primesList = []
    p = 2
    while (p * p <= n):

        # If prime[p] is not changed, then it is a prime
        if (prime[p] == True):

            primesList.append(p)

            # Update all multiples of p
            for i in range(p * 2, n + 1, p):
                prime[i] = False
        p += 1

    return prime, primesList

def find_prime_factors(n, prime_or_not, primes):
    for i in range(len(primes)):
        if n % primes[i] == 0:
            factor2 = int(n / primes[i])
            if prime_or_not[factor2]:
                # print("Prime factor of ", n , ": ",primes[i], factor2)
                return primes[i], factor2

# Extended Euclidean Algorithm
def gcd_extended(a, b, x, y):
    # Base Case
    if a == 0:
        x = 0
        y = 1
        return b

        # To store results of recursive call
    x1 = 1
    y1 = 1
    gcd = gcd_extended(b % a, a, x1, y1)

    # Update x and y using results of recursive call
    x = y1 - (b / a) * x1
    y = x1

    return gcd

def brute_force_attack(n, e, encrypted_data):
    prime_factors = []

    i = 2

    while (i * i <= n):
        if n % i == 0:
            prime_factors = [i, n / i]
            break
        i += 1

    p = prime_factors[0]
    q = prime_factors[1]
    phi = (p - 1) * (q - 1)

    # gcd = GCDExtended(e, phi, d, k)
    # print(d, k)

    # Private key
    d = mod_inverse(e, phi)

    # Decrypted data.
    decrypted_data = "".join([chr(pow(char, d, n)) for char in encrypted_data])
    return decrypted_data

def chosen_cipher_attack(n, e, msg, receiver):
    # Encrypt message with block size = 1 character.
    encrypted_data = [char * pow(2, e, n) for char in msg]

    decrypted_data = receiver.decrypt_msg(encrypted_data)

    ret = "".join([chr(char // 2) for char in decrypted_data])
    return ret
#
# brute_force_attack(197 * 199, 323, "hello")
# chosen_cipher_attack(199 * 197, 323, "hello")


import numpy as np
import scipy.spatial as sp
import matplotlib.pyplot as plt

# TODO: Find out how to calculate the distances (edges) of the triangles of a single simple triangle:

points = [[0, 0], [4, 0], [0, 3], [4, 6]]
points = np.array(points)
tri = sp.Delaunay(points)
fig = sp.delaunay_plot_2d(tri=tri)
plt.show()

print (tri.points)
print ("Uno")
print (tri.simplices)
print ("Dos")
print (points[tri.simplices])
print ("Tres")

triangles_all = points[tri.simplices]

for triangle in triangles_all:
    a_x = triangle[0][0]
    a_y = triangle[0][1]
    b_x = triangle[1][0]
    b_y = triangle[1][1]
    c_x = triangle[2][0]
    c_y = triangle[2][1]

    a_edge = np.sqrt( (b_x - c_x) ** 2 + (b_y - c_y) ** 2 )
    b_edge = np.sqrt( (a_x - c_x) ** 2 + (a_y - c_y) ** 2 )
    c_edge = np.sqrt( (a_x - b_x) ** 2 + (a_y - b_y) ** 2 )
    print (a_edge, b_edge, c_edge)

    s = (a_edge + b_edge + c_edge) / 2
    area = np.sqrt(s*(s-a_edge)*(s-b_edge)*(s-c_edge))
    print (area)


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

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

classification = linear_model.LogisticRegression(solver='liblinear', C=100)

classification.fit(a, b)

def plot_classification(classification, a , b):

	a_min, a_max = min(a[:, 0]) - 1.0, max(a[:, 0]) + 1.0
	b_min, b_max = min(a[:, 1]) - 1.0, max(a[:, 1]) + 1.0

	step_size = 0.01

	a_values, b_values = np.meshgrid(np.arange(a_min, a_max, step_size), np.arange(b_min, b_max, step_size))

	mesh_output1 = classification.predict(np.c_[a_values.ravel(), b_values.ravel()])

	mesh_output2 = mesh_output1.reshape(a_values.shape)

	plt.figure()

	plt.pcolormesh(a_values, b_values, mesh_output2, cmap=plt.cm.gray)

	plt.scatter(a[:, 0], a[:, 1], c=b , s=80, edgecolors='black', linewidth=1,cmap=plt.cm.Paired)
	# specify the boundaries of the figure
	plt.xlim(a_values.min(), a_values.max())
	plt.ylim(b_values.min(), b_values.max())
	# specify the ticks on the X and Y axes
	plt.xticks((np.arange(int(min(a[:, 0])-1), int(max(a[:, 0])+1), 1.0)))
	plt.yticks((np.arange(int(min(a[:, 1])-1), int(max(a[:, 1])+1), 1.0)))
	plt.show()

plot_classification(classification, a, b)


from math import sqrt,pi
import numpy as np
import matplotlib.pyplot as plt

class rksolve:

	def __init__(self,f):

		self.f = f #self.array_decorator(f)

		self.initial_conditions = None
		self.solution = None

	def iterate(self,a,b,N=1000):

		#f = self.f
		r0 = np.array(self.initial_conditions,float)

		h = (b-a)/N

		tpoints = np.arange(a,b,h)
		solution = np.empty(tpoints.shape + r0.shape,float)

		#r_points[0] = r0
		r = r0
		for i,t in enumerate(tpoints):
		    solution[i]=r
		    r += self.estimate_delta(r,t,h)

		self.h = h
		self.solution = solution
		self.t = tpoints

	def estimate_delta(self,r,t,h):

		f = self.f
		k1 = h*f(r,t)
		k2 = h*f(r+0.5*k1,t+0.5*h)
		k3 = h*f(r+0.5*k2,t+0.5*h)
		k4 = h*f(r+k3,t+h)
		return (k1+2*k2+2*k3+k4)/6

class rksolve_adaptive(rksolve):

	def iterate(self,a,b,delta=1):

		r0 = np.array(self.initial_conditions,float)

		h = (b-a)/10000
		solution = []
		time = []
		r = r0
		t = a

		solution.append(np.copy(r))
		time.append(t)

		ro = 1
		while t<b:
			if ro<2:
				h = h*ro**(1/4)
			else:
				h*=2
			# estimating ro
			r1 = r + self.estimate_delta(r,t,h)
			r1 += self.estimate_delta(r1,t+h,h)
			r2 = r + self.estimate_delta(r,t,2*h)
			difference = r1 - r2
			ro = 30*h*delta/sqrt(difference[0]**2 + difference[1]**2)

			if ro>1:
				t +=2*h
				r = r1
				solution.append(np.copy(r))
				time.append(t)

		self.h = h
		self.solution = np.array(solution)
		self.t = time

G = 6.67e-11
M = 1.9e30

def f(r,t):

	x,y,v_x,v_y = r

	d_x = v_x
	d_y = v_y

	r = sqrt(x**2 + y**2)

	dv_x = -G*M*x/r**3
	dv_y = -G*M*y/r**3

	return np.array([d_x,d_y,dv_x,dv_y],float)

prob = rksolve_adaptive(f)

R = 1.496e11
T = 3.156e7
v = 2*pi*R/T
prob.initial_conditions = [4e12,0,0,500]

delta = 1e3/365/24/60/60
prob.iterate(0,T*50,delta=delta)

x = prob.solution[:,0]
y = prob.solution[:,1]

plt.plot(x,y,'.')
plt.show()


# <Copyright 2022, Argo AI, LLC. Released under the MIT license.>

"""Utilities for querying distance to an object by infinity norm."""

import numpy as np

from av2.utils.typing import NDArrayFloat

def has_pts_in_infinity_norm_radius(points: NDArrayFloat, window_center: NDArrayFloat, window_sz: float) -> bool:
    """Check if a map entity has points within a search radius from a single query point.

    Note: Distance is measured by the infinity norm.

    Args:
        points: (N,2) or (N,3) array, representing map entity coordinates.
        window_center: (1,2), or (2,) array, representing query point.
        window_sz: search radius, in meters.

    Returns:
        boolean array of shape (N,) indicating which points lie within the search radius.

    Raises:
        ValueError: If `points` is not in R^2 or R^3.
    """
    if points.ndim != 2 or points.shape[1] not in (2, 3):
        raise ValueError(f"Input points array must have shape (N,2) or (N,3) - received {points.shape}.")

    if points.shape[1] == 3:
        # take only x,y dimensions
        points = points[:, :2]

    if window_center.ndim == 2:
        window_center = window_center.squeeze()
    if window_center.size == 3:
        window_center = window_center[:2]

    # reshape just in case was given column vector
    window_center = window_center.reshape(1, 2)

    dists = np.linalg.norm(points - window_center, ord=np.inf, axis=1)  # type: ignore
    return bool(dists.min() < window_sz)


"""

https://en.wikipedia.org/wiki/Spherical_harmonics
https://en.wikipedia.org/wiki/Table_of_spherical_harmonics

"""

from sympy import *
from sympy.abc import *
import sys
import os

def associated_legendre(m, l):
    p = 0
    for k in range(m, l+1):
        p += factorial(k)/factorial(k-m) * x**(k-m) * binomial(l, k) * binomial((l+k-1)/2, l)
    return expand(simplify(-1**m * 2**l * (1-x*x)**(m/2) * p))

def associated_legendre_full(m, l):
    k = 1
    if m < 0:
        m = -m
        k = (-1)**m * factorial(l-m)/factorial(l+m)
    return k*associated_legendre(m, l)

# the x in the legendre polynomial is defined to be cos(theta)
def spherical(m, l, k):
    theta = Symbol('theta')
    phi = Symbol('phi')
    P = associated_legendre_full(m, l)
    s = (k*P)*exp(I*m*phi)
    s = s.subs(x, cos(theta))
    s = simplify(s)
    return s

def acoustic(m, l):
    k = sqrt((2*l+1)/(4*pi) * factorial(l-m)/factorial(l+m))
    return spherical(m, l, k)

def geodesy(m, l):
    k = sqrt((2*l+1) * factorial(l-m)/factorial(l+m))
    return spherical(m, l, k)

def magnetics(m, l):
    k = sqrt(factorial(l-m)/factorial(l+m))
    return spherical(m, l, k)

# the condon-shortley phase refers to the factor (-1)^m
def quantum(m, l):
    return (-1)**m * acoustic(m, l)

if len(sys.argv) < 3:
    print("usage: m l")
    sys.exit()

m = int(sys.argv[1])
l = int(sys.argv[2])
init_printing()
print("m={} l={}".format(m, l))
print("Acoustic Spherical Harmonics")
pprint(acoustic(m, l))
print("Quantum Spherical Harmonics (Condon-Shortley Phase)")
pprint(quantum(m, l))
print("Geodesy Spherical Harmonics")
pprint(geodesy(m, l))
print("Magnetic Spherical Harmonics")
pprint(magnetics(m, l))


# Crank-Nicolson method to solve the heat equation

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as pl
import numpy as np
import matplotlib.patches as mpatches

t0 = 0.0
t_final = 1.0
n_grid = 20
dt = t_final / n_grid
dx = 1.0 / n_grid
T = np.arange(t0, t_final+dt, dt)
X = np.arange(0, 1+dx, dx)
ax = pl.figure().add_subplot(111, projection='3d')
ax.set_xlabel('t')
ax.set_ylabel('x')
ax.set_zlabel('U')
ax.set_xlim([t0,t_final])
ax.set_ylim([0, 1])
Umax= .15
ax.set_zlim([0, Umax])

# Exact solution
def exact(t, x):
    return np.exp(-t)*np.sin(np.pi*x)/(np.pi*np.pi)

for t in T:
    for x in X:
        if t>t0:
            ax.plot([t-dt, t],[x, x],[exact(t-dt, x), exact(t, x)], 'b-', linewidth=0.5)
        if x>0.0:
            ax.plot([t, t],[x-dx, x],[exact(t, x-dx), exact(t,x)], 'b-', linewidth=0.5)

# Crank-Nicolson method
r = dx/(dt*dt)/(np.pi*np.pi)
U = [[0.0 for _ in X] for _ in T]
A = [[0.0 for _ in X] for _ in X]
A_prime = [[0.0 for _ in X] for _ in X]
b = [0.0 for _ in X]
for i in range(len(X)):
    if i in [0, len(X)-1]:
        A[i][i] = 1.0
        A_prime[i][i] = 1.0
    else:
        A[i][i] = 2+2*r
        A[i][i-1] = -r
        A[i][i+1] = -r
        A_prime[i][i] = 2-2*r
        A_prime[i][i-1] = r
        A_prime[i][i+1] = r
A = np.linalg.solve(A_prime, A)
for i in range(len(T)):
    if i==0:
        for j in range(len(X)):
            U[i][j] = exact(T[i], X[j])
            b[j] = U[i][j]
    else:
        b = np.linalg.solve(A, b)
        b[0], b[-1] = 0.0, 0.0
        for j in range(len(X)):
            U[i][j] = b[j]

for i in range(len(T)):
    for j in range(len(X)):
        if i>0:
            ax.plot([T[i-1], T[i]],[X[j], X[j]],[U[i-1][j], U[i][j]], 'r-', linewidth=0.5)
        if j>0:
            ax.plot([T[i], T[i]],[X[j-1], X[j]],[U[i][j-1], U[i][j]], 'r-', linewidth=0.5)

bluePatch = mpatches.Patch(color='blue', label='Exact')
redPatch = mpatches.Patch(color='red', label='Crank-Nicolson')
pl.legend(handles = [bluePatch, redPatch], loc=2)

pl.show()

Code/Numerical Analysis & Machine Learning/CrankNicolsonHeatEquation.py


"""Statistical tests to estimate population means using statsmodels

These functions are created from using basic python libraries

The module contains useful functions for evaluating AB tests
1. one_mean_conf_interval
2. one_mean_hypothesis
3. two_means_diff_conf_interval
4. two_means_hypothesis

"""
import numpy as np
import statsmodels.stats.api as sms
from statsmodels.stats.weightstats import ttest_ind
import scipy.stats

def one_mean_conf_interval(values: np.ndarray,
                           conf_level: float = 0.95) -> tuple:
    """calculates confidence interval for mean

    Args:
        values (np.array): list of sample values
        conf_level (float, optional): confidence level. Defaults to 0.95.

    Returns:
        tuple: lower and upper bounds of confidence interval
    """
    return sms.DescrStatsW(values).tconfint_mean(alpha=1-conf_level)

def one_mean_hypothesis(values: np.ndarray, null_val: float = 0,
                        alternative: str = "two-sided") -> tuple:
    """Null hypothesis testing that mean of population is equal to null_val

    Args:
        values (np.ndarray): sample values
        null_val (float, optional): null value. Defaults to 0.
        alternative (str, optional): two-sided/larger/smaller.
                                     Defaults to "two-sided".

    Returns:
        tuple: t statistic,  p_value of the test
    """
    stats = sms.DescrStatsW(values)
    tstat, pvalue, _ = stats.ttest_mean(null_val, alternative=alternative)
    return (tstat, pvalue)

def two_means_diff_conf_interval(values1: np.ndarray, values2: np.ndarray,
                                 conf_level: float,
                                 pooled: bool = False) -> tuple:
    """Calculates confidence interval for the difference of two means

    Args:
        values1 (np.array): sample 1 values
        values2 (np.array): sample 2 values
        conf_level (float): confidence level
        pooled (bool, optional): whether to calculate pooled std.
                                 Defaults to False.

    Returns:
        tuple: lower and upper values of confidence interval
    """
    cm = sms.CompareMeans(sms.DescrStatsW(values1), sms.DescrStatsW(values2))
    alpha = 1 - conf_level
    diff_ci = cm.tconfint_diff(usevar='pooled' if pooled else "unequal",
                               alpha=alpha)
    return diff_ci

def two_means_hypothesis(values1: np.ndarray, values2: np.ndarray,
                         pooled: bool = False,
                         alternative: str = "two-sided") -> tuple:
    """Perform t test  comparing two means

    Args:
        values1 (np.array): sample 1 values
        values2 (np.array): sample 2 values
        pooled (bool, optional): whether to calculate pooled std.
                                 Defaults to False.
        alternative (str, optional): two-sided/larger/smaller.
                                     Defaults to "two-sided".
    Returns:
        tuple: t statistic,  p_value of the test
    """
    usevar = 'pooled' if pooled else "unequal"
    (tstat, pval, df) = ttest_ind(values1, values2, usevar=usevar,
                                  alternative=alternative)
    return (tstat, pval)

def multiple_mean_hypothesis(*args) -> tuple:
    """Computes Anova test to get whether the mean of at least one group is
    different
    Args:
        *args consecutive sample group values each group sample
              is represented by a list
    Returns:
        tuple: f statistic, p value
    """
    result = scipy.stats.f_oneway(*args)
    return (result.statistic, result.pvalue)

import numpy,import scipy,import statsmodels,from statsmodels


import numpy as np
import pandas as pd

df = pd.DataFrame({
    'a': [4, 5, 3, 1, 2],
    'b': [20, 10, 40, 50, 30],
    'c': [25, 20, 5, 15, 10]
})

# Change False to True for this block of code to see what it does

# DataFrame apply() - use case 2
if False:
    print(df.apply(np.mean))
    print(df.apply(np.max))

def second_max(column):
    ordered = column.sort_values(ascending=False)
    return ordered.iloc[1]

def second_largest(dataframe):
    """
    Fill in this function to return the second-largest value of each
    column of the input DataFrame.
    """
    return dataframe.apply(second_max)

print(second_largest(df))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Oct 27 06:47:19 2020

Script to illustrate calculation of partial derivatives using finite differences

@author: zettergm
"""

# Imports
import numpy as np
import matplotlib.pyplot as plt

# Grid and function to be differentiated
lx=20
ly=20
x=np.linspace(-5,5,lx)
y=np.linspace(-5,5,ly)
[X,Y]=np.meshgrid(x,y)
f=np.exp(-X**2/2/2)*np.exp(-Y**2/2/1)
# Possibly compute gradient and laplacian analytically to test...

# Coordinate differences
dx=x[1]-x[0]
dy=y[1]-y[0]

# Compute the gradient of f, centered diffs. with fwd/bwd at edges
gradx=np.zeros((ly,lx))       #note first index is treated as "y"
grady=np.zeros((ly,lx))
gradx[:,0]=(f[:,1]-f[:,0])/dx
for ix in range(1,lx-1):
    gradx[:,ix]=(f[:,ix+1]-f[:,ix-1])/2/dx
gradx[:,lx-1]=(f[:,lx-1]-f[:,lx-2])/dx

grady[0,:]=(f[1,:]-f[0,:])/dy
for iy in range(1,lx-1):
    grady[iy,:]=(f[iy+1,:]-f[iy-1,:])/2/dy
grady[lx-1,:]=(f[ly-1,:]-f[ly-2])/dy

# Compute Laplacian f by taking div(grad(f)), centered diffs + edges as above
divx=np.zeros((ly,lx))
divx[:,0]=(gradx[:,1]-gradx[:,0])/dx
for ix in range(0,lx-1):
    divx[:,ix]=(gradx[:,ix+1]-gradx[:,ix-1])/2/dx
divx[:,lx-1]=(gradx[:,lx-1]-gradx[:,lx-2])/dx

divy=np.zeros((ly,lx))
divy[0,:]=(grady[1,:]-grady[0,:])/dy
for iy in range(0,ly-1):
    divy[iy,:]=(grady[iy+1,:]-grady[iy-1,:])/2/dy
divy[ly-1,:]=(grady[ly-1,:]-grady[iy-2,:])/dy
laplacianf=divx+divy

# Take curl of the gradient (to check that is ~0); only concerned with z-comp
# dvy/dx - dvx/dy is z-comp of curl
curlx=np.zeros((ly,lx))
curlx[:,0]=(grady[:,1]-grady[:,0])/dx
for ix in range(0,lx-1):
    curlx[:,ix]=(grady[:,ix+1]-grady[:,ix-1])/2/dx
curlx[:,lx-1]=(grady[:,lx-1]-grady[:,lx-2])/dx

curly=np.zeros((ly,lx))
curly[0,:]=(gradx[1,:]-gradx[0,:])/dy
for iy in range(0,ly-1):
    curly[iy,:]=(gradx[iy+1,:]-gradx[iy-1,:])/2/dy
curly[ly-1,:]=(gradx[ly-1,:]-gradx[ly-2,:])/dy
curl=curlx-curly

# Plot the function and derivatives
plt.figure(1)
plt.pcolor(X,Y,f)
plt.xlabel("x")
plt.ylabel("y")
plt.title("f(x,y) and grad(f)")
plt.colorbar()
plt.quiver(X,Y,gradx,grady,color="white",scale=10)
plt.show()

plt.figure(2)
plt.pcolor(X,Y,laplacianf)
plt.xlabel("x")
plt.ylabel("y")
plt.title("laplacian(f)")
plt.colorbar()
plt.show()

plt.figure(3)
plt.pcolor(X[1:-2,1:-2],Y[1:-2,1:-2],curl[1:-2,1:-2])
plt.xlabel("x")
plt.ylabel("y")
plt.title("curl(grad(f))")
plt.colorbar()
plt.show()


"""
This module groups orrelation based measures of similarity between different
time series.
"""

import numpy as np

################################ CORRELATION ##################################
# See more in
# http://scikit-learn.org/stable/modules/covariance.html
# dynamics.corr('pearson')
# np.corrcoef(X[tlag:, i], X[:X.shape[0]-tlag, j])[1,0]

def lagged_PearsonCorrelation(X, timelag=0):
    """Computes the Pearson Correlation pairwise in between the lagged
    time-series of all the elements of the system.
    """

    # initialization
    n = X.shape[1]
    m = 1 if type(timelag) in [int, float] else len(timelag)
    if m == 1:
        timelag = [timelag]
    M = np.zeros((n, n, m))

    # loop over the required timelags
    for lag in range(m):
        tlag = timelag[lag]
        # loop over the possible combinations of elements
        for i in range(n):
            for j in range(n):
                aux = np.corrcoef(X[tlag:, i], X[:X.shape[0]-tlag, j])
                # assignation
                M[i, j, lag] = aux[1, 0]

    return M

#def myxcorr_1to1(x1, y1, timeLag=0):
#    # Not mine
#    # Not used
#    # TODO: Test this
#    crossCorr = []
#    x = ((np.array(x1))[np.newaxis])
#    y = ((np.array(y1))[np.newaxis])
#    n = x.shape[1]
#    for i in range(-timeLag-1, 0, 1):
#        j = -i
#        suma = np.dot(y[:, j-1:n], x[:, 0:n-j+1])
#        crossCorr.append(suma)
#    for i in range(0, timeLag, 1):
#        suma = np.dot(x[:, i:n], y[:, 0:n-i])
#        crossCorr.append(suma)
#    crossCorr_array = np.asarray(crossCorr)
#    x_sum = np.dot(x, x)
#    final_result = crossCorr_array/math.sqrt(x_sum)
#    y_sum = np.dot(y, y)
#    final_result_1 = final_result/math.sqrt(y_sum)
#    return final_result_1


# -*- coding: utf-8 -*-
"""
Created on Thu May 28 18:24:59 2015

@author: pietro
@website:http://pennestri.me
@mail:pietro.pennestri@gmail.com
"""

import matplotlib.pyplot as plt
import numpy as np
import math
from scipy.optimize import curve_fit
plt.close("all")

ydata = np.array([0.5,0.75,1.1,1.5,1.9])
xdata = np.array([2.92,3.15,3.29,3.5,3.81])
num_elements=len(xdata)

def func(x, a, b):
    return a*x+ b
#
# curve_fit: Math procedure of the scipy math library
# popt:
# Optimal values for the parameters so
#that the sum of the squared error of
# (func-ydata)^2 is minimized
# pcov:
# The diagonals of pcov provide the variance
# of the parameter estimate

popt, pcov = curve_fit(func, xdata, ydata)
print popt

a=popt[0]
b=popt[1]

#error
k=0
s=0
for x in xdata:
    y=func(x,a,b)
    s=s+(y-ydata[k])**2
    k=k+1
s=math.sqrt(s/num_elements)
print "Square root of sum of squares of residuals=",s

print '------'
print pcov
plt.figure()
plt.plot(xdata, ydata, 'ko', label="Original Data")
plt.plot(xdata, func(xdata, *popt), 'r-', label="Fitted Curve")
plt.xlabel('Arduino voltage (V)')
plt.ylabel('Alcohol concentration  (mg/l)')
#plt.xscale('log')#
#plt.yscale('log')#
plt.grid()
plt.show()


import numpy as np
from scipy.fft import fft
from scipy import interpolate

def normalize(lower, upper, vals):
    """
    Normalize all values so that they're between the lower and the
    upper bounds that were passed in.

    :param lower: The lower bound
    :type lower: float

    :param upper: The upper bound
    :type upper: float

    :param vals: A list of numbers
    :type vals: list[float]

    :returns: The list of numbers redistributed across the new bounds
    :rtype: list[float]
    """
    return [(lower + (upper - lower)*v) for v in vals]

def remap(x, x1, x2, y1, y2):
    """
    Remaps value x to a new range.

    :param x: Value to act on

    :param x1: Old Minimum
    :param x2: Old Maximum

    :param y1: New Minimum
    :param y2: New Maximum

    :returns: The original value mapped to the new range.
    """
    if (x2 == x1 and x2 == 0) or (y2 == y1 and y2 == 0):
        return 0
    return (((x - x1) * (y2 - y1)) / (x2 - x1)) + y1

def to_bins(ar, b, xvals=None):
    """
    Given an array ar, and number of buckets b, return a normalized
    set of bins (values in range [0,1])

    :param ar: Array to act on
    :type ar: Python list or numpy array

    :param b: Number of bins to sum over
    :type b: int

    :param xvals: Values to use as x values/coordinates for ar's "y values"
    :type xvals: array of numbers

    :returns: An array of bins that have values between 0 and 1
    :rtype: numpy array
    """
    a = len(ar)
    n = int(a / b)

    if b <= a:
        bins = []
        for i in range(0, b):
            arr = []
            for j in range(i*n, (i+1)*n):
                if j >= a:
                    break
                arr.append(ar[j])
            bins.append(np.sum(arr) / len(arr))
        bins = np.array(bins)
        mx = np.max(bins)
        return bins if mx == 0 else bins / mx
    else:
        # Number of buckets is bigger than array, need to
        # interpolate those values.

        # Using scipy, which has a better interpolation method
        if not xvals is None:
            f = interpolate.interp1d(xvals, ar, fill_value="extrapolate")
        else:
            f = interpolate.interp1d(np.arange(a), ar, fill_value="extrapolate")

        interpolated = f(np.arange(b))
        return interpolated / np.max(interpolated)

def get_spectrum(y, Fs):
    """
    Given a signal, y, compute its frequency domain using a Fast
    Fourier Transform (FFT).  Return the one-sided representation.

    :param y: The signal (list of values)
    :type y: list[float]

    :param Fs: The sampling frequency used for the signal
    :type Fs: int

    :returns: A tuple of the frequency range and the absolute amplitude of
              each frequency.
    :rtype: tuple
    """
    signal_length = len(y)
    k = np.arange(signal_length)
    T = signal_length / Fs
    frq = k / T # two-sides frequency range
    frq = frq[range(signal_length // 2)]    # Convert to one-sided frequency range

    # FFT Computation and Range
    Y = fft(y)
    Y = abs(Y[range(signal_length // 2)])

    # Now want to normalize the values to 0-1
    #Y = np.nan_to_num(Y / np.max(Y))
    Y = Y * 2 / (2 * (signal_length // 2))

    # And set tiny values to 0
    #Y[Y <= 0.001] = 0

    return (frq, Y)


# The code here is a translation of the MATLAB code provided at
# https://www.mathworks.com/matlabcentral/fileexchange/41459-6-functions-for-generating-artificial-datasets

import numpy as np

def spirals(N = 1000, degrees = 570, start = 90, noise = 0.2):
    """
    Generate "two spirals" dataset with N instances.
    Input:
    N -> Number of samples in the dataset
    degrees -> controls the length of the spirals
    start -> determines how far from the origin the spirals start, in degrees
    noise displaces the instances from the spiral. 0 is no noise, at 1 the
    spirals will start overlapping
    Output:
    data -> (Nx3) dataset: (xcoord,ycoord,label)
    """

    deg2grad = (2*np.pi)/360
    start = start*deg2grad

    #Number of samples in spirals 1 and 2
    N1 = int(np.floor(1.0*N/2))
    N2 = N - N1

    #Spiral 1
    n = start + np.sqrt(np.random.rand(N1,1))*degrees*deg2grad
    d1x =  -np.cos(n)*n + np.random.rand(N1,1)*noise
    d1y = np.sin(n)*n + np.random.rand(N1,1)*noise

    spiral1 = np.concatenate((d1x,d1y,\
                             np.zeros((N1,1))),axis = 1)

    # Spiral 2
    n = start + np.sqrt(np.random.rand(N2,1))*degrees*deg2grad
    d2x = np.cos(n)*n+np.random.rand(N2,1)*noise
    d2y = -np.sin(n)*n + np.random.rand(N2,1)*noise
    spiral2 = np.concatenate((d2x,d2y,\
                             np.ones((N2,1))),axis = 1)

    #Concatenating the final data
    data = np.concatenate((spiral1,spiral2),axis = 0)
    return data

def concentric_clusters(N = 1000, r1 = 1, r2 = 5, w1 = 0.8, w2 = 1.0/3, arms = 64):
    """
    Generates two concentric circular clusters.
    Input:
    N -> Number of samples in the dataset
    r1 -> Radius cluster 1
    r2 -> Radius cluster 2
    w1 -> Cluster 1 weight
    w2 -> Cluster 2 weight
    arms -> Number of stripes (arms) in the circle
    Output:
    data -> (Nx3) dataset: (xcoord,ycoord,label)
    """

    #Number of samples in each cluster
    N1 = int(np.floor(1.0*N/2))
    N2 = N - N1

    phi1 = np.random.rand(N1,1) * 2 * np.pi;
    dist1 = r1 + 1.0*(np.random.randint(0,5,size =(N1,1)))/5*w1*r1
    d1x = dist1* np.cos(phi1)
    d1y = dist1* np.sin(phi1)
    cluster1 = np.concatenate((d1x,d1y,\
                             np.zeros((N1,1))),axis = 1)

    perarm = int(np.round(N2/arms))
    N2 = perarm*arms;
    radperarm = (2*np.pi)/arms;
    phi2 = 1.0*(np.arange(1,N2+1,dtype = int) - np.arange(1,N2+1,\
            dtype=int)%perarm)/perarm*(radperarm)
    dist2 = r2 * (1 - w2/2) + (r2*w2*np.arange(1,N2+1,\
            dtype=int)%perarm)/perarm
    d2x = dist2*np.cos(phi2)
    d2y = dist2*np.sin(phi2)
    cluster2 = np.concatenate((d2x[:,np.newaxis],d2y[:,np.newaxis],\
                             np.ones((N2,1))),axis = 1)

    #Concatenating the final data
    data = np.concatenate((cluster1,cluster2),axis = 0)
    return data

def corners(N = 100,scale = 0,gapwidth = 2,cornerwidth = 2):
    """
    Generates for "corner" clusters .
    Input:
    N -> Number of samples in the dataset
    scale -> Corner scale
    gapwidth -> gap between corners
    cornerwidth -> corner width
    Output:
    data -> (Nx3) dataset: (xcoord,ycoord,label)
    """

    N = int(N/8)*8
    per_corner  = N//4

    xplusmin = np.concatenate((np.ones((per_corner,1)),\
                               -np.ones((per_corner,1)),\
                               np.ones((per_corner,1)),\
                               -np.ones((per_corner,1))),\
                               axis = 0)

    yplusmin = np.concatenate((np.ones((per_corner,1)),\
                               -np.ones((2*per_corner,1)),\
                               np.ones((per_corner,1))),\
                               axis = 0)

    #Horizontal edge
    x = xplusmin[::2]*gapwidth+xplusmin[::2]*scale*(np.random.rand(2*per_corner).reshape(-1,1))

    y = yplusmin[::2]*gapwidth + cornerwidth*yplusmin[::2]*(np.random.rand(2*per_corner).reshape(-1,1))

    z = np.floor(np.arange(2*per_corner,dtype = int)/(per_corner*0.5))

    horizontal = np.concatenate((x,y,z[:,np.newaxis]),axis = 1)

    # Vertical edge
    x2 = xplusmin[1::2]*gapwidth + cornerwidth*xplusmin[1::2]*\
                                 (np.random.rand(2*per_corner).reshape(-1,1))

    y2 = yplusmin[1::2]*gapwidth+yplusmin[1::2]*scale*\
                                 (np.random.rand(2*per_corner).reshape(-1,1))

    z2 = np.floor(np.arange(2*per_corner,dtype = int)/(per_corner*0.5))
    vertical = np.concatenate((x2,y2,z2[:,np.newaxis]),axis = 1)

    #Concatenating the final data
    data = np.concatenate((vertical,horizontal),axis = 0)
    return data

def crescent_full_moon(N = 1000,r1 = 5,r2 = 10,r3 = 15):
    """
    Generates 2 clusters. One shape as a full moon and the other as a crescent moon.
    Input:
    N -> Number of samples in the dataset
    r1 ->
    r2 ->
    r3 ->
    Output:
    data -> (Nx3) dataset: (xcoord,ycoord,label)
    """

    N = int(N/4)*4
    N1 = int(N/4)
    N2 = N-N1

    # Full moon
    phi1 = np.random.rand(N1,1)*2*np.pi
    R1 = np.sqrt(np.random.rand(N1, 1))
    moon = np.concatenate((np.cos(phi1)*R1*r1,np.sin(phi1)*R1*r1,\
                           np.zeros((N1,1))),axis = 1)
    # Crescent moon
    d = r3 - r2
    phi2 = np.pi + np.random.rand(N2,1)*np.pi
    R2 = np.sqrt(np.random.rand(N2,1))
    crescent = np.concatenate((np.cos(phi2)*(r2 + R2 * d),\
                               np.sin(phi2)*(r2 + R2 * d),\
                               np.ones((N2,1))),axis = 1)
    #concatenating the final data
    data = np.concatenate((moon,crescent),axis = 0)
    return data


import numpy as np

class SimpleLinearRegressionV1:

    def __init__(self):
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        assert x_train.ndim == 1 and y_train.ndim == 1,\
            "needs single feature train data"
        assert len(x_train) == len(y_train),\
            "the size of x and y must be equals"
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)
        self.a_ = np.sum((x_train - x_mean) * (y_train - y_mean)) / np.sum((x_train - x_mean) ** 2)
        self.b_ = y_mean - self.a_ * x_mean
        return self

    def predict(self, x_predict):
        assert isinstance(x_predict, (int, float)) or x_predict.ndim == 1,\
            "needs single feature data to predict"
        assert self.a_ is not None and self.b_ is not None,\
            "must be fit before oredict"
        return self.a_ * x_predict + self.b_

    def __repr__(self):
        return "SimpleLinearRegressionV1()"

class SimpleLinearRegressionV2:

    def __init__(self):
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        assert x_train.ndim == 1 and y_train.ndim == 1,\
            "needs single feature train data"
        assert len(x_train) == len(y_train),\
            "the size of x and y must be equals"
        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)
        self.a_ = (x_train - x_mean).dot(y_train - y_mean) / (x_train - x_mean).dot((x_train - x_mean))
        self.b_ = y_mean - self.a_ * x_mean
        return self

    def predict(self, x_predict):
        assert isinstance(x_predict, (int, float)) or x_predict.ndim == 1,\
            "needs single feature data to predict"
        assert self.a_ is not None and self.b_ is not None,\
            "must be fit before oredict"
        return self.a_ * x_predict + self.b_

    def score(self, x_test, y_test):
        assert len(x_test) == len(y_test),\
        "the size of y_true must be equal to the size of y_predict"
        return 1 - np.sum((y_test - self.predict(x_test)) ** 2) / len(y_test) / np.var(y_test)

    def __repr__(self):
        return "SimpleLinearRegressionV2()"


from fractions import Fraction
import numpy as np
from numpy.random import randint
import sys

class RationLP:
    def __init__(self, A, b, c):
        self.A = [[Fraction(x) for x in row] for row in A]
        self.b = [Fraction(x) for x in b.flat]
        self.c = [Fraction(x) for x in c.flat]
        self.n = len(self.c)
        self.m = len(self.b)

    def print_row(self, vec, fout):
        for x in vec:
            print(x, end=' ', file=fout)
        print(file=fout)

    def save(self, path):
        with open(path, 'w') as fout:
            print(self.n, file=fout)
            print(self.m, file=fout)
            self.print_row(self.c, fout)
            self.print_row(self.b, fout)
            for row in self.A:
                self.print_row(row, fout)

# Adapted from https://math.stackexchange.com/a/244164/76028
def generate_feasible(n, m):
    v = randint(0, 2 * n, size=(n, 1))
    A = randint(0, n * m, size=(m, n))
    b = A @ v + randint(0, 4, size=(m, 1)) / 4.0
    c = randint(-n, n, size=(n, 1))
    return A, b, c

def generate_unbounded(n, m):
    u = randint(0, 2 * n, size=(n, 1))
    v = randint(0, 2 * n, size=(n, 1))
    v[v == 0] = 1
    A = randint(0, 100, size=(m, n))
    Av = A @ v
    A[Av[:, 0] > 0, :] *= -1
    assert (A@v < 0).all()
    b = A @ u + randint(0, 4, size=(m, 1)) / 4.0
    c = randint(-2 * n, 2 * n, size=(n, 1))
    if c.T @ v <= 0:
        c = -c
    return A, b, c

def generate_infeasible(n, m):
    A, b, c = generate_unbounded(m, n)
    return -A.T, -c, -b

def pack_save(fname, A, b, c):
    prog = RationLP(A, b, c)
    prog.save(fname)

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("The program needs two integer command line arguments")
        sys.exit(1)

    n = int(sys.argv[1])
    m = int(sys.argv[2])

    name_template = 'inputs/test_{{}}_{}x{}.txt'.format(m, n)

    pack_save(name_template.format('feasible'), *generate_feasible(n, m))
    pack_save(name_template.format('infeasible'), *generate_infeasible(n, m))
    pack_save(name_template.format('unbounded'), *generate_unbounded(n, m))


# utf-8
'''**1) Crie dois arrays 1D de forma automática: o primeiro com números pares entre 0 e 8; o segundo com números ı
́mpares entre 1 e 9. Experimente realizar as operações aritméticas de soma,
subtração, multiplicação e divisão sobre eles (primeiro o array par e depois o array ímpar, nessa ordem).**'''

import numpy as np
print()
print('=' * 39)
print('Ex.1')

a = np.arange(0, 10, 2)
print(a)

b = np.arange(1, 10, 2)
print(b)

print(a + b)
print(a - b)
print(a / b)
print(a * b)

'''**2) Construa a matriz ilustrada pela figura abaixo (Dica: pesquise sobre o método `reshape`).
Em seguida, obtenha cada um dos "pedaços" (ou cortes) do array 2D destacados na figura (em cores) e,
para cada um deles, calcule a soma, a média, a variância e o desvio padrão dos valores.**

![Questão 2](aula3-q2.png)'''
print()
print('=' * 39)
print('Ex.2')

p = np.arange(6)
s = np.arange(10, 16)
t = np.arange(20, 26)
qa = np.arange(30, 36)
qi = np.arange(40, 46)
se = np.arange(50, 56)
fig = np.concatenate((p, s, t, qa, qi, se))
fig = fig.reshape(6, 6)
print(fig)

r = fig[2, :]
ro = r[r % 2 == 0]
x = fig[4, :]
xo = x[x % 2 == 0]

roxo = np.concatenate((ro, xo), axis=0, out=None, dtype=int, casting='same_kind')
print(f'\nslice roxo {roxo}')
print(f'média slice roxo {roxo.mean()}')
print(f'variância slice roxo {roxo.var()}')
print(f'desvio padrão slice roxo {roxo.std()}')

azul = fig[:, 2]
print(f'\nslice azul {azul}')
print(f'média slice azul {azul.mean()}')
print(f'variância slice azul {azul.var()}')
print(f'desvio padrão slice azul {azul.std()}')

vermelho = fig[0, 3:5]
print(f'\nslice vermelho {vermelho}')
print(f'média slice vermelho {vermelho.mean()}')
print(f'variância slice vermelho {vermelho.var()}')
print(f'desvio padrão slice vermelho {vermelho.std()}')

verde = (fig[4:, 4:]).reshape(1, 4)
print(f'\nslice verde {verde}')
print(f'média slice verde {verde.mean()}')
print(f'variância slice verde {verde.var()}')
print(f'desvio padrão slice verde {verde.std()}')

'''**3) Com base na matriz abaixo, obtenha:**
  (a) Um vetor cotendo o seno dos elementos da segunda linha;
  (b) A sua inversa, sua transposta e um vetor com os elementos da sua diagonal principal;
  (c) A soma e a média dos seus elementos.'''
print()
print('=' * 39)
print('Ex.3')
ma = [[2, 45, 22, 12], [44, 34, 68, 3], [5, 7, 78, 2], [12, 34, 5, 9]]
ma_arr = np.array(ma)
print(f'\n{ma_arr}')

print('\n(a)')
sen_arr = np.sin(ma_arr[1, :])
print(sen_arr)

print('\n(b.1)')
print(f'{ma_arr[::-1]}')

print('\n(b.2)')
print(ma_arr.T)

print('\n(b.3)')
print(ma_arr.diagonal())

print('\n(b.3)')
print(f'A soma do array é {ma_arr.sum()} e a média {ma_arr.mean()}')


# -*- coding: utf-8 -*-
"""
Created on Sat Dec 11 16:58:25 2021

@author: DELL
"""

import numpy as np

array = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]) #1*4 vect

print(array.shape)

a = array.reshape(3,5)
print("shape",a.shape)
print("dimension",a.ndim)
print("data type: ",a.dtype.name)
print("size: ",a.size)

print("type",type(a))

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

zeros = np.zeros((3,4))

zeros[0,0]=5
print(zeros)
np.ones((3,4))

np.empty((2,3))

a= np.arange(10,50,5)
print(a)

a = np.linspace (10,50,20)
print(a)

#%%
a = np.array([1,2,3])
b = np.array([4,5,6])

print(a+b)
print(a-b)
print(a**2)

print(np.sin(a))

print (a<2)

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

b = np.array([[1,2,3],[4,5,6]])

#element wisw product

print(a*b)

#matrix product
a.dot(b.T)

print(np.exp(a))

a = np.random.random((5,5))

print(a.sum())
print(a.max())
print(a.min())

print(a.sum(axis=0))#sutun toplar
print(a.sum(axis=1)) #satır toplar

print(np.sqrt(a))
print(np.square(a))# a**2

#%%
import numpy as np
array = np.array([1,2,3,4,5,6,7])

print(array[0])

print(array[0:4])

reverse_array = array [::-1]
print(reverse_array)

array1 = np.array([[1,2,3,4,5],[6,7,8,9,10]])
print(array1[1,1])

print(array1[:,1])

print( array1[1,1:4])

print([array1[-1, :]])

print([array1[:, -1]])

#%%
#shape manipilation
array = np.array([[1,2,3],[4,5,6],[7,8,9]])

#flatten

a=array.ravel()

array2 = a.reshape(3,3)

arrayT = array2.T

print(arrayT.shape)

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

#%%stacking arrays

array1 = np.array([[1,2],[3,4]])
array2 = np.array([[-1,-2],[-3,-4]])
#vertical
array3 = np.vstack((array1,array2))
#horizontal
array4 = np.hstack((array1,array2))

#%%

liste = [1,2,3,4]

array = np.array(liste)

liste2 = list(array)


import numpy as np
import pandas as pd
import math
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

def cal_bid_spread(bid_price: float, offer_price: float) -> float:
    ''' Function to calculate bid spread

    Bid spread use to calculate ratio of best offer price and best bid price
    0 is the lowest spread

    Args:
        bid_price: Highest price of bidding
        offer_price: Lowest price of offer

    Returns:
        bid spread
    '''

    bid_spread = (offer_price / bid_price) - 1

    return bid_spread

def cal_wap(bid_price: float, bid_size: float, offer_price: float, offer_size: float) -> float:
    ''' Function to calculate weighted averaged price

    weighted averaged price (wap) is a metric to calculate stock price

    Args:
        bid_price: Highest price of bidding
        bid_size: Size of highest bidding price
        offer_price: Lowest price of offer
        offer_size: Size of lowest offering price

    Returns:
        weighted averaged price
    '''

    wap = ((bid_price * offer_size) + (offer_size * bid_size)) / \
        (bid_size + offer_size)

    return wap

def cal_series_wap(book_df: pd.DataFrame) -> pd.DataFrame:
    ''' Function to calculateb weighted averaged price of DataFrame

    weighted averaged price (wap) is a metric to calculate stock price

    Args:
        book_df: DataFrame contains booking information

    Returns:
        DataFrame contains booking information with wap
    '''

    book_df.loc[:, "wap"] = (book_df['bid_price1'] * book_df['ask_size1']
                             + book_df['ask_price1'] * book_df['bid_size1']) \
        / (book_df['bid_size1'] + book_df['ask_size1'])

    return book_df

def cal_log_return(stock_price_t1: float, stock_price_t2: float) -> float:
    ''' Function to calculate log return

    Log return to calculate return of each stock in two point in time.
    Log rerturn is more mathematically desirable compare to raw return

    Args:
        stock_price_t1: stock price at time 1
        stock_price_t2: stock price at time 2

    Returns:
        log returns
    '''

    log_returns = math.log(stock_price_t2 / stock_price_t1)

    return log_returns

def cal_series_log_return(book_df: pd.DataFrame) -> pd.DataFrame:
    ''' Function to calculate log return

    Log return to calculate return of each stock in two point in time.
    Log rerturn is more mathematically desirable compare to raw return

    Args:
        book_df: DataFrame contains booking information

    Returns:
        DataFrame contains booking information with wap and log return
    '''

    book_df = cal_series_wap(book_df)
    book_df.loc[:, "log_return"] = np.log(book_df['wap']).diff()

    # Replace second in bucket = 0 to NaN because there should be nothing to calculate from
    book_df.loc[(book_df["seconds_in_bucket"] == 0), "log_return"] = np.NaN

    return book_df

def cal_realized_volatility(log_return_series: pd.Series) -> float:
    ''' Function to calculate realized_volatility

    Calculate volatility between time 1 and time 2

    Args:
        log_return_series: a series with log returns

    Returns:
        realized_volatility
    '''

    log_return_series = log_return_series.dropna()
    realized_volatility = np.sqrt(np.sum(np.square(log_return_series)))

    return realized_volatility

def root_mean_squared_percentage_error(y_true: np.array, y_pred: np.array, percentage: bool = False) -> float:
    ''' Function to calculate root mean square percentage error

    Calculate root mean square percentage error between two array

    Args:
        y_true: array of actual value
        y_pred: array of prediction by estimator(s)
        percentage: boolean to indicate true for percentege false for percentage/100

    Returns:
        root mean square percentage error
    '''

    rmspe = np.sqrt(np.mean(np.square((y_true - y_pred) / y_true)))

    if percentage is True:
        rmspe = rmspe * 100

    return rmspe

def symmetric_mean_absolute_percentage_error(y_true: np.array, y_pred: np.array) -> float:
    ''' Function to calculate symmetric mean absolute percentage error

    Calculate symmetric mean absolute percentage error between two array

    Args:
        y_true: array of actual value
        y_pred: array of prediction by estimator(s)

    Returns:
        symmetric mean absolute percentage error
    '''

    smape = 100/len(y_true) * np.sum(
        2 * np.abs(y_pred - y_true) / (np.abs(y_true) + np.abs(y_pred)))

    return smape

def evaluation(y_true: np.array, y_pred: np.array) -> dict:
    ''' Function to calculate metrics for models evaluation
    Calculate metrics for evaluate regression including:
    residual, average value, sum_error, mae, rmse, rmspe, smape, r2

    Args:
        y_true: array of actual value
        y_pred: array of prediction by estimator(s)

    Returns:
        Dictionary of metrics
    '''

    residual = y_true - y_pred
    # Average true and prediction
    y_true_mean = np.mean(y_true)
    y_pred_mean = np.mean(y_pred)
    # This call tell if the estimator over/under-predicted
    sum_error = np.sum(residual)
    error_mean = y_true_mean - y_pred_mean

    mae = mean_absolute_error(y_true, y_pred)
    rmse = mean_squared_error(y_true, y_pred, squared=False)
    rmspe = root_mean_squared_percentage_error(y_true, y_pred, percentage=True)
    smape = symmetric_mean_absolute_percentage_error(y_true, y_pred)

    # Again R2 is really problematic and should not be use in this instance,
    # but the example notebook has them
    r2 = r2_score(y_true, y_pred)

    metrics_result = {
        "residual": residual,
        "true_average": y_true_mean,
        "prediction_average": y_pred_mean,
        "sum_error": sum_error,
        "average_error": error_mean,
        "mae": mae,
        "rmse": rmse,
        "rmspe": rmspe,
        "smape": smape,
        "r2": r2
    }

    return metrics_result


def transform(dataset, SX=0.5, SY=0.5, SZ=0.5, noise=15.0):
    """Deblur Images with a Weiner Filter."""

    import numpy as np
    from numpy import exp, square, pi
    from scipy.fftpack import fftn, ifftn, fftshift

    #Import information from dataset
    array = dataset.active_scalars
    dim = array.shape

    #Point Spread Function (Estimated with Gaussian Function)
    def gaussian(SX, SY, SZ):
        x = np.arange(-dim[0]/2, dim[0]/2)
        y = np.arange(-dim[1]/2, dim[1]/2)
        z = np.arange(-dim[2]/2, dim[2]/2)
        [x, y, z] = np.meshgrid(x, y, z, indexing='ij')
        Kx = x/dim[0]
        Ky = y/dim[1]
        Kz = z/dim[2]
        r = square(Kx)+square(Ky)+square(Kz)
        G = exp(-2*square(pi)*SX*SY*SZ*r)

        return G

    #Wiener Transformation/Reconstruction
    def wiener(psf, img, SZ):
        snr = noise
        if snr != 0:
            W = (1/psf)*(square(abs(psf))/(square(abs(psf))+1/snr))
        else:
            W = (1/psf)

        img = abs(ifftn(fftshift(W*(fftn(img)))))
        img = img.real.astype(float, order='F')
        return img

    #Transformation/Reconstruction
    H = gaussian(SX, SY, SZ)
    H = H + np.finfo(complex).tiny
    final = wiener(H, array, SZ)
    final = final/np.amax(final) #Normalize the Image

    #Set the result as the new scalars.
    dataset.active_scalars = np.asfortranarray(final)


import numpy as np

print('--- Overview ---')

x = np.random.uniform(0, 1, size=1000000)
print(x)
print(x.mean())

print('--------------------\n')

print('--- Basic ---')

my_list = [0, 1, 2, 3, 4]
print(my_list)

arr = np.array(my_list)
print(arr)
print(type(arr))

print('--------------------\n')

print('--- Arange integers, takes in start, stop, and step size ---')

a = np.arange(0, 10)
print(a)

a = np.arange(0, 10, 2)
print(a)

print('--------------------\n')

print('--- Create an array of zeros ---')

a = np.zeros((5, 5))
print(a)

print('--------------------\n')

print('--- Create an array of ones ---')

a = np.ones((2, 4))
print(a)

print('--------------------\n')

print('--- Create an array of random integers ---')

a = np.random.randint(0, 10)
print(a)

print('--------------------\n')

print('--- Create 2d matrix of random integers ---')

a = np.random.randint(0, 10, (3, 3))
print(a)

print('--------------------\n')

print('--- Create linearly spaced array ---')

a = np.linspace(0, 10, 6)
print(a)

print('--------------------\n')

print('--- Operations On Arrays ---')

arr = np.random.randint(0, 100, 10)
print(arr)
print(arr.max())
print(arr.min())
print(arr.mean())
print(arr.argmin())
print(arr.argmax())
print(arr.reshape(2, 5))

print('--------------------\n')

print('--- Additional Functionality ---')

mat = np.arange(0, 100).reshape(10, 10)
print(mat)
print()

row = 0
col = 1

print('--- Select an individual number ---')

print(mat[row, col])
print()

print('--- Select an entire column ---')

print(mat[:, col])
print()

print('--- Select an entire row ---')

print(mat[row, :])
print()

print('--- Masking ---')

print(mat > 50)
print(mat[mat > 50])

print('--------------------\n')


"""
reference: https://github.com/RRdmlearning/Machine-Learning-From-Scratch/blob/master/linear_regression/linear_regression.py

    https://towardsdatascience.com/building-a-logistic-regression-in-python-301d27367c24
loss function: l=\frac{1}{m}\sum _{i=1}^{m}(x_iw - y_i)^2
matrix form: l=(y-xw)^T(y-xw)
SGD: \frac{\partial{l}}{\partial w}=x^T(y-xw)
least square method: w^*=(X^TX)^{-1}X^Ty
"""
import numpy as np
from sklearn.datasets import make_regression

def split_train_test(x, y, seed=0, training_ratio=0.8):
    if seed:
        np.random.seed(seed)
    idx = np.arange(x.shape[0])
    np.random.shuffle(idx)
    x, y = x[idx], y[idx]
    train_counts = int(x.shape[0] * training_ratio)
    train_x, train_y = x[: train_counts, :], y[: train_counts]
    test_x, test_y = x[train_counts, :], y[train_counts:]
    return train_x, train_y, test_x, test_y

class L1Regularation(object):
    def __init__(self, alpha=0.1):
        self.alpha = alpha

    def __call__(self, w):
        reg_loss = np.sum(np.fabs(w))
        return reg_loss * self.alpha

    def grad(self, w):
        return self.alpha * np.sign(w)

class L2Regularation(object):
    def __init__(self, alpha=0.1):
        self.alpha = alpha

    def __call__(self, w):
        reg_loss = w.T.dot(w)
        return self.alpha * reg_loss

    def grad(self, w):
        return 2.0 * self.alpha * w

class LinearRegression(object):
    def __init__(self, learning_rate=0.01, n_iterations=2000, solver='sgd', regularization=None):
        """
        :param learning_rate:
        :param n_iterations:
        :param solver: optimize algorithm: [sgd, lsm] least square method/stochastic gradient descent
        :param regularization:
        """
        self.learning_rate = learning_rate
        self.n_iterations = n_iterations
        self.solver = solver
        if regularization is None:
            self.regularization = lambda x: 0
            self.regularization.grad = lambda x: 0
        else:
            self.regularization = regularization
        assert self.solver in ['sgd', 'lsm']

    def init_weights(self, n_features):
        self.w = np.random.normal(size=(n_features, 1))

    def fit(self, X, y):
        """
        :param X: (m, n)
        :param y: (m, 1)
        :return:
        """
        training_errors = list()
        y = np.reshape(y, (-1, 1))
        assert 2 == len(X.shape) and 2 == len(y.shape)
        self.init_weights(n_features=X.shape[1])
        if self.solver == 'sgd':
            for idx in range(1, 1 + self.n_iterations):
                y_pred = X.dot(self.w)
                training_loss = np.mean(0.5 * (y_pred - y) ** 2) + self.regularization(self.w)
                training_errors.append(training_loss)
                grad = X.T.dot(y_pred - y) + self.regularization.grad(self.w)
                self.w = self.w - self.learning_rate * grad
                if idx % 50 == 0:
                    print('training loss=%.4f' % training_loss)
        elif self.solver == 'lsm':
            X, y = np.matrix(X), np.matrix(y)
            if abs(np.linalg.det(X.T.dot(X))) < 1e-8:
                print('the matrix was irreversible.')
                return
            X_T_X_I = (X.T.dot(X)).I
            X_T_Y = X.T.dot(y)
            self.w = X_T_X_I.dot(X_T_Y)
        else:
            raise ValueError('')

    def predict(self, X):
        X = np.matrix(X)
        return X.dot(self.w)

    def coef_(self):
        return self.w.flatten()

if __name__ == '__main__':
    X, y = make_regression(n_samples=100, n_features=10, noise=20)
    # train_x, train_y, test_x, test_y = split_train_test(X, y)
    model = LinearRegression(regularization =L2Regularation())
    # model.fit(train_x, train_y)

    model.fit(X, y)


import openseespy.opensees as ops
from math import pi,ceil
import numpy as np
from numpy import cos,cosh
import matplotlib.pyplot as plt
from PyPonding.structures import wf,wf_shapes

# Define units
inch = 1.0
kip = 1.0
lb  = kip/1000.0
ft  = 12.0*inch
in_per_ft = inch/ft
ksi = kip/inch**2
psf = lb/ft**2
pcf = psf/ft
mm  = 1/25.4*inch
m   = 1000*mm
kN  = 1/4.448222*kip
kNm = kN*m

# Input parameters
Fy      = 50.0*ksi
E       = 29000.0*ksi
Hk      = 1.0e-4*E
TW      = 10*ft
shape_name = 'W14X22';
L       = 40*ft
qD      = 10.0*psf
gamma   = 62.4*pcf

# Lookup shape data
shape_data = wf_shapes[shape_name]
d  = shape_data['d']*inch
bf = shape_data['bf']*inch
tf = shape_data['tf']*inch
tw = shape_data['tw']*inch

# Create wide-flange object
wf_section = wf(d,tw,bf,tf,Fy,E,Hk)

# Set additional properties
wf_section.L        = L
wf_section.gamma    = gamma
wf_section.TW       = TW
wf_section.zi       = 0.0*inch
wf_section.zj       = 0.0*inch
wf_section.wD       = qD*TW # Dead load per length

# Set OpenSees analysis options
wf_section.material_type = 'Elastic'
wf_section.num_steps     = 2000
wf_section.max_volume    = 249450
wf_section.vol_tol       = wf_section.max_volume/wf_section.num_steps/10000.
wf_section.extra_results = True

# Run OpenSees analyses
(data_volume,data_height,extra_results) = wf_section.perform_OpenSees_analysis();
x_OPS = extra_results[0]
y_OPS = extra_results[1]
M_OPS = extra_results[2]

# Compute Closed-form Results
C  = wf_section.C()
I  = wf_section.Iz()
wi = (qD + gamma*(2*inch))*TW

x  = np.linspace(0.0, L, num=100)

y1 = -wi*x*(L**3-2*L*x**2+x**3)/(24*E*I)
M1 = 0.5*wi*x*(L-x)

fact = pi*C**0.25
y2 = -wi/(2*gamma*TW)*( (cos(fact*(0.5-x/L))/cos(fact*0.5) - 1) - (1 - cosh(fact*(0.5-x/L))/cosh(fact*0.5)) )
M2 = (wi*L**2)/(2*pi**2*C**0.5)*( cos(fact*(0.5-x/L))/cos(0.5*fact) - cosh(fact*(0.5-x/L))/cosh(0.5*fact) )

# Plot Results
plt.rc('text',usetex=True)
plt.rc('font',family='serif')
plt.rc('axes',labelsize=8)
plt.rc('axes',titlesize=8)
plt.rc('legend',fontsize=8)
plt.rc('xtick',labelsize=8)
plt.rc('ytick',labelsize=8)

fig = plt.figure(figsize=(7.00,2.50))
ax = fig.add_axes([0.09,0.21,0.40,0.75])
line2, = plt.plot(x/m,y2/mm,'k-')
line3, = plt.plot(x/m,y1/mm,'k--')
line1, = plt.plot(x_OPS/m,y_OPS/mm,'ko')
plt.legend((line1, line2, line3), ('Numerical Results', 'Closed-form Solution', 'No Ponding Effect'),frameon=False)
plt.xlabel('Position Along Length of Beam (m)\n(a)')
plt.ylabel('Displacement (mm)')
plt.xlim(0,L/m)
plt.ylim(-100,0)

ax = fig.add_axes([0.59,0.21,0.40,0.75])
line2, = plt.plot(x/m,M2/kNm,'k-')
line3, = plt.plot(x/m,M1/kNm,'k--')
line1, = plt.plot(x_OPS/m,M_OPS/kNm,'ko')
plt.legend((line1, line2, line3), ('Numerical Results', 'Closed-form Solution', 'No Ponding Effect'),frameon=False)
plt.xlabel('Position Along Length of Beam (m)\n(b)')
plt.ylabel('Bending Moment (kN-m)')
plt.xlim(0,L/m)
plt.ylim(0,100)
plt.savefig('Example_Defl_and_Moment.png',dpi=300)
plt.savefig('Example_Defl_and_Moment.pdf')

plt.show()


from math import floor, ceil
import numpy as np
from scipy import ndimage
from scipy.fftpack import dct
import cv2
import time

def dss(img1, img2, sigma=1.55, C=(1000, 300)):
    """
    DSS DCT Subband Similarity index for measuring image quality
    DSS = DSS_INDEX(IMG1, IMG2) calculates the DCT Subband Similarity (DSS)
    score for image IMG1, with the image IMG2 as the reference. IMG1 and
    IMG2 should be 2D grayscale images, and must be of the same size.
    DSS = DSS_INDEX(IMG1, IMG2, SIGMA, C) calculates the DSS score
    with control over parameters of the computation. Parameters include:
    sigma - Specifies the standard deviation of the Gaussian that
            determines the proportion between the weight given to low
            spatial frequencies and to high spatial frequencies.
            Default value: sigma = 1.55
    C     - Specifies constants in the DSS subband similarity equations
            (see the reference paper below). C should be a vector of
            size [1 2] where the first element in C is for the DC
            equation and the second element in C is for the AC equation.
            Default value: C = [1000 300]
    This function is an implementation of the algorithm described in the
    following paper:
        Amnon Balanov, Arik Schwartz, Yair Moshe, and Nimrod Peleg,
        "Image Quality Assessment based on DCT Subband Similarity," 22nd
        IEEE International Conference on Image PRocessing (ICIP 2015).
    Example
    ---------
    This example shows how to compute DSS score for a noisy image given
    the original reference image.
    img2 = imread('cameraman.tif');
    img1 = imnoise(img2, 'gaussian', 0, 0.001);
    subplot(1,2,1); imshow(img2); title('Reference Image');
    subplot(1,2,2); imshow(img1); title('Noisy Image');
    dss = dss_index(img1,img2);
    fprintf('The DSS score is 0.4f\n',dss);
    Version 1.00
    Copyright(c) 2015, Yair Moshe
    Signal and Image Processing Laboratory (SIPL)
    Department of Electrical Engineering
    Technion - Israel Institute of Technology
    Technion City, Haifa 32000, Israel
    Tel: +(972)4-8294746
    e-mail: yair@ee.technion.ac.il
    WWW: sipl.technion.ac.il
    """

    # Parse inputs
    if img1.ndim != 2:
        raise TypeError("Images must be greyscale")
    if img2.shape != img2.shape:
        raise ValueError("Image 1 and 2 must be of same size")
    try:
        float(sigma)
    except Exception:
        raise TypeError("Sigma must be a scalar")
    if not isinstance(C, tuple):
        raise TypeError("C must be a tuple")

    # Compute DSS
    # Crop images size to the closest multiplication of 8
    nRows, nCols = img1.shape
    nRows = 8*floor(nRows/8)
    nCols = 8*floor(nCols/8)

    img1 = img1[:nRows, :nCols]
    img2 = img2[:nRows, :nCols]

    # Channel decomposition for both images by 8x8 2D DCT
    img1Decomp = dct_decomp(img1)
    img2Decomp = dct_decomp(img2)
    # Create a Gaussian window that will be used to weight subbands scores
    r = np.arange(1, 9, 1)
    X,Y = np.meshgrid(r, r)
    distance = np.sqrt((X-0.5)**2 + (Y-0.5)**2)
    w = np.exp(-((distance**2)/(2*sigma**2))).real

    # Compute similarity between each subband in img1 and img2
    subbandSimilarity = np.zeros((8, 8))
    smallWeightThresh = 1e-2
    for m in range(8):
        for n in range(8):
            # Skip subbands with very small weight
            if(w[m,n] < smallWeightThresh):
                w[m,n] = 0
                continue

            subbandSimilarity[m,n] = subband_similarity(
                img1Decomp[m::8, n::8],
                img2Decomp[m::8, n::8],
                m, n, C)

    # Weight subbands similarity scores
    dss = np.sum(np.sum(subbandSimilarity * (w/np.sum(w))))
    #np.savetxt('img_python.txt', sortedVarLeftTerm, fmt="%.5f", delimiter=",", newline="\n")
    return dss

# Channel decomposition for an image by 8x8 2D DCT
def dct_decomp(img):
    nRows, nCols = img.shape
    D = dctmtx(8)
    doubleImg = img.astype(np.float64)
    decomp = np.zeros(img.shape)
    for blockNumInRow in range(nRows//8):
        for blockNumInColumn in range(nCols//8):
            curBlock = doubleImg[0 + 8*(blockNumInRow) : 8 + 8*(blockNumInRow), 0 + 8*(blockNumInColumn):8 + 8*(blockNumInColumn)]
            decomp[0 + 8*(blockNumInRow) : 8 + 8*(blockNumInRow), 0 + 8*(blockNumInColumn):8 + 8*(blockNumInColumn)] = np.matmul(np.matmul(D,curBlock), D.transpose())
    return decomp

# Discrete cosine transform matrix by matlab
# https://fr.mathworks.com/help/images/discrete-cosine-transform.html#f21-16137
def dctmtx(N):
    p, q = np.ogrid[1:N, 1:2*N:2]
    return np.concatenate((np.sqrt(1/N)*np.ones((1,N)) , np.sqrt(2/N) * np.cos(np.pi/(2*N) * p * q)), axis=0)

def matlab_style_gauss2D(shape=(3,3),sigma=0.5):
    """
    2D gaussian mask - should give the same result as MATLAB's
    fspecial('gaussian',[shape],[sigma])
    """
    m,n = [(ss-1.)/2. for ss in shape]
    y,x = np.ogrid[-m:m+1,-n:n+1]
    h = np.exp( -(x*x + y*y) / (2.*sigma*sigma) )
    h[ h < np.finfo(h.dtype).eps*h.max() ] = 0
    sumh = h.sum()
    if sumh != 0:
        h /= sumh
    return h

# Compute similarity between a subband in img1Subband and img2Subband
def subband_similarity(img1Subband, img2Subband, m, n, Cs):
    size = 3 # constant
    sigma = 1.5 # constant
    percentile = 0.05 # constant

    if((m == 0) and (n == 0)):
        C = Cs[0] # DC
    else:
        C = Cs[1] # AC
    # Compute local variance
    window = matlab_style_gauss2D(shape=(size,size), sigma=sigma)
    mu1 = ndimage.convolve(img1Subband, window, mode="constant")
    mu2 = ndimage.convolve(img2Subband, window, mode="constant")
    sigma1_sq = ndimage.convolve(img1Subband*img1Subband, window, mode="constant") - mu1*mu1
    sigma2_sq = ndimage.convolve(img2Subband*img2Subband, window, mode="constant") - mu2*mu2
    sigma12 = ndimage.convolve(img1Subband*img2Subband, window, mode="constant") - mu1*mu2
    sigma1_sq[sigma1_sq < 0] = 0
    sigma2_sq[sigma2_sq < 0] = 0
    varLeftTerm = (2*np.sqrt(sigma1_sq * sigma2_sq) + C) / (sigma1_sq + sigma2_sq + C)
    # Spatial pooling of worst scores
    percentileIndex = round(percentile * (varLeftTerm.size))
    sortedVarLeftTerm = np.sort(varLeftTerm.flatten())
    similarity = np.mean(sortedVarLeftTerm[:percentileIndex])
    # For DC, multiply by a right term
    if ((m == 0) and (n == 0)):
        varRightTerm = ((sigma12 + C) / (np.sqrt(sigma1_sq * sigma2_sq) + C))
        sortedVarRightTerm = np.sort(varRightTerm.flatten())
        simRightTerm = np.mean(sortedVarRightTerm[:percentileIndex])
        similarity = similarity * simRightTerm
    return similarity


import numpy as np
import matplotlib.pyplot as plt

def pdf(costh, P_mu):
    # define our probability density function
    return 0.5 * (1.0 - 1.0 / 3.0 * P_mu * costh)

def acc_rej(N_measurements, P_mu):
    x = np.random.uniform(-1.0, 1.0, size=N_measurements)

    x_axis = np.linspace(-1.0,1.0, 1000)
    fmax= np.amax(pdf(x_axis,P_mu)) #find the maximum of the function

    u = np.random.uniform(0, fmax, size= N_measurements)

    # we use a mask in order to reject the values we don't want
    data_pdf = x[u < pdf(x,P_mu)]
    return data_pdf

N_measurements=10000000

for P_mu in np.arange(-1.,1.2,0.2):
    data_pdf = acc_rej(N_measurements,P_mu)
    mean = np.mean(data_pdf)
    P_mu_est=-9.*mean
    print(P_mu, abs(P_mu-P_mu_est))
    plt.plot(P_mu, abs(P_mu-P_mu_est), ".")

plt.xlabel(r"$P_\mu$")
plt.ylabel(r'$|P_\mu - \hat{P_\mu}|$')

# plt.savefig(r"C:\Users\Aleix López\Desktop\acc_rej.jpg")
plt.show()

Projects/Probability and Monte Carlo Techniques/_3_dependency.py