import numpy as np
import re, pprint, scipy, scipy.linalg
from numpy import linalg as LA
from numpy.linalg import inv
from scipy.linalg import hilbert, lu
from scipy.interpolate import lagrange
from fractions import Fraction

# get the shape of the data e.g. [10][5]
def getShape(data_str):
    count_semi = 0

    first_semi = data_str.find(';')                 # find first ';' in the line
    pos_semi = data_str[:first_semi].count(',')     # count amount of ',' from start of line to ';'
    count_semi += data_str.count(';')               # count amount of ';' in file

    return count_semi, pos_semi

# push contents of file to matrix
def pushToMatrix(data_str,i,j):
    current_digit = re.findall("[-+]?[.]?[\d]+(?:,\d\d\d)*[\.]?\d*(?:[eE][-+]?\d+)?", data_str)
    x = np.asarray(current_digit)
    ans = np.split(x,i)

    m = np.asmatrix(ans).astype(np.float64)
    return m

# convert matrix to comma-semi-colon-format
# print message to terminal & write output to file
def exportTomFormat(m):
    s = ""
    i,j = m.shape
    print "Matrix shape: [" + str(i) +" "+ str(j) +"]\n"
    for row in range(0,i):
        for col in range(0,j):
            s += str(m[row,col])
            if col == j-1:
                s
            else:
                s += ","

        s += ";"

    # write output to a file (will create file if not existing)
    # NOTE: does NOT append to file - will overwrite contents
    f = open('output_file.txt', 'w')
    f.write(s)  # python will convert \n to os.linesep
    f.close()

    print "- Written to 'output.txt' -\n\n**************************************\n"

# # sum contents of matrix
# def addMatrixElement(m):
#     mat = m.flatten().sum()
#     return mat

# sum each row
def sumOfRow(m):
    m = np.asmatrix(m)
    i,j = m.shape
    arr = []

    for row in m:
        r = 0
        r = np.sum(row)
        arr.append(r)

    return arr

# get euclidean norm of matrix
def vectorNorm(m):
    mat = m.flatten()
    norm_matrix = LA.norm(mat)                  # Euclidean norm
    return norm_matrix

# using numpy library for cond and infinity norm
def condNumberNumpy(m):
    inf_norm_matrix = LA.cond(m, np.inf)        # infinity norm inf = max(sum(abs(x), axis=1))
    return inf_norm_matrix

# own cond number fuction
# needs to be passed a matrix
def condNumber(m):
    matrix_total = 0
    inverse_matrix_total = 0

    # matrix
    for i in m:
        print "cond of row: " + str(abs(i).sum())
        if matrix_total < abs(i).sum():
            matrix_total = abs(i).sum()
    print "The largest: [" + str(matrix_total) + "]\n"

    # inverse of matrix
    inv_m = inv(m)
    for i in inv_m:
        print "cond of row: " + str(abs(i).sum())
        if inverse_matrix_total < abs(i).sum():
            inverse_matrix_total = abs(i).sum()
    print "The largest: [" + str(inverse_matrix_total) + "]\n"

    return matrix_total * inverse_matrix_total

# convert matrix elements to fractions
def convertToFractionMatrix(decimal_matrix):
    two_d_fract_array = []
    x,y = decimal_matrix.shape
    for h in decimal_matrix:
        for i in h:
            two_d_fract_array.append(Fraction(str(i)))
    fract_matrix = np.asmatrix(np.split(np.asarray(two_d_fract_array),x)) # reshape the matrix
    return fract_matrix

# create Hilbert Matrix return matrix -> fractions
# Not great - better to use convertToFractionMatrix() after calculation
def createHilbertFractionMatrix(sq_size):
    fract_hill =[]
    hill = hilbert(sq_size)                    # for decimals just use this line (from library)
    for h in hill:
        for i in h:
            fract_hill.append(Fraction(str(i)))

    reshaped_array = np.split(np.asarray(fract_hill),sq_size)
    print "The Hilbert Matrix shape: " + str(np.asarray(reshaped_array).shape) + "\n"
    return np.asmatrix(reshaped_array)

# def gausselim(A,B):
#     """
#     Solve Ax = B using Gaussian elimination and LU decomposition.
#     A = LU   decompose A into lower and upper triangular matrices
#     LUx = B  substitute into original equation for A
#     Let y = Ux and solve:
#     Ly = B --> y = (L^-1)B  solve for y using "forward" substitution
#     Ux = y --> x = (U^-1)y  solve for x using "backward" substitution
#     :param A: coefficients in Ax = B
#     :type A: numpy.ndarray of size (m, n)
#     :param B: dependent variable in Ax = B
#     :type B: numpy.ndarray of size (m, 1)
#     """
#     # LU decomposition with pivot
#     pl, u = lu(A, permute_l=True)
#     # forward substitution to solve for Ly = B
#     y = np.zeros(B.size)
#     for m, b in enumerate(B.flatten()):
#         y[m] = b
#         # skip for loop if m == 0
#         if m:
#             for n in xrange(m):
#                 y[m] -= y[n] * pl[m,n]
#         y[m] /= pl[m, m]

#     # backward substitution to solve for y = Ux
#     x = np.zeros(B.size)
#     lastidx = B.size - 1  # last index
#     for midx in xrange(B.size):
#         m = B.size - 1 - midx  # backwards index
#         x[m] = y[m]
#         if midx:
#             for nidx in xrange(midx):
#                 n = B.size - 1  - nidx
#                 x[m] -= x[n] * u[m,n]
#         x[m] /= u[m, m]
#     return x

# get permutation from LU
def getPermutation(P):
    perm = []
    for i in P:
        for j in i:
            if j == 1:
                 perm.append(i.tolist().index(j)+1)

    return perm

# three column vectors from tridiagonal matrix
def getTridiagonal(m):
    print m
    x,y = m.shape
    vector_one = []
    vector_two = []
    vector_three = []
    i = 0

    while i < y and i < x:

        vector_two.append(m[i][i])
        if i < x-1:
            vector_three.append(m[i+1][i])
        if i < y-1:
            vector_one.append(m[i][i+1])
        i+=1

    return np.asmatrix(vector_one).T, np.asmatrix(vector_two).T, np.asmatrix(vector_three).T

def countNumLen(n):
    count=0
    while(n>0):
        count=count+1
        n=n//10

if __name__ == '__main__':
    f = open('read.txt', 'r').read().strip()    # save file to string

    # print "**************************************\n"

    # x,y = getShape(f)
    # print "Data shape: ["+ str(x) +"]["+ str(y) +"]\n"
    # print "**************************************\n"

    # read_matrix = pushToMatrix(f,x,y)
    # print "The data provided as a matrix: \n"+str(read_matrix)+"\n"
    # print "**************************************\n"

    # sum_matrix = addMatrixElement(read_matrix)
    # print "Elements added together: ["+str(sum_matrix)+"]\n"
    # print "**************************************\n"

    # norm_matrix = vectorNorm(read_matrix)
    # print "Vector Norm: ["+str(norm_matrix)+"]\n"
    # print "**************************************\n"

    # cond_norm_matrix = condNumberNumpy(read_matrix)
    # print "Condition number: ["+str(cond_norm_matrix)+"]\n"
    # print "**************************************\n"

    # print "Condition number extra input test: [[.01, 98796],[.0001, 7896]]\n"
    # print "Cond = " + str(condNumber(np.asmatrix([[.01, 98796],[.0001, 7896]]))) + "\n"
    # print "**************************************\n"

    # own_cond_norm_matrix = condNumber(read_matrix)
    # print "Own condition number: ["+str(own_cond_norm_matrix)+"]\n"
    # print "**************************************\n"

    # hillbert_matrix = createHilbertFractionMatrix(3)
    # print "Hilbert Matrix fractions: \n" + str(hillbert_matrix) + "\n"
    # print "**************************************\n"

    # sum_hilbert = addMatrixElement(hillbert_matrix)
    # print "Sum of Hilbert Matrix fractions: [" + str(sum_hilbert) + "]\n"
    # print "**************************************\n"

    # print "Multiply Hilbert by inverse\n"
    # print np.round(np.dot(hilbert(4),inv(hilbert(4))))
    # print
    # print "**************************************\n"

    # print "LU Decomposition: \n"
    # LU_array = np.asarray([[1,2,3],[4,5,6],[7,8,9]])
    # b = [[6,15,24]]

    # # P = permutation matrix
    # P, L, U = scipy.linalg.lu(LU_array, permute_l=False, overwrite_a=False, check_finite=True)

    # print "Permutation Matrix: \n" + str(P) +"\n"
    # print "Permutation : " + str(getPermutation(P)) + "\n"

    # # L = lower triangle
    # print "Lower triangle: \n" + str(L) +"\n"

    # # U = upper triangle
    # print "Upper triangle: \n" + str(U) +"\n"

    # bb = P*b
    # print "bb: \n" + str(np.asmatrix(bb))

    # y = np.linalg.lstsq(L,bb)
    # print "y: \n" + str(np.asmatrix(y))
    # print "**************************************\n"

    # top_diagonal, main_diagonal, bottom_diagonal = getTridiagonal(LU_array)
    # print
    # print "Tridiagonal of Matrix - three column vectors: \n\n" + str(top_diagonal) + "\n\n" + str(main_diagonal) + "\n\n" + str(bottom_diagonal) +"\n"
    # print "**************************************\n"

    # print main_diagonal.shape
    # print bottom_diagonal.shape
    # # print np.dot(B,c)

    # print
    # print main_diagonal.shape
    # print bottom_diagonal.shape
    # print np.cross(main_diagonal.T, bottom_diagonal.T)
    # print
    # print "**************************************\n"

    # exportTomFormat(LU_array)

    # print "**************************************\n"
    # print "Cholesky: \n"

    # chol_matrix = [[4, 2, 1, 1],[2, 5, 0, 3],[1, 0, 7, 2],[1, 3, 2, 8]]
    # print np.matrix(chol_matrix)
    # print
    # # b = [[8,10,10,14]]
    # # print b
    # # print
    # c = np.linalg.cholesky(chol_matrix)
    # print c

    # print "\n**************************************\n"
    # print "Testing Hilbert: \n"
    # print condNumberNumpy(hilbert(10))
    # print LA.norm(hilbert(10), np.inf)
    # print "\n**************************************\n"
    # print "LaGrange Polynomial Interpolation: \n"
    # x = np.array(read_matrix.flatten())
    # print x
    # y = np.array(read_matrix.flatten())
    # poly = lagrange(x, y)
    # print poly
    # print "\n**************************************\n"
    # LU = np.asarray([[1,2,3],[4,5,6],[7,8,9]])
    # print condNumber(hilbert(7))

    for i in range(1,10):
        print "Hilbert = " + str(i)
        A = hilbert(i)
        print "the hilbert matrix: \n"+str(A)+"\n"
        b = sumOfRow(hilbert(i))
        print "b: "
        print b
        x = np.linalg.lstsq(A,b)
        print "AX = b: "
        print x
        print


import numpy as np
import math

# angle between two vectors
def vector_vector_angle(v1, v2):
    a1 = np.arctan2(v1[1], v1[0])
    a2 = np.arctan2(v2[1], v2[0])
    sign = 1 if a1 > a2 else -1
    angle = a1 - a2
    K = -sign * np.pi * 2
    if np.abs(K + angle) < np.abs(angle):
        angle += K
    return angle

# pair of points on lines p1,p2 and p3,p4 closest to each other
def line_line_closest(p1,p2,p3,p4,check=False):
    p1 = np.asarray(p1)
    p2 = np.asarray(p2)
    p3 = np.asarray(p3)
    p4 = np.asarray(p4)

    p13 = p1 - p3
    p43 = p4 - p3
    p21 = p2 - p1

    d1343 = np.dot(p13, p43)
    d4321 = np.dot(p43, p21)
    d1321 = np.dot(p13, p21)
    d4343 = np.dot(p43, p43)
    d2121 = np.dot(p21, p21)

    denom = d2121 * d4343 - d4321 * d4321
    if check and abs(denom) == 0:
        return None
    numer = d1343 * d4321 - d1321 * d4343

    mua = numer / denom
    mub = (d1343 + d4321 * (mua)) / d4343

    if check:
        if mua < 0 or mua > 1 or mub < 0 or mub > 1:
            return None

    pa = p1 + mua * p21
    pb = p3 + mub * p43

    return pa, pb

# point on line p1,p2 closest to point p3
def line_point_closest(p1, p2, p3):
    p1 = np.asarray(p1)
    p2 = np.asarray(p2)
    p3 = np.asarray(p3)
    u = ((p3 - p1)*(p2 - p1)).sum() / np.square(np.linalg.norm(p2 - p1))
    return p1 + u * (p2 - p1)

# point on ray p1->p2 closest to point p3
def ray_point_closest(p1, p2, p3):
    p1 = np.asarray(p1)
    p2 = np.asarray(p2)
    p3 = np.asarray(p3)
    u = ((p3 - p1)*(p2 - p1)).sum() / np.square(np.linalg.norm(p2 - p1))
    u = max(u, 0)
    return p1 + u * (p2 - p1)

# numpy multiplication order is "reversed" from openFrameworks,
# or the matrices can be transposed: A*B = B^T*A

# from 0/0 to width/height
# to -1,+1 to +1/-1 (y axis is flipped)
# note that depth is not in world units, but normalized by z_near/z_far
# designed for multiple points
def screen_to_world(screen, depth, viewport, extrinsics, camera_matrix):
    principal_point = camera_matrix[:2,2]
    screen -= principal_point - (viewport - 1) / 2
    n = len(screen)
    camera = np.array([
        2 * screen[:,0] / viewport[0] - 1,
        1 - 2 * screen[:,1] / viewport[1],
        [depth] * n
    ])
    camera = camera.T
    return camera_to_world(camera, extrinsics, viewport, camera_matrix)

def to_homogenous(points):
    ones = np.ones((len(points), 1), points.dtype)
    return np.hstack((points, ones))

def from_homogenous(xyzw):
    return xyzw[:,:3] / xyzw[:,3].reshape(-1,1)

def camera_to_world(camera, extrinsics, viewport, camera_matrix):
    mvp_matrix = get_model_view_projection_matrix(extrinsics, viewport, camera_matrix)
    world = np.matmul(to_homogenous(camera), np.linalg.inv(mvp_matrix))
    return from_homogenous(world)

def get_model_view_projection_matrix(extrinsics, viewport, camera_matrix):
    return np.matmul(get_model_view_matrix(extrinsics), get_projection_matrix(viewport, camera_matrix))

def get_model_view_matrix(extrinsics):
    return np.linalg.inv(extrinsics.T)

def perspective(fovy, aspect, z_near, z_far):
    tan_half_fovy = math.tan(fovy / 2)
    result = np.zeros((4,4))
    result[0,0] = 1 / (aspect * tan_half_fovy)
    result[1,1] = 1 / tan_half_fovy
    result[2,3] = -1
    result[2,2] = -(z_far + z_near) / (z_far - z_near)
    result[3,2] = -(2 * z_far * z_near) / (z_far - z_near)
    return result

def get_projection_matrix(viewport, camera_matrix, z_near=1, z_far=1000):
    aspect = viewport[0] / viewport[1]
    fovy = 2 * math.atan(viewport[1] / (2 * camera_matrix[1,1]))
    return perspective(fovy, aspect, z_near, z_far)

def vec_to_extrinsics(rvec,tvec):
    R, jacobian = cv2.Rodrigues(np.mat(rvec))
    arr = np.array([[R[0,0],R[0,1],R[0,2],tvec[0]],
                    [R[1,0],R[1,1],R[1,2],tvec[1]],
                    [R[2,0],R[2,1],R[2,2],tvec[2]],
                    [0,0,0,1]])
    mat = np.mat(arr)
    extrinsics = np.transpose(np.linalg.inv(mat))
    return extrinsics


from formulas import RelativeDiffusivity
import math
import json
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.colors import BoundaryNorm
from matplotlib.ticker import MaxNLocator

f = open('diffusivity.json','r')
data = json.loads(f.read())
actual = np.asarray(data)

T = [298]
P = actual[:,0]
predicted = np.zeros((len(T),len(P)))
for i in range(0,len(T)):
    for j in range(0,len(P)):
        predicted[i][j] = RelativeDiffusivity(T[i],P[j])

E1 = np.zeros(len(P))
E2 = np.zeros(len(P))
mean = np.mean(actual[:,1])
for i in range(0, len(predicted[0])):
    E1[i] = math.pow(actual[i][1] - predicted[0][i],2)
    E2[i] = math.pow(actual[i][1] - mean,2)
sumE1 = np.sum(E1)
sumE2 = np.sum(E2)
R2 = 1-sumE1/sumE2
print(R2)

assert R2 == 0.997460771783034, 'R2 value does not match expected'

fig = plt.figure(figsize=(9,5))
plt.axes([0.1,0.1,0.8,0.8], xlabel='Pressure - P (bar)', ylabel='Relative Diffusivity - D')
plt.plot(P, actual[:,1], 'gs', P, predicted[0], 'r^')
plt.legend(['Observed', f'Model $R^2 = {R2:.5g}$', 'best'])
plt.show()

# T = [298,338,373,523,573,623,673]
# P = np.linspace(0,4000,200)
# R = np.zeros((len(T),len(P)))
# for i in range(0,len(T)):
#     for j in range(0,len(P)):
#         C = U4 + U5/(U6 + T[i])
#         B = U7 + U8/T[i] + U9*T[i]
#         D1000 = U1*math.exp(U2*T[i] + U3*T[i]**2)
#         try:
#             D = D1000 + C*math.log((B + P[j])/(B + 1000))
#         except:
#             D = 0
#         R[i][j] = D

# plt.figure()
# plt.plot(P, R[0], 'r', P, R[1], 'b', P, R[2], 'g', P, R[3], 'r--', P, R[4], 'b--', P, R[5], 'g--', P, R[6], 'k')
# plt.legend(T)
# plt.show()

# print(f'Relative Diffusivity D = {D}') #78.38066291198618 @P=100 T=298.15


# -*- coding: utf-8 -*-
"""
Created on Sun Mar 25 06:45:12 2018

@author: James
"""

import numpy as np
import matplotlib.pyplot as plt

# Show the difference in distribution across different std
samples_std1 = np.random.normal(20, 1, 100000)
samples_std3 = np.random.normal(20, 3, 100000)
samples_std10 = np.random.normal(20, 10, 100000)

# Make histograms
plt.hist(samples_std1, density=True, histtype="step", bins=100)
plt.hist(samples_std3, density=True, histtype="step", bins=100)
plt.hist(samples_std10, density=True, histtype="step", bins=100)
plt.legend(("std = 1", "std = 3", "std = 10"))
plt.ylim(-0.01, 0.42)
plt.title("Visualising std Differences")
plt.show()


import numpy as np

a = np.array([[3, 0.841, -0.841],
              [2, -1250, 0],
              [-2.71, -2.71, 20]])   #gera um array aleatorio(com numeros float e negativos
b = np.array([[1.951],
              [-624.25],
              [-7.809]])

#função pro metodo de gauss:
a = a.astype('float')   #transforma a matriz em float, pois como int daria erro de arredondamento
b = b.astype('float')
##elinação:
###garantir pivos n nulos:
tam = np.size(a, 0) #Numero de elementos na coluna 0
len = len(a[0][:])
print(f'{a}\n{b}')
for i in range(tam):    #busca pivos = 0 e soma alguma linha com eles
    if a[i][i] == 0:
        for c in range(tam):    #encontra uma linha cujo elemento na coluna do pivo[i][i] != 0
            if a[c][i] != 0:
                a[i][:] = a[i][:] + a[c][:]
                b[i][:] = b[i][:] + b[c][:]
                break
###Eliminar td abaixo da diagonal principal mantendo as correlações
for k in range(len):    #coluna a ser operada
    for i in range(k + 1, tam):  # linha a ser corrigida
        base_a = a[k][:]    #linha anterior
        base_b = b[k][:]
        if a[i][k] != 0:
            m = a[i][k]/base_a[k]   #numero para multiplicar e zerar o elemento abaixo
            a[i][:] = a[i][:] - m*base_a    #opera a linha
            b[i][:] = b[i][:] - m * base_b  #opera a linha
print(f'{a}\n{b}')


"""hydrogen.py:
this file contains the implementation of the
real valued hydrogen wave functions.
"""

__author__ = 'Miguel Angel Avila Torres'
__copyright__ = 'Copyright 2021, hydro-wave-visualizer'
__credits__ = ['Miguel Angel Avila Torres']
__license__ = 'The Legacy License'
__version__ = '1.0.0'
__maintainer__ = f'{__author__}'
__email__ = None
__status__ = 'Release'

import numpy as np

a_0: float = 5.29177210903E-11  # First Bohr Radius

def hydrogen_1s(r: float, theta: float = 0, phi: float = 0):
    return np.exp(-r/a_0) / (np.sqrt(np.pi)*a_0**(3/2))

def hydrogen_2s(r: float, theta: float = 0, phi: float = 0):
    return (2 - (r / a_0)) * np.exp(-r/(2*a_0)) / (4*np.sqrt(2*np.pi)*a_0**(3 / 2))

def hydrogen_2p(r: float, theta: float = 0, phi: float = 0):
    return ((r/a_0)*np.exp(-r/(2*a_0))*np.cos(theta)) / (4*np.sqrt(2*np.pi)*a_0**(3 / 2))

def hydrogen_3s(r: float, theta: float = 0, phi: float = 0):
    return (27 - 18*(r/a_0) + 2*((r**2)/(a_0**2))) * (np.exp(-r/(3*a_0))) / (81*np.sqrt(3*np.pi)*a_0**(3/2))

def hydrogen_3p(r: float, theta: float = 0, phi: float = 0):
    return np.sqrt(2) * (6 - (r/a_0)) * (r/a_0) * np.exp(-r/(3*a_0)) * np.cos(theta) / (81*np.sqrt(np.pi)*a_0**(3/2))

def hydrogen_3d(r: float, theta: float = 0, phi: float = 0):
    return ((r**2)/(a_0**2)) * np.exp(-r/(3*a_0)) * (3*(np.cos(theta)**2) - 1) / (81*np.sqrt(6*np.pi)*a_0**(3/2))

def squared_h1s(r: float, theta: float, phi: float):
    return hydrogen_1s(r, theta, phi) ** 2

def squared_h2s(r: float, theta: float, phi: float):
    return hydrogen_2s(r, theta, phi) ** 2

def squared_h2p(r: float, theta: float, phi: float):
    return hydrogen_2p(r, theta, phi) ** 2

def squared_h3s(r: float, theta: float, phi: float):
    return hydrogen_3s(r, theta, phi) ** 2

def squared_h3p(r: float, theta: float, phi: float):
    return hydrogen_3p(r, theta, phi) ** 2

def squared_h3d(r: float, theta: float, phi: float):
    return hydrogen_3d(r, theta, phi) ** 2


from IPython.display import display
import sympy

sympy.var('offset, rho, h, z, z1, z2')

display(sympy.simplify(sympy.integrate(1, (z, -h/2+offset, h/2+offset))))

display(sympy.simplify(sympy.integrate(1, (z, z1, z2))))

display(sympy.simplify(sympy.integrate(z**2, (z, -h/2+offset, h/2+offset))))

display(sympy.simplify(sympy.integrate(z**2, (z, z1, z2))))


#!/usr/bin/env python
'''Module for integer sequence generation and related conditional tests.'''

import math
import itertools as it
import random
import collections
import numpy as np

## SEQUENCE GENERATORS
def prime_stream():
    '''Yield the next prime number starting with 2.'''
    start = 13
    c = 2*3*5*7*11
    yield 2; yield 3; yield 5; yield 7; yield 11

    sieve = {}
    mod = frozenset(i for i in range(c) if math.gcd(i, c) == 1)
    skip = tuple([1 if n % c in mod else 0 for n in range(start, start+c, 2)])

    for n in it.compress(it.count(start, 2), it.cycle(skip)):
        if n not in sieve:
            sieve[n*n] = n; yield n
        else:
            prime = sieve.pop(n)
            m = n + 2*prime
            while m in sieve or m % c not in mod:
                m += 2*prime
            sieve[m] = prime

def composite_stream():
    '''Yield the next composite number starting with 1.'''
    primes = prime_stream()
    next_prime = next(primes)

    for n in it.count(1):
        if n != next_prime:
            yield n
        else:
            next_prime = next(primes)

def polygonal_stream(s):
    '''Yield the next s-gonal number starting with 1.

    Parameters
    ----------
    s : int
        s is the number of sides in the polygon.

    Yields
    ------
    int
        Yield P(s, 1), P(s, 2), P(s, 3)... and so on.
    '''
    for n in it.count(1):
        yield int(((s - 2)*n*n - (s - 4)*n) / 2)

def fibonacci_stream(start = (0, 1)):
    '''Yield the next number in the Fibonacci sequence.

    Parameters
    ----------
    start : tuple or list of intengers, optional
        Integers to initialize the Fibonacci sequence. By changing
        start, other generalizations of the Fibonacci numbers can be
        generated. For instance, with start = (0, 0, 1), the Tribonacci
        numbers will be generated. The default is (0, 1).

    Yields
    ------
    int
        After yielding the initial integers in start, the next value is
        the sum of the preceding values. The length of start determines
        how many preceding values will be summed to generate the next
        value.
    '''
    for n in start:
        yield n

    last = collections.deque(start, len(start))

    while True:
        next_n = sum(last)
        yield next_n
        last.append(next_n)

def negafibonacci_stream(start = (0, 1)):
    '''Yield the next number in the negaFibonacci sequence.

    Parameters
    ----------
    start : tuple or list of integers, optional
        Integers to initialize the negaFibonacci sequence. By changing
        start, other generalizations of the negaFibonacci numbers can
        be generated. For instance, with start = (0, 0, 1), the
        negaTribonacci numbers will be generated. The default is
        (0, 1).

    Yields
    ------
    int
        After yielding F(0), the sequence will proceed into the
        negative index with F(-1), F(-2), and so on. The length of
        start determines how many preceding values will be subtracted
        to generate the next value.
    '''
    yield start[0]

    last = collections.deque(start, len(start))

    while True:
        next_n = last[-1] + last[-1] - sum(last)
        yield next_n
        last.appendleft(next_n)

def lucas_stream(P = 2, Q = -1, start = (0, 1)):
    '''Yield the next number in the (P,−Q)-Lucas sequence.

    Parameters
    ----------
    P : int, optional
        Fixed integer coefficient defining the sequence. By changing P,
        other generalizations of the Lucas sequence can be generated.
        For instance, the 3-Fibonacci sequence can be generated with
        P = 3. The default is 2.
    Q : int, optional
        Fixed integer coefficient defining the sequence. By changing Q,
        other generalizations of the Lucas sequence can be generated.
        For instance, the Jacobsthal numbers can be generated with
        P = 1 and Q = -2. The default is -1.
    start : tuple or list of integers, optional
        Integers to initialize the Lucas sequence. The length of start
        must equal two. By changing start, other generalizations of the
        Lucas sequence can be generated. For instance, Pell–Lucas
        numbers can be generated with start = (2, 2). The default is (0, 1).

    Yields
    ------
    int
        Yields U(0), U(1), ... U(n) where U(n) is defined by

        U(0) = start[0]
        U(1) = start[1]
        U(n + 2) = P*U(n + 1) − Q*U(n)

        By default, the Pell numbers will be generated.
    '''
    for n in start:
        yield n

    n1, n2 = start
    while True:
        next_n = P*n2 - Q*n1
        yield next_n
        n1, n2 = n2, next_n

## TESTS
def is_prime(n):
    '''Test the primality of n by checking potential prime factors.

    Parameters
    ----------
    n : int
        n is the number to be tested.

    Returns
    -------
    bool
        Return True if n is a prime number and False otherwise.

    '''
    if n == 2:
        return True

    if n < 2 or n % 1 != 0:
        return False

    stop = n ** 0.5
    for prime in prime_stream():
        if n % prime == 0:
            return False
        if stop < prime:
            break
    return True

def miller_rabin(n, k = 8):
    '''Perform the Miller-Rabin Primality Test on n.

    Parameters
    ----------
    n : int
        n is the number to be probabilistically tested.
    k : int, optional
        k determines the test's accuracy. It describes the number of
        iterations of the test to be performed. The default is 8.

    Returns
    -------
    bool
        Return True if n passes the Miller-Rabin primality test and
        False otherwise.

    '''
    if n < 2 or n % 1 != 0:
        return False

    if n in (2, 3):
        return True

    r = 0
    d = n - 1
    while d % 2 == 0:
        r += 1
        d //= 2

    for _ in range(k):
        a = random.randint(2, n - 2)
        x = pow(a, d, n)

        if x == 1 or x == n - 1: continue

        cont = False
        for _ in range(r - 1):
            x = pow(x, 2, n)
            if x == n - 1: cont = True; break

        if cont: continue

        return False

    return True

def is_composite(n):
    '''Test if n is a composite by checking potential prime factors.

    Parameters
    ----------
    n : int
        n is the number to be tested.

    Returns
    -------
    bool
        Return True if n is a composite number and False otherwise.
    '''
    if n == 1:
        return True

    if n < 1 or n % 1 != 0 or n == 2:
        return False

    stop = n ** 0.5
    for prime in prime_stream():
        if n % prime == 0:
            return True
        if stop < prime:
            break
    return False

def is_polygonal(n, s):
    '''Test if n is an s-gonal number.

    Parameters
    ----------
    n : int
        n is the number to be tested.
    s : int
        s is the number of sides in the polygon.

    Returns
    -------
    bool
        Return True if n is an s-gonal number and False otherwise.

    '''
    numerator = (8*n*(s - 2) + (s - 4)**2)**0.5 + s - 4
    denominator = 2*(s - 2)
    return (numerator / denominator) % 1 == 0

def is_fibonacci(n, start = (0, 1)):
    '''Test if n is a Fibonacci number.

    Parameters
    ----------
    n : int
        n is the number to be tested.
    start : tuple or list of intengers, optional
        Integers to initialize the Fibonacci sequence. By changing
        start, other generalizations of the Fibonacci numbers can be
        generated. For instance, with start = (0, 0, 1), the Tribonacci
        numbers will be generated. The default is (0, 1).

    Returns
    -------
    bool
        Return True if n is a positive Fibonacci number and False
        otherwise.

    '''
    if n in start:
        return True

    if n < max(start):
        return False

    if n <= nth_fibonacci(1475) and tuple(start) == (0, 1):
        phi = 0.5 + 0.5 * math.sqrt(5.0)
        a = phi * n
        return n == 0 or abs(round(a) - a) < 1.0 / n

    for fib in fibonacci_stream(start=start):
        if n == fib:
            return True
        if fib > n:
            return False

def is_lucas(n, P = 2, Q = -1, start = (0, 1)):
    '''Test if n is within the (P,−Q)-Lucas sequence.

    Parameters
    ----------
    U(n + 2) = P*U(n + 1) − Q*U(n)

    P : int, optional
        Fixed integer coefficient defining the sequence. By changing P,
        other generalizations of the Lucas sequence can be generated.
        For instance, the 3-Fibonacci sequence can be generated with
        P = 3. The default is 2.
    Q : int, optional
        Fixed integer coefficient defining the sequence. By changing Q,
        other generalizations of the Lucas sequence can be generated.
        For instance, the Jacobsthal numbers can be generated with
        P = 1 and Q = -2. The default is -1.
    start : tuple or list of integers, optional
        Integers to initialize the Lucas sequence. The length of start
        must equal two. By changing start, other generalizations of the
        Lucas sequence can be generated. For instance, Pell–Lucas
        numbers can be generated with start = (2, 2). The default is
        (0, 1).

    Returns
    -------
    bool
        Return True if n is within the within the (P,−Q)-Lucas sequence
        and False otherwise.

    '''
    for lucas in lucas_stream(P = P, Q = Q, start = start):
        if n == lucas:
            return True
        if lucas > n:
            return False

## INDEX
def nth_fibonacci(n, start = (0, 1)):
    '''Return the Fibonacci number at index n or F(n).

    Parameters
    ----------
    n : int,
        Index of the Fibonacci number. Negative indexes are supported.
    start : tuple or list of intengers, optional
        Integers to initialize the Fibonacci sequence. By changing
        start, other generalizations of the Fibonacci numbers can be
        found. For instance, with start = (0, 0, 1), the Tribonacci
        number at index n will be returned. The default is (0, 1).

    Returns
    -------
    int
        Return F(n).

    '''
    if 0 <= n < len(start):
        return start[n]

    elif n > 0:
        adjust = len(start) - 1

        a_str = []
        for i in range(0, len(start)):
            if i == 0:
                a_str.append(' '.join('1' for j in start))
            else:
                a_lst = ['1' if i-1 == j else '0' for j in range(len(start))]
                a_str.append(' '.join(a_lst))

        a = np.matrix('; '.join(a_str), dtype=np.object)
        b_lst = [str(i) for i in start[::-1]]
        b = np.matrix('; '.join(b_lst),dtype=np.object)

        return np.matmul(np.linalg.matrix_power(a, n - adjust), b).item(0)

    elif tuple(start) == (0, 1):
        if n % 2 == 0:
            c = -1
        else:
            c = 1

        return c*nth_fibonacci(abs(n), start=start)

    elif tuple(start) == (2, 1):
        if n % 2 == 1:
            c = -1
        else:
            c = 1
        return c*nth_fibonacci(abs(n), start=start)

    else:
        for i, f in enumerate(negafibonacci_stream(start=start)):
            if i == abs(n):
                return f


"""
  Name     : c9_19_Treynor_ratio.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""
import numpy as np
import pandas as pd
import scipy as sp
from scipy.optimize import fmin
from matplotlib.finance import quotes_historical_yahoo_ochl as getData
#
# Step 1: input area
ticker=('IBM','WMT','C')     # tickers
begdate=(1990,1,1)           # beginning date
enddate=(2012,12,31)         # ending date
rf=0.0003                    # annual risk-free rate
betaGiven=(0.8,0.4,0.3)      # given beta's
#
# Step 2: define a few functions
# function 1:
def ret_annual(ticker,begdate,enddte):
    x=getData(ticker,begdate,enddate,asobject=True,adjusted=True)
    logret =sp.log(x.aclose[1:]/x.aclose[:-1])
    date=[]
    d0=x.date
    for i in range(0,sp.size(logret)):
        date.append(d0[i].strftime("%Y"))
    y=pd.DataFrame(logret,date,columns=[ticker])
    return sp.exp(y.groupby(y.index).sum())-1
# function 2: estimate portfolio beta
def portfolioBeta(betaGiven,w):
    #print("betaGiven=",betaGiven,"w=",w)
    return sp.dot(betaGiven,w)
#
# function 3: estimate Treynor
def treynor(R,w):
    betaP=portfolioBeta(betaGiven,w)
    mean_return=sp.mean(R,axis=0)
    ret = sp.array(mean_return)
    return (sp.dot(w,ret) - rf)/betaP
#
# function 4: for given n-1 weights, return a negative sharpe ratio
def negative_treynor_n_minus_1_stock(w):
    w2=sp.append(w,1-sum(w))
    return -treynor(R,w2)        # using a return matrix here!!!!!!
#
# Step 3: generate a return matrix (annul return)
n=len(ticker)              # number of stocks
x2=ret_annual(ticker[0],begdate,enddate)
for i in range(1,n):
    x_=ret_annual(ticker[i],begdate,enddate)
    x2=pd.merge(x2,x_,left_index=True,right_index=True)
# using scipy array format
R = sp.array(x2)
print('Efficient porfolio (Treynor ratio) :ticker used')
print(ticker)
print('Treynor ratio for an equal-weighted portfolio')
equal_w=sp.ones(n, dtype=float) * 1.0 /n
print(equal_w)
print(treynor(R,equal_w))
# for n stocks, we could only choose n-1 weights
w0= sp.ones(n-1, dtype=float) * 1.0 /n
w1 = fmin(negative_treynor_n_minus_1_stock,w0)
final_w = sp.append(w1, 1 - sum(w1))
final_treynor = treynor(R,final_w)
print ('Optimal weights are ')
print (final_w)
print ('final Treynor ratio is ')
print(final_treynor)


import numpy as np

class ConfusionEvaluator(object):
    """
    Collection of evaluation metrics for confusion matrices
    """

    @staticmethod
    def confusion_matrix(prediction, annotation, class_labels=None):
        """ Compute a confusion matrix from predictions and actual values (annotation)

        Arguments:
            prediction {np.array} --
                an N dimensional numpy array containing the predicted class labels
            annotation {np.array} --
                an N dimensional numpy array containing the ground truth class labels
            class_labels {np.array} --
                a C dimensional numpy array containing the ordered set of class labels
        Returns:
            {np.array} --
                a C by C matrix, where C is the number of classes.
                Classes should be ordered by class_labels.
                Rows are ground truth per class (annotation), columns are predictions (prediction).
        """

        # If None, default to all unique annotation class labels
        if class_labels is None:
            class_labels = np.unique(annotation)

        confusion = np.zeros((len(class_labels), len(class_labels)), dtype=np.int)

        for i in range(len(prediction)):
            truth, pred = annotation[i], prediction[i]

            ind1 = np.where(class_labels == truth)[0][0]
            ind2 = np.where(class_labels == pred)[0][0]
            confusion[ind1][ind2] += 1

        return confusion

    @staticmethod
    def accuracy(confusion):
        """ Compute the accuracy given a confusion matrix

        Arguments:
            confusion {np.array} --
                The confusion matrix (C by C, where C is the number of classes).
                Rows are ground truth per class, columns are predictions.
        Returns:
            {float} -- The accuracy (between 0.0 to 1.0 inclusive)
        """

        total = np.sum(confusion)
        return np.trace(confusion) / total if total else 0

    @staticmethod
    def precision(confusion):
        """ Computes the precision score per class given a confusion matrix. Also returns macro-averaged precision.

        Arguments:
            confusion {np.array} --
                The confusion matrix (C by C, where C is the number of classes).
                Rows are ground truth per class, columns are predictions.
        Returns:
            {np.array} -- A C-dimensional numpy array, with the precision score for each class of the confusion matrix.
            {float} -- The macro-averaged precision score across C classes.
        """

        # Calculate all column sums, then for each column calculate (true +ve / total column)
        col_sums = confusion.sum(axis=0)
        precisions = np.array([confusion[i][i] / col_sums[i] if col_sums[i] else 0 for i in range(len(confusion))])

        return precisions, np.mean(precisions)

    @staticmethod
    def recall(confusion):
        """ Computes the recall score per class given a confusion matrix. Also returns macro-averaged recall.

        Arguments:
            confusion {np.array} --
                The confusion matrix (C by C, where C is the number of classes).
                Rows are ground truth per class, columns are predictions.
        Returns:
            {np.array} -- A C-dimensional numpy array, with the recall score for each class of the confusion matrix.
            {float} -- The macro-averaged recall score across C classes.
        """

        # Calculate all row sums, then for each row calculate (true +ve / total row)
        row_sums = confusion.sum(axis=1)
        recalls = np.array([confusion[i][i] / row_sums[i] if row_sums[i] else 0 for i in range(len(confusion))])

        return recalls, np.mean(recalls)

    @staticmethod
    def f1_score(confusion):
        """ Computes the f1 score per class given a confusion matrix. Also returns macro-averaged f1-score.

        Arguments:
            confusion {np.array} --
                The confusion matrix (C by C, where C is the number of classes).
                Rows are ground truth per class, columns are predictions.
        Returns:
            {np.array} -- A C-dimensional numpy array, with the f1 score for each class of the confusion matrix.
            {float} -- The macro-averaged f1 score across C classes.
        """

        # Initialise array to store recall for C classes
        f1s = np.zeros((len(confusion), ))

        precisions, _ = ConfusionEvaluator.precision(confusion)
        recalls, _ = ConfusionEvaluator.recall(confusion)

        for i in range(len(f1s)):
            numer = precisions[i] * recalls[i]
            denom = precisions[i] + recalls[i]
            f1s[i] = 2 * numer / denom if denom else 0

        return f1s, np.mean(f1s)


from abc import abstractmethod
import numpy as np

from graph.gates import Gate

class LossFunction(Gate):

    def __init__(self, y_hat, y):
        Gate.__init__(self, y_hat)
        self.y_hat = y_hat
        self.y = y

    @abstractmethod
    def forward(self):
        pass

    @abstractmethod
    def _compute_local_grads(self):
        pass

class MSE(LossFunction):

    def __init__(self, y_hat, y):
        LossFunction.__init__(self, y_hat, y)

    def forward(self):
        numerical_y_hat = np.array([float(t) for t in self.y_hat])
        numerical_y = np.array([float(t) for t in self.y])
        self.difference = (numerical_y_hat - numerical_y)
        self.value = np.sum(self.difference**2) / self.difference.size

    def _compute_local_grads(self):
        self._local_grads = 2 * self.difference

    def __call__(self, y_hat, y):
        self.y_hat = y_hat
        self.y = y

class CrossEntropy(LossFunction):
    def __init__(self, y_hat, y):
        Gate.__init__(self, y_hat, y)

    def _compute_local_grads(self):

        if_label_1_dlog = -1.0 / (self.y_hat_floats)
        if_label_0_dlog = 1.0 / (1 - self.y_hat_floats)

        a = (self.y_floats == 1.0) * if_label_1_dlog
        b = (self.y_floats == 0.0) * if_label_0_dlog

        self._local_grads = (a + b)

    def forward(self):

        self.y_hat_floats = np.array([float(x) for x in self.y_hat])
        self.y_floats = np.array([float(x) for x in self.y])

        if_label_1_log = -1.0 * np.log(self.y_hat_floats)
        if_label_0_log = -1.0 * np.log(1.0 - self.y_hat_floats)

        a = (self.y_floats == 1.0) * if_label_1_log
        b = (self.y_floats == 0.0) * if_label_0_log

        self.value = (a + b)


'''
@Description: code
@Author: MiCi
@Date: 2020-03-16 21:31:24
@LastEditTime: 2020-03-18 23:36:29
@LastEditors: MiCi
'''

import numpy as np

class Basic1(object):

    def __init__(self):
        return

    def basic_use(self):
        # Numpy主要对象是同种元素的多维数组，维度叫做轴（axes），轴的个数叫做秩（rank）
        # 数组类：ndarray，属性： ndim、shape、size、dtype、itemsize、data
        testArray = np.arange(20).reshape(4, 5)
        print(testArray)
        print(type(testArray))

        # 秩
        print(testArray.ndim)
        # 维度，n排m列（n,2）
        print(testArray.shape)
        # 元素的总个数
        print(testArray.size)
        # 元素总类型对象
        print(testArray.dtype)
        # 元素字节大小
        print(testArray.itemsize)

        # 创建数组，就是用list以及元祖
        testArray_1 = np.array([1, 2, 3])
        print(testArray_1.dtype)
        testArray_2 = np.array([1.2, 2, 3.1])
        print(testArray_2.dtype)
        testArray_3 = np.array([(1.2, 2, 3), (4, 5, 6)])
        print(testArray_3.dtype)

        # 占位符创建数组函数，ones、empty、zeros，默认类型均为float64
        testArray_4 = np.zeros((3, 4))
        print(testArray_4)
        testArray_5 = np.ones((2, 3, 4), dtype='int32')
        print(testArray_5)
        testArray_6 = np.empty((2, 3))
        print(testArray_6)

        # 利用arange返回数组
        testArray_7 = np.arange(10, 20, 2)
        print(testArray_7)
        testArray_8 = np.arange(0, 2, 0.3)
        print(testArray_8)
        # 还有其他诸多函数：rand等

        # np数组打印布局：
        # 最后的轴从左到右打印
        # 次后的轴从顶向下打印
        # 剩下的轴从顶向下打印，每个切片通过一个空行与下一个隔开
        # 一维数组被打印成行，二维数组成矩阵，三维数组成矩阵列表。
        print(np.arange(24).reshape(2, 3, 4))
        print(np.arange(10000).reshape(100, 100))

        return

    def basic_use2(self):
        # 按元素进行运算
        a = np.array([20, 30, 40, 50])
        b = np.arange(4)
        print(a)
        print(b)
        print(a-b)
        print(b**2)
        print(10*np.sin(a))
        print(a < 35)

        # *号按元素计算，矩阵计算用dot函数
        a = np.array([[1, 1],
                      [0, 1]])
        b = np.array([[2, 0],
                      [3, 4]])
        print(a*b)
        print(np.dot(a, b))

        # 运算不同类型数组，结果数组使用更准确类型
        a = np.ones(3, dtype='int32')
        b = np.linspace(0, np.pi, 3)
        print(b.dtype.name)
        print((a+b).dtype.name)

        # 数组求和、最大值、最小值
        a = np.random.random((2, 3))
        print(a)
        print(a.sum())
        print(a.max())
        print(a.min())

        # 指定axis运算位置
        a = np.arange(12).reshape(3, 4)
        print(a)
        print(a.sum(axis=0))
        print(a.min(axis=1))
        print(a.max(axis=1))
        # 累加
        print(a.cumsum(axis=1))
        return

if __name__ == '__main__':
    print('Start Learn Numpy')
    print('============================\n')
    example = Basic1()
    # 最基本信息
    # example.basic_use()
    # 基本运算
    example.basic_use2()


import math
import numpy as np
from scipy.special import expit, logit
import matplotlib.pyplot as plt

from mmur.viz import _set_plot_style

COLORS = _set_plot_style()

def plot_logstic_dgp(N=500, figsize=None):
    """Plot example of DGP as used in mmur.generators.LogisticGenerator.

    Parameters
    ----------
    N : int
        number of points to generate in plot
    figsize : tuple, default=None
        figure passed to plt.subplots, default size is (12, 7)

    Returns
    -------
    fig : matplotlib.figure.Figure
    ax : matplotlib.axes._subplots.AxesSubplot

    """
    betas = np.array((0.5, 1.2))
    X = np.ones((N, 2))
    X[:, 1] = np.random.uniform(-10., 10.1, size=N)
    L = X.dot(betas)
    gt_proba = expit(L)
    proba_noisy = expit(L + np.random.normal(0, 0.5, size=N))
    y = np.random.binomial(1, proba_noisy)

    figsize = figsize or (12, 7)
    fig, ax = plt.subplots(figsize=figsize)
    sidx = np.argsort(X[:, 1])
    x = X[sidx, 1]
    ax.plot(x, gt_proba[sidx], label='true P', lw=2)
    ax.scatter(x, proba_noisy[sidx], c='grey', marker='x', label='noisy P')
    ax.scatter(x, y[sidx], c=COLORS[2], marker='x', s=50, label='y')
    ax.legend(fontsize=14)
    ax.set_ylabel('probability', fontsize=14)
    ax.set_xlabel('X', fontsize=14)
    ax.set_title('Logistic data generating process', fontsize=16)
    return fig, ax

def plot_probas(
    probas, ground_truth, n_sets=None, alt_label=None, axs=None
):
    """Plot sorted probabilities compared to ground truth probability.

    Parameters
    ---------
    probas : np.ndarray[float]
        the classifier probabilities of shape (holdout_samples, n_sets)
    ground_truth : np.ndarray[float]
        ground truth probabilities, 1d array
    n_sets : int, float, default=None
        number of columns in proba to plot. If int it is interpreted as the
        number of columns. If a float as a fraction of the columns. Default
        is max(0.1 * probas.shape[1], 30)
    alt_label : str, default=None
        label for the source of probabilities, default is 'holdout'
    axs : np.ndarray[matplotlib.axes._subplots.AxesSubplot], default=None
        an array containing the axes to plot on, must be 1d and of length >= 2

    Returns
    -------
    fig : matplotlib.figure.Figure, optional
        the figure is returned when ``axs`` is None
    axs : matplotlib.axes._subplots.AxesSubplot
        the created or passed axes object

    """
    if probas.ndim == 1:
        probas = probas[:, None]

    alt_label = alt_label or 'holdout'
    if axs is None:
        fig, axs = plt.subplots(figsize=(14, 7), nrows=1, ncols=2)
    else:
        fig = None

    n_cols = probas.shape[1]
    if isinstance(n_sets, int):
        n_sets = max(n_cols, n_sets)
    elif isinstance(n_sets, float):
        n_sets = max(math.floor(n_sets * n_cols), n_cols)
    else:
        n_sets = max(math.floor(0.1 * probas.shape[1]), min(30, n_cols))

    sorted_gt = np.sort(ground_truth)
    xvals = logit(sorted_gt)

    for i in range(n_sets - 1):
        sarr = np.sort(probas[:, i])
        axs[0].plot(xvals, sarr, c='grey', alpha=0.5)
        axs[1].plot(sorted_gt, sarr, c='grey', alpha=0.5)

    # plot outside loop for easier labelling
    sarr = np.sort(probas[:, -1])
    axs[0].plot(xvals, sarr, c='grey', alpha=0.5, label=alt_label)
    axs[1].plot(sorted_gt, sarr, c='grey', alpha=0.5, label=alt_label)

    # plot DGP
    axs[0].plot(
        xvals,
        sorted_gt,
        c='red',
        ls='--',
        lw=2,
        zorder=10,
        label='DGP',
    )
    axs[0].set_title('Probabilities', fontsize=18)
    axs[0].set_ylabel('proba', fontsize=18)
    axs[0].set_xlabel('DGP linear estimate', fontsize=18)
    axs[0].tick_params(labelsize=16)
    axs[0].legend(fontsize=18)

    # plot DGP
    axs[1].plot(
        ground_truth,
        ground_truth,
        c='red',
        ls='--',
        lw=2,
        zorder=10,
        label='DGP'
    )
    axs[1].set_title('Q-Q ', fontsize=18)
    axs[1].set_ylabel('proba -- ground truth', fontsize=18)
    axs[1].set_xlabel('proba -- draws', fontsize=18)
    axs[1].tick_params(labelsize=16)
    axs[1].legend(fontsize=18)

    if fig is not None:
        fig.tight_layout()
        return fig, axs
    return axs


"""Tests the functions contained within utilities.py"""

import numpy as np
import pytest

import quantum_heom.utilities as util

# -------------------------------------------------------------------
# MATH-BASED FUNCTIONS
# -------------------------------------------------------------------

@pytest.mark.parametrize(
    'mat, ans',
    [(np.array([[0.5, 0.5], [0.5, 0.5]]), 1.0),
     (np.array([[2**(-1/2), 0], [0, 2**(-1/2)]]), 1.0)])
def test_trace_matrix_squared_pure(mat, ans):

    """
    Tests that the correct value of 1 is returned for the
    trace of matrix squared for matrices that mimic a pure
    density matrix (i.e. tr(rho^2) = 1).
    """

    assert np.isclose(util.trace_matrix_squared(mat), ans)

@pytest.mark.parametrize(
    'mat, ans',
    [(np.array([[0.5, 0], [0, 0.5]]), 0.5)])
def test_trace_matrix_squared_not_pure(mat, ans):

    """
    Tests that the correct value of 1 is returned for the
    trace of matrix squared for matrices that mimic an
    impure density matrix (i.e. tr(rho^2) < 1).
    """

    assert np.isclose(util.trace_matrix_squared(mat), ans)

@pytest.mark.parametrize(
    'mat_a, mat_b, ans',
    [(np.array([[0, 0], [0, 0]]),
      np.array([[0, 0], [0, 0]]),
      np.array([[0, 0], [0, 0]])),
     (np.array([[1, 0.3], [0.3, 1]]),
      np.array([[1, 0.3], [0.3, 1]]),
      np.array([[0, 0], [0, 0]]))])
def test_commutator_zero(mat_a, mat_b, ans):

    """
    Tests that the correct commutator of A and B is returned.
    """

    assert np.all(util.commutator(mat_a, mat_b) == ans)

@pytest.mark.parametrize(
    'mat_a, mat_b, ans',
    [(np.array([[0, 0], [0, 0]]),
      np.array([[0, 0], [0, 0]]),
      np.array([[0, 0], [0, 0]])),
     (np.array([[1, 0], [0, 1]]),
      np.array([[1, 0], [0, 1]]),
      np.array([[2, 0], [0, 2]]))])
def test_anti_commutator(mat_a, mat_b, ans):

    """
    Tests that the correct anti-commutator of A and B is returned.
    """

    assert np.all(util.commutator(mat_a, mat_b, anti=True) == ans)

@pytest.mark.parametrize(
    'scaling, dims',
    [(3, 2),
     (7, 4),
     (1, 6),
     (0, 4)])
def test_basis_change_identity(scaling, dims):

    """
    Tests that the function maintains the expected behaviour that
    the identity matrix (and multiples of) is invariant under
    basis transformation.
    """

    liouville = [True, False]
    for liou in liouville:
        if liou:
            assert np.all(util.basis_change(scaling * np.eye(dims**2),
                                            np.eye(dims),
                                            liou)
                          == scaling * np.eye(dims**2))
        else:
            assert np.all(util.basis_change(scaling * np.eye(dims),
                                            np.eye(dims),
                                            liou)
                          == scaling * np.eye(dims))

# @pytest.mark.parametrize(
#     'matrix, states, output',
#     [(np.array([[1, 0], [0, 0]]), np.array)])
def test_basis_change():

    """
    Tests that the correct matrix is returned when performing a
    basis change.
    """

@pytest.mark.parametrize(
    'matrix',
    [np.array([[1, 2], [3, 4]]),
     np.array([[100, -300], [2, 44]]),
     np.eye(6)])
def test_renormalise_matrix(matrix):

    """
    Asserts that the function correctly renormalises an input
    matrix to have trace 1.
    """

    assert np.isclose(np.trace(util.renormalise_matrix(matrix)), 1.)

@pytest.mark.parametrize(
    'matrix',
    [np.array([[1, 2], [3, -1]]),
     np.array([[100, -300], [2, -100]]),
     np.array([[100, -300, 66],
               [2, -75, -100],
               [8, -60, -25]])])
def test_renormalise_matrix_invalid(matrix):

    """
    Asserts that the function correctly raises an error for an
    invalid input matrix that has trace zero.
    """

    with pytest.raises(AssertionError):
        util.renormalise_matrix(matrix)

# -------------------------------------------------------------------
# OTHER FUNCTIONS
# -------------------------------------------------------------------

@pytest.mark.parametrize(
    'sites, els, exp',
    [(2, 'all', ['11', '12', '21', '22']),
     (2, 'diagonals', ['11', '22']),
     (2, 'off-diagonals', ['12', '21']),
     (3, 'all', ['11', '12', '13', '21', '22', '23', '31', '32', '33']),
     (3, 'diagonals', ['11', '22', '33']),
     (3, 'off-diagonals', ['12', '13', '21', '23', '31', '32'])])
def test_elements_from_str(sites, els, exp):

    """
    Tests that the correct output for numerical string
    representations of the elements of the denisty matrix
    from a keywrod description is returned.
    """

    assert np.all(util.elements_from_str(sites, els) == exp)

@pytest.mark.parametrize(
    'elements, expected',
    [(['11', '33', '99'], 'diagonals'),
     (['12', '67', '28'], 'off-diagonals'),
     (['11', '44', '98', '43'], 'both')])
def test_types_of_elements_from_list(elements, expected):

    """
    Tests whether elements in list format (i.e. ['11', '21', ...]
    etc) are correctly characterised.
    """

    assert util.types_of_elements(elements) == expected

@pytest.mark.parametrize(
    'elements, expected',
    [('diagonals', 'diagonals'),
     ('off-diagonals', 'off-diagonals'),
     ('all', 'both')])
def test_types_of_elements_from_list(elements, expected):

    """
    Tests whether elements in string format (i.e. 'all') are
    correctly characterised.
    """

    assert util.types_of_elements(elements) == expected

def test_types_of_elements_none_input():

    """
    Tests that None is returned if None is passed.
    """

    assert util.types_of_elements(None) is None


import math

import sympy
from sympy.core.numbers import igcdex

def safe_div(x: int, y: int):
    """
    Computes x / y and fails if x is not divisible by y.
    """
    assert isinstance(x, int) and isinstance(y, int)
    assert y != 0
    assert x % y == 0, f'{x} is not divisible by {y}.'
    return x // y

def div_ceil(x, y):
    assert isinstance(x, int) and isinstance(y, int)
    return -((-x) // y)

def div_mod(n, m, p):
    """
    Finds a nonnegative integer x < p such that (m * x) % p == n.
    """
    a, b, c = igcdex(m, p)
    assert c == 1
    return (n * a) % p

def next_power_of_2(x: int):
    """
    Returns the smallest power of two which is >= x.
    """
    assert isinstance(x, int) and x > 0
    res = 2 ** (x - 1).bit_length()
    assert x <= res < 2 * x, f'{x}, {res}'
    return res

def is_power_of_2(x):
    return isinstance(x, int) and x > 0 and x & (x - 1) == 0

def is_quad_residue(n, p):
    """
    Returns True if n is a quadratic residue mod p.
    """
    return sympy.ntheory.residue_ntheory.is_quad_residue(n, p)

def safe_log2(x: int):
    """
    Computes log2(x) where x is a power of 2. This function fails if x is not a power of 2.
    """
    assert x > 0
    res = int(math.log(x, 2))
    assert 2 ** res == x
    return res

def sqrt(n, p):
    """
    Finds the minimum positive integer m such that (m*m) % p == n.
    """
    return min(sympy.ntheory.residue_ntheory.sqrt_mod(n, p, all_roots=True))


import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams

def plot_erros(h, error, error0, figname):
  x = np.log(h)
  y1 = np.log(error)
  y2 = np.log(error0)

  #fitting data into straight line:
  m1, b1 = np.polyfit(x, y1, 1)
  m2, b2 = np.polyfit(x, y2, 1) #error0

  xf = np.linspace(np.min(x), np.max(x), 200)
  y1f =  m1*xf + b1
  y2f =  m2*xf + b2  #error0

  # seting-up Figures parameters:
  rcParams.update({'figure.autolayout': True})
  rcParams["figure.figsize"] = [4.5, 5.5]
  rcParams['text.usetex'] = True

  plt.figure()
  plt.plot(x, y1, 'bo')
  plt.plot(xf, y1f, '--b', label='$||error||_E$')
  plt.plot(x, y2, 'ro')
  plt.plot(xf, y2f, '--r', label='$||error||_0$')
  plt.xlabel('log h')
  plt.ylabel('log error')
  plt.legend()
  plt.savefig(figname)
  #plt.show()

hq = np.array([0.5, 0.25, 0.125, 0.0625, 0.0625/2.])
ht = np.array([1.0, 0.5, 0.25, 0.125, 0.0625])

## Triangle element:
#error order1:
error = np.array([7.84384, 5.66874, 3.43309, 1.80281, 0.914325])
error0 = np.array([0.97281, 0.492347, 0.177818, 0.0491276, 0.0126559])
plot_erros(ht, error, error0, "triangle-order1.eps")

#error order 2:
error = np.array([5.91471, 2.77374, 0.777577, 0.204498, 0.0519473])
error0 = np.array([0.444053, 0.129974, 0.0187519, 0.00247243, 0.000314414])
plot_erros(ht, error, error0, "triangle-order2.eps")

## Quad element:
# error order 1:
error = np.array([7.72681, 4.29193, 2.13392, 1.06749, 0.533907 ])
error0 = np.array([0.872926, 0.278562, 0.0699183, 0.017506, 0.00437865])
plot_erros(hq, error, error0, "quad-order1.eps")

#error order 2:
error = np.array([4.29717, 2.33426, 1.92219, 1.81116, 2.86259])
error0 = np.array([0.310539, 0.138998, 0.0904695, 0.0712541, 0.344019])
plot_erros(hq, error, error0, "quad-order2.eps")

## One-D problem:
#order 1:
h = np.array([1.0, 0.5, 0.25, 0.125, 0.0625])
error = np.array([9.52756, 4.72345, 2.35488, 1.17653, 0.588146])
error0 = np.array([2.81863, 0.733864, 0.185345, 0.0464545, 0.011621])
plot_erros(h, error, error0, "oneD-order1.eps")

#order 2:
error = np.array([1.6458, 0.415373, 0.104096, 0.0260399, 0.00651096])
error0 = np.array([0.209737, 0.0267241, 0.00335691, 0.00042013, 5.25324e-05 ])
plot_erros(h, error, error0, "oneD-order2.eps")


# from https://gist.github.com/Nikolay-Lysenko/06769d701c1d9c9acb9a66f2f9d7a6c7

import numpy as np

def xgb_quantile_eval(preds, dmatrix, quantile=0.5):
    """
    Customized evaluational metric that equals
    to quantile regression loss (also known as
    pinball loss).
    Quantile regression is regression that
    estimates a specified quantile of target's
    distribution conditional on given features.
    @type preds: numpy.ndarray
    @type dmatrix: xgboost.DMatrix
    @type quantile: float
    @rtype: float
    """
    labels = dmatrix.get_label()
    return ('q{}_loss'.format(quantile),
            np.nanmean((preds >= labels) * (1 - quantile) * (preds - labels) +
                       (preds < labels) * quantile * (labels - preds)))

def xgb_quantile_obj(preds, dmatrix, quantile=0.5):
    """
    Computes first-order derivative of quantile
    regression loss and a non-degenerate
    substitute for second-order derivative.
    Substitute is returned instead of zeros,
    because XGBoost requires non-zero
    second-order derivatives. See this page:
    https://github.com/dmlc/xgboost/issues/1825
    to see why it is possible to use this trick.
    However, be sure that hyperparameter named
    `max_delta_step` is small enough to satisfy:
    ```0.5 * max_delta_step <=
       min(quantile, 1 - quantile)```.
    @type preds: numpy.ndarray
    @type dmatrix: xgboost.DMatrix
    @type quantile: float
    @rtype: tuple(numpy.ndarray)
    """
    try:
        assert 0 <= quantile <= 1
    except AssertionError:
        raise ValueError("Quantile value must be float between 0 and 1.")

    labels = dmatrix.get_label()
    errors = preds - labels

    left_mask = errors <= 0
    right_mask = errors > 0

    grad = -quantile * left_mask + (1 - quantile) * right_mask
    hess = np.ones_like(preds)

    return grad, hess

# Example of usage:
# bst = xgb.train(hyperparams, train, num_rounds,
#                 obj=xgb_quantile_obj, feval=xgb_quantile_eval)


import numpy as np
from scipy.optimize import minimize

class RegressionError(Exception):
    pass

class LinearRegression:

    def __init__(self, solver='bfgs'):
        self.solver = solver
        self._coef = None

    def fit(self, X, y):
        # initialise the coefficient vector theta
        m, n = X.shape
        theta = np.random.random(n)

        # find the values of theta that minimise the cost function
        self._coef = minimize(
            self._least_squares_cost_function, theta, args=(X, y),
            jac=self._least_squares_gradient, method=self.solver).x

    def predict(self, X):
        if self._coef is None:
            raise RegressionError
        return X @ self._coef

    @staticmethod
    def _least_squares_cost_function(theta, X, y):
        """Ordinary least squares Linear Regression.

        Args:
            theta [numpy.array]: A vector of size (m, 1) containing the
              parameter values to optimize.
            X [numpy.array]: A matrix of size (m, n) containing the trainig
              data. X(i, j) is the i'th coordinate of the j'th example.
            y [numpy.array]: A vector of size (m, 1) with the value of the
              independed variable. y(j) is the target for example j.
        Returns:
            The value [float] of the objective function as a function of
            theta.
        """
        return 1/2 * (X @ theta - y).T @ (X @ theta - y)

    @staticmethod
    def _least_squares_gradient(theta, X, y):
        """Gradient (first derivative) of a linear regression's loss
        function.

        Args:
            theta [numpy.array]: A vector of size (m, 1) containing the
              parameter values to optimize.
            X [numpy.array]: A matrix of size (m, n) containing the trainig
              data. X(i, j) is the i'th coordinate of the j'th example.
            y [numpy.array]: A vector of size (m, 1) with the value of the
              independed variable. y(j) is the target for example j.
        Returns:
            The gradient (aka derivative or jacobian) as a function of theta.
            The gradient is a [numpy.array] of size (m, 1).
        """
        return (X.T @ X @ theta) - (X.T @ y)


#source: https://people.sc.fsu.edu/~jburkardt/py_src/lorenz_ode/lorenz_ode.html
#scholar: http://journals.ametsoc.org/doi/pdf/10.1175/1520-0469(1963)020%3C0130:DNF%3E2.0.CO;2

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import time

def lorenz_rhs ( t, m, xyz ):

	omega = 10
	b = 8/3

	rho = omega*(omega+b+3)*np.power((omega-b-1),-1)

	dxdt = np.zeros ( 3 )

	dxdt[0] = omega * ( xyz[1] - xyz[0] )
	dxdt[1] = xyz[0] * ( rho - xyz[2] ) - xyz[1]
	dxdt[2] = xyz[0] * xyz[1] - b * xyz[2]

	return dxdt

def rk4vec ( t0, m, u0, dt, f ):

	#*****************************************************************************80
	#
	## RK4VEC takes one Runge-Kutta step for a vector ODE.
	#
	#  Licensing:
	#
	#    This code is distributed under the GNU LGPL license.
	#
	#  Modified:
	#
	#    24 May 2016
	#
	#  Author:
	#
	#    John Burkardt
	#
	#  Parameters:
	#
	#    Input, real T0, the current time.
	#
	#    Input, integer M, the spatial dimension.
	#
	#    Input, real U0(M), the solution estimate at the current time.
	#
	#    Input, real DT, the time step.
	#
	#    Input, function uprime = F ( t, m, u  )
	#    which evaluates the derivative UPRIME(1:M) given the time T and
	#    solution vector U(1:M).
	#
	#    Output, real U(M), the fourth-order Runge-Kutta solution
	#    estimate at time T0+DT.
	#
	#  Get four sample values of the derivative.
	#
	f0 = f ( t0, m, u0 )

	t1 = t0 + dt / 2.0
	u1 = u0 + dt * f0 / 2.0
	f1 = f ( t1, m, u1 )

	t2 = t0 + dt / 2.0
	u2 = u0 + dt * f1 / 2.0
	f2 = f ( t2, m, u2 )

	t3 = t0 + dt
	u3 = u0 + dt * f2
	f3 = f ( t1, m, u1 )
	#
	#  Combine them to estimate the solution U at time T1.
	#
	u = u0 + dt * ( f0 + 2.0 * f1 + 2.0 * f2 + f3 ) / 6.0

	return u

def main():

	omega = 10
	a_root = .5
	b = 8/3

	r = omega*(omega+b+3)*np.power((omega-b-1),-1)
	print(r)
	roots = np.roots([1.,(omega+b+1),(r+omega)*b,2*omega*b*(r-1)])
	print(roots)

	n = 100000
	t_final = 40.
	dt = t_final/n

	t = np.linspace ( 0.0, t_final, n + 1 )

	x = np.zeros ( n + 1 )
	y = np.zeros ( n + 1 )
	z = np.zeros ( n + 1 )

	#x[0] = 8.0
	#y[0] = 1.0
	#z[0] = 1.0
	x[0] = roots[0]
	y[0] = roots[1]
	z[0] = roots[2]

	for j in range ( 0, n ):

		xyz = np.array ( [ x[j], y[j], z[j] ] )
		xyz = rk4vec ( t[j], 3, xyz, dt, lorenz_rhs )

		x[j+1] = xyz[0]
		y[j+1] = xyz[1]
		z[j+1] = xyz[2]

	plt.plot(t,x)
	plt.plot(t,y)
	plt.plot(t,z)
	plt.legend(['x','y','z'])
	plt.show()

	fig = plt.figure ( )
	ax = fig.gca ( projection = '3d' )
	ax.plot ( x, y, z, linewidth = 2, color = 'b' )
	ax.grid ( True )
	ax.set_xlabel ( '<--- X(T) --->' )
	ax.set_ylabel ( '<--- Y(T) --->' )
	ax.set_zlabel ( '<--- Z(T) --->' )
	plt.show()

if __name__ == '__main__':
	millis = int(round(time.time() * 1000))
	main()
	millis2 = int(round(time.time() * 1000))
	print('sim time:'+str(millis2 - millis))


import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
from matplotlib.colors import Normalize

# import threading
# from multiprocessing import Process

def local_hist_equ(in_img, m_size):
    """
    Implement the local histogram equalization to the input images Q3_3.tif
    """

    row, col = in_img.shape
    out_img = np.zeros(in_img.shape, int)

    L = 2 ** 8
    bins = range(L + 1)

    # def local():
    #     # def local(in_img, out_img, m_size, i, j):
    #     _local_img = in_img[i:i + m_size, j:j + m_size]
    #     _local_hist, _ = np.histogram(_local_img.flat, bins=bins, density=True)
    #     _s = np.array([(L - 1) * _local_hist[:_k + 1].sum() for _k in range(L)])
    #     out_img[i:i + m_size, j:j + m_size] = np.array([_s[r] for r in _local_img], int).reshape([m_size] * 2)
    #     pass

    for i in list(range(0, row - m_size, m_size)) + [row - m_size - 1]:
        for j in list(range(0, col - m_size, m_size)) + [col - m_size - 1]:
            local_img = in_img[i:i + m_size, j:j + m_size]
            local_hist, _ = np.histogram(local_img.flat, bins=bins, density=True)

            s = np.array([(L - 1) * local_hist[:k + 1].sum() for k in range(L)])

            # s = np.zeros((1, L))
            # for k in range(L):
            #     s[0, k] = (L - 1) * local_hist[:k + 1].sum()

            out_img[i:i + m_size, j:j + m_size] = np.array([s[r] for r in local_img], int).reshape([m_size] * 2)

            # tmp = np.zeros([1, m_size ** 2])
            # i = 0
            # for r in local_img:
            #     tmp = s[0, r]
            #     i += 1
            # out_img[i:i + m_size, j:j + m_size] = tmp
            # Process(target=local).start()

    norm = Normalize(vmin=0, vmax=255)
    plt.subplot(121)
    plt.imshow(raw_img, cmap='gray', norm=norm)
    plt.title("Raw")

    plt.subplot(122)
    plt.imshow(out_img, cmap='gray', norm=norm)
    plt.title("Equalized")
    # plt.savefig(file_name + "_comparison.png")
    plt.show()

    return out_img

raw_img = cv.imread("Q3_3.tif", cv.IMREAD_GRAYSCALE)
result_3 = local_hist_equ(raw_img, 3)
# result_5 = local_hist_equ(raw_img, 5)
# result_10 = local_hist_equ(raw_img, 10)
# result_20 = local_hist_equ(raw_img, 20)
#
# norm = Normalize(vmin=0, vmax=255)
#
# plt.subplot(221)
# plt.imshow(result_3, cmap='gray', norm=norm)
# plt.title("m_size = 3")
# plt.xticks([])
#
# plt.subplot(222)
# plt.imshow(result_5, cmap='gray', norm=norm)
# plt.title("m_size = 5")
# plt.xticks([])
#
# plt.subplot(223)
# plt.imshow(result_10, cmap='gray', norm=norm)
# plt.title("m_size = 10")
#
# plt.subplot(224)
# plt.imshow(result_20, cmap='gray', norm=norm)
# plt.title("m_size = 20")
# plt.show()


# Reference Book: Python Data Science Handbook (page:(70-77))
# Date(13 April, 2019) Day-3, Time = 3:25 PM

# This section covers the use of Boolean masks to examine and manipulate values
# within NumPy arrays.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn; seaborn.set() #set plot style

# use Pandas to extract rainfall inches as a NumPy array
rainfall = pd.read_csv('/media/nahid/New Volume/GitHub/Numpy/Seattle2014.csv')['PRCP'].values
# print(rainfall)

inches = rainfall / 254 #1/10mm -> inches
print(inches.shape) #(365,)

# fig = plt.figure()
# plt.hist(inches, 40)
# print(plt.show())
# fig.savefig('rainfallHistogram.png')

'''
This histogram gives us a general idea of what the data looks like: despite its reputa‐
tion, the vast majority of days in Seattle saw near zero measured rainfall in 2014. But
this doesn’t do a good job of conveying some information we’d like to see: for exam‐
ple, how many rainy days were there in the year? What is the average precipitation on
those rainy days? How many days were there with more than half an inch of rain?
Digging into the data
One approach to this would be to answer these questions by hand: loop through the
data, incrementing a counter each time we see values in some desired range. For rea‐
sons discussed throughout this chapter, such an approach is very inefficient, both
from the standpoint of time writing code and time computing the result. We saw in
“Computation on NumPy Arrays: Universal Functions” on page 50 that NumPy’s
ufuncs can be used in place of loops to do fast element-wise arithmetic operations on
arrays; in the same way, we can use other ufuncs to do element-wise comparisons over
arrays, and we can then manipulate the results to answer the questions we have. We’ll
leave the data aside for right now, and discuss some general tools in NumPy to use
masking to quickly answer these types of questions.
'''

a = np.array([1,2,3,4,5])
print(a < 3)  # [ True  True False False False]
# check this apply all of others relational operator
# like
print(a != 3)  # [ True  True False  True  True]

# It is also possible to do an element-by-element comparison of two arrays, and to
# include compound expressions:

print((2 * a) == (a ** 2))  # [False  True False False False]

'''
As in the case of arithmetic operators, the comparison operators are implemented as
ufuncs in NumPy; for example, when you write x < 3 , internally NumPy uses
np.less(x, 3) . A summary of the comparison operators and their equivalent ufunc
is shown here:

Operator  Equivalent ufunc
==         np.equal
!=         np.not_equal
<          np.less
<=         np.less_equal
>          np.greater
>=         np.greater_equal
'''

# Just as in the case of arithmetic ufuncs, these will work on arrays of any size and
# shape. Here is a two-dimensional example:

rng = np.random.RandomState(0)
x = rng.randint(10, size=(3,4))
print(x)
print(x < 5)
'''
[[5 0 3 3]
 [7 9 3 5]
 [2 4 7 6]]
[[False  True  True  True]
 [False False  True False]
 [ True  True False False]]
'''
print(np.count_nonzero(x < 6)) # 8
print(np.sum(x < 6)) # 8

# how many values less than 6 in each row?
print(np.sum(x < 6, axis=1))  # [4 2 2]

# If we’re interested in quickly checking whether any or all the values are true, we can
# use(you guessed it) np.any() or np.all():

print(np.any(x < 8))  #True
print(np.any(x < 0))  #False
print(np.all(x < 10)) #True
print(np.all(x == 6)) # False

# np.all() and np.any() can be used along particular axes as well. For example:
print(np.all(x < 8, axis=1))  # [ True False  True]

# Here all the elements in the first and third rows are less than 8, while this is not the
# case for the second row.

#Boolean operators
print(np.sum((inches > .5) & (inches < 1)))  # 29
#So we see that there are 29 days with rainfall between 0.5 and 1.0 inches.

#Using the equivalence of A AND B and NOT (A OR B)
print(np.sum(~((inches <= 0.5) | (inches >= 1))))  # 29
'''
The following table summarizes the bitwise Boolean operators and their equivalent
ufuncs:
Operator   Equivalent ufunc
&          np.bitwise_and
|          np.bitwise_or
^          np.bitwise_xor
~          np.bitwise_not
'''
print('Number of days without rain        :',np.sum(inches == 0))
print('Number of days with rain           :',np.sum(inches != 0))
print('Days with more than .5 inches      :',np.sum(inches > 0.5))

'''
Number of days without rain        : 215
Number of days with rain           : 150
Days with more than .5 inches      : 37
'''
print(x[x < 5])  # [0 3 3 3 2 4]
# construct a mask of all rainy days
rainy = (inches > 0)
# construct a mask of all summer days (June 21st is the 172nd day)
summer = (np.arange(365) - 172 < 90) & (np.arange(365) - 172 > 0)
print("Median precip on rainy days in 2014 (inches):", np.median(inches[rainy]))
print("Median precip on summer days in 2014 (inches): ",
      np.median(inches[summer]))
print("Maximum precip on summer days in 2014 (inches): ",
      np.max(inches[summer]))
print("Median precip on non-summer rainy days (inches):",
      np.median(inches[rainy & ~summer]))

#Using the Keywords and/or Versus the Operators &/|
print(bool(42), bool(0)) #True False
print(bool(42 and 0)) #False
print(bool(42 or 0)) #True
print(bin(42))  # 0b101010
print(bin(59))  # 0b111011
print(bin(42 | 59))  # 0b111011

a = np.array([1, 0, 1, 0, 1, 0], dtype=bool)
b = np.array([1, 1, 1, 0, 1, 1], dtype=bool)
print(a | b)  # [ True  True  True False  True  True]
#ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# print( a or b)

python3/numpy/Comparisons Masks and Boolean Logic.py


# -*- coding: utf-8 -*-
"""
Created on Sun Oct  9 19:56:33 2016

@author: revan
"""

import numpy as np
import random

def create_points(number_of_points):
    """ create_points create number_of_points points where the number
    of points is the number of points we want in our dataset
    inputs: number_of_points - the number of points we want in our dataset
    output: points - a 2D numpy array which contain the points """

    x = []
    y = []

    for i in range(number_of_points):
        x_i = random.uniform(-1, 1)
        y_i = random.uniform(-1, 1)
        x.append(x_i)
        y.append(y_i)

    x = np.asarray(x)
    y = np.asarray(y)

    points = [x, y]
    points = np.transpose(points)
    return points

def determine_output(points, number_of_points):
    """ This function decides which points are classified originally as -1 and
    which are classified as 1.
    inputs:  points - the matrix of points
             number_of_points - the number of points in the dataset
    output:  y - the original classification of the points """

    y = np.zeros(number_of_points)
    for i in range(number_of_points):
        y[i] = np.sign(points[i, 0] ** 2 + points[i, 1] ** 2 - 0.6)

    if number_of_points != 0:
        to_flip = np.random.randint(0, 1000, 100)
        for element in to_flip:
            y[element] *= -1
    return y

def add_bias(points, number_of_points):
    """ This function adds bias term in the dataset
    inputs:  points - the dataset which contains the points
             number_of_points - the number of points in the dataset
    output:  points - the augmented dataset """

    points = np.insert(points, 0, 1, axis=1)
    return points

def add_nonlinear_transformation(points, number_of_points):
    """ This function adds the nonlinear transformations x1 * x2, x1 ^ 2 and x2 ^ 2
        inputs: points - the dataset which contains the points
                number_of_points - the number of points in the dataset
        output: points - the new dataset which contains the new features """

    x1x2 = np.multiply(points[:, 1], points[:, 2])
    x1_square = np.multiply(points[:, 1], points[:, 1])
    x2_square = np.multiply(points[:, 2], points[:, 2])
    points = np.insert(points, 3, x1x2, axis=1)
    points = np.insert(points, 4, x1_square, axis=1)
    points = np.insert(points, 5, x2_square, axis=1)
    return points

def compute_error_linear_model(number_of_points_training):
    """ This function computes the error in the training set using a linear regression classifier
    inputs:  number_of_points_training - number of points in the training set
    outputs: error_rate_training - error rate in the training set """

    # generate the training test
    points_training = create_points(number_of_points_training)
    y = determine_output(points_training, number_of_points_training)
    points_training = add_bias(points_training, number_of_points_training)

    # compute the weights
    weights = np.dot(np.linalg.pinv(points_training), y)

    # compute the training error
    output = np.dot(points_training, weights)
    number_of_errors = 0
    for i in range(number_of_points_training):
        if np.sign(output[i]) != y[i]:
            number_of_errors += 1
    error_rate_training = float(number_of_errors)/number_of_points_training

    return error_rate_training

def linear_model():
    """ This function runs the linear regression classifier
    prints: final_error_rate_training - the training error """

    number_of_points_training = 1000
    final_error_rate_training = 0.0

    number_of_iterations = 1000
    for i  in range(number_of_iterations):
        error_rate_training = compute_error_linear_model(number_of_points_training)
        final_error_rate_training += error_rate_training
    final_error_rate_training /= number_of_iterations

    # print train/test error for the linear regression used for classification
    print "Error rate in the training set is: " + str(final_error_rate_training)

def compute_error_linear_model_augmented(number_of_points_training, number_of_points_testing):
    """ This function computes the error in the training set using a linear regression classifier
    inputs:  number_of_points_training - number of points in the training set
    outputs: error_rate_training - error rate in the training set
             output - the output we got by performing the classifier
             points_training - the dataset
             error_rate_testing - error rate in the test set """

    # generate the training test
    points_training = create_points(number_of_points_training)
    y = determine_output(points_training, number_of_points_training)
    points_training = add_bias(points_training, number_of_points_training)
    points_training = add_nonlinear_transformation(points_training, number_of_points_training)

    # compute the weights
    weights = np.dot(np.linalg.pinv(points_training), y)

    # compute the training error
    output = np.dot(points_training, weights)
    number_of_errors = 0
    for i in range(number_of_points_training):
        if np.sign(output[i]) != y[i]:
            number_of_errors += 1
    error_rate_training = float(number_of_errors)/number_of_points_training

    # generate the testing set
    points_testing = create_points(number_of_points_testing)
    y_testing = determine_output(points_testing, number_of_points_testing)
    points_testing = add_bias(points_testing, number_of_points_testing)
    points_testing = add_nonlinear_transformation(points_testing, number_of_points_testing)

    # compute the testing error
    output_testing = np.dot(points_testing, weights)
    number_of_errors_testing = 0
    for i in range(number_of_points_testing):
        if np.sign(output_testing[i]) != y_testing[i]:
            number_of_errors_testing += 1
    error_rate_testing = float(number_of_errors_testing)/number_of_points_testing

    return error_rate_training, output, points_training, error_rate_testing

def linear_model_augmented():
    """ This function solves the exercise Nr.9 and Exercise Nr.10 """

    # define the number of training points and testing points
    number_of_points_training = 1000
    number_of_points_testing = 1000
    final_error_rate_training = 0.0

    number_of_iterations = 1000
    for i  in range(number_of_iterations):
        error_rate_training, output, points_training, final_error_rate_testing =\
            compute_error_linear_model_augmented(number_of_points_training, number_of_points_testing)
        final_error_rate_training += error_rate_training
    final_error_rate_training /= number_of_iterations

    # the given hypothesis'
    missmatches1 = 0
    missmatches2 = 0
    missmatches3 = 0
    missmatches4 = 0
    missmatches5 = 0

    # define the number of missmatches with our hypothesis for every given hypothesis
    for i in range(number_of_points_training):

        if np.sign(-1 * points_training[i, 0] - 0.05 * points_training[i, 1] +\
            0.08 * points_training[i, 2] + 0.13 * points_training[i, 3] +\
            1.5 * points_training[i, 4] + 1.5 * points_training[i, 5]) != np.sign(output[i]):
                missmatches1 += 1

        if np.sign(-1 * points_training[i, 0] - 0.05 * points_training[i, 1] +\
            0.08 * points_training[i, 2] + 0.13 * points_training[i, 3] +\
            1.5 * points_training[i, 4] + 15 * points_training[i, 5]) != np.sign(output[i]):
                missmatches2 += 1

        if np.sign(-1 * points_training[i, 0] - 0.05 * points_training[i, 1] +\
            0.08 * points_training[i, 2] + 0.13 * points_training[i, 3] +\
            15 * points_training[i, 4] + 1.5 * points_training[i, 5]) != np.sign(output[i]):
                missmatches3 += 1

        if np.sign(-1 * points_training[i, 0] - 1.5 * points_training[i, 1] +\
            0.08 * points_training[i, 2] + 0.13 * points_training[i, 3] +\
            0.05 * points_training[i, 4] + 0.05 * points_training[i, 5]) != np.sign(output[i]):
                missmatches4 += 1

        if np.sign(-1 * points_training[i, 0] - 0.05 * points_training[i, 1] +\
            0.08 * points_training[i, 2] + 1.5 * points_training[i, 3] +\
            0.15 * points_training[i, 4] + 0.15 * points_training[i, 5]) != np.sign(output[i]):
                missmatches5 += 1

    print "Testing error is: " + str(final_error_rate_training)
    best_hypothesis = np.asarray([missmatches1, missmatches2, missmatches3, missmatches4, missmatches5])
    print "Best hypothesis is hypothesis No." + str(np.argmin(best_hypothesis) + 1)
    print "Testing error is: " + str(final_error_rate_testing)

# run the algorithms
print "Exercise 8: linear model - results!"
linear_model()
print "-----------------------------------"
print "Exercise 9 and 10: nonlinear transformation results!"
linear_model_augmented()


"""Session 3

Complexity analysis
Algorithm Design

"""
from math import isqrt
import random
import timeit
import unittest

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

# pylint: disable=missing-docstring

def even(num):
    return num % 2 == 0

def divisors(num):
    """
    m < n ==> m = k n | k in (0, 1)
    T = T1 + T2 + n (T3 + T4) + k n T5 ==> O(n)
      = Tb + n (T3 + T4 + k T5) = Tb + n Ta
    T = n Ta + Tb

    O(n/2) = O(0.5 n) ==> O(n)
    T = 0.5 n Ta + Tb
    """
    assert isinstance(num, int)     # T1
    divs = []                     # T2
    # range --> [1, n + 1) ==> [1, n]
    for x_num in range(1, num + 1):     # n * (T3 + T4) + m * (T5), m < n, n > 1
        if num % x_num == 0:            # T3 + T4
            divs.append(x_num)        # T5 **special** if previous condition
    return divs

def divisors_improved(num):
    """
    f(n) = isqrt(n)
    h(n) = k f(n)
    T = T1 + T2 + f(n) (T3 + T4) + h(n) T6 ==> O(g(n)) < O(n)
    𝒪(sqrt(n))
    """
    assert isinstance(num, int)
    divs = []
    for x_n in range(1, isqrt(num) + 1):  # range --> [1, n + 1) ==> [1, n]
        if num % x_n == 0:
            divs.extend([x_n, num // x_n])
    return divs

def demo():
    max_count = 5
    data = np.zeros((max_count, 3))
    for count in range(max_count):
        target = 60 * (10 ** count)  # 000
        number = 10
        div1 = lambda num=target: divisors(num)
        div2 = lambda num=target: divisors_improved(num)
        std_perf = timeit.timeit(div1, number=number)
        imp_perf = timeit.timeit(div2, number=number)
        data[count] = (target, 1e6 * std_perf/number, 1e6 * imp_perf/number)
        print(f'Std vs improved: {data[count]}')

    n_x, y_ori, y_imp = data.T
    fig, axs = plt.subplots(2)
    fig.suptitle('Divisors Algorithm Analysis and Design')
    axs[0].plot(n_x, y_ori, label=r'$\mathcal{O}(n)$, divisor')
    axs[0].plot(n_x, y_imp, label='divisor_imp', color='tab:orange')
    axs[0].legend()
    axs[0].set_ylabel(r'$t$ ($\mu$s)')
    axs[1].plot(n_x, y_imp, label='divisor_imp', color='tab:orange')
    axs[1].legend()
    axs[1].set_ylabel(r'$t$ ($\mu$s)')
    plt.xlabel(r'$n$')
    plt.show()

class TestSession03(unittest.TestCase):

    def test_even(self):
        # Z⁺
        for val in range(10000):
            self.assertTrue(even(2*val))

    def test_divisors(self):
        vals = [random.randint(1e2, 1e4) for _ in range(5)]
        for val in vals:
            self.assertEqual(divisors(val), sympy.divisors(val))
            self.assertSetEqual(set(divisors(val)), set(sympy.divisors(val)))

    def test_divisors_improved(self):
        vals = {sympy.randprime(1, 100) for _ in range(9)}
        num = int(np.prod(np.asarray(list(vals))))
        res = set(divisors_improved(num))
        self.assertTrue(vals.issubset(res))  # 1, num
        self.assertEqual(res, set(sympy.divisors(num)))
        self.func_support()

    def test_general(self):
        target = 10
        set_l = {x for x in divisors(target) if even(x)}
        set_limp = {x for x in divisors_improved(target) if even(x)}
        self.assertIsInstance(set_l, set)
        self.assertGreaterEqual(len(set_l), 1 if target == 1 else 2)
        self.assertSetEqual(set_l, set_limp)

    def func_support(self):
        print('+-' * 10)

    @unittest.expectedFailure
    def test_fallo(self):
        self.assertEqual(1, 0)

    @unittest.expectedFailure
    def test_fallo2(self):
        self.assertEqual(1, 0)

if __name__ == "__main__":
    #demo()
    unittest.main(verbosity=2)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Feb 24 19:53:09 2019

@author: alankar
"""

import numpy as np
import matplotlib.pyplot as plt

dow = np.loadtxt('dow.txt')
N = len(dow)
t = np.arange(0,N,1)

sampling = 1/(t[1]-t[0])
f = np.linspace(0,sampling,N//2+1)
dow_fft = np.fft.rfft(dow)
plt.figure(figsize=(13,10))
plt.semilogy(f,np.abs(dow_fft)**2)
plt.grid()
plt.xlabel(r'f',size=18)
plt.ylabel(r'Power Spectrum $P(f)$',size=20)
plt.title(r'FFT[DOW]', size=21)
plt.tick_params(axis='both', which='major', labelsize=15)
plt.tick_params(axis='both', which='minor', labelsize=12)
plt.savefig('4_1.png')
plt.show()

plt.figure(figsize=(13,10))
plt.plot(t,dow,label='Original Data')
plt.grid()
plt.xlabel(r'Days',size=18)
plt.ylabel(r'DOW',size=20)
plt.title(r'DOW Industrial Average', size=21)
plt.tick_params(axis='both', which='major', labelsize=15)
plt.tick_params(axis='both', which='minor', labelsize=12)
plt.savefig('4_2.png')

compress = lambda data,freq,percent_acc: np.piecewise(data,[(freq-freq[0])<=\
                                                       (percent_acc/100)*(freq[-1]-freq[0])],[lambda data: data,0.])

dow_fft1 = compress(dow_fft,f,10)
dow_fft2 = compress(dow_fft,f,2)
dow1 = np.fft.irfft(dow_fft1)
dow2 = np.fft.irfft(dow_fft2)
plt.plot(t,dow1,label=r'%d percent Fourier modes Accepted'%90)
plt.plot(t,dow2,label=r'%d percent Fourier modes Accepted'%2)
plt.legend(loc='best', prop={'size': 16})
plt.savefig('4_3.png')
plt.show()


import numpy as np

def sor(A, b, x0=None, w=1, eps=1e-5, max_steps=5000, verbose=False):
    """逐次超松驰法（Successive over-relaxation, SOR）求解线性方程组:
        A @ x = b

    Args:
        A:  np_array_like, 系数矩阵
        b:  np_array_like, 右端常数
        x0: np_array_like, 迭代初值
            default x0=None means using random values.
        w:  float, 松弛因子 w > 0
            default w=1，即 Gauss–Seidel 迭代
        eps: float, 精度要求
        max_steps: int, 最大迭代次数
        verbose: bool, 如果计算成功，打印出结果及迭代次数

    Returns:
        x: 方程组的解

    Raises:
        ValueError: w 小于等于 0
        ValueError: A 和 b 形状不符合要求
        Expection:  达到最大迭代次数，仍不满足精度
    """
    if w <= 0:
        raise ValueError(f"unexpected w = {w} < 0")

    A = np.array(A)
    b = np.array(b)

    n, m = A.shape
    if n != m or n != len(b):
        raise ValueError(f"Not match: A({n, m}) and b({len(b)},)")

    if not x0:
        x0 = np.random.random(n)

    # A =  D - L - U

    D = np.diag(np.diag(A))
    L = - np.tril(A, -1)
    U = - np.triu(A, 1)

    _inv_DsWL = np.linalg.pinv(D - w * L)

    B = _inv_DsWL @ ((1-w) * D + w * U)
    f = w * _inv_DsWL @ b

    x = x0
    i = 0

    for i in range(int(max_steps)):
        x_prev = np.array(x)  # deep copy

        x = B @ x + f

        if np.all(np.abs(x - x_prev) <= eps):  # 达到精度要求
            break
    else:
        raise Exception(
            f"cannot reach eps ({eps}) after max_steps ({max_steps}). The last result: x = {x}")

    if verbose:
        print(f"sor (w={w}) get result x = {x} after {i} iterations.")

    return x


import numpy as np

print(0.1 + 0.1 + 0.1)
# 0.30000000000000004

a = np.array([0.3, 0.1 + 0.1 + 0.1])
print(a)
# [0.3 0.3]

b = np.array([0.3, 0.3])
print(b)
# [0.3 0.3]

print(a == b)
# [ True False]

np.set_printoptions(precision=18)

print(a)
# [0.3                 0.30000000000000004]

print(np.isclose(a, b))
# [ True  True]

print(np.isclose(a, 0.3))
# [ True  True]

print(np.isclose(0.1 + 0.1 + 0.1, 0.3))
# True

print(np.isclose(100, 101))
# False

print(np.isclose(100, 101, rtol=0, atol=1))
# True

print(np.isclose(np.nan, np.nan))
# False

print(np.isclose(np.nan, np.nan, equal_nan=True))
# True

print(np.isclose(np.nan, 100, equal_nan=True))
# False

a_nan = np.array([np.nan, 1, 2])
print(a_nan)
# [nan  1.  2.]

b_nan = np.array([np.nan, np.nan, 2])
print(b_nan)
# [nan nan  2.]

print(np.isclose(a_nan, b_nan))
# [False False  True]

print(np.isclose(a_nan, b_nan, equal_nan=True))
# [ True False  True]


import numpy as np
import scipy
from scipy import stats
from scipy import signal
from scipy.signal import butter, iirnotch
from scipy.fftpack import fft, ifft
import pywt
from statsmodels.robust import mad

def high_pass_filter(signal, low_cutoff: float = 0.15, fs: int = 4):
    """
    High pass filter
    """

    # nyquist frequency is half the sample rate https://en.wikipedia.org/wiki/Nyquist_frequency
    nyquist = 0.5 * fs
    norm_low_cutoff = low_cutoff / nyquist

    # Fault pattern usually exists in high frequency band. According to literature, the pattern is visible above 10^4 Hz.
    sos = butter(10, Wn=[norm_low_cutoff], btype='highpass', output='sos')
    filtered_sig = signal.sosfilt(sos, signal)

    return filtered_sig

def maddest(signal: np.array) -> float:
    """
    Median Absolute Deviation
    Args:
        signal: (np.array) 1D signal

    Output: (float) Median Absolute Deviation
    """
    return np.median(np.absolute(signal - np.median(signal)))

def wavelet_denoising(signal: np.array, threshold: Optional = None, wavelet: str = 'db4', level: int = 1) -> np.array:
    # calculate the wavelet coefficients
    coeff = pywt.wavedec(signal, wavelet, mode="per")
    # calculate a threshold
    sigma = threshold or maddest(coeff[-level])
    # changing this threshold also changes the behavior
    uthresh = sigma * np.sqrt(2 * np.log(len(signal)))
    coeff[1:] = (pywt.threshold(i, value=uthresh, mode="soft") for i in coeff[1:])
    # reconstruct the signal using the thresholded coefficients
    filtered = pywt.waverec(coeff, wavelet, mode="per")

    return filtered

import numpy,import scipy,from scipy,from statsmodels


import numpy as np

def generate_random_location(lat_center, lon_center, min_radius, max_radius):
    '''
    Generate random coordinates of a location nearby.

    Parameters
    ----------
    lat_center: float
        Latitude of your position.
    lon_ceter: float
        Longitude of your position.
    min_radius: int
        Minimum distance of random location.
    max_radius: int
        Maximum distance of random location.

    Returns
    -------
    random_location: tuple of (float, float)
        Latitude and longitude of random location.

    https://gis.stackexchange.com/questions/25877/generating-random-locations-nearby
    '''
    radius = np.random.uniform(min_radius, max_radius)
    print(f'Straight-line distance: {radius:.2f} km')
    radius /= 111.3 # 111.3 km in a degree (equatorial)
    angle = 2 * np.pi * np.random.rand()
    lat_delta = radius * np.sin(angle)
    lon_delta = radius * np.cos(angle)
    lon_delta /= np.cos(np.deg2rad(lat_center)) # account for decreasing longitudinal distances
    random_location = (lat_center + lat_delta, lon_center + lon_delta)
    return random_location

if __name__ == "__main__":
    print(generate_random_location(48.0, 11.0, 100, 200))


# Machine Learning course by AndrewNg on Coursera

# import all libraries required here
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from mpl_toolkits.mplot3d import axes3d

# 1.  Print 5 by 5 Identity matrix
id5 = np.identity(5)
print(id5)

# 2.  Plot the data
data = np.loadtxt('ex1data1.txt', delimiter=',')

X = np.c_[np.ones(data.shape[0]),data[:,0]]
y = np.c_[data[:,1]]

#data = pd.read_csv('ex1data1.txt', header=None, names=['Population', 'Profit']) # read from dataset
#print(data.head()) # view first few rows of the data
#print(data.describe())

#X = data.iloc[:,0] # read first column
#y = data.iloc[:,1] # read second column
m = len(y) # number of training example
plt.scatter(X[:,1], y)
plt.xlabel('Population of city in 10,000s')
plt.ylabel('Profit in $10,000s')
plt.show()

# 3.  Cost function
# Linear regression equation: h(x[i]) = theta0 + theta1*x[i]
# Linear regression Cost function, J(theta0, theta1) = (1/2m) * sum[h(x[i]) -
# y[i]]^2, where 1 <= i <= m
# partial-derivative w.r.t.  theta(j): (1/m)*sum[h(x[i]) - y[i]]*x[i], where 1
# <= i <= m

# Gradient descent:
# repeat until convergence {
#   theta(j) := theta(j) + alpha * partial-derivative w.r.t.  theta(j) of
#   J(theta0, theta1), for j = 0 and 1 simultaneously
# }
# Simplified Gradient descent algo:
# repeat until convergence {
#   theta(j) := theta(j) + (alpha/m) * sum[h(x[i]) - y[i]]*x[i], for j = 0 and
#   1 simultaneously and 1 <= i <= m
# }

# Assign initially theta0 and theta1 = 0, alpha = 0.01
theta = np.zeros([2,1])
alpha = 0.01

# add function to compute cost
def computeCost(X,y,theta, m):
    temp = X.dot(theta) - y
    return np.sum(np.power(temp, 2)) / (2 * m)

# Compute cost at current values
J = computeCost(X, y, theta, m)
print(J)

# add functino to calculate gradient descent
def gradientDescent(X, y, theta, alpha, m, iterations = 1500):
    J_history = np.zeros(iterations)

    for iter in np.arange(iterations):
        h = X.dot(theta)
        theta = theta - (alpha/m)*(X.T.dot(h-y))
        J_history[iter] = computeCost(X,y,theta, m)
    return (theta, J_history)

# Compute gradient descent or theta for minimized cost J
theta, Cost_J = gradientDescent(X,y,theta, alpha, m)

print('theta: ', theta.ravel())

plt.plot(Cost_J)
plt.ylabel('Cost J')
plt.xlabel('Iterations')
plt.show()

# Plot the actual data and linear regression plot
xx = np.arange(5,23)
yy = theta[0] + theta[1]*xx

# Plot gradient descent
plt.scatter(X[:,1],y,s=30,c='r',marker='+',linewidths =1)
plt.plot(xx,yy,label='Linear regression (Gradient descent)')

# Compare with Scikit-learn Linear regression
regr = LinearRegression()
regr.fit(X[:,1].reshape(-1,1), y.ravel())
plt.plot(xx, regr.intercept_+regr.coef_*xx, label='Linear regression (Scikit-learn GLM)')

plt.xlim(4,24)
plt.xlabel('Population of City in 10,000s')
plt.ylabel('Profit in $10,000s')
plt.legend(loc=4);
plt.show()

# predict profit for a city with population of 35000 and 70000
print(theta.T.dot([1,3.5])*10000)
print(theta.T.dot([1,7])*10000)


import matplotlib.pyplot as plt
import numpy as np

from load_data import load_data
from multi_cost import multi_cost
from multi_gradient import gradient_descent
from prediction import predict_price

# Linear regression with multiple variables - predicting housing prices

# Load Data

filename = 'housing_data.txt'
housing_data = load_data(filename)

# Feature Normalization

# store the means and standard deviations for predictions
means = housing_data.mean()
stds = housing_data.std()

housing_data = (housing_data - housing_data.mean()) / housing_data.std()

# Inserting intercept parameter

housing_data.insert(0, 'Ones', 1)

# Convert pandas DataFrame to numpy arrays

cols = housing_data.shape[1]

x = housing_data.iloc[:, 0:cols-1]
y = housing_data.iloc[:, cols-1:cols]

x = x.values
y = y.values

# Set initial values

alpha = 0.03
iterations = 1000
theta = np.array([[0, 0, 0]])

# Cost Function

cost = multi_cost(x, y, theta)

# Gradient Descent

new_theta, cost_history = gradient_descent(x, y, theta, alpha, iterations)

# Plotting Data

fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(list(range(iterations)), cost_history, 'r')
plt.xlabel("Iterations")
plt.ylabel("Cost")
plt.title("Cost History in Epochs")
plt.show()

# Prediction

sq_feet = 1650
bedrooms = 3
new_price = predict_price(sq_feet, bedrooms, new_theta, means, stds)
print(f"The price for a {bedrooms} bedroom, {sq_feet} sq foot house is:\n\t${new_price}")


import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize

# Metodo con fit
def funzione(x, v0, Rg) :
    return v0/(x+Rg)

def derivata(x, V0, Rg) :
    return -V0/(Rg+x)**2

def chi2(x, popt, y, dy) :
    return np.sum(((y-funzione(x, *popt))/dy)**2)

# Dati
Rj, dRj, Ra, dRa = np.genfromtxt("resistenze.txt", skip_header=1, unpack=True)
Ij, dIj = np.genfromtxt("correnti.txt", skip_header=1, unpack=True)
Ij /= 1000
dIj /= 1000
Rx = Rj+Ra
dRx = (dRj**2+dRa**2)**0.5

# Fit
ndof = 10
dI_eff = dIj
popt, pcov = scipy.optimize.curve_fit(funzione, Rx, Ij, [4, 18], dI_eff, absolute_sigma=False)
chi2_new = chi2(Rx, popt, Ij, dI_eff)
chi2_old = -1
print(chi2_new)
for i in range (10) :
    dI_eff = ((derivata(Rx, *popt)*dRx)**2 + dIj**2)**0.5
    popt, pcov = scipy.optimize.curve_fit(funzione, Rx, Ij, [4, 18], dI_eff, absolute_sigma=False)
    chi2_old = chi2_new
    chi2_new = chi2(Rx, popt, Ij, dI_eff)
    print(chi2_new)

print("\nV0 ", popt[0], pcov[0][0]**0.5)
print("Rg ", popt[1], pcov[1][1]**0.5)
print("chi2 ", chi2_new)
print("chi2 ridotto {}/{}={}".format(chi2_new, ndof, chi2_new/ndof))
print("cov normalizzata", pcov[1][0]/(pcov[0][0]*pcov[1][1])**0.5, "\n")

# Grafici
# Plot funzione
x = np.linspace(1, 6, 4000)
x = 10**x
plt.figure()
plt.subplot(211)
plt.xscale('log')
plt.yscale('log')
plt.errorbar(Rx, Ij, yerr=dIj, xerr=dRx, fmt='.', label="Misure")
plt.plot(x, funzione(x, *popt), label="Fit")
plt.xlabel("R_eq [ohm]")
plt.ylabel("I [A]")
plt.legend()

# Plot residui normalizzati
plt.subplot(212)
plt.xscale('log')
plt.errorbar(Rx, (Ij-funzione(Rx, *popt))/dI_eff, fmt='o', label="Residui normalizzati")
plt.plot(x, x*0)
plt.xlabel("R_eq [ohm]")
plt.legend()
plt.show()

Lab 2/2 resistenza di thevenin e best fit/fit thevenin.py


import math
import numpy as np
import sombrero

def test_sombrero_initial():
    t = np.arange(0, 2*np.pi*50+0.001, 0.001) # t-values, dt of 0.001
    r0 = np.array([0, 0]) # initial conditions [x(0),y(0)]
    r = sombrero.runge_kutta_4thOrd(r0, t, F=0.4) # r vector
    x = np.array([i[0] for i in r]) # x points
    y = np.array([i[1] for i in r]) # y points
    assert (x[0] == 0 and y[0] == 0) # checking initial conditions

def test_sombrero_derivative_x():
    t = np.arange(0, 2*np.pi*50+0.001, 0.001) # t-values, dt of 0.001
    r0 = np.array([0, 0]) # initial conditions [x(0),y(0)]
    r = sombrero.runge_kutta_4thOrd(r0, t, F=0.4) # r vector
    x = np.array([i[0] for i in r]) # x points
    assert ((np.amin(x) > -1.5 or math.isclose(np.amin(x), -1.5, rel_tol=1e-01)) and (np.amax(x) < 1.5 or math.isclose(np.amax(x), 1.5, rel_tol=1e-01)))

def test_sombrero_derivative_y():
    t = np.arange(0, 2*np.pi*50+0.001, 0.001) # t-values, dt of 0.001
    r0 = np.array([0, 0]) # initial conditions [x(0),y(0)]
    r = sombrero.runge_kutta_4thOrd(r0, t, F=0.4) # r vector
    y = np.array([i[1] for i in r]) # y points
    assert ((np.amin(y) > -1.1 or math.isclose(np.amin(y), -1.1, rel_tol=1e-01)) and (np.amax(y) < 1.1 or math.isclose(np.amax(y), 1.1, rel_tol=1e-01)))