import math
import numpy as np

def basic_sigmoid(x):
    """
    Compute sigmoid of x.

    Arguments:
    x -- A scalar

    Return:
    s -- sigmoid(x)
    """

    s = 1 / (1+math.exp(-x))

    return s

def sigmoid(x):
    """
    Compute the sigmoid of x

    Arguments:
    x -- A scalar or numpy array of any size

    Return:
    s -- sigmoid(x)
    """

    s = 1 / (1+np.exp(-x))

    return s

def sigmoid_derivative(x):
    """
    Compute the gradient (also called the slope or derivative) of the sigmoid function with respect to its input x.
    You can store the output of the sigmoid function into variables and then use it to calculate the gradient.

    Arguments:
    x -- A scalar or numpy array

    Return:
    ds -- Your computed gradient.
    """

    s = sigmoid(x)
    ds =s * (1 - s)

    return ds

def image2vector(image):
    """
    Argument:
    image -- a numpy array of shape (length, height, depth)

    Returns:
    v -- a vector of shape (length*height*depth, 1)
    """

    v = image.reshape((image.shape[0]*image.shape[1]*image.shape[2], 1))

    return v

def normalizeRows(x):
    """
    Implement a function that normalizes each row of the matrix x (to have unit length).

    Argument:
    x -- A numpy matrix of shape (n, m)

    Returns:
    x -- The normalized (by row) numpy matrix. You are allowed to modify x.
    """

    x_norm = np.linalg.norm(x, ord = 2, axis = 1, keepdims = True)

    # Divide x by its norm.
    x = x / x_norm

    return x

def softmax(x):
    """Calculates the softmax for each row of the input x.

    Your code should work for a row vector and also for matrices of shape (n, m).

    Argument:
    x -- A numpy matrix of shape (n,m)

    Returns:
    s -- A numpy matrix equal to the softmax of x, of shape (n,m)
    """

    # Apply exp() element-wise to x.
    x_exp = np.exp(x)

    # Create a vector x_sum that sums each row of x_exp.
    x_sum =  np.sum(x_exp, axis = 1, keepdims = True)

    # Compute softmax(x) by dividing x_exp by x_sum.
    s = x_exp / x_sum

    return s

def any():
    x1 = [9, 2, 5, 0, 0, 7, 5, 0, 0, 0, 9, 2, 5, 0, 0]
    x2 = [9, 2, 2, 9, 0, 9, 2, 5, 0, 0, 9, 2, 5, 0, 0]

    ### VECTORIZED DOT PRODUCT OF VECTORS ###
    dot = np.dot(x1,x2)

    ### VECTORIZED OUTER PRODUCT ###
    outer = np.outer(x1,x2)

    ### VECTORIZED ELEMENTWISE MULTIPLICATION ###
    mul = np.multiply(x1,x2)

    ### VECTORIZED GENERAL DOT PRODUCT ###
    W = np.random.rand(3,len(x1))
    dot = np.dot(W,x1)

def L1(yhat, y):
    """
    Arguments:
    yhat -- vector of size m (predicted labels)
    y -- vector of size m (true labels)

    Returns:
    loss -- the value of the L1 loss function defined above
    """

    loss =  np.sum(np.abs(yhat-y))

    return loss

def L2(yhat, y):
    """
    Arguments:
    yhat -- vector of size m (predicted labels)
    y -- vector of size m (true labels)

    Returns:
    loss -- the value of the L2 loss function defined above
    """

    loss = sum((y-yhat)**2)

    return loss

# GRADED FUNCTION: propagate

def propagate(w, b, X, Y):
    """
    Implement the cost function and its gradient for the propagation explained above

    Arguments:
    w -- weights, a numpy array of size (num_px * num_px * 3, 1)
    b -- bias, a scalar
    X -- data of size (num_px * num_px * 3, number of examples)
    Y -- true "label" vector (containing 0 if non-cat, 1 if cat) of size (1, number of examples)

    Return:
    cost -- negative log-likelihood cost for logistic regression
    dw -- gradient of the loss with respect to w, thus same shape as w
    db -- gradient of the loss with respect to b, thus same shape as b

    Tips:
    - Write your code step by step for the propagation. np.log(), np.dot()
    """

    m = X.shape[1]

    A = sigmoid(np.dot(w.T,X) + b)
    cost = -1 / m * np.sum(Y*np.log(A)+(1-Y)*np.log(1-A), axis = 1, keepdims = True)

    dw = 1 / m * np.dot(X,(A-Y).T)
    db = 1 / m * np.sum(A-Y)

    assert(dw.shape == w.shape)
    assert(db.dtype == float)
    cost = np.squeeze(cost)
    assert(cost.shape == ())

    grads = {"dw": dw,
             "db": db}

    return grads, cost

    # GRADED FUNCTION: optimize

def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):
    """
    This function optimizes w and b by running a gradient descent algorithm

    Arguments:
    w -- weights, a numpy array of size (num_px * num_px * 3, 1)
    b -- bias, a scalar
    X -- data of shape (num_px * num_px * 3, number of examples)
    Y -- true "label" vector (containing 0 if non-cat, 1 if cat), of shape (1, number of examples)
    num_iterations -- number of iterations of the optimization loop
    learning_rate -- learning rate of the gradient descent update rule
    print_cost -- True to print the loss every 100 steps

    Returns:
    params -- dictionary containing the weights w and bias b
    grads -- dictionary containing the gradients of the weights and bias with respect to the cost function
    costs -- list of all the costs computed during the optimization, this will be used to plot the learning curve.

    Tips:
    You basically need to write down two steps and iterate through them:
        1) Calculate the cost and the gradient for the current parameters. Use propagate().
        2) Update the parameters using gradient descent rule for w and b.
    """

    costs = []

    for i in range(num_iterations):

        grads, cost = propagate(w, b, X, Y)

        dw = grads["dw"]
        db = grads["db"]

        w = w - learning_rate * dw
        b = b - learning_rate * db

        if i % 100 == 0:
            costs.append(cost)

        if print_cost and i % 100 == 0:
            print ("Cost after iteration %i: %f" %(i, cost))

    params = {"w": w,
              "b": b}

    grads = {"dw": dw,
             "db": db}

    return params, grads, costs

    def predict(w, b, X):
    '''
    Predict whether the label is 0 or 1 using learned logistic regression parameters (w, b)

    Arguments:
    w -- weights, a numpy array of size (num_px * num_px * 3, 1)
    b -- bias, a scalar
    X -- data of size (num_px * num_px * 3, number of examples)

    Returns:
    Y_prediction -- a numpy array (vector) containing all predictions (0/1) for the examples in X
    '''

    m = X.shape[1]
    Y_prediction = np.zeros((1,m))
    w = w.reshape(X.shape[0], 1)

    # Compute vector "A" predicting the probabilities of a cat being present in the picture
    A = sigmoid(np.dot(w.T,X) + b)

    for i in range(A.shape[1]):

        Y_prediction[0,i] = np.where(A[0,i]>0.5,1,0)

    assert(Y_prediction.shape == (1, m))

    return Y_prediction


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np

class CoordinatesConverter:

    @staticmethod
    def cart2pol(x, y):
        rho = np.sqrt(x ** 2 + y ** 2)
        phi = np.arctan2(y, x)
        return rho, phi

    @staticmethod
    def pol2cart(rho, phi):
        x = rho * np.cos(phi)
        y = rho * np.sin(phi)
        return x, y


import numpy as np
from scipy import stats

# generate data
N = 10
a = np.random.randn(N) + 2 # mean 2, variance 1
b = np.random.randn(N) # mean 0, variance 1

# roll your own t-test:
var_a = a.var(ddof=1) # unbiased estimator, divide by N-1 instead of N
var_b = b.var(ddof=1)
s = np.sqrt( (var_a + var_b) / 2 ) # balanced standard deviation
t = (a.mean() - b.mean()) / (s * np.sqrt(2.0/N)) # t-statistic
df = 2*N - 2 # degrees of freedom
p = 1 - stats.t.cdf(np.abs(t), df=df) # one-sided test p-value
print("t:\t", t, "p:\t", 2*p) # two-sided test p-value

# built-in t-test:
t2, p2 = stats.ttest_ind(a, b)
print("t2:\t", t2, "p2:\t", p2)


import numpy as np

from scipy.linalg import hilbert,lu

n = 10

H = hilbert(10)

#------------------------Q1-----------------------------
L = np.array([[0. for i in range(n)] for i in range(n)])
for i in range(0,n):
	L[i][i] = 1.

U = np.array([[0. for i in range(0,n)] for i in range(n)])
for i in range(0,n):
	for j in range(0,n):
		U[i][j] = H[i][j]

for i in range(n):
    for j in range(i+1,n):
        e = np.divide(U[j][i],U[i][i])
        L[j][i] = e
        to = np.array(U[i])
        to = e * to
        for k in range(n):
            U[j][k] -= to[k]

print("L")
for i in range(n):
    for j in range(n):
        print("%.12f" % L[i][j], end=" ")
    print()
print("\nU")

for i in range(n):
    for j in range(n):
        if(i > j):
            U[i][j] = 0.
        print("%.12f" % U[i][j], end=" ")
    print()

#------------------------Q2-----------------------------
b = np.array([1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0])

y = np.array([0. for i in range(n)])
x = np.array([0. for i in range(n)])

for i in range(n):
    t = b[i]
    for j in range(i):
        t -= y[j] * L[i][j]
    y[i] = t / L[i][i]

for i in range(n-1,-1,-1):
    t = y[i]
    for j in range(n-1,i-1,-1):
        t -= x[j] * U[i][j]
    x[i] = t / U[i][i]

for i in range(n):
    print("x%2d = %.10f" % (i+1,x[i]))
#------------------------Q3------------------------------
#Determinant of Upper-Triangular is the product of the diagonal components.
#And, Determinant of Orignal Matrix and Matrix U is same.
#So, we can obtain determinant by using the Matrix U.

det = 1.

for i in range(n):
    det = np.multiply(det,U[i][i])

print("Det of H = ",det)

#------------------------Q4------------------------------
#[Hx1,Hx2, ... , Hxn] = [e1,e2, ... ,en]
inv = [[],[],[],[],[],[],[],[],[],[]]

for p in range(n):
    b_inv = np.array([0. for j in range(n)])
    y_inv = np.array([0. for j in range(n)])
    x_inv = np.array([0. for j in range(n)])
    b_inv[p] = 1.
    for i in range(n):
        t = b_inv[i]
        for j in range(i):
            t -= y_inv[j] * L[i][j]
        y_inv[i] = t / L[i][i]

    for i in range(n-1,-1,-1):
        t = y_inv[i]
        for j in range(n-1,i-1,-1):
            t -= x_inv[j] * U[i][j]
        x_inv[i] = t / U[i][i]

    for i in range(n):
        inv[i].append(x_inv[i])

inv = np.array(inv)

print("H^-1")

for i in range(n):
    for j in range(n):
        print("%18.6f" % inv[i][j], end=" ")
    print()


'''
Finding the best fit linear slope for a dataset example
'''

from statistics import mean
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import style

style.use('fivethirtyeight')

# test data
xs = np.array([1,2,3,4,5,6], dtype=np.float64)
ys = np.array([5,4,6,5,6,7], dtype=np.float64)

# generate best fit slope based on averages and square means
def best_fit_slope_and_intercept(xs, ys):
    m = ((mean(xs) * mean(ys)) - mean(xs * ys)) / ((mean(xs) ** 2) - mean(xs ** 2))
    b = mean(ys) - m*mean(xs)

    return m, b

# y = mx + c
m,b = best_fit_slope_and_intercept(xs, ys)

regression_line = [(m * x) + b for x in xs] # create list of y values

# predictions
predict_x = 8
predict_y = (m * predict_x) + b

# plot
plt.scatter(xs, ys)
plt.scatter(predict_x, predict_y, color='g')
plt.plot(xs, regression_line)
plt.show()


'''
Demonstration of how to execute some basic operations:
    - Root finding
    - Interpolation
    - Integration

Shows how the functions in the old "ClimateUtilities.py" can be replaced
with numpy and scipy routines.

Dependencies
------------
numpy, matplotlib, scipy

License
-------
BSD 3-clause (see https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)

'''

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

#==============================================
#---Section: Math utilities-------------------
#==============================================

if __name__ == '__main__':

    # Usage Examples:
    # ===============

    # 1. Finding roots of a function (replaces the old "newtSolv")
    # ------------------------------------------------------------
    from scipy.optimize import newton

    def show_root(initial_guess, root):
        '''Show initial guess and resulting root value'''
        print('With initial guess {0}, we get the root {1}.'.format(
            initial_guess, root) )

    # Example 1.1: Function without parameters
    print('--- Example 1 ---')
    def g(x):
        return x*x - 1.

    initial_guess = 2.
    root = newton(g, initial_guess)
    show_root(initial_guess, root)

    # Example 1.2: Function with parameters
    print('--- Example 2 ---')
    def g(x, a, b):
        return a*x*x - b

    initial_guess = 2.
    a, b = 1, 2
    root = newton(g, initial_guess, args=(a, b))
    show_root(initial_guess, root)

    initial_guess = 1.
    root = newton(g, initial_guess, args=(a, b))
    show_root(initial_guess, root)

    # 2. Interpolation (replaces the old "interp" and "polint")
    # ---------------------------------------------------------
    from scipy.interpolate import interp1d

    # Generate some data
    x = np.linspace(0, 10, num=11, endpoint=True)
    y = np.cos(-x**2/9.0)
    xnew = np.linspace(0, 10, num=41, endpoint=True)

    # Make a "linear" and a "cubic" interpolation object
    f = interp1d(x, y)
    f2 = interp1d(x, y, kind='cubic')

    # Calculate and plot the interpolated data
    plt.plot(x, y, 'o', label='data')
    plt.plot(xnew, f(xnew), '-', label='linear')
    plt.plot(xnew, f2(xnew),'--', label='cubic')
    plt.legend()
    plt.show()

    # 3. Romberg Integration (replaces the old "romberg")
    # ---------------------------------------------------
    from scipy.integrate import romberg

    # Define a function
    def f(x):
        return x**2

    # Integrate the function, from -1 to 2:
    a, b = -1, 2
    integral = romberg(f, a, b)

    print('The integral of f(x) between {0} and {1} is: {2}'.format(a, b, integral))


#! /usr/bin/env python

"""
File: centered_diff.py
Copyright (c) 2016 Austin Ayers
License: MIT

Course: PHYS227
Assignment: 3.18
Date: Feb 11, 2016
Email: ayers111@mail.chapman.edu
Name: Austin Ayers
Description: Approxiates many derivatives
"""

import sympy as sp
import math

def quad(x):
    return (x**2)
def exponent(x):
    return math.exp(x)
def exponent2(x):
    return math.exp(-2*x**2)
def cosine(x):
    return sp.cos(x)
def ln(x):
    return sp.log(x)

def diff(f,x, h=1E-5):
    """
    Approximates a derivative of a function at a point
    """
    return ((f(x+h)-f(x-h))/(2*float(h)))
def test_diff():
    print(diff(quad, 5))
    assert(diff(quad, 5) - 10 < 0.00001)

def application():
    print("error of e^x @ (x=0): " + str(abs(diff(exponent, 0, .01) - 1)))
    print("error of e^(-2x^2) @ (x=0): " + str(abs(diff(exponent2, 0, .01))))
    print("error of cos(x) @ (x=2pi): " + str(abs(diff(cosine, 2*sp.pi, .01))))
    print("error of ln(x) @ (x=1): " + str(abs(diff(ln, 1, .01))))


# -*- coding: utf-8 -*-
import numpy as np
from playML.metrics import r2_score

class SimpleLinearRegression1(object):
    """
    自己手写的简陋实现简单线性回归算法
    """
    def __init__(self):
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        """

        :param x_train:
        :param y_train:
        :return:
        """
        assert x_train.ndim == 1, 'Simple Linear Regressor can only solve single feature training data.'
        assert len(x_train) == len(y_train), 'the size of x_train must be equal to the size of y_train'

        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)

        # 分子
        numerator = 0.0

        # 分母
        denominator = 0.0

        for x_i, y_i in zip(x_train, y_train):
            numerator += (x_i - x_mean)*(y_i - y_mean)
            denominator += (x_i - x_mean)**2

        self.a_ = numerator / denominator
        self.b_ = y_mean - self.a_ * x_mean

        return self

    def predict(self, x_predict):
        assert x_predict.ndim == 1, 'Simple Linear Regressor can only solve single feature training data.'
        assert self.a_ is not None and self.b_ is not None, 'must fit before predict'
        return np.array([self._predict(x) for x in x_predict])

    def _predict(self, x_single):
        return self.a_ * x_single + self.b_

    def __repr__(self):
        return 'SimpleLinearRegression1()'

class SimpleLinearRegression2(object):
    """
    自己手写的简陋实现简单线性回归算法，把for循环改为向量化运算，提升效率
    """
    def __init__(self):
        self.a_ = None
        self.b_ = None

    def fit(self, x_train, y_train):
        """

        :param x_train:
        :param y_train:
        :return:
        """
        assert x_train.ndim == 1, 'Simple Linear Regressor can only solve single feature training data.'
        assert len(x_train) == len(y_train), 'the size of x_train must be equal to the size of y_train'

        x_mean = np.mean(x_train)
        y_mean = np.mean(y_train)

        # 分子
        numerator = (x_train - x_mean).dot(y_train - y_mean)

        # 分母
        denominator = (x_train - x_mean).dot(x_train - x_mean)

        self.a_ = numerator / denominator
        self.b_ = y_mean - self.a_ * x_mean

        return self

    def predict(self, x_predict):
        assert x_predict.ndim == 1, 'Simple Linear Regressor can only solve single feature training data.'
        assert self.a_ is not None and self.b_ is not None, 'must fit before predict'
        return np.array([self._predict(x) for x in x_predict])

    def _predict(self, x_single):
        return self.a_ * x_single + self.b_

    def score(self, x_test, y_test):
        """
        根据测试数据集x_test和y_test 确定当前模型的准确度
        :param x_test:
        :param y_test:
        :return:
        """
        y_predict = self.predict(x_test)
        return r2_score(y_test, y_predict)

    def __repr__(self):
        return 'SimpleLinearRegression2()'

class SimpleLinearRegression(SimpleLinearRegression2):
    pass


import numpy as np
from random import randint

class Ham_15_11:
    """
    The class is used for hamming code [15,11,3]
    """

    def __init__(self,sourceCode=None):
        self._H = np.matrix([[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
                             [0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1],
                             [0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
                             [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]])
        self._G = np.matrix([[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                             [1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                             [0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                             [1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
                             [1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
                             [0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
                             [1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
                             [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
                             [1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
                             [0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0],
                             [1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1]])
        self._sourceCode = sourceCode
        self._codeRes = None

    def updateSourceCode(self,sourceCode):
        if not isinstance(sourceCode, str):
            raise TypeError("sourceCode: expected string, but got %r" % type(sourceCode).__name__)
        assert len(sourceCode) == 11
        sourceCode = np.matrix([int(e) for e in list(sourceCode)])
        self._sourceCode = sourceCode

    def updateCodeRes(self, codeRes):
        if not isinstance(codeRes, str):
            raise TypeError("codeRes: expected string, but got %r" % type(codeRes).__name__)
        assert len(codeRes) == 15
        codeRes = np.matrix([int(e) for e in list(codeRes)])
        self._codeRes = codeRes

    def encode(self):
        codeRes = self._sourceCode * self._G % 2
        self._codeRes = codeRes
        codeRes = codeRes.tolist()[0]
        codeRes = ''.join([str(e) for e in codeRes])
        return codeRes

    def decode(self):
        z = self._H * self._codeRes.T % 2
        mul = np.matrix([1,2,4,8])
        error = (mul * z).sum()
        codeRes = self._codeRes.tolist()[0]
        if not error == 0:
            codeRes[error-1] = (codeRes[error-1]+1) % 2
        codeRes = codeRes[2:3]+codeRes[4:7] + codeRes[8:]
        return ''.join([str(e) for e in codeRes])

if __name__ == '__main__':
    ham = Ham_15_11()
    with open('hamming_15_11.txt','w') as f:
        for i in range(2**11):
            sourceCode = bin(i).replace('0b','').rjust(11,'0')
            sourceCode = sourceCode[::-1]
            ham.updateSourceCode(sourceCode)
            codeRes = ham.encode()
            line = ''.join([sourceCode,', ',codeRes,'\n'])
            if i == 2**11-1:
                line=line[:-1]
            f.write(line)
        f.close()

    #this part used to check decode
    with open('hamming_15_11.txt', 'r') as f:
        checkpoint = 0
        for line in f:
            codeRes = line.split(' ')[1].replace('\n','')
            ham.updateCodeRes(codeRes)
            expectedAns = line.split(',')[0]
            ans = ham.decode()
            if not ans == expectedAns:
                print('check failed in {} -> {},{} expected'.format(codeRes,ans,expectedAns))
                exit(-1)
            checkpoint += 1
        print('%d points checked, decode test pass!!!' % checkpoint)
        f.close()

    #this part used to simulate error and check decode
    with open('hamming_15_11.txt', 'r') as f:
        checkpoint = 0
        for line in f:
            codeRes = line.split(' ')[1].replace('\n','')
            codeRes = [int(e) for e in codeRes]
            errorP = randint(0, 14)
            codeRes[errorP] = (codeRes[errorP]+1) % 2
            codeRes = ''.join(str(e) for e in codeRes)
            ham.updateCodeRes(codeRes)
            expectedAns = line.split(',')[0]
            ans = ham.decode()
            if not ans == expectedAns:
                print('check failed in {} -> {},{} expected'.format(codeRes,ans,expectedAns))
                exit(-1)
            checkpoint += 1
        print('%d points checked, decode( with one error) test pass!!!' % checkpoint)


"""Ordinary least squares and related problems."""
from typing import Optional

import numpy as np

from optimus.types import Function

class LeastSquares(Function):
    """Ordinary least squares of the form min ||Ax - b||^2."""

    is_c2 = True

    def __init__(self, inputs: np.ndarray, targets: np.ndarray):
        """Initialize a least squares problem.

        `inputs` is `A` (i.e. the matrix of features), and targets is
        `b` (i.e. the vector of observed values)."""
        self.inputs = inputs
        self.targets = targets
        self._cached_hessian: Optional[np.ndarray] = None

    def __call__(self, parameters: np.ndarray) -> float:
        difference_vector = self.inputs.dot(parameters) - self.targets
        return np.dot(difference_vector, difference_vector)

    def gradient(self, parameters: np.ndarray) -> np.ndarray:
        return 2 * (self.inputs.dot(parameters) - self.targets).T.dot(self.inputs)

    def partial_second_derivative(
        self, parameters: np.ndarray, first_variable: int, second_variable: int
    ) -> float:
        # This is reasonable because the hessian is constant.
        return self.hessian(parameters)[first_variable, second_variable]

    def hessian(self, parameters: np.ndarray) -> np.ndarray:
        if self._cached_hessian is None:
            self._cached_hessian = self.inputs.T.dot(self.inputs)
        return self._cached_hessian


import numpy as np

def index(a, weights = None):
    """
    Compute the Gini Coefficient.
    Thanks Gaëtan de Menten: https://stackoverflow.com/a/49571213/5890574

    Parameters
    ----------
    a : array_like
        1-D array containing the values of the distribution.
    weights : array_like, optional
        1-D array of integer weights associated with the values in `a`. Each value in
        `a` contributes to the average according to its associated weight.
        If `weights=None`, then all data in `a` are assumed to have a
        weight equal to one.

    Returns
    -------
    gini : float
        Returns the Gini Coefficient of the distribution provided.
    """
    a = np.asarray(a)
    if weights is not None:
        weights = np.asarray(weights)
        sorted_indices = np.argsort(a)
        sorted_x = a[sorted_indices]
        sorted_w = weights[sorted_indices]
        # Force float dtype to avoid overflows
        cumw = np.cumsum(sorted_w, dtype=float)
        cumxw = np.cumsum(sorted_x * sorted_w, dtype=float)
        return (np.sum(cumxw[1:] * cumw[:-1] - cumxw[:-1] * cumw[1:]) /
                (cumxw[-1] * cumw[-1]))
    else:
        sorted_x = np.sort(a)
        n = len(a)
        cumx = np.cumsum(sorted_x, dtype=float)
        # The above formula, with all weights equal to 1 simplifies to:
        return (n + 1 - 2 * np.sum(cumx) / cumx[-1]) / n


# -*- coding: utf-8 -*-
"""Linear regression for machine learning

This file demonstrate knowledge of linear regression. By building the algorithm
from scratch.The idea of linear regression is to take continuous data and find
the best fit of it to a line.
"y=mx+b" is the equation of a line, and we need to figure out the
best slope (m) and y-intercept (b) to fit the line best.

This is for simple 2d regression.

Example:

        $ python howItWorksLinearRegression.py

Todo:
    *
"""
import random

from statistics import mean

from matplotlib import style
import matplotlib.pyplot as plt

import numpy as np

style.use('fivethirtyeight')

# simple_x = np.array([1, 2, 3, 4, 5, 6], dtype=np.float64)
# simple_y = np.array([5, 4, 6, 5, 6, 7], dtype=np.float64)

def create_dataset(howmany, variance, step=2, correlation=False):
    # for test-data
    val = 1
    ys = []
    for i in range(howmany):
        y = val + random.randrange(-variance, variance)
        ys.append(y)
        if correlation and correlation == 'pos':
            val += step
        elif correlation and correlation == 'neg':
            val -= step
    xs = [i for i in range(len(ys))]
    return np.array(xs, dtype=np.float64), np.array(ys, dtype=np.float64)

simple_x, simple_y = create_dataset(40, 10, 2, correlation='pos')

def best_fit_slope_and_intercept(xs, ys):
    # Best fit m(slope)
    m = (mean(xs) * mean(ys) - mean(xs * ys)) / (mean(xs)**2 - mean(xs**2))
    # Best fit y(intercept)
    b = mean(ys) - m * mean(xs)
    return m, b

def squared_error(ys_orig, ys_line):
    # Figuring out the squared_error that we need to calculate R^2
    return sum((ys_line - ys_orig)**2)

def coefficient_of_determination(ys_orig, ys_line):
    # Figuring out R^2 = 1 - (squared_error(y_hat) / squared_error(mean(y)))
    y_mean_line = [mean(ys_orig) for y in ys_orig]  # line of mean(y)s
    squared_error_regressionline = squared_error(ys_orig, ys_line)
    squared_error_y_mean = squared_error(ys_orig, y_mean_line)
    return 1 - (squared_error_regressionline / squared_error_y_mean)

m, b = best_fit_slope_and_intercept(simple_x, simple_y)
regression_line = [(m * x) + b for x in simple_x]  # "y=mx+b"

predict_x = 8
predict_y = (m * predict_x) + b
r_squared = coefficient_of_determination(simple_y, regression_line)

print(r_squared)

plt.scatter(simple_x, simple_y)
plt.plot(simple_x, regression_line, color='g')
plt.scatter(predict_x, predict_y, color='r')
plt.show()


# euclid norm
# https://numpy.org/doc/stable/reference/generated/numpy.linalg.norm.html
from numpy import linalg as la
import numpy as np

a = np.arange(9) - 4
# print(np.arange(9))
# print(a)
b = a.reshape((3, 3))
# print(b)
'''
print(la.norm(a))
print(la.norm(b))
print(la.norm(b, 'fro'))
print(la.norm(a, np.inf))
print(la.norm(b, np.inf))
print(la.norm(a, -np.inf))
print(la.norm(b, -np.inf))
print(la.norm(a, 1))
print(la.norm(b, 1))
# print(la.norm(a, -1))
print(la.norm(b, -1))
print(la.norm(a, 2))
print(la.norm(b, 2))
# print(la.norm(a, -2))
print(la.norm(b, -2))
print(la.norm(a, 3))
# print(la.norm(a, -3))
'''
c = np.array([[1, 2, 3], [-1, 1, 4]])
# # using axis compute vector norms
# print(la.norm(c, axis=0))
# print(la.norm(c, axis=1))
# print(la.norm(c, ord=1, axis=1))

# using axis compute matrix norms
m = np.arange(12).reshape(2, 3, -1)
# print(la.norm(m, axis=(1, 2)))
# print(m[0, :, :])
# print(m[1, :, :])
# print(la.norm(m[0, :, :]), la.norm(m[1, :, :]))

m = np.arange(3) - 1
# print(m)
# print(m/la.norm(m))


import numpy
# reference: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
def line_low(x0, y0, x1, y1):
    res = []
    dx = x1 - x0
    dy = y1 - y0
    yi = 1
    if dy < 0:
        yi = -1
        dy = -dy
    D = 2*dy - dx
    y = y0
    for x in range(x0, x1 + 1):
        res.append((x,y))
        if D > 0:
            y = y + yi
            D = D - 2*dx
        D = D + 2*dy
    return res

def line_high(x0, y0, x1, y1):
    res = []
    dx = x1 - x0
    dy = y1 - y0
    xi = 1
    if dx < 0:
        xi = -1
        dx = -dx
    D = 2*dx - dy
    x = x0

    for y in range(y0, y1 + 1):
        res.append((x,y))
        if D > 0:
            x = x + xi
            D = D - 2*dy
        D = D + 2*dx
    return res

def bresenham_line(A, B):
    x0 = int(A[0])
    y0 = int(A[1])
    x1 = int(B[0])
    y1 = int(B[1])

    if abs(y1 - y0) < abs(x1 - x0):
        if x0 > x1:
            return line_low(x1, y1, x0, y0)
        else:
            return line_low(x0, y0, x1, y1)
    else:
        if y0 > y1:
            return line_high(x1, y1, x0, y0)
        else:
            return line_high(x0, y0, x1, y1)

# reference: https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
def bresenham_circle(C):
    x0 = int(C[0])
    y0 = int(C[1])
    radius = int(C[2])
    res = []
    x = int(radius-1)
    y = int(0)
    dx = int(1)
    dy = int(1)
    err = int(dx - (radius << 1))

    while (x >= y):
        res.append((x0 + x, y0 + y))
        res.append((x0 + y, y0 + x))
        res.append((x0 - y, y0 + x))
        res.append((x0 - x, y0 + y))
        res.append((x0 - x, y0 - y))
        res.append((x0 - y, y0 - x))
        res.append((x0 + y, y0 - x))
        res.append((x0 + x, y0 - y))

        if (err <= 0):
            y += 1
            err += dy
            dy += 2

        if (err > 0):
            x -= 1
            dx += 2
            err += dx - (radius << 1)

    return res


import numpy as np

from math import copysign, hypot

def gram_schmidt_process(A):
    """
    Perform QR decomposition of matrix A using Gram-Schmidt process.
    """
    (num_rows, num_cols) = np.shape(A)

    # Initialize empty orthogonal matrix Q.
    Q = np.empty([num_rows, num_rows])
    cnt = 0

    # Compute orthogonal matrix Q.
    for a in A.T:
        u = np.copy(a)
        for i in range(0, cnt):
            proj = np.dot(np.dot(Q[:, i].T, a), Q[:, i])
            u -= proj

        e = u / np.linalg.norm(u)
        Q[:, cnt] = e

        cnt += 1  # Increase columns counter.

    # Compute upper triangular matrix R.
    R = np.dot(Q.T, A)

    return (Q, R)

def householder_reflection(A):
    """
    Perform QR decomposition of matrix A using Householder reflection.
    """
    (num_rows, num_cols) = np.shape(A)

    # Initialize orthogonal matrix Q and upper triangular matrix R.
    Q = np.identity(num_rows)
    R = np.copy(A)

    # Iterative over column sub-vector and
    # compute Householder matrix to zero-out lower triangular matrix entries.
    for cnt in range(num_rows - 1):
        x = R[cnt:, cnt]

        e = np.zeros_like(x)
        e[0] = copysign(np.linalg.norm(x), -A[cnt, cnt])
        u = x + e
        v = u / np.linalg.norm(u)

        Q_cnt = np.identity(num_rows)
        Q_cnt[cnt:, cnt:] -= 2.0 * np.outer(v, v)

        R = np.dot(Q_cnt, R)
        Q = np.dot(Q, Q_cnt.T)

    return Q, R

def givens_rotation(A):
    """
    Perform QR decomposition of matrix A using Givens rotation.
    """
    (num_rows, num_cols) = np.shape(A)

    # Initialize orthogonal matrix Q and upper triangular matrix R.
    Q = np.identity(num_rows)
    R = np.copy(A)

    # Iterate over lower triangular matrix.
    (rows, cols) = np.tril_indices(num_rows, -1, num_cols)
    for (row, col) in zip(rows, cols):

        # Compute Givens rotation matrix and
        # zero-out lower triangular matrix entries.
        if R[row, col] != 0:
            (c, s) = _givens_rotation_matrix_entries(R[col, col], R[row, col])

            G = np.identity(num_rows)
            G[[col, row], [col, row]] = c
            G[row, col] = s
            G[col, row] = -s

            R = np.dot(G, R)
            Q = np.dot(Q, G.T)

    return Q, R

def _givens_rotation_matrix_entries(a, b):
    """
    Compute matrix entries for Givens rotation.
    """
    r = hypot(a, b)
    c = a/r
    s = -b/r

    return c, s


# import modules
import numpy as np

'''
# Description.
With the extreme points of the defined slope, this function obtains the
lower possible boundary in where a slip circle can be, i.e. obtains the
maximum depth computed from the slope toe.

# Input(s).
Height of the slope (slopeHeight).

Slope dip, can be given by an angle in gradians, angle in radians, a
horizontal distance value relative to a unitary vertical distance (i.e.
horz:1), or a bidimensional vector which represents a horizontal distance and
a vertical distance that not necessary representing the real slope distances
[horzDist, vertDist], (slopeDip).

Crown horizontal plane distance (crownDist).

Toe horizontal plane distance (toeDist).

# Output(s):
Vertical distance from the slide--toe to downwards (toeDepth).

# Example1: By giving next values:
slopeHeight = 12; slopeDip = np.array([2.5, 1]); crownDist = 10.0;\
toeDist = 10.0; it is obtained a toeDepth = 14.44.

---
toeDepth = obtainmaxdepthdist(slopeHeight, slopeDip, crownDist, toeDist)
'''
def obtainmaxdepthdist(slopeHeight, slopeDip, crownDist, toeDist):

    #Calculation assuming coordinates origin at the slip--toe
    extremeToePointVec = np.array([toeDist, 0])

    #slope vertical projection (horizontal distance)
    slopeDist = slopeHeight*slopeDip[0]/slopeDip[1]

    extremeCrownPointVec = np.array([-(slopeDist +crownDist), slopeHeight])

    #distance between the two extreme points
    differenceVec = extremeToePointVec-extremeCrownPointVec
    distExtrPts = np.sqrt(np.dot(differenceVec, differenceVec))
    maximumCircleRadius = distExtrPts/2*distExtrPts/differenceVec[0]

    #the toe depth is the difference between the maximum--circle radius and the
    #slope height
    toeDepth = maximumCircleRadius-slopeHeight

    return toeDepth
'''
BSD 2 license.

Copyright (c) 2016, Universidad Nacional de Colombia, Ludger O.
   Suarez-Burgoa and Exneyder Andrés Montoya Araque.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''


import numpy as np

def sigmoid_forward(x):
    """
    Sigmoid function, sigmoid(x) = 1/(1+exp(-x))
    :param x: input
    :return: output and cache
    """
    return 1 / (1 + np.exp(-x)), x

def sigmoid_backward(dout, cache):
    """
    backward of sigmoid function, dx = x(x-1)
    :param dout: grad of outputs
    :param cache: cache stored before
    :return: dx
    """
    x = cache
    return x * (x - 1) * dout

def tanh_forward(x):
    """
    Tanh function, tanh(x) = (exp(x) - exp(-x))/ (exp(x) + exp(-x))
    :param x: input
    :return: output
    """
    y = (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
    return y, y

def tanh_backward(dout, cache):
    """
    backward of tanh, dx = 1 - (tanh(x))^2
    :param dout:
    :param cache:
    :return:
    """
    tanh_x = cache
    return (1 - tanh_x ** 2) * dout

def softmax_forward(x):
    """
    Softmax function, softmax(x) = exp(x[i]) / sum(exp(x[i]))
    :param x: input
    :return: output
    """
    temp = np.sum(np.exp(x))
    return np.exp(x) / temp, x

def softmax_backward(dout, cache):
    """
    backward of softmax, if i=j dx=x[j](1-x[j]) if i!=j dx=-x[i]x[j]
    x.shape=(N, 1)
    :param dout: grad of outputs
    :return: grads of input
    """
    x = cache
    dx_1 = x * (1 - x)
    # sum_x_2 = np.sum(np.dot(x.T, x), axis=0, keepdims=True)
    # sum_x_2 -= x ** 2
    dx = dx_1 * dout

    return dx

def relu_forward(x):
    """
    ReLu function, relu(x) = max(0, x)
    :param x: input
    :return: output and cache
    """
    return np.maximum(0, x), x

def relu_backward(dout, cache):
    x = cache
    dx = dout
    dx[x <= 0] = 0
    return dx

def leaky_relu_forward(x, alpha=0.01):
    """
    Leaky ReLu function, leaky_relu(x)=max(alpha * x, x)
    :param x: input
    :param alpha: hyperparameter of leaky relu
    :return: output
    """
    return np.maximum(alpha * x, x)

if __name__ == '__main__':
    # x = np.random.randn(1, 10)
    # y, cache = relu_forward(x)
    # dy = np.random.randn(1, 10)
    # dx = relu_backward(dy, cache)
    # print(dx)
    x = np.ones((1, 2))
    y = np.array([1,2]).reshape(1,2)
    print(x[y<2])


import numpy as np

g = list(range(10))

# sum of array
g_array = np.sum(g)
print(g_array)

# Constructor of array
a = np.array([1,2,3,4])
# a.shape = (4,)
b = np.array([10,11,12,13])
# a + b => array([11,13,15,17])
"""
In normal python: a + b -> [1,2,3,4,10,11,12,13]
"""

a.fill(1)
# a = [1,1,1,1]

##########################################################
# Control the type of array
b= np.array([1,2,3,4.0], dtype = int32)

c = np.array([[10,11,12],[20,21,22]])
"""
c.dtype dtype('int64')
c.ndim = 2
c.shape = (2,3)
"""
# Transport matrix
c.T = [[10,20],
        [11,21],
        [12,22]]
"""
c.size = 6
c.nbytes = 48
c[0,0] = 10  -> don't like in normal python c[0][0]
"""

##########################################################
# Slicing:  var[lower:upper:step]
a = np.array([10,11,12,13,14])
# a[::2] -> array([10,12,14])

a = [[0,1,2,3,4,5],
    [10,11,12,13,14,15],
    [20,21,22,23,24,25],
    [30,31,32,33,34,35],
    [40,41,42,43,44,45],
    [50,51,52,53,54,55]]

"""
a[0, 3:5] -> array([]3,4)
a[4:, 4:] -> array([44,45],[54,55])
a[:, 2]   -> array([2,12,22,32,42,52])
a[2::2, ::2]    -> array([20,22,24],[40,42,44])
"""

##########################################################
a = np.arange(25).reshape(5,5)
"""
array([[ 0,  1,  2,  3,  4],
    [ 5,  6,  7,  8,  9],
    [10, 11, 12, 13, 14],
    [15, 16, 17, 18, 19],
    [20, 21, 22, 23, 24]])
"""
red = a[:, ::2]
yellow = a[4]
blue = [1::2, 0:3:2]

##########################################################
a = np.array([3,-1,-2,4,-6,8])
"""
a < 0
-> array([False,  True,  True, False,  True, False])
a[a<0]  -> array([-1,-2,-6])
(a < 8).any()   -> true
(a , 8).all()   -> false

&(and) , |(or) , ~(not) , ^(xor)  -> bitwise operators
and or not -> binary operators

(a > 3) & (a < 8)   -> array([False,False,False,True,False,False])

a.nonzero(arr) -> get the array which is built with the numbers which are not equal 0
"""


import numpy as np
import math
from scipy import linalg as la

def gmres(A,b, k=100, tol=1e-8):
    """
    Calculate approximate solution of Ax = b using GMRES algorithm.
    Inputs:
        A -- callable function that calculates Ax for any input vector x.
        b -- numpy array of length m
        k -- Maximum number of iterations of the GMRES algorithm. Defaults to 100.
        tol -- Stop iterating if the residual is less than `tol'. Defaults to 1e-8.
    Returns:
        Return (y, res) where 'y' is an approximate solution to Ax=b and 'res'
    is the residual.
    """
    # initialization steps
    m = b.size
    Q = np.empty((m,k))
    H = np.zeros((k+1,k))
    bnorm = la.norm(b,2)
    rhs = np.zeros(k+1)
    rhs[0] = bnorm
    Q[:,0] = b/bnorm

    for j in xrange(k-1):
        # Arnoldi iteration
        q = A(Q[:,j])
        for i in xrange(j+1):
            H[i,j] = np.inner(Q[:,i],q)
            q -= H[i,j]*Q[:,i]
        H[j+1,j] = la.norm(q,2)
        if H[j+1,j] > 1e-10:
            # don't divide by zero!
            q /= H[j+1,j]
        Q[:,j+1] = q

        # solve the least squares problem
        y, r = la.lstsq(H[:j+2,:j+1], rhs[:j+2])[:2]

        # compute the residual.
        r = math.sqrt(r)/bnorm
        if r < tol:
            # if we are sufficiently close to solution, return
            return Q[:,:j+1].dot(y), r
    return Q[:,:j+1].dot(y.flatten()), r


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

def plot_column_vectors_2d(matrix):
    """
    Plots column vectors from the supplied matrix in the 2D plane.  The matrix must have shape (2,X), where X >= 1.
    :param matrix: a (2,X) matrix; x >= 1
    :return: None.  Displays 2D plot.
    """
    if matrix.shape[0] != 2:
        raise ValueError("Matrix must have 2d column space")

    origin = np.zeros_like(matrix)

    fig, ax = plt.subplots()

    xmin, xmax = min(np.min(matrix[0]), 0), max(np.max(matrix[0]), 0)
    ymin, ymax = min(np.min(matrix[1]), 0), max(np.max(matrix[1]), 0)

    ax.axis(list(map(int, [xmin - 1, xmax + 1, ymin - 1, ymax + 1])))
    ax.grid(True)

    colors = np.linalg.norm(matrix, axis=0)
    colormap = plt.get_cmap('jet')

    norm = Normalize()
    norm.autoscale(colors)

    ax.quiver(origin[0], origin[1], matrix[0], matrix[1], scale=1, color=colormap(norm(colors)), angles='xy',
              scale_units='xy')

def plot_column_vectors_with_transform_2d(matrix, transform):
    """
    Displays a side-by-side plot of the column vectors in the supplied matrix and the column vectors in the transformed matrix matrix * transform.

    The matrix must have shape (2,X), where X >= 1.
    The transform must have shape (2,2)

    :param matrix: a (2,X) matrix; x >= 1
    :param transform: a (2,2) transformation matrix.
    :return: None. Displays 2 2D subplots.
    """
    if matrix.shape[0] != 2:
        raise ValueError("Matrix must have 2d column space")

    if transform.shape != (2, 2):
        raise ValueError("Transform matrix must have shape (2,2)")

    origin = np.zeros_like(matrix)

    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))

    colors = np.linalg.norm(matrix, axis=0)
    colormap = plt.get_cmap('jet')

    norm = Normalize()
    norm.autoscale(colors)

    trans_matrix = np.dot(transform, matrix)

    xmin, xmax = min(np.min(matrix[0]), 0), max(np.max(matrix[0]), 0)
    ymin, ymax = min(np.min(matrix[1]), 0), max(np.max(matrix[1]), 0)

    ax1.axis(list(map(int, [xmin - 1, xmax + 1, ymin - 1, ymax + 1])))
    ax1.set_title("$A$")
    ax1.grid(True)
    ax1.quiver(origin[0], origin[1], matrix[0], matrix[1], color=colormap(norm(colors)), scale=1, angles='xy',
               scale_units='xy')

    xmin, xmax = min(np.min(trans_matrix[0]), 0), max(np.max(trans_matrix[0]), 0)
    ymin, ymax = min(np.min(trans_matrix[1]), 0), max(np.max(trans_matrix[1]), 0)

    ax2.axis(list(map(int, [xmin - 1, xmax + 1, ymin - 1, ymax + 1])))
    ax2.set_title("$TA$")
    ax2.grid(True)
    ax2.quiver(origin[0], origin[1], trans_matrix[0], trans_matrix[1], color=colormap(norm(colors)), scale=1,
               angles='xy', scale_units='xy')


#These are the python libraries that are going to help us to create a plot
import matplotlib.pyplot as plt
import numpy as np

#This is the function that will be intergrated
def f(x):
    #x**4-2*x+1
    return x**4-2*x+1

#This 'Trapizoid_Rule' function will require a function,
#'b' value so the lower limit of a integral
#'a' value so the upper limit of a integral
# The amount of NUMERICAL PLOTS.

def Trapizoid_Rule(f, xmin, xmax, N):
    #the area has been initially set to 0
    area = 0
    #h is the step size
    h = (xmax-xmin)/N

    #the 'arange' function return evenly spaced numbers over a specified interval
    #It takes in the a & b limit parameters and Amount of NUMERICAL PLOTS
    npoints = np.arange(xmin, xmax, h)
    del_dis = np.delete(npoints, 0)
    area = h*((f(xmin)/2)+(f(xmax)/2)+sum(f(xmin+del_dis)))

    return area

#-----ENTER THE FOLLOWING----
#Function f
#upper limit (a)
#lower limit (b)
#Amount of NUMERICAL PLOTS

def integrate(f,a,b,N):

    integral = Trapizoid_Rule(f,a,b,N)
    integral2 = Trapizoid_Rule(f,a,b,N/2)

    x = np.linspace(a, b, int(N))
    #size of graph
    plt.figure(figsize=(14,7))
    #graph plotting function
    plt.plot(x,f(x),'--o',label=r'$f(x)$')

    #this function fills in the area between the a and b limits
    plt.fill_between(x,f(x), where =[(x>=a)and(x<=b) for x in x],color= 'gray', alpha = '0.7')

    #this function produces lines from the NUMERICAL PLOTS to the x-axis
    plt.vlines(x, 0, f(x), color='purple', linestyle=':')

    ###aixs lines##############
    plt.axhline(color='black')
    plt.axvline(color = 'black')
    ############################

    ###These are the axis labels######
    plt.ylabel("f(x)",fontsize=16)
    plt.xlabel("x",fontsize = 16)

    #this is the little box that displayed the colour of the function
    plt.legend(loc='upper right')

    plt.grid(color = 'gray', linewidth=1)
    plt.show()

    error = abs(integral-integral2)/3
    return integral,error

#This is the integrate function, the following parameters can be changed
#first--function--
#second--start time
#third--end time
#fourth--Numerical Plots
ans,err_est = integrate(f,0,2,1000)
#N=10, Error=0.10613333333333348
#N=100, Error=0.001066613333333244
#N=1000, Error=1.0666661333758043e-05

print('EXACT INTERGRAL=',ans,'||','ESTIMATED ERROR =',err_est)


# Question 2 Lab 03
# AB Satyaprakash (180123062)

# imports ----------------------------------------------------------------------
import numpy as np
# ------------------------------------------------------------------------------
# functions --------------------------------------------------------------------

def forwardDiff(fArray):
    sz = len(fArray)
    fdArray = [fArray]
    for i in range(1, sz):
        temp = []
        for j in range(sz-i):
            temp.append(fdArray[i-1][j+1]-fdArray[i-1][j])
        fdArray.append(temp)
    return fdArray

def newtonBDPoly(fArray, xArray):
    sz = len(fArray)
    xn, xn_1 = xArray[sz-1], xArray[sz-2]
    h = xn-xn_1
    # print(h)
    v = np.array([1/h, -xn/h])
    # print(v)
    fdArray = forwardDiff(fArray)
    # print(fdArray)
    px = np.array([0])

    for i in range(sz):
        term = np.array([1])
        for j in range(i):
            term = np.polymul(term, np.polyadd(v, np.array([j])))
            term = term/(j+1)
        term = term*fdArray[i][sz-i-1]
        px = np.polyadd(px, term)
    return px

# ------------------------------------------------------------------------------
# (i) f(−1/3) if f(−0.75) = −0.07181250, f(−0.5) = −0.02475000, f(−0.25) = 0.33493750, f(0) = 1.10100000
print('Part (i)-----------------------------------------------------------------\n')
X = [-0.75, -0.5, -0.25, 0]
F = [-0.07181250, -0.02475000, 0.33493750, 1.10100000]
val = -1/3  # since we need to approximate f(1/3)
# (A) Degree 1:

xArray = [X[1], X[2]]
fArray = [F[1], F[2]]
px = newtonBDPoly(fArray, xArray)
print("Newton's interpolating polynomial of degree 1 using nodes: {}, {} is {}".format(
    xArray[0], xArray[1], np.poly1d(px)))
print("Approximated value of f({}) using the above is {}".format(val, np.polyval(px, val)))

print('\n')

# (B) Degree 2:

xArray = [X[0], X[1], X[2]]
fArray = [F[0], F[1], F[2]]
px = newtonBDPoly(fArray, xArray)
print("Newton's interpolating polynomial of degree 2 using nodes: {}, {}, {} is \n{}".format(
    xArray[0], xArray[1], xArray[2], np.poly1d(px)))
print("Approximated value of f({}) using the above is {}".format(val, np.polyval(px, val)))

print('\n')

# (C) Degree 3:
xArray = [X[0], X[1], X[2], X[3]]
fArray = [F[0], F[1], F[2], F[3]]
px = newtonBDPoly(fArray, xArray)
print("Newton's interpolating polynomial of degree 3 using nodes: {}, {}, {}, {} is \n{}".format(
    xArray[0], xArray[1], xArray[2], xArray[3], np.poly1d(px)))
print("Approximated value of f({}) using the above is {}".format(val, np.polyval(px, val)))

# (ii) f(0.25) if f(0.1) = −0.62049958 , f(0.2) = −0.28398668 , f(0.3) = 0.00660095, f(0.4) = 0.24842440
print('\nPart (ii)--------------------------------------------------------------\n')
X = [0.1, 0.2, 0.3, 0.4]
F = [-0.62049958, -0.28398668, 0.00660095, 0.24842440]
val = 0.25  # since we need to approximate f(0.25)
# (A) Degree 1:

xArray = [X[1], X[2]]
fArray = [F[1], F[2]]
px = newtonBDPoly(fArray, xArray)
print("Newton's interpolating polynomial of degree 1 using nodes: {}, {} is {}".format(
    xArray[0], xArray[1], np.poly1d(px)))
print("Approximated value of f({}) using the above is {}".format(val, np.polyval(px, val)))

print('\n')

# (B) Degree 2:
xArray = [X[0], X[1], X[2]]
fArray = [F[0], F[1], F[2]]
px = newtonBDPoly(fArray, xArray)
print("Newton's interpolating polynomial of degree 2 using nodes: {}, {}, {} is \n{}".format(
    xArray[0], xArray[1], xArray[2], np.poly1d(px)))
print("Approximated value of f({}) using the above is {}".format(val, np.polyval(px, val)))

print('\n')

# (C) Degree 3:
xArray = [X[0], X[1], X[2], X[3]]
fArray = [F[0], F[1], F[2], F[3]]
px = newtonBDPoly(fArray, xArray)
print("Newton's interpolating polynomial of degree 3 using nodes: {}, {}, {}, {} is \n{}".format(
    xArray[0], xArray[1], xArray[2], xArray[3], np.poly1d(px)))
print("Approximated value of f({}) using the above is {}".format(val, np.polyval(px, val)))

# Question 2 ends --------------------------------------------------------------

Semester 6/MA 322 (Scientific Computing Theory)/Labs/Lab 3/Code/q2.py


# Author: Leland McInnes <leland.mcinnes@gmail.com>
#
# License: BSD 3 clause

# still to do here:
# add dot distance
# change cosine to angular in the right fashion, since angular is the preferred input of annoy

import numpy as np
import numba

@numba.njit(fastmath=True)
def euclidean(x, y):
    """Standard euclidean distance.

    ..math::
        D(x, y) = \sqrt{\sum_i (x_i - y_i)^2}
    """
    result = 0.0
    for i in range(x.shape[0]):
        result += (x[i] - y[i]) ** 2
    return np.sqrt(result)

@numba.njit(fastmath=True)
def manhattan(x, y):
    """Manhattan, taxicab, or l1 distance.

    ..math::
        D(x, y) = \sum_i |x_i - y_i|
    """
    result = 0.0
    for i in range(x.shape[0]):
        result += np.abs(x[i] - y[i])

    return result

@numba.njit(fastmath=True)
def hamming(x, y):
    result = 0.0
    for i in range(x.shape[0]):
        if x[i] != y[i]:
            result += 1.0

    return float(result) / x.shape[0]

@numba.njit(fastmath=True)
def cosine(x, y):
    result = 0.0
    norm_x = 0.0
    norm_y = 0.0
    for i in range(x.shape[0]):
        result += x[i] * y[i]
        norm_x += x[i] ** 2
        norm_y += y[i] ** 2

    if norm_x == 0.0 or norm_y == 0.0:
        return 1.0
    else:
        return 1.0 - (result / np.sqrt(norm_x * norm_y))

# is correlation dot product / inner distance ?
# if not, add dot product / innder distance :)
@numba.njit(fastmath=True)
def correlation(x, y):
    mu_x = 0.0
    mu_y = 0.0
    norm_x = 0.0
    norm_y = 0.0
    dot_product = 0.0

    for i in range(x.shape[0]):
        mu_x += x[i]
        mu_y += y[i]

    mu_x /= x.shape[0]
    mu_y /= x.shape[0]

    for i in range(x.shape[0]):
        shifted_x = x[i] - mu_x
        shifted_y = y[i] - mu_y
        norm_x += shifted_x ** 2
        norm_y += shifted_y ** 2
        dot_product += shifted_x * shifted_y

    if dot_product == 0.0:
        return 1.0
    else:
        return 1.0 - (dot_product / np.sqrt(norm_x * norm_y))

named_distances = {
    # general minkowski distances
    "euclidean": euclidean,
    "l2": euclidean,
    "manhattan": manhattan,
    "taxicab": manhattan,
    "l1": manhattan,
    # Standardised/weighted distances
    # Other distances
    "cosine": cosine, # input to annoy = angular
    # Binary distances
    "hamming": hamming,
    # "dot": dot,

}


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

import numpy as np
import matplotlib.pyplot as pl

#%% Q1 setup
def binomial(n, p, N):
    return np.math.factorial(N)/(np.math.factorial(n)*np.math.factorial(N-n))*(p**n)*((1-p)**(N-n))

def uniform(n, p, N):
    return 1/(N+1)

def KL(p, N, distp, distq):
    kl = 0
    for n in range(N):
        kl -= distp(n, p, N)*np.log2(distq(n, p, N)/distp(n, p, N))
    return kl

def align_yaxis(ax1, v1, ax2, v2):
    """adjust ax2 ylimit so that v2 in ax2 is aligned to v1 in ax1"""
    _, y1 = ax1.transData.transform((0, v1))
    _, y2 = ax2.transData.transform((0, v2))
    inv = ax2.transData.inverted()
    _, dy = inv.transform((0, 0)) - inv.transform((0, y1-y2))
    miny, maxy = ax2.get_ylim()
    ax2.set_ylim(miny+dy, maxy+dy)

#%% Q1(c)
KL_N10 = []
KL_N100 = []

for p in np.linspace(0, 1, 1000):
    KL_N10.append(KL(p, 10, uniform, binomial))
    KL_N100.append(KL(p, 100, uniform, binomial))

fig, ax = pl.subplots(1,1)
ax.plot(np.linspace(0, 1, 1000), KL_N10, 'b-', label="N=10")
ax2 = ax.twinx()
ax2.plot(np.linspace(0, 1, 1000), KL_N100, 'r-', label="N=100")
ax.set_xlabel("p")
ax.set_ylabel("KL divergence (N=10)")
ax2.set_ylabel("KL divergence (N=100)")
align_yaxis(ax, 0, ax2, 0)
ax.legend()
ax2.legend()

#%% Q1(d)
def poisson(n, p, N):
    lam = p*N
    return (lam**n)*(np.exp(-lam))/np.math.factorial(n)

KL_lam_N10 = []
KL_lam_N100 = []

for p in np.linspace(0, 1, 1000):
    KL_lam_N10.append(KL(p, 10, poisson, binomial))
    KL_lam_N100.append(KL(p, 100, poisson, binomial))

fig1, ax1 = pl.subplots(1,1)
ax1.plot(np.linspace(0, 1, 1000), KL_lam_N10, 'b-', label="N=10")
ax3 = ax1.twinx()
ax3.plot(np.linspace(0, 1, 1000), KL_lam_N100, 'r-', label="N=100")
ax1.set_xlabel("p")
ax1.set_ylabel("KL divergence (N=10)")
ax3.set_ylabel("KL divergence (N=10000)")
align_yaxis(ax1, 0, ax3, 0)
ax1.legend(loc=0)
ax3.legend(loc=6)

#%% Q5(a)
import math
def eff(N):
    return np.log2(N)/math.ceil(np.log2(N))

N_arr = []

for n in range(2,101):
    N_arr.append(eff(n))

fig2, ax4 = pl.subplots(1,1)
ax4.plot(np.arange(2, 101), N_arr, 'b-')
ax4.set_xlabel(r"$N$")
ax4.set_ylabel(r"Efficiency")

#%%
N_arr = np.array(N_arr)
print(np.arange(2,101)[np.argmin(N_arr)]) # N = 5 gives smallest efficiency
print(np.min(N_arr))
print(N_arr[-1])


import numpy as np

a = np.array([20,30,40,50])     # [20 30 40 50]
b = np.arange(4)        # [0 1 2 3]
print(a)
print(b)

c = a-b
print(c)

""" [20 30 40 50]
    [0 1 2 3]
    [20 29 38 47]
    """

d = b**2    # [0 1 4 9]
print(d)

e = 10 * np.sin(a)      # [ 9.12945251 -9.88031624  7.4511316  -2.62374854]
print(e)

print(e < 7)        # [False  True False  True]
print(a*b)     # [  0  30  80 150]

print(a@b)     # matris çarpımı sonucu : 260
print(a.dot(b)) # matris çarpımı sonucu : 260

f = np.ones((2,4))

""" [[1. 1. 1. 1.]
 [1. 1. 1. 1.]] """

g = np.zeros((2,4))

""" [[0. 0. 0. 0.]
 [0. 0. 0. 0.]] """

h = np.random.random((2,4))

""" [[0.24448762 0.30569748 0.38721877 0.42359117]
 [0.74705078 0.64296611 0.87855028 0.44236936]] """

i = np.sum(b)     # 6

j  = np.min(c)    # 20

k = np.max(h)     # 0.8785502826111841

l =np.sqrt(b)     # [0.         1.         1.41421356 1.73205081]

print(f)
print('----------------------')
print(g)
print('----------------------')
print(h)
print('----------------------')
print(i)
print('----------------------')
print(j)
print('----------------------')
print(k)
print('----------------------')
print(l)


"""
Simulating a black body curve

"""

from scipy.optimize import curve_fit
import pylab as plt
import numpy as np

def blackbody_lam(lam, T):
    """ Blackbody as a function of wavelength (um) and temperature (K).

    returns units of erg/s/cm^2/cm/Steradian
    """
    from scipy.constants import h,k,c
    lam = 1e-6 * lam # convert to metres
    return 2*h*c**2 / (lam**5 * (np.exp(h*c / (lam*k*T)) - 1))

wa = np.linspace(0.1, 2, 100)   # wavelengths in um
T1 = 5000.
T2 = 8000.
y1 = blackbody_lam(wa, T1)
y2 = blackbody_lam(wa, T2)
ytot = y1 + y2

np.random.seed(1)

# make synthetic data with Gaussian errors

sigma = np.ones(len(wa)) * 1 * np.median(ytot)
ydata = ytot + np.random.randn(len(wa)) * sigma

# plot the input model and synthetic data

plt.figure()
plt.plot(wa, y1, ':', lw=2, label='T1=%.0f' % T1)
plt.plot(wa, y2, ':', lw=2, label='T2=%.0f' % T2)
plt.plot(wa, ytot, ':', lw=2, label='T1 + T2\n(true model)')
plt.plot(wa, ydata, ls='steps-mid', lw=2, label='Fake data')
plt.xlabel('Wavelength (microns)')
plt.ylabel('Intensity (erg/s/cm$^2$/cm/Steradian)')

# fit two blackbodies to the synthetic data

def func(wa, T1, T2):
    return blackbody_lam(wa, T1) + blackbody_lam(wa, T2)

# Note the initial guess values for T1 and T2 (p0 keyword below). They
# are quite different to the known true values, but not *too*
# different. If these are too far away from the solution curve_fit()
# will not be able to find a solution. This is not a Python-specific
# problem, it is true for almost every fitting algorithm for
# non-linear models. The initial guess is important!

popt, pcov = curve_fit(func, wa, ydata, p0=(1000, 3000), sigma=sigma)

# get the best fitting parameter values and their 1 sigma errors
# (assuming the parameters aren't strongly correlated).

bestT1, bestT2 = popt
sigmaT1, sigmaT2 = np.sqrt(np.diag(pcov))

ybest = blackbody_lam(wa, bestT1) + blackbody_lam(wa, bestT2)

print 'True model values'
print '  T1 = %.2f' % T1
print '  T2 = %.2f' % T2

print 'Parameters of best-fitting model:'
print '  T1 = %.2f +/- %.2f' % (bestT1, sigmaT1)
print '  T2 = %.2f +/- %.2f' % (bestT2, sigmaT2)

degrees_of_freedom = len(wa) - 2
resid = (ydata - func(wa, *popt)) / sigma
chisq = np.dot(resid, resid)

print degrees_of_freedom, 'dof'
print 'chi squared %.2f' % chisq
print 'nchi2 %.2f' % (chisq / degrees_of_freedom)

# plot the solution

plt.plot(wa, ybest, label='Best fitting\nmodel')
plt.legend(frameon=False)

plt.show()


"""
Some code for B-Spline curve

S(x) = Sum_{j=0}^{n-1} c[j] * B[j,k;t](x)

B[i,0](x) = 1 if t[i] <= x <= t[i+1], otherwise 0
B[i,k](x) = (x - t[i]) / (t[i+k] - t[i]) * B[i, k-1](x) + (t[i+k+1] - x) / (t[i+k+1] - t[i+1]) * B[i+1, k-1](x)

Ref:
[1] https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.BSpline.html
"""

from scipy.interpolate import BSpline
import matplotlib.pyplot as plt
import numpy as np

def basic(x, i, k, t):
    """Basic elements in B-Spline"""
    if k == 0:
        return 1.0 if t[i] <= x < t[i + 1] else 0.0

    if t[i + k] == t[i]:
        c1 = 0.0
    else:
        c1 = (x - t[i]) / (t[i + k] - t[i]) * basic(x, i, k - 1, t)

    if t[i + k + 1] == t[i + 1]:
        c2 = 0.0
    else:
        c2 = (t[i + k + 1] - x) / (t[i + k + 1] - t[i + 1]) * basic(x, i + 1, k - 1, t)

    return c1 + c2

def bspline(x, t, c, k):
    """B-Spline function"""
    n = len(t) - k - 1
    assert (n >= k + 1) and (len(c) >= n)
    return sum(c[i] * basic(x, i, k, t) for i in range(n))

def main():
    k = 2
    t = [0, 1, 2, 3, 4, 5, 6]
    c = [-1, 2, 0, -1]
    sp1 = BSpline(t, c, k, True)  # if extrapolate is False, they are the same
    print(f'BSpline(2.5) = {sp1(2.5)}, bspline(2.5) = {bspline(2.5, t, c, k)}')
    xx = np.linspace(1.5, 4.5, 50)
    xx_fine = np.linspace(1.5, 4.5, 500)

    # figure, B-Spline basic function
    fig = plt.figure('B-Spline Basic Function')
    ax = fig.add_subplot(111)
    ax.plot(xx_fine, [basic(x, 2, 0, t) for x in xx_fine], 'k-', label='degree = 0')
    ax.plot(xx_fine, [basic(x, 2, 1, t) for x in xx_fine], 'b-', label='degree = 1')
    ax.plot(xx_fine, [basic(x, 2, 2, t) for x in xx_fine], 'r-', label='degree = 2')
    ax.grid(True)
    ax.set_title('B-Spline Basic Function B[2, k]')
    ax.legend(loc='best')
    plt.show(block=False)

    # figure: B-Spline
    fig = plt.figure('B-Spline')
    ax = fig.add_subplot(111)
    ax.plot(xx, [bspline(x, t, c, k) for x in xx], 'r-', label='naive')
    ax.plot(xx, sp1(xx), 'b.-', label='BSpline')
    ax.grid(True)
    ax.set_title('B-Spline')
    ax.legend(loc='best')
    plt.show(block=True)

if __name__ == '__main__':
    main()


# This function does the Gram-Schmidt process
# It transforms a matrix into a matrix of orthonormal vectors

import numpy as np
import numpy.linalg as la

# A => Matrix
def gsBasis(A):
  verySmallNumber = 1e-14
  B = np.array(A, dtype=np.float_)

  # loop over vectors in the matrix (column-wise)
  for i in range(B.shape[1]):
    # loop over all previous vectors before 'i'
    for j in range(i):
      # do the GS procedure
      B[:,i] = B[:,i] - (B[:,i] @ B[:,j]) * B[:,j]

    # if vector is linearly independent, normalize
    if la.norm(B[:,i]) > verySmallNumber:
      B[:, i] = B[:, i] / la.norm(B[:, i])
    else:
      B[:,i] = np.zeros_like(B[:,i])

  return B

# Some matrix definition
V = np.array([[1,0,2,6],
              [0,1,8,2],
              [2,8,3,1],
              [1,-6,2,3]], dtype=np.float_)

# A non-square matrix
U = np.array([[3,2,3],
              [2,5,-1],
              [2,4,8],
              [12, 2, 1]], dtype=np.float_)

print(gsBasis(V))
Normed = gsBasis(V)

# gsBasis on an orthonormal matrix returns itself
print(gsBasis(Normed))

def dimensions(A) :
    return np.sum(la.norm(gsBasis(A), axis=0))

print(dimensions(V))

# Now let's see what happens when we have one vector that is a linear combination of the others.
C = np.array([[1,0,2],
              [0,1,-3],
              [1,0,2]], dtype=np.float_)
gsBasis(C)


from scipy.stats import norm
from scipy.integrate import quad
import numpy as np

def d2(n=2, method="exact"):
    """
    Computes the d2 statistic used for measuring
    relative range standard deviation approximation.

    The d2 statistic is often found in statistical process
    control tables.

    That is, standard deviation can be approximated by
    R / d2 where R is the range of the data (max - min)
    and d2 is computed as below.

    See also:
    https://v8doc.sas.com/sashtml/qc/chapc/sect9.htm

    :param n:
        Number of distributions considered for computing
        d2. All are normal with mean=0 and std=1.
    :param method:
        Optional. Method to use. Default "exact".
            - "exact" computes the exact infinite integral.
            - "random" uses normal distributions generated
              on the fly to compute d2.
    :return:
        d2:
            the expectation value [that is, average here]
            of the ranges of the distributions
    """
    if method == "exact":
        def f(x, n):
            return 1 - (1 - norm.cdf(x)) ** n - (norm.cdf(x)) ** n

        d2 = quad(f, -np.inf, np.inf, args=(n))[0]
        return d2

    elif method == "random":
        x = {}
        # slots to fill with normally distributed samples
        for i in range(n):
            x[i] = norm.rvs(size=100000, loc=0, scale=1)

        x = np.vstack([x[i] for i in x])

        maxs = np.amax(x, axis=0)
        mins = np.amin(x, axis=0)

        r = maxs - mins

        d2 = np.average(r)
        return d2


import rotation
import numpy as np

def sphericalToCartesian(rho, lat, lon):
    phi = lat
    the = lon
    x = rho * np.cos(phi) * np.cos(the)
    y = rho * np.cos(phi) * np.sin(the)
    z = rho * np.sin(phi)
    return np.array([[x],
                    [y],
                    [z]])

def cartesianToSpherical(x,y,z):
    pho = np.sqrt(x**2 + y**2 + z**2)
    lon = np.arctan2(y,x)
    base = np.sqrt(x**2 + y**2)
    lat = np.arctan2(z, base)

    return (pho, (180/np.pi)*lat, (180/np.pi)*lon)

def localToWorldMatrix(lat, lon):
    lamda = lon * np.pi/180
    phi = lat * np.pi/180
    R = np.array([[-np.sin(lamda), -np.sin(phi) * np.cos(lamda), np.cos(phi) * np.cos(lamda)],
                [np.cos(lamda), -np.sin(phi) * np.sin(lamda), np.cos(phi) * np.sin(lamda)],
                [0, np.cos(phi), np.sin(phi)]])
    return R

def worldToLocalMatrix(lat, lon):
    # phi = lat
    # the = lon
    # R = rotation.RotX(180) * rotation.RotZ(90) * rotation.RotX(phi) * rotation.RotZ(the)
    R = localToWorldMatrix(lat, lon)
    return np.linalg.inv(R)

def pointWorldToLocal(p1_w, p0_w, R_wl):
    return R_wl * (p1_w - p0_w)

def pointLocalToWorld(p1_l, p0_w, R_lw):
    return R_lw * p1_l + p0_w

# if __name__ == "__main__":
#     R = localToWorldMatrix(30,60)
#     print(R)


# -*- coding: utf-8 -*-
"""
Created on Thu Dec  2 13:39:48 2021

@author: Oliver

"""

"""Roots of Equation Systems"""
import math

import numpy as np

"""Finding roots of multi-variable equations"""

x = 1.5
y = 3.5

dudx = lambda x, y: 2*x+y
dvdx = lambda y: 3*y**2
dudy = lambda x: x
dvdy = lambda x, y: 1+6*x*y

a = np.array([[dudx(x,y),dudy(x)], [dvdx(y),dvdy(x,y)]]) # Jacobian Matrix

initial_u_guess = lambda x, y: x**2 + x*y - 10
initial_v_guess = lambda x, y: y + 3*x*y**2 -57

x_new = x - ((initial_u_guess(x, y)*dvdy(x,y) - initial_v_guess(x, y)*x))/np.linalg.det(a)
y_new = y - (initial_v_guess(x, y)*dudx(x,y) - (initial_u_guess(x, y)*dvdx(y)))/np.linalg.det(a)
x_sol = 2
y_sol = 3
counter = 0
error = 0

while True:
    counter += 1
    x_new = x - ((initial_u_guess(x, y)*dvdy(x,y) - initial_v_guess(x, y)*x))/np.linalg.det(a)
    y_new = y - (initial_v_guess(x, y)*dudx(x,y) - (initial_u_guess(x, y)*dvdx(y)))/np.linalg.det(a)

    if x_sol - error<=x_new<=x_sol + error:
        print(f'The solution has been found after {counter} iterations and the values are x: {x_new} and y: {y_new}')
        break
    if counter == 3:
        print(f'The solution after {counter} iterations is: x: {x_new}, y: {y_new} with relative error in: x: {abs(x_new-x_sol)/x_sol} and y: {abs(y_new-y_sol)/y_sol}')
    else:
        x = x_new
        y = y_new

"""Roots of Polynomial Equations"""
# Factorization of Polynomials

f = [1,2,-24]
guess = 4
values =[f[0]]
z = f[0]
for i in range(0,len(f)-2):
    x = f[i+1] + z*guess
    print(x)
    z = x
    values.append(x)
print(values)

"""Polynomial Division"""

def expanded_synthetic_division(dividend, divisor):
    """Fast polynomial division by using Expanded Synthetic Division.
    Also works with non-monic polynomials.

    Dividend and divisor are both polynomials, which are here simply lists of coefficients.
    E.g.: x**2 + 3*x + 5 will be represented as [1, 3, 5]
    """
    out = list(dividend)  # Copy the dividend
    normalizer = divisor[0]
    for i in range(len(dividend) - len(divisor) + 1):
        # For general polynomial division (when polynomials are non-monic),
        # we need to normalize by dividing the coefficient with the divisor's first coefficient
        out[i] /= normalizer

        coef = out[i]
        if coef != 0:  # Useless to multiply if coef is 0
            # In synthetic division, we always skip the first coefficient of the divisor,
            # because it is only used to normalize the dividend coefficients
            for j in range(1, len(divisor)):
                out[i + j] += -divisor[j] * coef

    # The resulting out contains both the quotient and the remainder,
    # the remainder being the size of the divisor (the remainder
    # has necessarily the same degree as the divisor since it is
    # what we couldn't divide from the dividend), so we compute the index
    # where this separation is, and return the quotient and remainder.
    separator = 1 - len(divisor)
    return out[:separator], out[separator:]  # Return quotient, remainder.

if __name__=='__main__':
    print ("POLYNOMINAL SYNTHETIC DIVISION")
    N = [1, 2, -24]
    D = [1, -4]
    print (" %s /%s =" % (N,D),)
    print (" %s remainder %s" % expanded_synthetic_division(N, D))

"""Muller's Technique - Finding Roots"""

def f(x):
    return x**3 - 13*x - 12

def Muller(x_r, h, eps, maxit):
    iter = 0
    x2 = x_r
    x1 = x_r + h * x_r
    x0 = x_r - h * x_r
    while True:
        iter += 1
        h0 = x1 - x0
        h1 = x2 - x1
        d0 = (f(x1) - f(x0)) / h0
        d1 = (f(x2) - f(x1)) / h1
        a = (d1 - d0) / (h1 + h0)
        b = a * h1 + d1
        c = f(x2)
        rad = math.sqrt(abs(b**2 - 4*a*c))
        if abs(b + rad) > abs(b - rad):
            den = b + rad
        else:
            den = b - rad
        dx_r = -2 * c / den
        x_r = x2 + dx_r
        print(f'Iteration: {iter}, Value of root: {x_r}, Error: {abs((x2/x_r*100)-100)}%')
        if (abs(dx_r) < eps * x_r or iter >= maxit):
            break
        x0 = x1
        x1 = x2
        x2 = x_r
    return None
x_r = 20
h = 0.1
eps = 0.01
maxit = 10

solution = Muller(x_r, h, eps, maxit)
print(solution)


# Нахождение прямой, проходящей через набор точек
# Дмитрий Хизбуллин, 2021

import math
import numpy as np
from typing import Optional, Any
import matplotlib.pyplot as plt

def generate_points(axis: Optional[Any] = None) -> np.ndarray:
    """
    Функция, генерирующая массив точек, приблизительно лежащих на
    отрезке прямой.

    :param axis: Набор осей, на которых рисовать график
    :return: Numpy массив формы [N, 2] точек на прямой
    """

    # Давайте сгенерируем 10 точек, лежащих на прямой
    num_points = 10
    p_initial = np.array((-2, 3))
    speed = 1.0
    angle_degrees = -30
    angle_radians = angle_degrees / 180 * math.pi
    velocity = speed * np.array((math.cos(angle_radians),
                                 math.sin(angle_radians)))
    ideal_points = np.expand_dims(p_initial, 0) + \
                   np.outer(np.arange(0, num_points), velocity)
    # и добавим немного шума, чтобы промоделировать реальные измерения
    noise = 0.1 * np.random.randn(num_points, 2)
    points = ideal_points + noise

    if axis is not None:
        for ax in axis:
            ax.set_title("Входной набор точек")
            ax.plot(points[:, 0], points[:, 1], 'or')
            ax.grid(True, linestyle='--')
            ax.axis('equal')

    return points

def least_squares(points: np.ndarray, axis: Optional[Any] = None) \
        -> np.ndarray:
    """
    Функция для аппроксимации массива точек прямой, основанная на
    методе наименьших квадратов.

    :param points: Входной массив точек формы [N, 2]
    :param axis: Набор осей, на которых рисовать график
    :return: Numpy массив формы [N, 2] точек на прямой
    """

    x = points[:, 0]
    y = points[:, 1]
    # Для метода наименьших квадратов нам нужно, чтобы X был матрицей,
    # в которой первый столбец - единицы, а второй - x координаты точек
    X = np.vstack((np.ones(x.shape[0]), x)).T
    normal_matrix = np.dot(X.T, X)
    moment_matrix = np.dot(X.T, y)
    # beta_hat это вектор [перехват, наклон], рассчитываем его в
    # в соответствии с формулой.
    beta_hat = np.dot(np.linalg.inv(normal_matrix), moment_matrix)
    intercept = beta_hat[0]
    slope = beta_hat[1]
    # Теперь, когда мы знаем параметры прямой, мы можем
    # легко вычислить y координаты точек на прямой.
    y_hat = intercept + slope * x
    # Соберем x и y в единую матрицу, которую мы собираемся вернуть
    # в качестве результата.
    points_hat = np.vstack((x, y_hat)).T

    if axis is not None:
        for ax in axis:
            ax.set_title("Метод наименьших квадратов")
            ax.plot(x, y, 'or')
            ax.plot(x, y_hat, 'o-', mfc='none')
            ax.grid(True, linestyle='--')
            ax.axis('equal')

    return points_hat

def ransac(points: np.ndarray,
           min_inliers: int = 4,
           max_distance: float = 0.15,
           outliers_fraction: float = 0.5,
           probability_of_success: float = 0.99,
           axis: Optional[Any] = None) -> Optional[np.ndarray]:
    """
    RANdom SAmple Consensus метод нахождения наилучшей
    аппроксимирующей прямой.

    :param points: Входной массив точек формы [N, 2]
    :param min_inliers: Минимальное количество не-выбросов
    :param max_distance: максимальное расстояние до поддерживающей прямой,
                         чтобы точка считалась не-выбросом
    :param outliers_fraction: Ожидаемая доля выбросов
    :param probability_of_success: желаемая вероятность, что поддерживающая
                                   прямая не основана на точке-выбросе
    :param axis: Набор осей, на которых рисовать график
    :return: Numpy массив формы [N, 2] точек на прямой,
             None, если ответ не найден.
    """

    # Давайте вычислим необходимое количество итераций
    num_trials = int(math.log(1 - probability_of_success) /
                     math.log(1 - outliers_fraction**2))

    best_num_inliers = 0
    best_support = None
    for _ in range(num_trials):
        # В каждой итерации случайным образом выбираем две точки
        # из входного массива и называем их "суппорт"
        random_indices = np.random.choice(
            np.arange(0, len(points)), size=(2,), replace=False)
        assert random_indices[0] != random_indices[1]
        support = np.take(points, random_indices, axis=0)

        # Здесь мы считаем расстояния от всех точек до прямой
        # заданной суппортом. Для расчета расстояний от точки до
        # прямой подходит функция векторного произведения.
        # Особенность np.cross в том, что функция возвращает только
        # z координату векторного произведения, а она-то нам и нужна.
        cross_prod = np.cross(support[1, :] - support[0, :],
                              support[1, :] - points)
        support_length = np.linalg.norm(support[1, :] - support[0, :])
        # cross_prod содержит знаковое расстояние, поэтому нам нужно
        # взять модуль значений.
        distances = np.abs(cross_prod) / support_length

        # Не-выбросы - это все точки, которые ближе, чем max_distance
        # к нашей прямой-кандидату.
        num_inliers = np.sum(distances < max_distance)
        # Здесь мы обновляем лучший найденный суппорт
        if num_inliers >= min_inliers and num_inliers > best_num_inliers:
            best_num_inliers = num_inliers
            best_support = support

    # Если мы успешно нашли хотя бы один суппорт,
    # удовлетворяющий всем требованиям
    if best_support is not None:
        # Спроецируем точки из входного массива на найденную прямую
        support_start = best_support[0]
        support_vec = best_support[1] - best_support[0]
        # Для расчета проекций отлично подходит функция
        # скалярного произведения.
        offsets = np.dot(support_vec, (points - support_start).T)
        proj_vectors = np.outer(support_vec, offsets).T
        support_sq_len = np.inner(support_vec, support_vec)
        projected_vectors = proj_vectors / support_sq_len
        projected_points = support_start + projected_vectors

        if axis is not None:
            for ax in axis:
                ax.set_title("RANSAC")
                ax.scatter(best_support[:, 0], best_support[:, 1],
                            s=200, facecolors='none', edgecolors='k', marker='s')
                ax.plot(points[:, 0], points[:, 1], 'or')
                ax.plot(projected_points[:, 0], projected_points[:, 1],
                         'o-', mfc='none')
                ax.grid(True, linestyle='--')
                ax.axis('equal')
    else:
        projected_points = None

    return projected_points

def pca(points: np.ndarray, axis: Optional[Any] = None) -> np.ndarray:
    """
    Метод главных компонент (PCA) оценки направления
    максимальной дисперсии облака точек.

    :param points: Входной массив точек формы [N, 2]
    :param axis: Набор осей, на которых рисовать график
    :return: Numpy массив формы [N, 2] точек на прямой
    """

    # Найдем главные компоненты.
    # В первую очередь нужно центрировать облако точек, вычтя среднее
    mean = np.mean(points, axis=0)
    centered = points - mean
    # Функция вычисления собственных значений и векторов np.linalg.eig
    # требует ковариационную матрицу в качестве аргумента.
    cov = np.cov(centered.T)
    # Теперь мы можем посчитать главные компоненты, заданные
    # собственными значениями и собственными векторами.
    eigenval, eigenvec = np.linalg.eig(cov)
    # Мы хотим параметризовать целевую прямую в координатной системе,
    # заданной собственным вектором, собственное значение которого
    # наиболее велико (направление наибольшей вариативности).
    argmax_eigen = np.argmax(eigenval)
    # Нам понадобятся проекции входных точек на наибольший собственный
    # вектор.
    loc_pca = np.dot(centered, eigenvec)
    loc_maxeigen = loc_pca[:, argmax_eigen]
    max_eigenval = eigenval[argmax_eigen]
    max_eigenvec = eigenvec[:, argmax_eigen]
    # Ре-параметризуем прямую, взяв за начало отрезка проекции
    # первой и последней точки на прямую.
    loc_start = mean + max_eigenvec * loc_maxeigen[0]
    loc_final = mean + max_eigenvec * loc_maxeigen[-1]
    linspace = np.linspace(0, 1, num=len(points))
    # Получаем позиции точек, которые идут с одинаковым интервалом,
    # таким образом удаляя шум измерений и вдоль траектории движения.
    positions = loc_start + np.outer(linspace, loc_final - loc_start)

    if axis is not None:
        for ax in axis:
            ax.set_title("PCA")
            ax.plot(points[:, 0], points[:, 1], 'or')
            ax.plot(positions[:, 0], positions[:, 1], 'o-', mfc='none')
            ax.grid(True, linestyle='--')
            ax.axis('equal')

    return positions

def main():
    fig_all, axs = plt.subplots(2, 2)
    fig_all.set_size_inches(10.0, 6.0)

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(5.0, 3.0)
    points = generate_points(axis=(axs[0, 0], ax))
    fig.savefig('1_points.png', dpi=300)

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(5.0, 3.0)
    least_squares(points, axis=(axs[0, 1], ax))
    fig.savefig('2_leastsq.png', dpi=300)

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(5.0, 3.0)
    ransac(points, axis=(axs[1, 0], ax))
    fig.savefig('3_ransac.png', dpi=300)

    fig, ax = plt.subplots(1, 1)
    fig.set_size_inches(5.0, 3.0)
    pca(points, axis=(axs[1, 1], ax))
    fig.savefig('4_pca.png', dpi=300)

    for ax in axs.flat:
        ax.set(xlabel='x', ylabel='y')

    for ax in axs.flat:
        ax.label_outer()

    fig_all.savefig('0_all.png', dpi=300)

    plt.show()

    print("Done!")

if __name__ == "__main__":
    main()


# -*- coding: utf-8 -*-
"""
Created on Wed Apr  8 16:49:15 2020

@author: Mehul
"""
from statistics import mean
import numpy as np
import random

#xs=np.array([1,2,3,4,5,6,7],dtype=np.float64)
#ys=np.array([5,6,5,7,8,6,10],dtype=np.float64)

#creating a dataset for testing
def create_dataset(hm,variance,step=2,correlation=False,which_type='pos'):
	val=1
	ys=[]
	for i in range(hm):
		y=val+random.randrange(-variance,variance)
		ys.append(y)
		if correlation==True:
			if which_type=='pos':
				val+=step
			elif which_type=='neg':
				val-=val
	xs=[i for i in range(len(ys))]
	return np.array(xs,dtype=np.float64),np.array(ys,dtype=np.float64)

#defining a function to get the best fit slope
#here we pass in the array of points in the function and get the slope anf the intercept
def best_fit_slope_and_intercept(xs,ys):
	m =(((mean(xs)*mean(ys))-mean(xs*ys))/((mean(xs)**2)-mean(xs*xs)))
	b=mean(ys)-m*mean(xs)
	return m,b

# defining function to predict the outcome from the model
def predict_outcome(x_predict,m,b):
	y=m*x_predict+b
	return y

#defining a function for measuring r-squared
def sum_of_squared_error(ys_original,ys_line):
	return sum((ys_original-ys_line)**2)

def r_squared_value(ys_original,ys_line):
	ys_mean=[mean(ys_original) for y in ys_original]
	squared_error_regression_line=sum_of_squared_error(ys_original,ys_line)
	squared_error_mean_line=sum_of_squared_error(ys_original,ys_mean)
	return (1-(squared_error_regression_line/squared_error_mean_line))

#getting dataset
xs,ys=create_dataset(40,10,5,True,'pos')

#getting the slope and the intercept
m,b=best_fit_slope_and_intercept(xs,ys)

#making the regression line list using list comprehension
regression_line=[(m*x+b) for x in xs]

#making prediction using the data
x_predict=8
y_predict=predict_outcome(x_predict,m,b)

# r-squared and checking whether the best fit line really fits our  data well or not
#We can have a best fit line for a poorly fit dataset also, the point is to have a metric
#can actually tell us whether th line represents the actual relationship and explains a significant
#percentage of the variation.
r_squared=r_squared_value(ys,regression_line)

#visualise the results
from matplotlib import style
import matplotlib.pyplot as plt
style.use('fivethirtyeight')
plt.scatter(xs,ys,color='red')
plt.plot(xs,regression_line)# this connects the points and gives us a line
plt.scatter(x_predict,y_predict,s=100,color='green')
plt.show()

Simple Linear Regression/Simple Linear Regression from scratch/linear_regression_from_scratch.py


# Python3 steven
#https://en.wikipedia.org/wiki/Mandelbrot_set
import sys
import numpy as np
import matplotlib.pyplot as plt
# MandelBrot eqaution： z:=z**2 + c

Z0 = 0 + 0j #start value

def mandelbrot(N=10):  #generate madenlbrot series
    sets=[]
    c = complex(.1, .2)
    a = c
    while N>0:
        print(abs(a),' ',end='')
        sets.append(abs(a))
        a = a**2 + c

        N -= 1
    return sets

def yieldMandelbrot(N):  #binay oper only yield >2.0
    xvalues = np.linspace(-2, 2, N)
    yvalues = np.linspace(-2, 2, N)
    for u, x in enumerate(xvalues):
        for v, y in enumerate(yvalues):
            z = Z0
            c = complex(x, y)
            for _ in range(100):
                z = z * z + c
                if abs(z) > 2.0:
                    yield v,u,abs(z)
                    break

def yieldMandelbrotAll(N):
    xvalues = np.linspace(-2, 2, N)
    yvalues = np.linspace(-2, 2, N)
    for u, x in enumerate(xvalues):
        for v, y in enumerate(yvalues):
            z = Z0
            c = complex(x, y)
            for _ in range(100):
                z = z * z + c
                if abs(z) > 2.0:
                    break
                yield v,u,abs(z)

def genMandelbrotColor(N=1000):  #color image,3 channels
    M = np.zeros([N, N,3], int) # + 255
    for v,u,z in yieldMandelbrotAll(N): #map z(0~2) to 0~255 pixsel value
        #M[v, u, :] = int(z*256/2)
        #M[v, u, 0] = int(z*256/2) #r channel
        M[v, u, 1] = int(z*256/2) #g channel
        #M[v, u, 2] = int(z*256/2) #b channel
    return M

def genMandelbrotGray(N=1000):  #gray image[0~255]
    M = np.zeros([N, N], int)
    for v,u,z in yieldMandelbrotAll(N): #map z(0~2) to 0~255 pixsel value
        M[v, u] = int(z*256/2) #M[v, u] = 1
    return M

def genMandelbrot(N=1000):  #white&black two value[0,1] image
    M = np.zeros([N, N], int)
    if 1:
        for v,u,_ in yieldMandelbrot(N):
            M[v, u] = 1
        return M
    else:#First version
        xvalues = np.linspace(-2, 2, N)
        yvalues = np.linspace(-2, 2, N)
        for u, x in enumerate(xvalues):
            for v, y in enumerate(yvalues):
                z = 0 + 0j
                c = complex(x, y)
                for _ in range(100):
                    z = z * z + c
                    if abs(z) > 2.0:
                        M[v,u] = 1
                        break
        return M

def main():
    N = 1000

    print('number of parameter:', len(sys.argv))
    print('parameters:', str(sys.argv))
    if len(sys.argv)>1:
        N = int(sys.argv[1])

    #mandelbrot()
    plt.imshow(genMandelbrot(N),cmap='gray')
    #plt.imshow(genMandelbrotGray(N),cmap='gray')
    #plt.imshow(genMandelbrotColor(N))
    plt.title('Mandelbrot,N ='+str(N))
    plt.show()

if __name__=='__main__':
    main()


from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

import pandas as pd
import numpy as np

#get data

boston_dataset = load_boston()

data = pd.DataFrame(data=boston_dataset.data,
                    columns = boston_dataset.feature_names)
features = data.drop(['INDUS','AGE'], axis=1)

log_prices = np.log(boston_dataset.target)
target = pd.DataFrame(log_prices, columns=['PRICE'])

#target.shape

CRIME_IDX = 0
ZN_IDX = 1
CHAS_IDX = 2
RM_IDX = 4
PTRATIO_IDX = 8

ZILLOW_MEDIAN_PRICE = 583.3
SCALE_FACTOR = ZILLOW_MEDIAN_PRICE / np.median(boston_dataset.target)

property_stats = features.mean().values.reshape(1,11)

regr = LinearRegression().fit(features, target)
fitted_vals = regr.predict(features)

MSE = mean_squared_error(target, fitted_vals)
RMSE = np.sqrt(MSE)

def get_log_estimate(nr_rooms,
                    students_per_classroom,
                    next_to_river=False,
                    high_confidence=True):
#configure property
    property_stats[0][RM_IDX] = nr_rooms
    property_stats[0][PTRATIO_IDX] =students_per_classroom

    if next_to_river:
        property_stats[0][CHAS_IDX] = 1
    else:
        property_stats[0][CHAS_IDX] = 0

    #make prediction
    log_estimate = regr.predict(property_stats)[0][0]
 #log_estimate = regr.predict(property_stats)[0][1] access number not array

    #calc range
    if high_confidence:
        upper_bound = log_estimate + 2*RMSE
        lower_bound = log_estimate - 2*RMSE
        interval = 95
    else:
        upper_bound = log_estimate + 1*RMSE
        lower_bound = log_estimate - 1*RMSE
        interval = 68

    return log_estimate, upper_bound, lower_bound, interval

def get_dollar_estimate(rm, ptratio, chas=False, large_range=True):
    """
    Estimate the price of a property in Boston.

    Keywords argument:
    rm -- N. of rooms in the property
    ptratio -- N. of students per teacher in the classom
    chas -- True: if property is next to river
    large_range -- True: 95% of conf interval; False: 68% of conf interval

    """

    if rm < 1 or ptratio <1 :
        print ('not available, please try again')
        return

    log_est, upper, lower, conf = get_log_estimate(rm, ptratio,
                                                  next_to_river=chas, high_confidence=large_range)

    dollar_est = np.e**log_est * 1000 * SCALE_FACTOR
    dollar_high = np.e**upper * 1000 * SCALE_FACTOR
    dollar_low = np.e**lower * 1000 * SCALE_FACTOR
    rounded_est = np.round(dollar_est,-3)
    rounded_high = np.round(dollar_high,-3)
    rounded_low = np.round(dollar_low,-3)

    print(f'the estimiate is {rounded_est}')
    print(f'the {conf}% confidence interval valuation range is')
    print(f'between {rounded_low} and {rounded_high}')


"""
This module provides basic utilities related to Point type,
such as comparison function between two points.
"""
import numpy as np
from myConvexHull.dtype import Point

Y = 1
"A constant index to access the y value of a point."
X = 0
"A constant index to access the x value of a point."

def less_than(a, b) -> bool:
    # type: (Point, Point) -> bool
    """
    Compares two points and returns true if the first point's
    x value is less than the second point's x value or both
    points have the same x value but the first point's y value
    is less than the second point's y value.

    Args:

    `a`: the first `Point`

    `b`: the second `Point`

    Return:

    `True` if the true condition is met, `False` otherwise.
    """
    return a[X] < b[X] or (a[X] == b[X] and a[Y] < b[Y])

def greater_than(a, b) -> bool:
    # type: (Point, Point) -> bool
    """
    Compares two points and returns true if the first point's
    x value is more than the second point's x value or both
    points have the same x value but the first point's y value
    is more than the second point's y value.

    Args:

    `a`: the first `Point`

    `b`: the second `Point`

    Return:

    `True` if the true condition is met, `False` otherwise.
    """
    return a[X] > b[X] or (a[X] == b[X] and a[Y] > b[Y])

def distance(a, b) -> float:
    # type: (Point, Point) -> float
    """
    Calculates the distance between two points.

    Args:

    `a`: the first `Point`

    `b`: the second `Point`

    Return:

    The distance between the specified points.
    """
    return np.sqrt((a[X] - b[X]) ** 2 + (a[Y] - b[Y]) ** 2)


# -*- coding: utf-8 -*-
"""
Created on Thu Sep  9 09:22:42 2021

@author: Diana Sofía Carrillo
"""
from numpy import *

def gaussseidel(a, b, x):
    n = len(x)
    for i in range(n):
        s = 0
        for j in range (n):
            if i != j:
                s = s + a[i][j]*x[j]
        x[i] = (b[i] - s)/a[i][i]
    return x

def gaussseideliteraciones(a, b, x, e, m):
    n = len(x)
    t = x.copy()
    for k in range (m):
        x = gaussseidel(a, b, x)
        d = linalg.norm(array(x)-array(t), inf)
        if d < e:
            return [x, k]
        else:
            t = x.copy()
    return [[],m]

a = [[5, 2, 0],[0, -13, 5],[1, 1, 7]]
b = [45.34, -44.66, 16.2]
x = [1, 1, 1]
e = 10E-6
m = 20 #Num máximo de iteraciones
[x, k]=gaussseideliteraciones(a, b, x, e, m)
print("Solución:", x)
print("Iteraciones:", k)

def error_relativo(v_obtenido, a, b):
    v_real = linalg.solve(a, b)
    rta = linalg.norm(v_obtenido - v_real) / linalg.norm(v_real)
    return rta

print ("Error relativo:", error_relativo(x, a, b))


#Romberg Integration

"""
Name - Suryabrata Das

Sem: V

College_Roll_NO: 703

Paper-code: CMSA DSE-IB

Registration No: A01-1112-117-003-2018

Examination roll_no: 2021151264

Subject: Numerical Methods (DSE-I)

"""
import numpy as np
import matplotlib.pyplot as plt
def f1(x):
    f1 = np.sin(x)
    return f1;

# trapezoidal rule
def trapezoid(f,a,b,N):
    h = (b-a)/N
    xi = np.linspace(a,b,N+1)
    fi = f(xi)
    s = 0.0
    for i in range(1,N):
        s = s + fi[i]
    s = (h/2)*(fi[0] + fi[N]) + h*s
    return s

# romberg method starts from here

def romberg(f,a,b,eps,nmax):
# f ... function to be integrated
# [a,b] ... integration interval
# eps ... desired accuracy
# nmax ... maximal order of Romberg method
    Q = np.zeros((nmax,nmax),float)
    converged = 0
    for i in range(0,nmax):
        N = 2**i
        Q[i,0] = trapezoid(f,a,b,N)
        for k in range(0,i):
            n = k + 2
            Q[i,k+1] = 1.0/(4**(n-1)-1)*(4**(n-1)*Q[i,k] - Q[i-1,k])
        if (i > 0):
            if (abs(Q[i,k+1] - Q[i,k]) < eps):
                converged = 1

                break
            print("Integral Value: ",Q[i,k+1])
# main program
a = 0.0;b = 1.0 # integration interval [a,b]
romberg(f1,a,b,1.0e-12,10)


import numpy
import numpy.random

from numpy import bincount,any,sqrt
from numpy.random import randint

def birthday(num_people=88, num_trials=1000000, target_number=3):
    """
    Solve the generalized birthday problem using Monte-Carlo simulation.

    Given num_people in a room what is the probability that target_number
    or more of them share the same birthday.

    Assume years have 365 days

    Returns mean, standard deviation of the estimate
    """
    n=0
    for i in range(num_trials):
        m=bincount(randint(1,366,num_people))
        if any(m>=target_number):
            n=n+1
    # Mean of the results
    p=n/num_trials
    # std of the results
    # This works since all data is 0,1 then data**2 = 0,1 as well
    q=sqrt(n*(1-p)/(num_trials-1))
    return(p,q)

# Return P(less than 3 people with same birthday)
# Note this is 1-p(from above) and only works for 3 birthdays
def foo2(num_people=88, num_trials=1000000):
    n=0
    for i in range(num_trials):
        m=bincount(randint(1,366,num_people))
        if any(m>2):
            n=n+1
    p=1-n/num_trials
    return(p)

if __name__ == "__main__":
    # Set this true to run some example code
    if False:
        www=[]
        # Set random seed for reproducible results
        numpy.random.seed(42)
        for i in range(10):
            www.append(birthday(87,1000000,3))
            print("Completed trial",i,"of 0..9")
        www=numpy.array(www)


#!\usr\bin\python
"""
root_finder_examples.py
Author: Michael Seaman
implements the Newtonian method, Bisection method, and secant method
for finding roots to functions
"""

import numpy as np

def Newton(f, x, dfdx, epsilon=1.0E-7, N=100):
    """
    Uses Newtons method to approximate the location of a root in f(x),
    given the derivative dfdx and number of steps N, and the margin of error
    epsilon. returns a 3-tuple of x, n, and f(x)
    """
    n = 0
    f_value = f(x)
    while abs(f_value) > epsilon and n <=N:
        x = x - f_value/float(dfdx(x))
        n += 1
        f_value = f(x)
    return x, n, f(x)

def Bisection(f, a, b, epsilon = 1.0E-5):
    """
    Uses the bisection method to find an approximate root on f(x)
    returns root, iterations, and the approximate f(root)
    """
    fa = f(a)
    if fa * f(b) > 0:
        return
    i = 0
    while b-a > epsilon:
        i+= 1
        m = (a+b)/2.0
        fm = f(m)
        if fa * fm <= 0:
            b = m
        else:
            a = m
            fa = fm
    return m, i, f(m)

def Secant(f, x_minus2, x_minus1, epsilon = 1.0E-4, N = 10000):
    """
    Uses the Secant method to solve for f(x) = 0 given the values
    to start at x_-2 and x_-1. returns a 3-tuple of x, n, and f(x)
    """
    x = x_minus2
    n = 0
    while abs(f(x)) > epsilon and n <=N:
        n+= 1
        temp = x
        x = x_minus1 - ( (f(x_minus1)*(x_minus1 - x_minus2))/(f(x_minus1) - f(x_minus2)) )
        x_minus2 = x_minus1
        x_minus1 = temp
    return x, n, f(x)

def f_1(x):
    return x**3 + x - 27

def dfdx_1(x):
    return 3*x**2 + 1

def f_2(x):
    return -5*x + 10

def dfdx_2(x):
    return -5

def f_3(x):
    return x**2 + 1

def test_Bisection_on_positive_func():
    assert Bisection(f_3, -100, 100) == None

def test_Bisection_on_root():
    assert ( abs(Bisection(f_2, -100, 100)[0] -2) < 1.0E-5 and Bisection(f_2, -100, 100)[2] < 1.0E-5 )

def test_Newton_linear():
    """
    Tests the newtonian method on a line -5x + 10
    regardless of the input for x, the equation should finish in
    one step
    """
    xTestList = np.linspace(-300,300, 87)
    vectorized_Newton = np.vectorize(Newton)
    outputList = vectorized_Newton(f_2, xTestList, dfdx_2)
    stepList = outputList[1]
    zeroList = outputList[2]
    assert( np.all(stepList) == 1 and np.all(zeroList) < 1.0E-7 )


# coding:utf-8

# 输入训练样本的特征以及目标值，分别存储在变量X_train与y_train之中。
X_train = [[6], [8], [10], [14], [18]]
y_train = [[7], [9], [13], [17.5], [18]]

# 从sklearn.linear_model中导入LinearRegression。
from sklearn.linear_model import LinearRegression

# 使用默认配置初始化线性回归模型。
regressor = LinearRegression()
# 直接以披萨的直径作为特征训练模型。
regressor.fit(X_train, y_train)

# 导入numpy并且重命名为np。
import numpy as np

# 在x轴上从0至25均匀采样100个数据点。
xx = np.linspace(0, 26, 100)
xx = xx.reshape(xx.shape[0], 1)
# 以上述100个数据点作为基准，预测回归直线。
yy = regressor.predict(xx)

# 对回归预测到的直线进行作图。
import matplotlib.pyplot as plt

plt.scatter(X_train, y_train)
plt1, = plt.plot(xx, yy, label="Degree=1")
plt.axis([0, 25, 0, 25])
plt.xlabel('Diameter of Pizza')
plt.ylabel('Price of Pizza')
plt.legend(handles=[plt1])
plt.show()

# 输出线性回归模型在训练样本上的R-squared值。
print 'The R-squared value of Linear Regressor performing on the training data is', regressor.score(X_train, y_train)

# 从sklearn.preproessing中导入多项式特征产生器
from sklearn.preprocessing import PolynomialFeatures

# 使用PolynominalFeatures(degree=2)映射出2次多项式特征，存储在变量X_train_poly2中。
poly2 = PolynomialFeatures(degree=2)
X_train_poly2 = poly2.fit_transform(X_train)

# 以线性回归器为基础，初始化回归模型。尽管特征的维度有提升，但是模型基础仍然是线性模型。
regressor_poly2 = LinearRegression()

# 对2次多项式回归模型进行训练。
regressor_poly2.fit(X_train_poly2, y_train)

# 从新映射绘图用x轴采样数据。
xx_poly2 = poly2.transform(xx)

# 使用2次多项式回归模型对应x轴采样数据进行回归预测。
yy_poly2 = regressor_poly2.predict(xx_poly2)

# 分别对训练数据点、线性回归直线、2次多项式回归曲线进行作图。
plt.scatter(X_train, y_train)

plt1, = plt.plot(xx, yy, label='Degree=1')
plt2, = plt.plot(xx, yy_poly2, label='Degree=2')

plt.axis([0, 25, 0, 25])
plt.xlabel('Diameter of Pizza')
plt.ylabel('Price of Pizza')
plt.legend(handles=[plt1, plt2])
plt.show()

# 输出2次多项式回归模型在训练样本上的R-squared值。
print 'The R-squared value of Polynominal Regressor (Degree=2) performing on the training data is', regressor_poly2.score(
    X_train_poly2, y_train)

# 从sklearn.preprocessing导入多项式特征生成器。
from sklearn.preprocessing import PolynomialFeatures

# 初始化4次多项式特征生成器。
poly4 = PolynomialFeatures(degree=4)

X_train_poly4 = poly4.fit_transform(X_train)

# 使用默认配置初始化4次多项式回归器。
regressor_poly4 = LinearRegression()
# 对4次多项式回归模型进行训练。
regressor_poly4.fit(X_train_poly4, y_train)

# 从新映射绘图用x轴采样数据。
xx_poly4 = poly4.transform(xx)
# 使用4次多项式回归模型对应x轴采样数据进行回归预测。
yy_poly4 = regressor_poly4.predict(xx_poly4)

# 分别对训练数据点、线性回归直线、2次多项式以及4次多项式回归曲线进行作图。
plt.scatter(X_train, y_train)
plt1, = plt.plot(xx, yy, label='Degree=1')
plt2, = plt.plot(xx, yy_poly2, label='Degree=2')

plt4, = plt.plot(xx, yy_poly4, label='Degree=4')
plt.axis([0, 25, 0, 25])
plt.xlabel('Diameter of Pizza')
plt.ylabel('Price of Pizza')
plt.legend(handles=[plt1, plt2, plt4])
plt.show()

print 'The R-squared value of Polynominal Regressor (Degree=4) performing on the training data is', regressor_poly4.score(
    X_train_poly4, y_train)

# 准备测试数据。
X_test = [[6], [8], [11], [16]]
y_test = [[8], [12], [15], [18]]

# 使用测试数据对线性回归模型的性能进行评估。
regressor.score(X_test, y_test)

# 使用测试数据对2次多项式回归模型的性能进行评估。
X_test_poly2 = poly2.transform(X_test)
regressor_poly2.score(X_test_poly2, y_test)

# 使用测试数据对4次多项式回归模型的性能进行评估。
X_test_poly4 = poly4.transform(X_test)
regressor_poly4.score(X_test_poly4, y_test)

# 从sklearn.linear_model中导入Lasso。
from sklearn.linear_model import Lasso

# 从使用默认配置初始化Lasso。
lasso_poly4 = Lasso()
# 从使用Lasso对4次多项式特征进行拟合。
lasso_poly4.fit(X_train_poly4, y_train)

# 对Lasso模型在测试样本上的回归性能进行评估。
print lasso_poly4.score(X_test_poly4, y_test)

# 输出Lasso模型的参数列表。
print lasso_poly4.coef_

# 回顾普通4次多项式回归模型过拟合之后的性能。
print regressor_poly4.score(X_test_poly4, y_test)

# 回顾普通4次多项式回归模型的参数列表。
print regressor_poly4.coef_

# 输出普通4次多项式回归模型的参数列表。
print regressor_poly4.coef_

# 输出上述这些参数的平方和，验证参数之间的巨大差异。
print np.sum(regressor_poly4.coef_ ** 2)

# 从sklearn.linear_model导入Ridge。
from sklearn.linear_model import Ridge

# 使用默认配置初始化Riedge。
ridge_poly4 = Ridge()

# 使用Ridge模型对4次多项式特征进行拟合。
ridge_poly4.fit(X_train_poly4, y_train)

# 输出Ridge模型在测试样本上的回归性能。
print ridge_poly4.score(X_test_poly4, y_test)

# 输出Ridge模型的参数列表，观察参数差异。
print ridge_poly4.coef_

# 计算Ridge模型拟合后参数的平方和。
print np.sum(ridge_poly4.coef_ ** 2)