import numpy as np
from scipy.stats import chi2, multivariate_normal
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse

def get_error_ellipse_parameters(cov, confidence=None, sigma=None):
    """Returns parameters of an ellipse which contains a specified
    amount of normally-distributed 2D data, where the data is
    characterised by its covariance matrix.

    Parameters
    ----------
    cov : array_like
        Input covariance matrix of shape (2,2)
    confidence : float
        Fraction of data points within ellipse. 0 < confidence < 1.
        If confidence is not given, it is calculated according to sigma.
    sigma : float
        Length of axes of the ellipse in standard deviations. If
        confidence is also given, sigma is ignored.

    Returns
    -------
    semi_major : float
        Length of major semiaxis of ellipse.
    semi_minor : float
        Length of minor semiaxis of ellipse.
    angle : float
        Rotation angle of ellipse in radian.
    confidence : float
        Fraction of data expected to lie within the ellipse.
    sigma : float
        Length of major and minor semiaxes in standard deviations.
    """
    cov = np.array(cov)
    if(cov.shape != (2,2)):
        raise ValueError("The covariance matrix needs to be of shape (2,2)")
    if(confidence == None and sigma == None):
        raise RuntimeError("One of confidence and sigma is needed as input argument")
    if(confidence and sigma):
        print("Argument sigma is ignored as confidence is also provided!")

    if(confidence == None):
        if(sigma < 0):
            raise ValueError("Sigma needs to be positive")
        scaling = np.square(sigma)
        confidence = chi2.cdf(scaling, 2)
    if(sigma == None):
        if(confidence > 1 or confidence < 0):
            raise ValueError("Ensure that confidence lies between 0 and 1")
        scaling = chi2.ppf(confidence, 2)
        sigma = np.sqrt(scaling)
    eigenvalues, eigenvectors = np.linalg.eig(cov)

    maxindex = np.argmax(eigenvalues)
    vx, vy = eigenvectors[:, maxindex]
    angle = np.arctan2(vy, vx)
    semi_minor, semi_major = np.sqrt(np.sort(eigenvalues) * scaling)
    print("With sigma = {:.2f}, {:.1f}% of data points lie within ellipse.".format(sigma, confidence * 100))

    return semi_major, semi_minor, angle, confidence, sigma

##################
## Example usage
##################
if(__name__ == "__main__"):
    mean_x, mean_y = 5, -2
    covariance = [[1, -2.04], [-2.04, 5.16]]

    rv = multivariate_normal([mean_x, mean_y], covariance)
    data_points = rv.rvs(size = 500)

    fig = plt.figure()
    ax = fig.gca()
    plt.scatter(data_points[:,0], data_points[:,1], alpha = .5)

    confidence = 0.95
    semi_major, semi_minor, angle, confidence, sigma\
        = get_error_ellipse_parameters(covariance, confidence = confidence)
    ax.add_patch(Ellipse((mean_x, mean_y), 2*semi_major, 2*semi_minor, 180*angle/np.pi,\
            facecolor = 'none', edgecolor = 'red',\
            label = 'Confidence = {:.0f}% (sigma = {:.2f})'.format(confidence * 100, sigma)))

    sigma = 1
    semi_major, semi_minor, angle, confidence, sigma,\
        = get_error_ellipse_parameters(covariance, sigma = sigma)
    ax.add_patch(Ellipse((mean_x, mean_y), 2*semi_major, 2*semi_minor, 180*angle/np.pi,\
            facecolor = 'none', edgecolor = 'yellow',\
            label = 'Sigma = {:.0f} (confidence = {:.1f}%)'.format(sigma, confidence * 100)))
    ax.legend()
    fig.savefig('plot.png')
    plt.show()


#usr/bin/env/python
'''
Author  : Bhekimpilo Ndhlela
Author  : 18998712
module  : TW244 Applied Mathematics
task    : Assignment 01 problem2
since   : Saturday-28-07-2018
'''

from numpy import (exp, linspace, array, abs, zeros, shape)
import matplotlib.pyplot as plt
from sys import exit

def eulers_method(f, I, y0=1.0,(a,b)=(0.0,4.0), h=1.0):
    X = array([0.0, 1.0, 2.0, 3.0, 4.0])
    W = array([y0, 0.0, 0.0, 0.0, 0.0])

    for i in xrange(int(a), int(b)):
        W[i+1] = W[i] + h * f(X[i], W[i])
    absolute_error(W, X, 'Euler\'s Method')

def modified_eulers_method(f, I, y0=1.0,(a,b)=(0.0,4.0), h=1.0):
    X = array([0.0, 1.0, 2.0, 3.0, 4.0])
    W = array([y0, 0.0, 0.0, 0.0, 0.0])

    for i in xrange(int(a), int(b)):
        temp = W[i] + h*f(X[i], W[i])
        W[i+1] = W[i] + (h/2.0)*(f(X[i], W[i]) + f(X[i+1], temp))
    absolute_error(W, X, 'Improved Euler\'s Method')

def absolute_error(W, X, label, debug=True):
    Y = array([ I(n) for n in xrange(len(W))])
    abs_err = array([abs(ya - yc) for ya, yc in zip(Y, W)])
    if debug is True:
        print(label)
        for i , (err, w) in enumerate(zip(abs_err, W)):
            print 'x = ', i, '\t\tw = {:.10f} \ty = {:.10f}\terr = {:.10f}'.format(w, Y[i], abs_err[i])
    plot_comparison_func(Y, W, X, label)

def plot_comparison_func(Y, W, x, lbl):
    plt.title('Analytical vs. ' + lbl)
    plt.xlabel('x')
    plt.ylabel('y = f(x)')
    plt.plot(x, Y, '-k', linewidth=2, label='Analytical Solution')
    plt.plot(x, W, '--r', linewidth=2, label='Numerical Solution')
    plt.legend(bbox_to_anchor=(.4, .4))
    plt.show()

def plot_analytical_solution():
    X = linspace(0, 4, 1000)
    y = array([ exp(1 - exp(-x)) for x in X])
    plt.title('Plot of function f(x) = exp(1 - exp(-x))')
    plt.xlabel('x = linspace(0, 4, 1000)')
    plt.ylabel('f(x) = exp(1 - exp(-x))')
    plt.plot(X, y, '-k', linewidth=4)
    plt.show()

if __name__ == '__main__':
    f = lambda x, y: exp(-x) * y    # f(x, y) = y DE
    I = lambda x: exp(1 - exp(-x))  # Exact Solution
    plot_analytical_solution()
    eulers_method(f, I)
    modified_eulers_method(f, I)
else:
    exit('USAGE: python problem2.py')


import math
import numpy as np

#define data
data = [6.224, 6.665, 6.241, 5.302, 5.073, 5.127, 4.994, 5.012, 5.108, 5.377, 5.510, 6.372]
m = len(data)
b = np.reshape(data,(m,1))
time = [0.0, 1/12, 2/12, 3/12, 4/12, 5/12, 6/12, 7/12, 8/12, 9/12, 10/12, 11/12]

#Create the A matrix from the time
Amatrix = []
n = 0
while n < m:
    Amatrix.append([1.0, round(math.cos(2*math.pi*time[n]), 12), round(math.sin(2*math.pi*time[n]), 12),])
    n = n + 1
    pass
Amatrix = np.array(Amatrix)
print(Amatrix)

#Create and use Transpose
TransposeMatrix = Amatrix.transpose()
print(TransposeMatrix)
Cmatrix = np.matmul(TransposeMatrix, Amatrix)
print(Cmatrix)

#Fix error when ATranspose times A has a 0 on the diagonal, may cause problems if not careful
f = 0
while f < 3:
    if Cmatrix[f,f] == 0:
        Cmatrix[f,f] = .0000000000000001
        pass
    f = f + 1
    pass

TransposeTimesb = np.matmul(TransposeMatrix, b)
print(TransposeTimesb)
C = np.linalg.solve(Cmatrix,TransposeTimesb)
print(C)

#Calculate Error
r = np.subtract(b, np.matmul(Amatrix, C))
k = 0
SE = 0
while k < m:
    SE = SE + (r.item(k))**2

    k = k + 1
    pass
RMSE = math.sqrt(SE/m)

print("F3(t) = ", C.item(0), " + ", C.item(1), "* cos(2(pi)t) + ", C.item(2), "* sin(2(pi)t)")
print("RMSE = ", RMSE)


import numpy as np
from typing import Tuple

def R(theta: float) -> np.ndarray:
    """
        Returns the rotation matrix for rotating an object
        centered around the origin with a given angle

        Arguments:
            theta: angle in degrees

        Returns:
            R: 2x2 np.ndarray with rotation matrix
    """
    theta = np.radians(theta)
    return np.array(
        [[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]
    )

def cart2pol(x: float, y: float) -> Tuple[float, float]:
    """
        Cartesian to polar coordinates

        angles in degrees
    """
    rho = np.hypot(x, y)
    phi = np.degrees(np.arctan2(y, x))
    return rho, phi

def pol2cart(rho: float, phi: float) -> Tuple[float, float]:
    """
        Polar to cartesian coordinates

        angles in degrees
    """
    x = rho * np.cos(np.radians(phi))
    y = rho * np.sin(np.radians(phi))
    return x, y


import numpy as np
import matplotlib.pyplot as mpl
from scipy import interpolate
import time

# -------------------------------------|Declaração de funções|-------------------------------------#
def f0(x):
    return np.e ** np.cos(np.pi * x)

def d2f0(x):
    return np.pi ** 2 * (np.sin(np.pi * x) ** 2 - np.cos(np.pi * x)) * np.e ** (np.cos(np.pi * x))

def d4f0(x):
    return (
        np.pi ** 4
        * (
            np.sin(np.pi * x) ** 4
            - 6 * np.sin(np.pi * x) ** 2 * np.cos(np.pi * x)
            - 4 * np.sin(np.pi * x) ** 2
            + 3 * np.cos(np.pi * x) ** 2
            + np.cos(np.pi * x)
        )
        * np.e ** (np.cos(np.pi * x))
    )

def f1(x):
    return np.sin(np.pi * x ** 2)

def d2f1(x):
    return 2 * np.pi * (-2 * np.pi * x ** 2 * np.sin(np.pi * x ** 2) + np.cos(np.pi * x ** 2))

def d4f1(x):
    return (
        4
        * np.pi ** 2
        * (
            4 * np.pi ** 2 * x ** 4 * np.sin(np.pi * x ** 2)
            - 12 * np.pi * x ** 2 * np.cos(np.pi * x ** 2)
            - 3 * np.sin(np.pi * x ** 2)
        )
    )

def f2(x):
    return 1 / (1 + x ** 5)

def d2f2(x):
    return 10 * x ** 3 * (5 * x ** 5 / (x ** 5 + 1) - 2) / (x ** 5 + 1) ** 2

def d4f2(x):
    return (
        120
        * x
        * (125 * x ** 15 / (x ** 5 + 1) ** 3 - 150 * x ** 10 / (x ** 5 + 1) ** 2 + 40 * x ** 5 / (x ** 5 + 1) - 1)
        / (x ** 5 + 1) ** 2
    )

def f2_g(x):
    if x != -1:
        return 1 / (1 + x ** 5)

def f3(x):
    return np.cos(np.e ** np.cos(np.pi * x))

def d2f3(x):
    return (
        np.pi ** 2
        * (
            -np.e ** (np.cos(np.pi * x)) * np.sin(np.pi * x) ** 2 * np.cos(np.e ** (np.cos(np.pi * x)))
            - np.sin(np.pi * x) ** 2 * np.sin(np.e ** (np.cos(np.pi * x)))
            + np.sin(np.e ** (np.cos(np.pi * x))) * np.cos(np.pi * x)
        )
        * np.e ** (np.cos(np.pi * x))
    )

def d4f3(x):
    return (
        np.pi ** 4
        * (
            np.e ** (3 * np.cos(np.pi * x)) * np.sin(np.pi * x) ** 4 * np.cos(np.e ** (np.cos(np.pi * x)))
            + 6 * np.e ** (2 * np.cos(np.pi * x)) * np.sin(np.pi * x) ** 4 * np.sin(np.e ** (np.cos(np.pi * x)))
            - 6
            * np.e ** (2 * np.cos(np.pi * x))
            * np.sin(np.pi * x) ** 2
            * np.sin(np.e ** (np.cos(np.pi * x)))
            * np.cos(np.pi * x)
            - 7 * np.e ** (np.cos(np.pi * x)) * np.sin(np.pi * x) ** 4 * np.cos(np.e ** (np.cos(np.pi * x)))
            + 18
            * np.e ** (np.cos(np.pi * x))
            * np.sin(np.pi * x) ** 2
            * np.cos(np.pi * x)
            * np.cos(np.e ** (np.cos(np.pi * x)))
            + 4 * np.e ** (np.cos(np.pi * x)) * np.sin(np.pi * x) ** 2 * np.cos(np.e ** (np.cos(np.pi * x)))
            - 3 * np.e ** (np.cos(np.pi * x)) * np.cos(np.pi * x) ** 2 * np.cos(np.e ** (np.cos(np.pi * x)))
            - np.sin(np.pi * x) ** 4 * np.sin(np.e ** (np.cos(np.pi * x)))
            + 6 * np.sin(np.pi * x) ** 2 * np.sin(np.e ** (np.cos(np.pi * x))) * np.cos(np.pi * x)
            + 4 * np.sin(np.pi * x) ** 2 * np.sin(np.e ** (np.cos(np.pi * x)))
            - 3 * np.sin(np.e ** (np.cos(np.pi * x))) * np.cos(np.pi * x) ** 2
            - np.sin(np.e ** (np.cos(np.pi * x))) * np.cos(np.pi * x)
        )
        * np.e ** (np.cos(np.pi * x))
    )

def trapezio(f, df, x, fx, n, a, b):

    inicio = time.time()

    v = np.linspace(a, b, num=n)
    h = abs(v[1] - v[0])

    x.append(v[0])
    fx.append(f(v[0]))

    res = np.zeros((3))

    for i in range(1, n):

        x.append(v[i])
        fx.append(f(v[i]))

        res[0] += (h / 2) * (fx[i - 1] + fx[i])

    res[1] = erro(df, n, a, b, h, "T")

    fim = time.time()

    res[2] = fim - inicio

    print("Regra dos Trapezios:")
    print("\t-> Resultado:", res[0])
    print("\t-> Erro:", res[1])
    print("\t-> Tempo:", res[2], end="\n\n")

    return res

def simpson(f, df, x, fx, n, a, b):

    inicio = time.time()

    v = np.linspace(a, b, num=n)
    h = abs(v[1] - v[0])

    x.append(v[0])
    fx.append(f(v[0]))

    res = np.zeros((3))

    for i in range(2, n, 2):

        x.append(v[i - 1])
        x.append(v[i])
        fx.append(f(v[i - 1]))
        fx.append(f(v[i]))

        res[0] += (h / 3) * (fx[i - 2] + 4 * fx[i - 1] + fx[i])

    res[1] = erro(df, n, a, b, h, "S")

    fim = time.time()

    res[2] = fim - inicio

    print("Regra de Simpson:")
    print("\t-> Resultado:", res[0])
    print("\t-> Erro:", res[1])
    print("\t-> Tempo:", res[2], end="\n\n")

    return res

def erro(df, n, a, b, h, tipo):

    x0 = np.linspace(a, b, num=1000)

    if tipo == "t" or tipo == "T":
        return (n * (h ** 3) / 12) * np.max(np.abs(df(x0)))

    elif tipo == "s" or tipo == "S":
        return (n * (h ** 5) / 180) * np.max(np.abs(df(x0)))

def f_de_x(f, fx, x, a, b):

    for i in range(int(a * 50), int(b * 50 + 1)):
        i /= 50

        x.append(i)
        fx.append(f(i))

def grafico_trapezio(f, xf, t, xt, funcao):

    mpl.figure()
    mpl.plot(xf, f, label=funcao, color="k")
    mpl.stem(
        xt,
        t,
        basefmt="b",
        use_line_collection=True,
        linefmt="blue",
        markerfmt="blue",
        label="integração numérica pela Regra dos Trapézios",
    )
    mpl.fill_between(xt, t, 0, facecolor="#8112ff", alpha=0.3)
    mpl.xlabel("x")
    mpl.ylabel("f(x)")
    mpl.legend()
    mpl.grid(True)

def grafico_simpson(f, xf, fxs, xs, funcao):

    mpl.figure()
    mpl.plot(xf, f, label=funcao, color="k")
    mpl.stem(
        xs,
        fxs,
        basefmt="r",
        use_line_collection=True,
        linefmt="red",
        markerfmt=" ",
        label="integração numérica pela Regra de Simpson",
    )

    for i in range(2, n, 2):
        fxp = []
        xp = []
        fx = interpolate.interp1d(xs[i - 2 : i + 1], fxs[i - 2 : i + 1], kind="quadratic")
        xp = np.linspace(xs[i - 2], xs[i], 50)
        fxp = fx(xp)

        mpl.plot(xp, fxp, color="r")
        mpl.fill_between(xp, fxp, 0, facecolor="#f2600c", alpha=0.3)

    mpl.xlabel("x")
    mpl.ylabel("f(x)")
    mpl.legend()
    mpl.grid(True)

# -------------------------------------------------------------------------------------------------#

# -------------------------------------|Variáveis de controle|-------------------------------------#

# Número de pontos (impar)
n = 1000001

a = 0  # Intervalo inicial
b = 1  # Intervalo final

funcao0 = False
funcao1 = False
funcao2 = False
funcao3 = True

graficos = False
# -------------------------------------------------------------------------------------------------#

# ------------------------------------|Declaração de variáveis|------------------------------------#
f = [f0, f1, [f2, f2_g], f3]
df = [[d2f0, d4f0], [d2f1, d4f1], [d2f2, d4f2], [d2f3, d4f3]]
xt = [[], [], [], []]
fxt = [[], [], [], []]
xs = [[], [], [], []]
fxs = [[], [], [], []]
x = [[], [], [], []]
fx = [[], [], [], []]
# -------------------------------------------------------------------------------------------------#

# Caso n seja par, incrementa-se 1, pois n precisa de ser ímpar
if n % 2 == 0:
    n += 1

# --|Calculando e printando as integrais numéricas com seus respectivos erros e tempo de execução|--#
if funcao0 == True:
    print("\nÁrea de e^cos(pi*x) entre", a, "e", b, "com", n, "pontos", end="\n\n")
    trapezio(f[0], df[0][0], xt[0], fxt[0], n, a, b)
    simpson(f[0], df[0][1], xs[0], fxs[0], n, a, b)

if funcao1 == True:
    print("\nÁrea de sen(pi*x^2) entre", a, "e", b, "com", n, "pontos", end="\n\n")
    trapezio(f[1], df[1][0], xt[1], fxt[1], n, a, b)
    simpson(f[1], df[1][1], xs[1], fxs[1], n, a, b)

if funcao2 == True:
    print("\nÁrea de 1/(1 + x^5) entre", a, "e", b, "com", n, "pontos", end="\n\n")
    trapezio(f[2][0], df[2][0], xt[2], fxt[2], n, a, b)
    simpson(f[2][1], df[2][1], xs[2], fxs[2], n, a, b)

if funcao3 == True:
    print("\nÁrea de cos(e^cos(pi*x)) entre", a, "e", b, "com", n, "pontos", end="\n\n")
    trapezio(f[3], df[3][0], xt[3], fxt[3], n, a, b)
    simpson(f[3], df[3][1], xs[3], fxs[3], n, a, b)
# -------------------------------------------------------------------------------------------------#

# --------------------------------------|Plotando os gráficos|-------------------------------------#
if graficos == True:

    if funcao0 == True:
        f_de_x(f[0], fx[0], x[0], -2, 2)
        grafico_trapezio(fx[0], x[0], fxt[0], xt[0], "e^cos(pi*x)")
        grafico_simpson(fx[0], x[0], fxs[0], xs[0], "e^cos(pi*x)")

    if funcao1 == True:
        f_de_x(f[1], fx[1], x[1], -2, 2)
        grafico_trapezio(fx[1], x[1], fxt[1], xt[1], "sen(pi*x^2)")
        grafico_simpson(fx[1], x[1], fxs[1], xs[1], "sen(pi*x^2)")

    if funcao2 == True:
        f_de_x(f[2][1], fx[2], x[2], -2, 2)
        grafico_trapezio(fx[2], x[2], fxt[2], xt[2], "1/(1 + x^5)")
        grafico_simpson(fx[2], x[2], fxs[2], xs[2], "1/(1 + x^5)")

    if funcao3 == True:
        f_de_x(f[3], fx[3], x[3], -2, 2)
        grafico_trapezio(fx[3], x[3], fxt[3], xt[3], "cos(e^cos(pi*x))")
        grafico_simpson(fx[3], x[3], fxs[3], xs[3], "cos(e^cos(pi*x))")

    mpl.show()
# -------------------------------------------------------------------------------------------------#

Lista-implementacao-3/2 - Integracao Numerica/integracao numerica.py


# The Fibonacci numbers, commonly denoted F(n) form a sequence,
# called the Fibonacci sequence, such that each number is the sum of the two preceding ones,
# starting from 0 and 1. That is,
# F(0) = 0,   F(1) = 1
# F(N) = F(N - 1) + F(N - 2), for N > 1.
# Given N, calculate F(N).

# Example 1:
# Input: 2
# Output: 1
# Explanation: F(2) = F(1) + F(0) = 1 + 0 = 1.

# Example 2:
# Input: 3
# Output: 2
# Explanation: F(3) = F(2) + F(1) = 1 + 1 = 2.

# Example 3:
# Input: 4
# Output: 3
# Explanation: F(4) = F(3) + F(2) = 2 + 1 = 3.

# Note:
# 0 ≤ N ≤ 30.

class Solution(object):
    def fib(self, N):
        """
        :type N: int
        :rtype: int
        """
        # M1. 原始递归
        # 时间复杂度: O(2^n) 递归树分析
        # 空间复杂度: O(n) 栈帧分析

        # if N == 0:
        #     return 0
        # if N < 3:
        #     return 1
        # return self.fib(N-2) + self.fib(N-1)

        # M2. 尾递归
        # 时间复杂度: O(n) 尾递归过程分析
        # 空间复杂度: O(n) 栈帧分析

        # def helper(first, second, N):
        #     if N == 0:
        #         return 0
        #     if N < 3:
        #         return 1
        #     if N == 3:
        #         return first + second
        #     return helper(second, first+second, N-1)
        # return helper(1, 1, N)

        # M3. DP循环
        # 时间复杂度: O(n)
        # 空间复杂度: O(n)

        # import numpy as np
        # if N == 0:
        #     return 0
        # tmp = np.zeros(N+1, dtype=int)
        # tmp[0] = 0
        # tmp[1] = 1
        # for i in range(2, N+1):
        #     tmp[i] = tmp[i-1] + tmp[i-2]
        # return tmp[N]

        # M4. DP循环 空间优化
        # 时间复杂度: O(n)
        # 空间复杂度: O(1)

        if N == 0:
            return 0
        if N < 3:
            return 1
        first, second = 0, 1
        res = 0
        for i in range(2, N+1):
            res = first + second
            first = second
            second = res
        return res


import numpy as np

def householder(_A):
	A = _A.copy()
	n = A.shape[1]
	v = np.zeros_like(A)
	for k in range(n):
		sigma = np.sign(A[k, k]) * np.sqrt((A[k:, k] ** 2).sum())
		if (A[k:, k] ** 2).sum() < 1e-10:
			continue
		v[k, k] += sigma
		v[k:, k] += A[k:, k]
		beta = v[:, k].dot(v[:, k])
		for j in range(k, n):
			A[:, j] -= 2 * (v[:, k].dot(A[:, j]) / beta) * v[:, k]
	return A, v

def QR(A):
	r, _ = householder(A)
	# A=QR, Q=AR^{-1}
	q = A.dot(np.linalg.inv(r))
	# q, r = np.linalg.qr(A)
	return q, r

def check(A):
	for i in range(1, A.shape[0]):
		if abs(A[i, :i-1]).sum() > 1e-3:
			return False
	return True

def solve(A):
	cnt = 0
	while check(A) == False and cnt <= 1000:
		q, r = QR(A)
		A = r.dot(q)
		cnt += 1
	if cnt >= 1000:
		print('Cannot solve A!')
		return None
	return A.diagonal()

def gen53():
	print('t53 result'.center(30, '-'))
	# A = np.array([[4,0,0],[4,5,5],[2,5,5.]])
	# A = np.array([[1,0,0], [0,1,0], [0,0,1], [-1,1,0],[-1,0,1], [0,-1,1.]])
	# print(QR(A))
	# exit()
	# A = np.array([
	# 	[2.9766, 0.3945, 0.4198, 1.1159],
	# 	[0.3945, 2.7328, -0.3097, 0.1129],
	# 	[0.4198, -0.3097, 2.5675, 0.6079],
	# 	[1.1159, 0.1129, 0.6079, 1.7231],
	# 	])
	A = np.array([
		[.5, .5, .5, .5],
		[.5, .5, -.5, -.5],
		[.5, -.5, .5, -.5],
		[.5, -.5, -.5, .5]
		])
	print(solve(A))
	print('end t53'.center(30, '-')+'\n')

if __name__ == '__main__':
	gen53()


import numpy as np

"""
meshgrid的结果，
第一个是横坐标轴的数据的集合
第二个是纵坐标轴数据的集合
两者合起来构成一个网格点的集合

x[0]与y[0] 逐个元素组合，是四个点的坐标，这些点构成一条横线。纵坐标是y[i], 横坐标是x[i]
"""
grid_x, grid_y = np.meshgrid(np.linspace(-3, 3, 4), np.linspace(-3, 3, 4))
print(grid_x)
print("-----------------")
print(grid_y)


import numpy as np

#solve (x_1)+4*(x_2)=2,-2*(x_1)+x_2=14
A=np.array([[1,4]
           ,[-2,1]])

print("det(A)=",np.linalg.det(A))
#det(A)= 9.000000000000002
#the reason that 2 appear here:
#the decimal calcuation error
#det(A)!=0 -> not singular matrix
# -> has unique solution

b=np.array([2,14])
x=np.linalg.solve(A,b)
print(x)
#[-6.  2.]

class Uniqueness_of_solution:
    def __init__(self):
        pass
    def judge_solution(self,A,b):
        #to avoid the decimal error
        #determine by the value of the det(A)by a small float number
        if abs(np.linalg.det(A))<0.0000001:
            print("doesn't have a unique solution")
        else:
            print("has a unique solution:")
            print(np.linalg.solve(A,b))
            return np.linalg.solve(A,b)

#solve:
#x-4y+6z=3
#-2x+8y-12z=-6
#2x-y+3z=1

C=np.array([[1,-4,6]
           ,[-2,8,-12]
           ,[2,-1,3]])

D=np.array([3,-6,1])

sol=Uniqueness_of_solution()
sol.judge_solution(A,b)
#[-6.  2.]
sol.judge_solution(C,D)
#doesn't have a unique solution

#What if doesn't have a unique solution and using linalg.solve?
# ans=np.linalg.solve(C,D)
# print(ans)
#terminal:
#numpy.linalg.LinAlgError: Singular matrix

#solve for the traffic flows
# (x_1)-(x_2)=160
# (x_2)-(x_3)=-40
# (x_3)-(x_4)=210
# (x_4)-(x_1)=-330

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

F=np.array([160,-40,210,-330])

print("det(E)=",np.linalg.det(E))
if np.linalg.det(E)!=0:
    print("non-singular matrix")
else:
    print("singular matrix")
# det(E)= 0.0
# singular matrix

#solve for the traffic flows (if (x_4)=100)

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

H=np.array([430,160,310])

print("det(G)=",np.linalg.det(G))
if np.linalg.det(G)!=0:
    print("non-singular matrix")
    print("the solution is:")
    print(np.linalg.solve(G,H))
else:
    print("singular matrix")

# det(G)= -1.0
# non-singular matrix
# the solution is:
# [430. 270. 310.]


"""Test functions. Functions to be minimized."""
import numpy as np

def function_sphere(vector):
    """Return the value of the sphere function for the given vector.
    :param vector: n-dimensional array.
    :return value: value of the function at this point in the n-dimensional space.
    """
    return sum([x*x for x in vector])

def function_ackley(vector):
    """Implementations of the Ackley function.
    :param vector: n-dimensional array of floats.
    :return value: value of the Ackley function for the given point in the space.
    """
    n = len(vector)               # dimension of the vector
    sv = function_sphere(vector)  # value of the sphere function

    a = -0.2 * np.sqrt( 1/n * sv)
    b = 1/n * sum([np.cos( 2 * np.pi * x) for x in vector])
    value = -20 * np.exp(a) - np.exp(b) + 20 + np.e

    return value

def function_himmelblau(vector):
    """Compute the value of the Himmelblau's function for a given 2d point in R^2.
    :param vector: 2D array of floats.
    :return value: value of the function at the given point.
    """
    value = np.power(np.power(vector[0], 2) + vector[1] - 11, 2)
    value += np.power(vector[0] + np.power(vector[1], 2) - 7, 2)

    return value

def function_rastrigin(vector):
    """Computes the rastrigin function.
    :param vector: n-dimensional array of floats, vector of dimension n.
    :return value: value of the function at that point.
    """
    A = 10
    An = A * len(vector) # A * n, where n is the dimension of the space
    v = sum([np.power(x, 2) - A * np.cos(2 * np.pi * x) for x in vector])

    value = An + v
    return value


import numpy as np

def standard_norm(data):
    means = data.mean(axis =1)
    stds = data.std(axis= 1, ddof=1)
    data = (data - means[:, np.newaxis]) / stds[:, np.newaxis]
    return np.nan_to_num(data)

def l1_norm(data):
    _norm = np.array([x.sum(axis=0) for x in data])
    data = data/_norm[:, np.newaxis]
    return np.nan_to_num(data)

def l2_norm(data):
    _norm = np.array([np.sqrt((x*x).sum(axis=0)) for x in data])
    data = data/_norm[:, np.newaxis]
    return np.nan_to_num(data)


'''
Y is the dependant variable and X is the independant variable
We are going to fit a line
        Y = a0 + a1*x
using Gradient Descent minimizing the SSE.
This code will work for any variable with single attribute, i.e.
it is Linear Regression in 1 variable.
'''
import random
import matplotlib.pyplot as plt
import numpy as np

#Sum of Squares Error
def sse(n,a0,a1,x,y):
    """
    Compute the sse sse sse.

    Args:
        n: (array): write your description
        a0: (array): write your description
        a1: (array): write your description
        x: (array): write your description
        y: (array): write your description
    """
    s=0
    mean=np.mean(y)
    for i in range(n):
        s+=(a0+a1*x[i]-mean)**2
    return s/(2*n)

#Calculate the cost function
def cost(n,a0,a1,x,y,ch,p=2):
    """
    Calculate the cost between two points.

    Args:
        n: (todo): write your description
        a0: (todo): write your description
        a1: (todo): write your description
        x: (todo): write your description
        y: (todo): write your description
        ch: (todo): write your description
        p: (todo): write your description
    """
    s=0;
    if ch=='sum-of-squares':
        for i in range(n):
            s+=(a0+a1*x[i]-y[i])**2
        return s/(2*n)
    if ch=='l-p norm':
        for i in range(n):
            s+=abs(a0+a1*x[i]-y[i])**p
        return s**(1/p)

#Partial Differential with respect to a0
def dela0(n,a0,a1,x,y):
    """
    Dela0 dela0.

    Args:
        n: (array): write your description
        a0: (array): write your description
        a1: (array): write your description
        x: (array): write your description
        y: (array): write your description
    """
    s=0;
    for i in range(n):
        s+=(a0+a1*x[i]-y[i])
    return s/n

#Partial Differential with respect to a1
def dela1(n,a0,a1,x,y):
    """
    Dela1 dela1 dela1 dela

    Args:
        n: (array): write your description
        a0: (array): write your description
        a1: (array): write your description
        x: (array): write your description
        y: (array): write your description
    """
    s=0;
    for i in range(n):
        s+=(a0+a1*x[i]-y[i])*x[i]
    return s/n

def predict(x, y, alphas=np.linspace(0.001,1,10), it=1000):
    """
    Predict the predicted )

    Args:
        x: (array): write your description
        y: (array): write your description
        alphas: (array): write your description
        np: (array): write your description
        linspace: (array): write your description
        it: (array): write your description
    """
    mx=max(x)
    my=max(y)

    # Normalize values in the range 0-1
    for i in range(len(x)):
        x[i]/=mx
        y[i]/=my
    coeff, r2, cos = grad_desc(x, y, alphas, it)
    coeff, x, y = rescale(x, y, coeff, mx, my)
    r2_alpha(r2, alphas)
    plot_predict(x, y, coeff, r2, cos, it)
    # Store all predictions for which R^2 is maximum in an array
    a0=coeff[r2.index(max(r2))][0]
    a1=coeff[r2.index(max(r2))][1]
    pred=a0+x*a1
    return pred

def grad_desc(x, y, alphas, it):
    """
    Describe the objective function.

    Args:
        x: (todo): write your description
        y: (todo): write your description
        alphas: (todo): write your description
        it: (todo): write your description
    """
    r2=[]# Array to store calculated R^2 values
    coeff=[] #Array to store Predicted Coefficients for Linear Regression

    for alpha in alphas:
        cos=[]
        #Initialize random weights
        a0=random.random()
        a1=random.random()
        for i in range(it):
            # Reduce the coefficient by alpha times partial differential
            temp0=a0-alpha*dela0(len(x),a0,a1,x,y)
            temp1=a1-alpha*dela1(len(x),a0,a1,x,y)
            a0=temp0
            a1=temp1
            #Add the cost for each iteration
            cos.append(cost(len(x),a0,a1,x,y,ch='sum-of-squares'))
        # Calculate and store the R^2 value for a particular learning rate alpha
        r2.append(1-(cos[-1]/(cos[-1]+sse(len(x),a0,a1,x,y))))
        #Store the predicted coefficients for regression
        coeff.append([a0,a1])
    return coeff, r2, cos

def r2_alpha(r2, alphas):
    """
    Plot r2 alpha

    Args:
        r2: (todo): write your description
        alphas: (array): write your description
    """
    #Plot for R^2 vs alpha
    plt.plot(alphas, r2)
    plt.title('R^2 vs. Learning Rate')

    #Max. value of R^2 over all values of alpha
    print(max(r2))
    #Value of alpha for maximum R^2
    print(np.linspace(0.001,1,10)[r2.index(max(r2))])

def rescale(x, y, coeff, mx, my):
    """
    Rescale x y - axis.

    Args:
        x: (todo): write your description
        y: (todo): write your description
        coeff: (todo): write your description
        mx: (todo): write your description
        my: (todo): write your description
    """
    # Bring the data back to scale
    for i in range(len(coeff)):
        coeff[i][0]*=my
        coeff[i][1]*=my/mx
    for i in range(len(x)):
        x[i]*=mx
        y[i]*=my
    return coeff, x, y

def plot_predict(x, y, coeff, r2, cos, it):
    """
    Plots the r2d plot

    Args:
        x: (array): write your description
        y: (array): write your description
        coeff: (array): write your description
        r2: (array): write your description
        cos: (array): write your description
        it: (array): write your description
    """
    # Plot the training data, cost function and Predicted vs Actual values
    fig1,ax=plt.subplots(1,2,figsize=(14,4))
    ax[0].plot([x for x in range(it)],cos)
    ax[0].set_title('Cost Function')
    ax[0].set_xlabel('No. of Iterations')
    ax[1].scatter(x,y,marker='x',color='r',label="Training Data")
    ax[1].plot(np.arange(1,12),[coeff[r2.index(max(r2))][0]+coeff[r2.index(max(r2))][1]*x for x in np.arange(1,12)],label="Linear Regression")
    plt.legend()
    ax[1].set_title('Predicted vs Actual')
    plt.xlabel("Experience in Years")
    plt.ylabel("Salary")
    plt.show()

Machine Learning & AI/Linear_Regression_with_Gradient_Descent.py


from scipy.fftpack import fft
import numpy as np

def get_fft(t,x):

    """
    This function returns fast-fourier transform. fftpack in scipy is used for this purpose, however,
    numpy.fft.fft can also be used in similar manner.

    t:       time
    x:       signal

    fr:      frequency axis
    X_fr:    amplitude complex number
    amp:     amplitude
    angle:   phase angle
    """

    # Sampling Frequency
    Fs = 1 / (t[1] - t[0])

    # Generate Frequency Axis
    n = np.size(t)
    n_half = int(n / 2)
    fr = (Fs / 2) * np.linspace(0, 1, n_half)

    # Compute FFT
    X     = fft(x)
    X_fr  = (1 / n_half) * X[0:n_half]
    amp   = np.absolute(X_fr)
    angle = np.angle(X_fr)

    return fr, X_fr, amp, angle

def get_ifft(X):

    """
    X:            amplitude complex number
    """
    return np.fft.ifft(X).real * np.size(X) / 2

def fft_comps_cutoff(t, x, cutoff = 0.01):

    fr, X_fr, amp, angle = get_fft(t, x)

    # filter
    amp_norm = amp / amp.max()
    mask = amp_norm > cutoff

    return fr[mask], X_fr[mask], amp[mask], angle[mask]

def construct_time_signal_from_comps(t_vec, freq, amplitude, angle):

    y_vec = np.zeros_like(t_vec)
    for fr, amp, a in zip(freq, amplitude, angle):
        # y_vec += amp * np.sin(2 * np.pi * fr * t_vec + a)
        y_vec += amp * np.sin(2 * np.pi * fr * t_vec) # + a)

    return y_vec


import numpy as np

import matplotlib.pyplot as plt
#%matplotlib inline

#import matplotlib.image as img
#import PIL.Image as Image
from PIL import Image
import math
import cmath

import time

import csv

from numpy import binary_repr

from fractions import gcd

class Haar(object):
    """
    This class Haar implements all the procedures for transforming a given 2D digital image
    into its corresponding frequency-domain image (Haar Transform)
    """

    def __init__():
        pass

    #Compute the Haar kernel.
    @classmethod
    def computeKernel(self, N):
        """
        Computes/generates the haar kernel function.

        Parameters
        ----------
        N : int
            Size of the kernel to be generated.

        Returns
        -------
        kernel : ndarray
            The generated kernel as a matrix.
        """

        i = 0
        kernel = np.zeros([N, N])
        n = int(math.log(N, 2))

        #Fill for the first row of the kernel
        for j in xrange(N):
            kernel[i, j] = 1.0/math.sqrt(N)

        # For the other rows of the kernel....
        i += 1
        for r in xrange(n):
             for m in xrange(1, (2**r)+1):
                j=0
                for x in np.arange(0, 1, 1.0/N):
                    if (x >= (m-1.0)/(2**r)) and (x < (m-0.5)/(2**r)):
                        kernel[i, j] = (2.0**(r/2.0))/math.sqrt(N)
                    elif (x >= (m-0.5)/(2**r)) and (x < m/(2.0**r)):
                        kernel[i, j] = -(2.0**(r/2.0))/math.sqrt(N)
                    else:
                        kernel[i, j] = 0
                    j += 1
                i += 1
        return kernel

    @classmethod
    def computeForwardHaar(self, imge):
        """
        Computes/generates the 2D Haar transform.

        Parameters
        ----------
        imge : ndarray
            The input image to be transformed.

        Returns
        -------
        final2DHaar : ndarray
            The transformed image.
        """

        N = imge.shape[0]
        kernel = Haar.computeKernel(N)

        imge1DHaar = np.dot(kernel, imge)

        #Transpose the kernel as it is not symmetric
        final2DHaar = np.dot(imge1DHaar, kernel.T)

        return final2DHaar/N

    @classmethod
    def computeInverseHaar(self, imgeHaar):
        """
        Computes/generates the inverse of 2D Haar transform.

        Parameters
        ----------
        imgeHaar : ndarray
            The Haar transformed image.

        Returns
        -------
        imgeInverse : ndarray
            The inverse of the transformed image.
        """

        N = imgeHaar.shape[0]
        kernel = Haar.computeKernel(N)

        imge1DInverse = np.dot(kernel.T, imgeHaar)
        imgeInverse = np.dot(imge1DInverse, kernel)

        return imgeInverse/N


#!/usr/bin/env python
# GET TRANSFORMATION MATRIX FROM FIXED-ANGLES ROTATIONS AND A TRANSLATION
# SANTIAGO GARCIA AND ELKIN GUERRA

import numpy as np
import math

class Transformation:
    """
    Get transformation matrix from fixed-angles rotations and a translation.

    :returns: transformation matrix size(4, 4)
    :param angle_x: rotation of {B} with respect of {A} in "x" axis.
    :param angle_y: rotation of {B} with respect of {A} in "y" axis.
    :param angle_z: rotation of {B} with respect of {A} in "z" axis.
    :param vector_AB: vector from origin of {A} to origin of {B}.
    """

    def __init__(self, angle_x, angle_y, angle_z, vector_AB):
        # Add extra "1" to vector_AB
        vector_AB.append(1)
        self.vector_AB = np.transpose([vector_AB])

        # Initialize rotation matrices in zero
        self.RX = np.eye(3)
        self.RY = np.eye(3)
        self.RZ = np.eye(3)

        # Change the rotation matrices based on inputs
        self.create_rotation_matrix("x", angle_x)
        self.create_rotation_matrix("y", angle_y)
        self.create_rotation_matrix("z", angle_z)

        # Create homogeneous transformation matrix
        self.create_transformation_matriz()

    def create_rotation_matrix(self, axis, angle):

        if axis == "x":
            self.RX = np.array([
                [1, 0, 0],
                [0, math.cos(angle), -math.sin(angle)],
                [0, math.sin(angle), math.cos(angle)]
            ])

        if axis == "y":
            self.RY = np.array([
                [math.cos(angle), 0, math.sin(angle)],
                [0, 1, 0],
                [-math.sin(angle), 0, math.cos(angle)]
            ])

        if axis == "z":
            self.RZ = np.array([
                [math.cos(angle), -math.sin(angle), 0],
                [math.sin(angle), math.cos(angle), 0],
                [0, 0, 1]
            ])

    def create_transformation_matriz(self):
        # Get rotation matrix with fixed angles approach (Rxyz = Rz.Ry.Rx)
        R_ZYX = np.dot(np.dot(self.RZ, self.RY), self.RX)

        extra_zeros_perspective = np.array([[0, 0, 0]])
        self.TM = np.concatenate((R_ZYX, extra_zeros_perspective))
        self.TM = np.concatenate((self.TM, self.vector_AB), axis=1)

# TESTS
if __name__ == "__main__":
    test = Transformation(0, 0, math.radians(30), [10, 5, 0])
    print("\nRX:\n", test.RX)
    print("\nRY:\n", test.RY)
    print("\nRZ:\n", test.RZ)
    print("\nTM:\n", test.TM)

    test = Transformation(0, 0, math.radians(90), [1, 2, 3])
    print("\nRX:\n", test.RX)
    print("\nRY:\n", test.RY)
    print("\nRZ:\n", test.RZ)
    print("\nTM:\n", test.TM)


"""
    A/B split test calculator
    ----------

    This module implements the statistical calculation of the A/B test split significance. The
    implementation was taken from https://www.periscopedata.com/blog/ab-testing-in-redshift.html
    which contains the code to do the statistical analysis using the normal approximation method
    in redshift with scipy. This was translated to python using scipy too.
"""

from scipy.stats import norm

def standard_error(sample_size, successes):
    """
    Calculates the standard error of a sample proportion.

    Formula: σp = sqrt [ p(1 - p) / n ].
    with:
    p = proportion of successes in sample (successes / sample size)

    :param sample_size: the size of the sample
    :param successes: the number of successes on the given sample.
    :return: the standard error on the sample proportion -> σp
    """
    p = successes / sample_size
    return (p * (1 - p) / sample_size) ** 0.5

def significance(size_a, successes_a, size_b, successes_b):
    """
    Calculates the significance for an A/B test.

    :param size_a: Sample size of the experiment A
    :param successes_a: Successes of the experiment A
    :param size_b: Sample size fo the experiment B
    :param successes_b: Successes of the experiment b
    :return: The significance of the test.
    """
    # Raising an error if the condition of size_sample > successes is not met.
    if size_a < successes_a or size_b < successes_b:
        raise ValueError('The size numbers must be greater than the number of successes for an '
                         'experiment')

    p_a = successes_a / size_a
    p_b = successes_b / size_b
    se_a = standard_error(size_a, successes_a)
    se_b = standard_error(size_b, successes_b)

    numerator = (p_b - p_a)
    denominator = (se_a ** 2 + se_b ** 2) ** 0.5

    return norm.sf(abs(numerator / denominator))


import numpy as np

# We create a 5 x 5 ndarray that contains integers from 0 to 24
X = np.arange(25).reshape(5, 5)

# We print X
print()
print('Original X = \n', X)
print()

# We use Boolean indexing to select elements in X:
print('The elements in X that are greater than 10:', X[X > 10])
print('The elements in X that less than or equal to 7:', X[X <= 7])
print('The elements in X that are between 10 and 17:', X[(X > 10) & (X < 17)])

# We use Boolean indexing to assign the elements that are between 10 and 17 the value of -1
X[(X > 10) & (X < 17)] = -1

# We print X
print()
print('X = \n', X)
print()

## Set Operations

# We create a rank 1 ndarray
x = np.array([1,2,3,4,5])

# We create a rank 1 ndarray
y = np.array([6,7,2,8,4])

# We print x
print()
print('x = ', x)

# We print y
print()
print('y = ', y)

# We use set operations to compare x and y:
print()
print('The elements that are both in x and y:', np.intersect1d(x,y))
print('The elements that are in x that are not in y:', np.setdiff1d(x,y))
print('All the elements of x and y:',np.union1d(x,y))

## Sorting

# We create an unsorted rank 1 ndarray
x = np.random.randint(1,11,size=(10,))

# We print x
print()
print('Original x = ', x)

# We sort x and print the sorted array using sort as a function.
print()
print('Sorted x (out of place):', np.sort(x))

# When we sort out of place the original array remains intact. To see this we print x again
print()
print('x after sorting:', x)

# We sort x but only keep the unique elements in x
print(np.sort(np.unique(x)))

## Sorting in place

# We create an unsorted rank 1 ndarray
x = np.random.randint(1,11,size=(10,))

# We print x
print()
print('Original x = ', x)

# We sort x and print the sorted array using sort as a method.
x.sort()

# When we sort in place the original array is changed to the sorted array. To see this we print x again
print()
print('x after sorting:', x)

# When sorting rank 2 ndarrays, we need to specify to the np.sort() function whether we are sorting by rows or columns.
# This is done by using the axis keyword.

# We create an unsorted rank 2 ndarray
X = np.random.randint(1,11,size=(5,5))

# We print X
print()
print('Original X = \n', X)
print()

# We sort the columns of X and print the sorted array
print()
print('X with sorted columns :\n', np.sort(X, axis = 0))

# We sort the rows of X and print the sorted array
print()
print('X with sorted rows :\n', np.sort(X, axis = 1))

## Quiz question
X = np.arange(1, 26).reshape(5, 5)
print(X)
print(X[X%2 == 1])


#AUTHOR : YASA VISWAMBHAR REDDY
#MATRICULATION NUMBER : 65074
#Personal Programming Project
#------------------------------------#
#A python test file to check optimizers
# command to run all test cases
# pytest test_optimization.py
# -----------------------------------#
import pytest
from optimization import optimality_criteria,Moving_asymptoes
from numpy import array,round,array_equiv,linalg,equal,zeros,ones,all

def test__optimality_criteria_simple_function():
    '''
    FUNCTIONAL TESTING
    AIM : To check the performance of optimal criteria function by solving a simple equation with simple constrains
            Linear function
            f(x1,x2)=x1+x2-2=0
            subjected to
            inequality constrained
            constrain=sum(x1+x2)<=1
            x1<1
            x2<1
    Expected result : [0.5,0.5]
    Remarks :passed sucessfully

    '''
    def fun(x):
        '''
        linear function
        f(x1,x2)=x1+x2-2=0
        '''
        f=x[0]+x[1]-1
        return f

    def dfun(x):
        '''
        derivatives of function
        df/dx1=1
        fd/dx2=1
        '''
        df_dx1=1
        df_dx2=1
        df=array([df_dx1,df_dx2])
        return df

    def dcon(x):
        '''
        inequality constrained
        constrain=sum(x1+x2)<=1
        x1<1
        x2<1
        '''
        dc_dx1=-1
        dc_dx2=-1
        dc=array([dc_dx1,dc_dx2])
        return dc
    #initial guess to obtain optimal solution
    initial_x=array([1,1])

    iteration=1
    x=initial_x
    xplot=zeros((51,len(initial_x)))
    residual=0
    while iteration<50:
        iteration+=1
        xold=x
        df=dfun(x)
        dc=dcon(x)
        constrain=1
        #updated x variables obtained from optimal criteria (penality based method)
        xlist,residual=optimality_criteria(df,dc,x,constrain)
        x=xlist
        xplot[iteration,:]=x
        #exit conditon
        if linalg.norm(x-xold)<1e-4:
            exit
    x_exact=array([0.5,0.5])
    error=all(abs(x-x_exact)<1e-2)
    o=0
    if error:
        o=1
    assert (o==1) is True

def test__optimality_criteria_quadratic_function():
    '''
    FUNCTIONAL TESTING
    AIM : To check the performance of optimal criteria function by solving a quadratic equation with simple constrains
            Linear function
            f=(x0+x1)^2-2*(x0-x1)^2-1
            subjected to
            inequality constrained
            constrain=sum(x1+x2)<=1
            x1<1
            x2<1
    Expected result : [0.5,0.5]
    Remarks :passed sucessfully
    '''
    def fun(x):
        '''
            quadratic function
            f=(x0+x1)^2-2*(x0-x1)^2-1
        '''
        f=(x[0]+x[1])**2-2*(x[0]-x[1])**2-1
        return f

    def dfun(x):
        '''
        derivatives of function
        df/fx0=-2*x[0]+6*x[1]
        df/dx1=6*x[1]-2*x[1]
        '''
        #df_dx0=2*(x[1])+2
        #df_dx1=4*x[1]+2*x[0]
        df_dx0=-2*x[0]+6*x[1]
        df_dx1=-2*x[1]+6*x[0]
        df=array([df_dx0,df_dx1])
        return df

    def dcon(x):
        '''
        derivatives of constrains
        '''
        dc_dx0=-1
        dc_dx1=-1
        dc=array([dc_dx0,dc_dx1])
        return dc
    #initial guess to obtain optimal solution
    initial_x=array([1,1])
    iteration=1
    x=initial_x
    xplot=zeros((51,len(initial_x)))
    residual=0
    while iteration<50:
        iteration+=1
        xold=x
        df=dfun(x)
        dc=dcon(x)
        constrain=1
        #updated x variables obtained from optimal criteria (penality based method)
        xlist,residual=optimality_criteria(df,dc,x,constrain)
        x=xlist

        xplot[iteration,:]=x
        #print(xplot)
        #exit conditon
        if linalg.norm(x-xold)<1e-3:
            exit
    x_exact=array([0.5,0.5])
    x=round(x,3)
    print(x)
    error=all(abs(x-x_exact)<1e-2)
    o=0
    if error:
        o=1
    assert (o==1) is True

def test__MMA_literature_equation():
    '''
    FUNCTIONAL TESTING
    AIM : To check the performance of method of moving asymptotes function by solving a quadratic equation with complex constrains.
        The equation and constrains and expected outputs are obtained from MMA paper.
            A quadratic function
            f(x0,x1,x2)=x0^2+x1^2+x3^2
            subjected to
                c1=(x0-5)**2+(x1-2)**2+(x2-1)**2-9
                c2=(x0-3)**2+(x1-4)**2+(x2-3)**2-9
                0 =< x(j) =< 5; for j = 1; 2; 3
    Expected result : [2.0175, 1.7800, 1.237]
    Remarks :passed sucessfully
    '''
    def quad_function(x):
        '''
        A quadratic function
        f(x0,x1,x2)=x0^2+x1^2+x3^2
        '''
        return x[0]**2+x[1]**2+x[2]**2

    def dfunction(x):
        '''
        derivative of the function
        df_dx0=2*x0
        df_dx1=2*x1
        df_dx2=2*x2
        '''
        df_dx=array([2*x[0],2*x[1],2*x[2]])
        return df_dx

    def constrain(x):
        '''
        Constrains of the function
        '''
        c1=(x[0]-5)**2+(x[1]-2)**2+(x[2]-1)**2-9
        c2=(x[0]-3)**2+(x[1]-4)**2+(x[2]-3)**2-9
        C=array([c1,c2])
        return C

    def dconstrains(x):
        '''
        derivative of constrains w.r.t variables x0,x1,x2
        '''
        c11=2*(x[0]-5)
        c12=2*(x[1]-2)
        c13=2*(x[2]-1)
        c21=2*(x[0]-3)
        c22=2*(x[1]-4)
        c23=2*(x[2]-3)
        dc=array([[c11,c12,c13],[c21,c22,c23]])
        return dc
    #initial guess
    x=array([4,3,2])
    f0=quad_function(x)
    df0=dfunction(x)
    c0=constrain(x)
    dc0=dconstrains(x)
    #print(x,df0,dc0,f0,c0)

    xval = array([4,3,2])
    print(xval)
    nx=len(xval)
    #initializing the parameter required for MMA
    #maximum and minimum of the variables
    xmin = zeros(nx)
    xmax = 5*ones(nx)

    L = xmin
    U = xmax

    loop=0
    max_loop=50
    #MMA requires previous two iteration values
    x1=xval
    x2=xval
    l=0
    all_values=[]
    while loop<=max_loop:
        vel=2
        nel=3
        f0=quad_function(xval)
        df0=dfunction(xval)
        c0=constrain(xval)
        dc0=dconstrains(xval)
        #the optimal solution is obtained from moving asymptoes (gradient based method)
        x,L,U=Moving_asymptoes(df0,dc0,f0,c0,xval,x1,x2,L,U,loop,nel,vel,xmin,xmax,False)
        print(x.T)

        x2 = x1.copy()
        x1 = xval.copy()
        x3=x.T
        xval=x3[0]
        print(xval)
        all_values.append(x3)
        #print(xold-xnew)

        l+=1
        if abs(linalg.norm(x1-xval))<0.0001: #exit condition
            f0=quad_function(xval)
            df0=dfunction(xval)
            c0=constrain(xval)
            dc0=dconstrains(xval)
            print(x3,df0,dc0,f0,c0)
            break
    x_output=x3[0]
    print(x_output)
    x_exact=array([2.0175, 1.7800, 1.237])
    error= all(abs(x_exact-x_output)<1e-3)
    o=0
    if error:
        o=1
    assert (o==1) is True


import numpy as np
import matplotlib.pyplot as pyplot

def step_func(x) :
    '''
    안쓴다.
    '''
    return np.array(x>0, dtype=np.int)

def sigmoid_func(x) :
    '''
    안쓴다.
    '''
    return 1/(1+np.exp(-x))

def ReLU_func(x):
    '''
    쓴다.
    '''
    return np.maximum(0, x)

def parametric_ReLU_func(x):
    '''
    쓴다
    '''
    a=0.2
    return np.where(x>0, x, a*x)

def identity_func(x):
    '''
    출력층의 활성함수
     항등함수. 출력=입력
     회귀문제에서 사용
    '''
    return x

def softmax_func_overflow(x):
    '''
    출력층 활성함수
     신경망의 출력값으로 확률벡터를 얻는다. (해석 용이)
     분류문제에서 사용
     신경망의 출력값을 0~1 로 제한. 모든 출력값의 합은 1.
    '''
    expX=np.exp(x)
    sumX=np.sum(expX)
    return expX/sumX

def softmax_func(x):
    '''
    출력층 활성함수
     신경망의 출력값으로 확률벡터를 얻는다. (해석 용이)
     분류문제에서 사용
     신경망의 출력값을 0~1 로 제한. 모든 출력값의 합은 1.
     이전 버전에서 오버플로우가 발생하므로 x 에서 x 의 최대값을 빼서 오버플로우를 막는다.
    '''
    maxX=np.max(x)
    expX=np.exp(x-maxX)
    sumX=np.sum(expX)
    return expX/sumX

if __name__ == '__main__' :
    print('activation function')
    x=np.arange(-5, 5, 0.1)
    y_step=step_func(x)
    y_sig=sigmoid_func(x)
    y_ReLU=ReLU_func(x)
    y_para_ReLU=parametric_ReLU_func(x)

    pyplot.plot(x,y_step, '--')
    pyplot.plot(x,y_sig, '-.')
    pyplot.plot(x,y_ReLU,':')
    pyplot.plot(x,y_para_ReLU, ',')
    pyplot.show()

    print('\nsoftmax function')
    x=np.array([2.3, -0.9, 3.6])
    y=softmax_func_overflow(x)
    print(y, np.sum(y))

    # x1 = np.array([900, 1000, -1000]) # 입력이 너무 큰 경우 overflow
    # y1 = softmax_func_overflow(x1)
    # print(y1, np.sum(y1))

    print('\n개선된 softmax function') # overflow 가 해결됨
    x2=np.array([900, 1000, 1000])
    y2=softmax_func(x2)
    print(y2, np.sum(y2))


import numpy as np
import inspect

# 1) Stwórz wektor zer o rozmiarze 10

v = np.zeros((10,), dtype=int)

assert v.sum() == 0
assert v.shape == (10,)

# ---------------------------------------------------
# 2) Napisz funkcję zwracającą ilość danych jaką zajmuje tablica numpy

def memof(a):
    return a.nbytes

assert memof(np.zeros((12,10),dtype=np.int32))==480

# ---------------------------------------------------
# 3) Napisz funkcję tworzącą wektor zer o rozmiarze n z jedynką na piątym miejscu

def make_v(n):

    # Tworzenie wektora z 10 zerami
    v = np.zeros((n,), dtype=int)

    # Ustawienie jedynki na piątym miejscu
    v[4] = 1
    return v

assert make_v(14)[4] == 1
np.testing.assert_array_equal( make_v(14)[:4] , 0)
np.testing.assert_array_equal( make_v(14)[5:] , 0)

# ---------------------------------------------------
# 4) Utwórz wektor z wartościami od 10 do 49 włącznie

def make10_49():
    v = np.array(range(10, 50))
    return v

assert make10_49()[7] == 17

# ---------------------------------------------------
# 5) Odwóć kolejność elementów wektora

def reverse(v):
    v = v[::-1]
    return v

np.testing.assert_equal(reverse(np.array([1,2,3])), np.array([3,2,1]))

# ---------------------------------------------------
# 6) Stwórz macierz jednostkową o rozmiarze n x n

def identity_matrix(n):
    v = np.eye(n)
    return v

np.testing.assert_equal(identity_matrix(2), np.array([[1, 0],  [0, 1]]))

# ---------------------------------------------------
# 7) Utwórz macierz n×n z wartościami od 1 do n**2

# Tak by każdy rząd zawierał wartości rosnące o 1
def n2_col(n):
    # Inicjalizacja talicy z wartościami od 1 do n**2,
    # a następnie zmienienie jej kształtu na macierz n x n
    v = np.arange(1, n ** 2 + 1).reshape(n, n)
    return v

np.testing.assert_equal( n2_col(2), np.array([[1, 2],  [3, 4]]) )

# Tak by każda kolumna zawierała wartości rosnące o 1
def n2_row(n):
    # Zamiana kolumn z wierszami tak aby wartości nie roszły w
    # wierszach tylko w kolumnach
    v = n2_col(n).transpose()
    return v

np.testing.assert_equal( n2_row(2), np.array([[1, 3],  [2, 4]]) )

# ---------------------------------------------------
# 8) Utwórz macierz n×m z losowymi wartościami

# Z przedziału [0,1)
def rand1(n, m):
    v = np.random.uniform(0,1,size=(n,m))
    return v

assert np.min(rand1(n=10, m=11)) >= 0
assert np.max(rand1(n=10, m=10)) < 1
assert np.shape(rand1(n=10, m=15)) == (10, 15)

# Z przedziału [a,b)
def rand2(n, m, a, b):
    v = np.random.uniform(a, b, size=(n, m))
    return v

assert np.min(rand2(n=10, m=12, a=3, b=7)) >= 3
assert np.max(rand2(n=10, m=12, a=3, b=7)) < 7
assert np.shape(rand2(n=10, m=12, a=3, b=7)) == (10, 12)

# ---------------------------------------------------
# 9) Znajdź wskaźniki dla których wartości wektora są równe zero

def is_zero(x):
    return np.where(x == 0)[0]

x = np.array([1,2,0,1,0,11])
np.testing.assert_equal(is_zero(x), np.array([2,4]))

# ---------------------------------------------------
# 10) Oblicz dla zadanego wektora jego wartość najmniejszą, największą oraz średnią.

def mystats(x):
    return np.min(x), np.max(x), np.average(x)

x = np.array([1,2,0,1,0,11])
assert  mystats(x) == (0, 11, 2.5)

# ---------------------------------------------------
# 11) Stwórz dwuwymiarową tablicę z zerami w środku i jedynkami na zewnątrz.
def zeros_padded(n):

    # Stworzenie macierzy n x n wypełnionej zerami
    matrix = np.zeros((n, n))

    # Zastępienie krańcowych wartości jedynkami
    matrix = np.pad(matrix[1:-1, 1:-1], 1, 'constant', constant_values=1)

    return matrix

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

np.testing.assert_equal(zeros_padded(n=4),
                        padded_array)

# ---------------------------------------------------
# 12) Używając `np.pad` dodaj do tablicy otoczenie z wartością 3

def pad3(x):

    # Do całej macierzy dodajemy obramowanie o szerokości 1 elementu
    # Obramowanie będzie wypełnione 3
    matrix = np.pad(x, 1, 'constant', constant_values=3)
    return matrix

x = np.ones((2,3))
x_pad3 = np.array([[ 3.,  3.,  3.,  3.,  3.],
                   [ 3.,  1.,  1.,  1.,  3.],
                   [ 3.,  1.,  1.,  1.,  3.],
                   [ 3.,  3.,  3.,  3.,  3.]])
np.testing.assert_equal(pad3(x), x_pad3)

# ---------------------------------------------------
# 13) Dla danej tablicy zastąp maksymalne wartości zerami.

def maxto0(x):
    # Wyznaczenie maksimum w danym macierzu
    maximium = np.max(x)

    # Zamienienie maksymalnych wartości na zera
    x[np.where(x == maximium)] = 0

    return x

x_expected = np.array([[1, 0, 1, 2],
                       [0, 2, 1, 0],
                       [2, 0, 2, 1]])

x = np.array([[1, 3, 1, 2],
              [3, 2, 1, 3],
              [2, 0, 2, 1]])

np.testing.assert_equal(maxto0(x),x_expected)

# ---------------------------------------------------
# 14) Niech będzie dana tablica k parametrów zmierzonych w n pomiarach:
#       xij:  j-ty parametr w i-tym pomiarze

# Stwórz funkcję nie zawierającą pętli, która obliczy:
# - średnią po pomiarach dla wszyskich zmiennych
# - odchylenie od wartości średniej dla każdej zmiennej we wszystkich pomiarach
# - odchylenie średniokwadratowe dla każdej zmiennej

def data_stats(x):

    # Liczba wierszy w danym macierzu
    n = x.shape[0]

    # Suma wszystkich pomiarów (suma danej kolumny) podzielona przez n pomiarów (liczba wierszy)
    x_avg = 1 / n * np.sum(x, axis=0)

    # Od każdego wiersza w macierzy odejmujemy średnie wartości poszczególnych kolumn
    x_delta = x - x_avg

    # Odchylenie średniokwadratowe dla każdej zmiennej (dla każdej kolumny)
    x_sigma = 1 / n * np.sum((x - x_avg) ** 2, axis=0)

    return x_avg, x_delta, x_sigma

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

average, delta, sigma = data_stats(example_matrix)
expected_average = np.array([ 3.2, 3. ,  2.2,  2.4])
expected_delta = np.array([[-0.2,  1. , -0.2,  0.6],
                           [-0.2,  1. ,  0.8,  1.6],
                           [ 0.8,  0. , -0.2, -0.4],
                           [-0.2, -1. , -1.2, -0.4],
                           [-0.2, -1. ,  0.8, -1.4]])
expected_sigma = np.array([0.16, 0.8 , 0.56, 1.04])

np.testing.assert_allclose(average,
                           expected_average)

np.testing.assert_allclose(delta,
                           expected_delta)

np.testing.assert_allclose(sigma,
                           expected_sigma)

blacklist = [".mean",".average","for","while","std"]
assert all([ not keyword  in inspect.getsource(data_stats) for keyword in blacklist])

print("All tests were successful.")


import numpy as np
#Evaluate the linear regression
def compute_cost(X, y, theta):
    '''
    Comput cost for linear regression
    '''
    #Number of training samples
    m = y.size

    predictions = X.dot(theta).flatten()

    sqErrors = (predictions - y) ** 2

    J = (1.0 / (2 * m)) * sqErrors.sum()

    return J

def gradient_descent(X, y, theta, alpha, num_iters):
    '''
    Performs gradient descent to learn theta
    by taking num_items gradient steps with learning
    rate alpha
    '''
    m = y.size
    J_history = np.zeros(shape=(num_iters, 1))

    for i in range(num_iters):

        predictions = X.dot(theta).flatten()

        errors_x1 = (predictions - y) * X[:, 0]
        errors_x2 = (predictions - y) * X[:, 1]

        theta[0][0] = theta[0][0] - alpha * (1.0 / m) * errors_x1.sum()
        theta[1][0] = theta[1][0] - alpha * (1.0 / m) * errors_x2.sum()

        J_history[i, 0] = compute_cost(X, y, theta)

    return theta, J_history


import numpy as np

def power_method(A, error_tol):
	lim = 10000 #Numero maximo de iteracoes
	error = np.inf #atribuicao de infinito para o erro
	n = A.shape[1] #pegando a dimensao da matriz A quadrada
	y0 = np.zeros(n)
	y0[0] = 1 #chute inicial normalizado

	for k in range (0, lim):
		xk = A.dot(y0) #produto de matrizes (x^k) = A * y^(k-1)
		yk = xk/np.linalg.norm(xk) #normalizando xk
		error = np.abs(np.abs(y0.dot(yk))-1) #teste de alinhamento, calculando o erro
		if error <= error_tol: # se o erro for menor que a tolerancia recebida como parametro, pode parar a iteracao
			break
		y0 = yk #atribuindo o novo y0

	lambda_1 = y0.dot(A.dot(y0)) #calculando o lambda_1 = y^k * (A * y^k)

	return lambda_1, y0 #retornando o autovalor e seu autovetor associado

A = np.array([[12, 2, 3],
              [ 2, 3, 5],
              [ 3, 5,-2]], dtype='double')

(D,V) = np.linalg.eig(A) #usando uma funcao pronta para calcular todos os autovalores
print('Método do Python: {0:.15f}'.format(np.max(abs(D))))
(autovalor, autovetor) = power_method(A, 0.000000001) #usando o metodo da potencia implementado com erro em torno de 10^-9
print('Método Implementado: {0:.15f}'.format(autovalor))


import numpy as np

def forward_euler(f,y0,Delta_t,numsteps):
    """Perform numsteps of the forward euler method starting at y0
    of the ODE y'(t) = f(y,t)
    Args:
        f: function to integrate takes arguments y,t
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    y = np.zeros(numsteps+1)
    t = np.arange(numsteps+1)*Delta_t
    y[0] = y0
    for n in range(1,numsteps+1):
        y[n] = y[n-1] + Delta_t * f(y[n-1], t[n-1])
    return t, y

def inexact_newton(f,x0,delta = 1.0e-7, epsilon=1.0e-6, LOUD=False):
    """Find the root of the function f via Newton-Raphson method
    Args:
        f: function to find root of
        x0: initial guess
        delta: finite difference parameter
        epsilon: tolerance

    Returns:
        estimate of root
    """
    x = x0
    if (LOUD):
        print("x0 =",x0)
    iterations = 0
    while (np.fabs(f(x)) > epsilon):
        fx = f(x)
        fxdelta = f(x+delta)
        slope = (fxdelta - fx)/delta
        if (LOUD):
            print("x_",iterations+1,"=",x,"-",fx,"/",slope,"=",x - fx/slope)
        x = x - fx/slope
        iterations += 1
    #print("It took",iterations,"iterations")
    return x #return estimate of root

def backward_euler(f,y0,Delta_t,numsteps):
    """Perform numsteps of the backward euler method starting at y0
    of the ODE y'(t) = f(y,t)
    Args:
        f: function to integrate takes arguments y,t
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    y = np.zeros(numsteps+1)
    t = np.arange(numsteps+1)*Delta_t
    y[0] = y0
    for n in range(1,numsteps+1):
        solve_func = lambda u: u-y[n-1] - Delta_t*f(u,t[n])
        y[n] = inexact_newton(solve_func,y[n-1])
    return t, y

def inexact_newton(f,x0,delta = 1.0e-7, epsilon=1.0e-6, LOUD=False):
    """Find the root of the function f via Newton-Raphson method
    Args:
        f: function to find root of
        x0: initial guess
        delta: finite difference parameter
        epsilon: tolerance

    Returns:
        estimate of root
    """
    x = x0
    if (LOUD):
        print("x0 =",x0)
    iterations = 0
    while (np.fabs(f(x)) > epsilon):
        fx = f(x)
        fxdelta = f(x+delta)
        slope = (fxdelta - fx)/delta
        if (LOUD):
            print("x_",iterations+1,"=",x,"-",fx,"/",slope,"=",x - fx/slope)
        x = x - fx/slope
        iterations += 1
    #print("It took",iterations,"iterations")
    return x #return estimate of root

def backward_euler(f,y0,Delta_t,numsteps):
    """Perform numsteps of the backward euler method starting at y0
    of the ODE y'(t) = f(y,t)
    Args:
        f: function to integrate takes arguments y,t
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    y = np.zeros(numsteps+1)
    t = np.arange(numsteps+1)*Delta_t
    y[0] = y0
    for n in range(1,numsteps+1):
        solve_func = lambda u: u-y[n-1] - Delta_t*f(u,t[n])
        y[n] = inexact_newton(solve_func,y[n-1])
    return t, y

def RK4(f,y0,Delta_t,numsteps):
    """Perform numsteps of the 4th order Runge-Kutta method starting at y0
    of the ODE y'(t) = f(y,t)
    Args:
        f: function to integrate takes arguments y,t
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    y = np.zeros(numsteps+1)
    t = np.arange(numsteps+1)*Delta_t
    y[0] = y0
    for n in range(1,numsteps+1):
        dy1 = Delta_t * f(y[n-1], t[n-1])
        dy2 = Delta_t * f(y[n-1] + 0.5*dy1, t[n-1] + 0.5*Delta_t)
        dy3 = Delta_t * f(y[n-1] + 0.5*dy2, t[n-1] + 0.5*Delta_t)
        dy4 = Delta_t * f(y[n-1] + dy3, t[n-1] + Delta_t)
        y[n] = y[n-1] + 1.0/6.0*(dy1 + 2.0*dy2 + 2.0*dy3 + dy4)
    return t, y

def forward_euler_system(Afunc,c,y0,Delta_t,numsteps):
    """Perform numsteps of the forward euler method starting at y0
    of the ODE y'(t) = A(t) y(t) + c(t)
    Args:
        Afunc: function to compute A matrix
        c: nonlinear function of time
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    unknowns = y0.size
    y = np.zeros((unknowns,numsteps+1))
    t = np.arange(numsteps+1)*Delta_t
    y[0:unknowns,0] = y0
    for n in range(1,numsteps+1):
        yold = y[0:unknowns,n-1]
        A = Afunc(t[n-1])
        y[0:unknowns,n] = yold + Delta_t * (np.dot(A,yold) + c(t[n-1]))
    return t, y

def swap_rows(A, a, b):
    """Rows two rows in a matrix, switch row a with row b

    args:
        A: matrix to perform row swaps on
        a: row index of matrix
        b: row index of matrix

    returns: nothing

    side effects:
    changes A to rows a and b swapped
    """
    assert (a>=0) and (b>=0)
    N = A.shape[0] #number of rows
    assert (a<N) and (b<N) #less than because 0-based indexing
    temp = A[a,:].copy()
    A[a,:] = A[b,:].copy()
    A[b,:] = temp.copy()
def BackSub(aug_matrix,x):
    """back substitute a N by N system after Gaussian elimination

    Args:
        aug_matrix: augmented matrix with zeros below the diagonal
        x: length N vector to hold solution
    Returns:
        nothing
    Side Effect:
    x now contains solution
    """
    N = x.size
    for row in range(N-1,-1,-1):
        RHS = aug_matrix[row,N]
        for column in range(row+1,N):
            RHS -= x[column]*aug_matrix[row,column]
        x[row] = RHS/aug_matrix[row,row]
    return
def GaussElimPivotSolve(A,b,LOUD=0):
    """create a Gaussian elimination with pivoting matrix for a system

    Args:
        A: N by N array
        b: array of length N
    Returns:
        solution vector in the original order
    """
    [Nrow, Ncol] = A.shape
    assert Nrow == Ncol
    N = Nrow
    #create augmented matrix
    aug_matrix = np.zeros((N,N+1))
    aug_matrix[0:N,0:N] = A
    aug_matrix[:,N] = b
    #augmented matrix is created

    #create scale factors
    s = np.zeros(N)
    count = 0
    for row in aug_matrix[:,0:N]: #don't include b
        s[count] = np.max(np.fabs(row))
        count += 1
    if LOUD:
        print("s =",s)
    if LOUD:
        print("Original Augmented Matrix is\n",aug_matrix)
    #perform elimination
    for column in range(0,N):

        #swap rows if needed
        largest_pos = np.argmax(np.fabs(aug_matrix[column:N,column]/s[column])) + column
        if (largest_pos != column):
            if (LOUD):
                print("Swapping row",column,"with row",largest_pos)
                print("Pre swap\n",aug_matrix)
            swap_rows(aug_matrix,column,largest_pos)
            #re-order s
            tmp = s[column]
            s[column] = s[largest_pos]
            s[largest_pos] = tmp
            if (LOUD):
                print("A =\n",aug_matrix)
        #finish off the row
        for row in range(column+1,N):
            mod_row = aug_matrix[row,:]
            mod_row = mod_row - mod_row[column]/aug_matrix[column,column]*aug_matrix[column,:]
            aug_matrix[row] = mod_row
    #now back solve
    x = b.copy()
    if LOUD:
        print("Final aug_matrix is\n",aug_matrix)
    BackSub(aug_matrix,x)
    return x

def backward_euler_system(Afunc,c,y0,Delta_t,numsteps):
    """Perform numsteps of the forward euler method starting at y0
    of the ODE y'(t) = A(t) y(t) + c(t)
    Args:
        Afunc: function to compute A matrix
        c: nonlinear function of time
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    unknowns = y0.size
    y = np.zeros((unknowns,numsteps+1))
    t = np.arange(numsteps+1)*Delta_t
    y[0:unknowns,0] = y0
    for n in range(1,numsteps+1):
        yold = y[0:unknowns,n-1]
        A = Afunc(t[n])
        LHS = np.identity(unknowns) - Delta_t * A
        RHS = yold + c(t[n])*Delta_t
        y[0:unknowns,n] = GaussElimPivotSolve(LHS,RHS)
    return t, y

def cn_system(Afunc,c,y0,Delta_t,numsteps):
    """Perform numsteps of the forward euler method starting at y0
    of the ODE y'(t) = A(t) y(t) + c(t)
    Args:
        Afunc: function to compute A matrix
        c: nonlinear function of time
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    unknowns = y0.size
    y = np.zeros((unknowns,numsteps+1))
    t = np.arange(numsteps+1)*Delta_t
    y[0:unknowns,0] = y0
    for n in range(1,numsteps+1):
        yold = y[0:unknowns,n-1]
        A = Afunc(t[n])
        LHS = np.identity(unknowns) - 0.5*Delta_t * A
        A = Afunc(t[n-1])
        RHS = yold + 0.5*Delta_t * np.dot(A,yold) + 0.5*(c(t[n-1]) + c(t[n]))*Delta_t
        y[0:unknowns,n] = GaussElimPivotSolve(LHS,RHS)
    return t, y

def RK4_system(Afunc,c,y0,Delta_t,numsteps):
    """Perform numsteps of the forward euler method starting at y0
    of the ODE y'(t) = f(y,t)
    Args:
        f: function to integrate takes arguments y,t
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    unknowns = y0.size
    y = np.zeros((unknowns,numsteps+1))
    t = np.arange(numsteps+1)*Delta_t
    y[0:unknowns,0] = y0
    for n in range(1,numsteps+1):
        yold = y[0:unknowns,n-1]
        A = Afunc(t[n-1])
        dy1 = Delta_t * (np.dot(A,yold) + c(t[n-1]))
        A = Afunc(t[n-1] + 0.5*Delta_t)
        dy2 = Delta_t * (np.dot(A,y[0:unknowns,n-1] + 0.5*dy1)
                         + c(t[n-1] + 0.5*Delta_t))
        dy3 = Delta_t * (np.dot(A,y[0:unknowns,n-1] + 0.5*dy2)
                         + c(t[n-1] + 0.5*Delta_t))
        A = Afunc(t[n] + Delta_t)
        dy4 = Delta_t * (np.dot(A,y[0:unknowns,n-1] + dy3) + c(t[n]))
        y[0:unknowns,n] = y[0:unknowns,n-1] + 1.0/6.0*(dy1 + 2.0*dy2 + 2.0*dy3 + dy4)
    return t, y

def new2(f,y0,Delta_t,numsteps):
    """Perform numsteps of the backward euler method starting at y0
    of the ODE y'(t) = f(y,t)
    Args:
        f: function to integrate takes arguments y,t
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    y = np.zeros(numsteps+1)
    t = np.arange(numsteps+1)*Delta_t
    y[0] = y0
    for n in range(1,numsteps+1):
        tcur = t[n-1]
        fshift = lambda u,t: f(u,t+tcur)
        tmp,y1 = backward_euler(fshift,y[n-1],Delta_t*0.5,1)
        tmp,y2 = backward_euler(fshift,y[n-1],Delta_t,1)
        y[n] = y[n-1] + Delta_t*(1.0/(1.0+Delta_t) * f(y1[1],t[n-1]+0.5*Delta_t) +
                                 Delta_t/(1.0+Delta_t) * f(y2[1],t[n]))
    return t, y

def new2_system(Afunc,c,y0,Delta_t,numsteps):
    """Perform numsteps of the forward euler method starting at y0
    of the ODE y'(t) = A(t) y(t) + c(t)
    Args:
        Afunc: function to compute A matrix
        c: nonlinear function of time
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    unknowns = y0.size
    y = np.zeros((unknowns,numsteps+1))
    t = np.arange(numsteps+1)*Delta_t
    y[0:unknowns,0] = y0
    for n in range(1,numsteps+1):
        tcur = t[n-1]
        Af = lambda t: Afunc(t+tcur)
        cf = lambda t: c(t+tcur)
        tmp,y1 = backward_euler_system(Af,cf,y[0:unknowns,n-1],Delta_t*0.5,1)
        tmp,y2 = backward_euler_system(Af,cf,y[0:unknowns,n-1],Delta_t,1)
        y1 = y1[0:unknowns,1]
        y2 = y2[0:unknowns,1]
        th = t[n-1] + 0.5*Delta_t
        Ah = Afunc(th)
        A = Afunc(t[n])
        y[0:unknowns,n] = y[0:unknowns,n-1] + Delta_t*(1.0/(1.0+Delta_t) * (np.dot(Ah,y1) + c(th)) +
                                 Delta_t/(1.0+Delta_t) * (np.dot(A,y2) + c(t[n])) )
    return t, y

def crank_nicolson(f,y0,Delta_t,numsteps):
    """Perform numsteps of the backward euler method starting at y0
    of the ODE y'(t) = f(y,t)
    Args:
        f: function to integrate takes arguments y,t
        y0: initial condition
        Delta_t: time step size
        numsteps: number of time steps

    Returns:
        a numpy array of the times and a numpy
        array of the solution at those times
    """
    numsteps = int(numsteps)
    y = np.zeros(numsteps+1)
    t = np.arange(numsteps+1)*Delta_t
    y[0] = y0
    for n in range(1,numsteps+1):
        solve_func = lambda u: u-y[n-1] - 0.5*Delta_t*(f(u,t[n])
                                                       + f(y[n-1],t[n-1]))
        y[n] = inexact_newton(solve_func,y[n-1])
    return t, y


"""
@author = mbilkhu
Code for Logistic Regression
"""

import numpy as np

def load_dataset():
    X = np.array([[0,0],[0,1],[1,0],[1,1]])
    y = np.array([0,1,1,0])
    W = np.random.randn(1,2)
    b = np.ones(1)
    x = X.T
    y = y.T
    print("X Shape:- " +  str(x.shape))
    print("Y Shape:- " +  str(y.shape))
    return x,y,W,b

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

def sigmoid_gradient(x):
    return x * (1-x)

def forward_propagate(W, x, b):
    z = np.dot(W, x) + b
    a = sigmoid(z)
    return a

def compute_loss(y, a):
    x = np.multiply(y, np.log(a)) + np.multiply((1-y), np.log(1-a))
    cost = np.sum(x, dtype=np.float32)
    return -np.squeeze(cost)

def gradient_descent(y, a, x):
    dz = (a-y) * sigmoid_gradient(a)
    dw = np.dot(dz, x.T)
    db = dz
    return dw, db

def main():
    x,y,W,b = load_dataset()
    loss = []
    n_epochs = 60000
    learning_rate = 0.01
    for i in range(n_epochs):
        a = forward_propagate(W, x, b)
        cost = compute_loss(y, a)
        loss.append(cost)
        dw, db = gradient_descent(y, a, x)
        W = W - learning_rate * dw
        b = b - learning_rate * db
        if i%250 == 0:
            print("Loss after epoch %d = %f " % (i, cost))
    print(a)

if __name__=='__main__':
    main()


import math
from cmath import pi

import numpy as np

def cylinder_area(r:float,h:float):
    """Obliczenie pola powierzchni walca.
    Szczegółowy opis w zadaniu 1.

    Parameters:
    r (float): promień podstawy walca
    h (float): wysokosć walca

    Returns:
    float: pole powierzchni walca
    """
    if r > 0 and h > 0:
        return 2 * pi * r * h + pi * r * r * 2
    else:
        return math.nan

def fib(n:int):
    """Obliczenie pierwszych n wyrazów ciągu Fibonnaciego.
    Szczegółowy opis w zadaniu 3.

    Parameters:
    n (int): liczba określająca ilość wyrazów ciągu do obliczenia

    Returns:
    np.ndarray: wektor n pierwszych wyrazów ciągu Fibonnaciego.
    """
    if n > 0 and isinstance(n, int):
        result = np.ndarray(shape=(1, n), dtype=int)
        result[0][0] = 1  # jak zaczynam od 0 to testy nie przechodzą
        if n == 1:  # dostaje dosyć sprzeczne odpowiedzi od testów więc dorzucam ten warunek
            return result[0]
        if n >= 2:
            result[0][1] = 1
        if n >= 3:
            i = 2
            while n > i:
                result[0][i] = result[0][i - 1] + result[0][i - 2]
                i += 1
        return result

    else:
        return None

def matrix_calculations(a:float):
    """Funkcja zwraca wartości obliczeń na macierzy stworzonej
    na podstawie parametru a.
    Szczegółowy opis w zadaniu 4.

    Parameters:
    a (float): wartość liczbowa

    Returns:
    touple: krotka zawierająca wyniki obliczeń
    (Minv, Mt, Mdet) - opis parametrów w zadaniu 4.
    """
    M = np.array([[a, 1, -a], [0, 1, 1], [-a, a, 1]])
    try:
        Minv = np.linalg.inv(M)
    except np.linalg.LinAlgError:
        Minv = math.nan
    Mt = M.T
    Mdet = np.linalg.det(M)
    return Minv, Mt, Mdet

def custom_matrix(m:int, n:int):
    """Funkcja zwraca macierz o wymiarze mxn zgodnie
    z opisem zadania 7.

    Parameters:
    m (int): ilość wierszy macierzy
    n (int): ilość kolumn macierzy

    Returns:
    np.ndarray: macierz zgodna z opisem z zadania 7.
    """
    if n >= 0 and m >= 0 and isinstance(n, int) and isinstance(m, int):
        result = np.ndarray([m, n])
        for i, row in enumerate(result):
            for j, _ in enumerate(row):
                if i > j:
                    result[i][j] = i
                else:
                    result[i][j] = j
        return result
    else:
        return None

Metody numeryczne 2021/Laboratorium 1/main.py


# Author: Martin Konečnik
# Contact: martin.konecnik@gmail.com
# Licenced under MIT

# 1-Vzorčenje
# Predlagan IDE PyCharm Community Edition (na voljo za Windows, macOS in Linux)
# https://www.jetbrains.com/pycharm/download
# Navodila za pridobitev potrebnih knjižnic:
# https://www.jetbrains.com/help/pycharm/installing-uninstalling-and-upgrading-packages.html
# Kratka navodila. Znotraj GUI knjižnice dodamo prek File->Settings->Project: Name->Project Interpreter.
# V tem oknu na desni strani kliknemo na plus in vpišemo ime knjižnice.
# Privzeta bližnjica za zagon izbora je Alt+Shift+E

import numpy as np
import scipy.signal
from matplotlib import cm  # color mapping
import pylab as pylab
import matplotlib.pyplot as plt
import sounddevice as sd
from pathlib import Path
from PIL import Image
from mpl_toolkits.mplot3d import axes3d
from mpl_toolkits.mplot3d import art3d

# ----------------------------------------------------------------------------------------
# Vzorčenje in Nyquistov teorem;
Fvz = 100  # Frekvenca vzorčenja (v Hz)
T = 1  # dolžina signala (v s)
i = np.arange(float(T) * Fvz) / Fvz  # vektor časovnih indeksov
f1 = 5  # frekvenca sinusoide
A1 = 1  # amplituda sinusoide
faza1 = 0.0  # faza sinusoide

# ukazi.m:10 -- NOTE: Enak rezultat kot v Matlab 2017b
# izris sinuside pri razlicnih fazah
plt.figure()  # Ta vrstica ni nujna, če odpremo le eno okno.
for faza1 in np.arange(0, 6.1, 0.1):
    plt.cla()
    # pri množenju z matriko je potrebno uporabiti numpy.np.dot(...)
    s = np.dot(A1, np.sin(np.dot(2 * np.pi * f1, i) + faza1 * np.pi))
    plt.plot(i, s)
    setattr(plt.gca, 'YLim', [-1, 1])
    plt.title('Fvz = {0} Hz, Frekvenca = {1} Hz, faza = {2} $\pi$'.format(Fvz, f1, round(faza1, 1)))
    plt.xlabel('Čas (s)')
    plt.ylabel('Amplituda (dB)')
    plt.tight_layout()
    plt.waitforbuttonpress()

# ukazi.m:23 -- NOTE: Preverjeno z Matlab
# izris sinusid pri različnih frekvencah
faza1 = 0.0
plt.figure()
for f1 in np.arange(Fvz + 1):
    plt.cla()  # počistimo graf za naslednjo iteracijo
    s = np.dot(A1, np.sin(np.dot(2 * np.pi * f1, i) + faza1 * np.pi))
    plt.plot(i, s)
    plt.ylim(-1, 1)
    plt.title('Fvz = {0} Hz, Frekvenca = {1} Hz, faza = {2} $\pi$'.format(Fvz, f1, faza1))
    plt.xlabel('Čas (s)')
    plt.ylabel('Amplituda (dB)')
    plt.pause(0.025)

# ukazi.m:37 -- NOTE: Preverjeno z Matlab
# izris sinusoid s frekvenco f1 in Fvz-f1
f1 = 1
s1 = np.sin(np.dot(2 * np.pi * f1, i) + faza1 * np.pi)
plt.figure()
plt.plot(i, s1, 'b')
f2 = Fvz - f1
s2 = np.sin(np.dot(np.dot(np.dot(2, np.pi), f2), i) + np.dot(faza1, np.pi))
plt.plot(i, s2, 'r')
plt.xlabel('Čas (s)')
plt.ylabel('Amplituda')
plt.title('Fvz = {0} Hz, Frekvenca1 = {1} Hz, Frekvenca2 = {2} Hz, faza = {3} $\pi$'.format(Fvz, f1, f2, faza1))
plt.tight_layout()
# ----------------------------------------------------------------------------------------

# glej tudi primera v Mathematici: (WheelIllusion.nbp in SamplingTheorem.nbp)

# V Z O R Č E N J E    Z V O K A
# -----------------------------------------------------------------------------------------
# ukazi.m:56 -- NOTE: Primerljiv rezultat v Matlab
# vzorčenje zvoka
Fs = 44100  # vzorčevalna frekvenca
bits = 16  # bitna ločljivost
nchans = 1  # 1 (mono), 2 (stereo).
posnetek = sd.rec(5 * Fs, Fs, nchans, blocking=True)

plt.figure()
plt.plot(posnetek)

sd.play(posnetek, 44100)
sd.play(posnetek, 44100 / 2)
sd.play(posnetek, 2 * 44100)

# -----------------------------------------------------------------------------------------
# ukazi.m:73 -- NOTE: Primerljiv rezultat v Matlab
# ali zaznate fazne spremembe? Spreminjajte faza1 med 0 in 2.0 in poženite ta demo...
Fvz = 44100  # vzorčevalna frekvenca
T = 3  # čas v sekundah
i = np.arange(0.0, T * Fvz, 1) / Fvz  # vektor časovnih indeksov
f1 = 500  # frekvenca sinusoide
A1 = 0.3  # amplituda sinusoide
faza1 = 1.0  # faza sinusoide

s = np.dot(A1, np.sin(np.dot(2 * np.pi * f1, i) + faza1 * np.pi))  # tvorjenje sinusoide
s2 = np.dot(A1, np.sin(np.dot(2 * np.pi * f1, i) + 0 * np.pi))  # tvorjenje sinusoide

sd.play(np.concatenate((s, s2)), Fvz)  # pozor, dvojni oklepaji pri concatenate, ker sta s1 in s2 en parameter!
# "navadna" polja združiš z s+s2, v numpy.array pa to sešteje istoležne elemente

# -----------------------------------------------------------------------------------------
# ukazi.m:88 -- NOTE: Primerljiv rezultat v Matlab
# trije poskusi: 1. f1 = 50;
#                2. f1 = 450;
#                3. f1 = 1450;
#                4. f1 = 2450;

Fvz = 44100  # vzorčevalna frekvenca
T = 3  # čas v sekundah
i = np.arange(T * Fvz) / Fvz  # vektor časovnih indeksov
f1 = 50  # frekvenca sinusoide
A1 = 5.5  # amplituda sinusoide
faza1 = 0.0  # faza sinusoide
f2 = f1 + 1  # frekvenca druge sinusoide

s1 = np.dot(A1, np.sin(np.dot(2 * np.pi * f1, i) + faza1 * np.pi))  # tvorjenje prve sinusoide
s2 = np.dot(A1, np.sin(np.dot(2 * np.pi * f2, i) + faza1 * np.pi))  # tvorjenje druge sinusoide
sd.play(np.concatenate((s1, s2)), Fvz)

# -----------------------------------------------------------------------------------------
# ukazi.m:106 -- NOTE: Primerljiv rezultat v Matlab
# ali zaznate zvok netopirja pri 90000 Hz? Nyquist?
Fvz = 44100  # vzorčevalna frekvenca
T = 3
i = np.arange(T * Fvz) / Fvz  # vektor časovnih indeksov
fnetopir = 140000  # frekvenca sinusoide
A1 = 5.5  # amplituda sinusoide
faza1 = 1.0  # faza sinusoide

s = np.dot(A1, np.sin(np.dot(2 * np.pi * fnetopir, i) + faza1 * np.pi))  # tvorjenje sinusoide
sd.play(s, Fvz)

# ukazi.m:118 -- NOTE: Preverjeno z Matlab
# izris sinuside pri razlicnih fazah (verzija 2)
Fvz = 100
T = 1
i = np.arange(T * Fvz) / Fvz
f1 = 5
A1 = 5
faza1 = 0.0

# spremninjanje frekvence...
plt.close('all')
fig, ax = plt.subplots(2)  # create a figure with 2 subplots
fig.tight_layout(rect=[0, 0.03, 1, 0.95])

for f1 in np.arange(0, Fvz+1):
    ax[0].clear()
    ax[1].clear()

    s = np.sin(np.dot(2 * np.pi * f1, i) + faza1 * np.pi)
    ax[0].plot(s)
    ax[0].set_ylim(-1, 1)
    ax[0].set_title('Časovna domena: Fvz = {0} Hz, Frekvenca = {1} Hz, faza = {2} $\pi$'.format(Fvz, f1, faza1))

    ax[1].plot(abs(np.fft.fft(s)), 'r')
    ax[1].set_ylim(-1, 1)
    ax[1].set_title('Frekvenčna domena (abs): Fvz = {0} Hz, Frekvenca = {1} Hz, faza = {2} $\pi$'.format(Fvz, f1, faza1))

    plt.waitforbuttonpress()

# in faze... (več o tem na naslednjih vajah)
f1 = 5
A1 = 5
faza1 = 0.0
plt.close('all')
fig, ax = plt.subplots(2)
fig.tight_layout(rect=[0, 0.03, 1, 0.95])

for faza1 in np.arange(0, 2.1, 0.1):
    ax[0].clear()
    ax[1].clear()

    s = np.sin(np.dot(2 * np.pi * f1, i) + faza1 * np.pi)
    ax[0].plot(s)
    ax[0].set_ylim(-1, 1)
    ax[0].set_title('Časovna domena: Fvz = {0} Hz, Frekvenca = {1} Hz, faza = {2} $\pi$'.format(Fvz, f1, round(faza1, 1)))

    ax[1].plot(abs(np.fft.fft(s)), 'r')
    ax[1].set_ylim(-1, 1)
    ax[1].set_title('Frekvenčna domena (abs): Fvz = {0} Hz, Frekvenca = {1} Hz, faza = {2} $\pi$'.format(Fvz, f1, round(faza1, 1)))

    plt.waitforbuttonpress()

# S L I K E
# -----------------------------------------------------------------------------------------
# ukazi.m:181 -- NOTE: Preverjetno v Matlabu. Del ne deluje pravilno (označeno)
# vzorčenje slik in Moire
# Če datoteke ne najde, preverite pod "Settings -> Project: Name -> Project Structure" kje je root.
A = pylab.array(Image.open(Path('./1-Vzorcenje/Moire.jpg')))
plt.figure(figsize=(10, 10))
plt.axis('off')
plt.imshow(A)
plt.title('originalna slika')

pvz = 3
plt.figure()
plt.axis('off')
plt.imshow(A[::pvz, ::pvz])
plt.title('podvzorčena slika: faktor podvzorčenja {0}'.format(pvz))

# Celotna slika bistveno svetlejša kot v matlabu. Pri bitni ločljivosti 2, sta namesto sivin rumena in modra barva.
# Podatki?
st_bit = 2
kvant = 2 ** (9 - st_bit)
plt.figure(figsize=(10, 10))
plt.axis('off')
plt.imshow(np.dot(np.round(A[:, :, :] / kvant), kvant))
plt.title('slika pri bitni ločljivosti {0}'.format(st_bit))

fig, ax = plt.subplots(2, 2)
fig.tight_layout()

ax[0, 0].imshow(np.dot(np.round(A[:, :, :] / kvant), kvant))
ax[0, 0].set_title('slika pri bitni ločljivosti {0}'.format(st_bit))
ax[0, 0].set_xticklabels([])
ax[0, 0].set_yticklabels([])

ax[0, 1].imshow(np.dot(np.round(A[:, :, 0] / kvant), kvant))
ax[0, 1].set_title('ravnina R pri bitni ločljivosti {0}'.format(st_bit))
ax[0, 1].set_xticklabels([])
ax[0, 1].set_yticklabels([])

ax[1, 0].imshow(np.dot(np.round(A[:, :, 1] / kvant), kvant))
ax[1, 0].set_title('ravnina G pri bitni ločljivosti {0}'.format(st_bit))
ax[1, 0].set_xticklabels([])
ax[1, 0].set_yticklabels([])

ax[1, 1].imshow(np.dot(np.round(A[:, :, 2] / kvant), kvant))
ax[1, 1].set_title('ravnina B pri bitni ločljivosti {0}'.format(st_bit))
ax[1, 1].set_xticklabels([])
ax[1, 1].set_yticklabels([])

# -----------------------------------------------------------------------------------------
# ukazi.m:215 -- Note: Plotting not working properly yet. Data shown in 2D.
# spekter slik, Moire in Diskretna Fourierova transformacija (fft2)
A = pylab.array(Image.open(Path('./1-Vzorcenje/Moire.jpg')))
plt.figure().set_size_inches(10, 10)
plt.imshow(A)
plt.title('originalna slika')
plt.axis('off')

plt.close('all')

# ukazi.m:224
B = np.double(A[:, :, 0])

fig = plt.figure()
fig.set_size_inches(7, 7)
ax = fig.add_subplot(111, projection='3d')
X = Y = np.array([np.arange(100), ]*100)  # Creates a 100 * 100 array
Z = abs(np.fft.fft2(B - np.mean(np.ravel(B)), s=(100, 100)))
wire = ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)

# Retrive data from internal storage of plot_wireframe, then delete it
nx, ny, _ = np.shape(wire._segments3d)
wire_x = np.array(wire._segments3d)[:, :, 0].ravel()
wire_y = np.array(wire._segments3d)[:, :, 1].ravel()
wire_z = np.array(wire._segments3d)[:, :, 2].ravel()
wire.remove()

# create data for a LineCollection
wire_x1 = np.vstack([wire_x, np.roll(wire_x, 1)])
wire_y1 = np.vstack([wire_y, np.roll(wire_y, 1)])
wire_z1 = np.vstack([wire_z, np.roll(wire_z, 1)])
to_delete = np.arange(0, nx*ny, ny)
wire_x1 = np.delete(wire_x1, to_delete, axis=1)
wire_y1 = np.delete(wire_y1, to_delete, axis=1)
wire_z1 = np.delete(wire_z1, to_delete, axis=1)
scalars = np.delete(wire_z, to_delete)

segs = [list(zip(xl, yl, zl)) for xl, yl, zl in \
                 zip(wire_x1.T, wire_y1.T, wire_z1.T)]

# Plots the wireframe by a  a line3DCollection
my_wire = art3d.Line3DCollection(segs, cmap="hsv")
my_wire.set_array(scalars)
ax.add_collection(my_wire)

plt.colorbar(my_wire)
plt.show()

# ukazi.m:226 -- Note: Not implemented. Same chart as previous section.
B = np.double(A[:, :, 1])
X, Y = np.meshgrid(np.arange(100), np.arange(100))
Z = abs(np.fft.fft2(B - np.mean(np.ravel(B)))[0:100, 0:100])
colors = cm.Blues(Z)
rcount, ccount, _ = colors.shape

fig = plt.figure()
fig.set_size_inches(7, 7)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rcount=rcount, ccount=ccount, facecolors=colors, shade=False)
surf.set_facecolor((0, 0, 0, 0))
plt.title('G ravnina')
plt.show()

# ukazi.m:228 -- Note: Not implemented. Same chart as previous section.
B = np.double(A[:, :, 2])
X, Y = np.meshgrid(np.arange(100), np.arange(100))
Z = abs(np.fft.fft2(B - np.mean(np.ravel(B)))[0:100, 0:100])
colors = cm.Blues(Z)
rcount, ccount, _ = colors.shape

fig = plt.figure()
fig.set_size_inches(7, 7)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rcount=rcount, ccount=ccount, facecolors=colors, shade=False)
surf.set_facecolor((0, 0, 0, 0))
plt.title('B ravnina')
plt.show()

# ukazi.m:231 -- Note: Not implemented. Same chart as previous section.
# prevzorčena slika..................................
pvz = 4
B = np.double(A[0::pvz, 0::pvz, 1])
X, Y = np.meshgrid(np.arange(100), np.arange(100))
Z = abs(np.fft.fft2(B - np.mean(np.ravel(B)))[0:100, 0:100])
colors = cm.Blues(Z)
rcount, ccount, _ = colors.shape

fig = plt.figure()
fig.set_size_inches(7, 7)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rcount=rcount, ccount=ccount, facecolors=colors, shade=False)
surf.set_facecolor((0, 0, 0, 0))
plt.title('R ravnina, po podvzorenju s faktorjem {0}'.format(pvz))
plt.show()

# ukazi.m:235
B = np.double(A[0::pvz, 0::pvz, 2])
X, Y = np.meshgrid(np.arange(100), np.arange(100))
Z = abs(np.fft.fft2(B - np.mean(np.ravel(B)))[0:100, 0:100])
colors = cm.Blues(Z)
rcount, ccount, _ = colors.shape

fig = plt.figure()
fig.set_size_inches(7, 7)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rcount=rcount, ccount=ccount, facecolors=colors, shade=False)
surf.set_facecolor((0, 0, 0, 0))
plt.title('G ravnina, po podvzorenju s faktorjem {0}'.format(pvz))
plt.show()

# ukazi.m:237 -- Note: Not implemented. Same chart as previous section.
B = np.double(A[0::pvz, 0::pvz, 3])
X, Y = np.meshgrid(np.arange(100), np.arange(100))
Z = abs(np.fft.fft2(B - np.mean(np.ravel(B)))[0:100, 0:100])
colors = cm.Blues(Z)
rcount, ccount, _ = colors.shape

fig = plt.figure()
fig.set_size_inches(7, 7)
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rcount=rcount, ccount=ccount, facecolors=colors, shade=False)
surf.set_facecolor((0, 0, 0, 0))
plt.title('B ravnina, po podvzorenju s faktorjem {0}'.format(pvz))
plt.show()

# -----------------------------------------------------------------------------------------
# ukazi.m:241
# podvzorčenje slik in operator povprečenja

A = pylab.array(Image.open(Path('./1-Vzorcenje/Moire.jpg')))
plt.figure().set_size_inches(10, 10)
plt.imshow(A)
plt.title('originalna slika')
plt.axis('off')

pvz = 3  # faktor podvzorčenja
plt.figure()
plt.imshow(A[0::pvz, 0::pvz, :])
plt.title('podvzorčena slika: faktor podvzorčenja {0}'.format(pvz))

# ukazi.m:253 -- Note: Mislim, da je ok, čeprav rezultat različen kot v Matlab (poglej spodaj).
# operator povprečenja (verzija 1)
# Zglajena slika v Matlabu ima pri meni moder odtenek. Nisem prepričan, če tako mora biti (tukaj odtenka ni).
D = 3  # premer lokalne okolice piksla, na kateri se izračuna povprečna vrednost
B = np.ndarray((A.shape[0] - D + 1, A.shape[1] - D + 1, D))
for r in np.arange(0, A.shape[0] - D).reshape(-1):
    for c in np.arange(0, A.shape[1] - D).reshape(-1):
        C = A[r + np.arange(0, D - 1), c + np.arange(0, D - 1), 0]
        B[r, c, 0] = np.mean(np.ravel(C))
        C = A[r + np.arange(0, D - 1), c + np.arange(0, D - 1), 1]
        B[r, c, 1] = np.mean(np.ravel(C))
        C = A[r + np.arange(0, D - 1), c + np.arange(0, D - 1), 2]
        B[r, c, 2] = np.mean(np.ravel(C))

plt.figure()
plt.imshow(np.uint8(B))
plt.title('zglajena slika')

# ukazi.m:270 -- Note: Naslovi se prekrivajo.
# operator povpreenja (verzija 2)
# isti operator povprečenja kot zgoraj, implementiran nekoliko drugače (veliko hitreja izvedba)
D = 3
B = np.ndarray((A.shape[0] + D - 1, A.shape[1] + D - 1, D))
B[:, :, 0] = scipy.signal.convolve2d(np.double(A[:, :, 0]), np.ones((D, D), np.float) / D ** 2)
B[:, :, 1] = scipy.signal.convolve2d(np.double(A[:, :, 1]), np.ones((D, D), np.float) / D ** 2)
B[:, :, 2] = scipy.signal.convolve2d(np.double(A[:, :, 2]), np.ones((D, D), np.float) / D ** 2)
B = np.uint8(B)
plt.figure()
plt.imshow(B)
plt.title('zglajena slika')

# prikaz
pvz = 3  # faktor podvzorčenja
plt.figure()
plt.subplot(1, 2, 1)
plt.imshow(A[0::pvz, 0::pvz, :])
plt.title('podvzorčena slika: faktor podvzorčenja {0}'.format(pvz))
plt.subplot(1, 2, 2)
plt.imshow(B[1::pvz, 1::pvz, :])
plt.title('zglajena podvzorena slika: faktor podvzorenja {0}'.format(pvz))


from sympy import *
from rodrigues_R_utils import *

ksi_0, eta_0, c = symbols('ksi_0 eta_0 c');
px, py, pz = symbols('px py pz')
sx, sy, sz = symbols('sx sy sz')
tie_px, tie_py, tie_pz = symbols('tie_px tie_py tie_pz');
ksi_kp, eta_kp = symbols('ksi_kp eta_kp')

position_symbols = [px, py, pz]
rodrigues_symbols = [sx, sy, sz]
tie_point_symbols = [tie_px, tie_py, tie_pz]
all_symbols = position_symbols + rodrigues_symbols + tie_point_symbols

RT_wc = matrix44FromRodrigues(px, py, pz, sx, sy, sz)
r=RT_wc[:-1,:-1]
t=Matrix([px, py, pz]).vec()

denom=r[0,2]*(tie_px-t[0]) + r[1,2]*(tie_py-t[1]) + r[2,2]*(tie_pz-t[2])
ksi=ksi_0 - c * ( r[0,0]*(tie_px-t[0]) + r[1,0]*(tie_py-t[1]) + r[2,0]*(tie_pz-t[2]) ) /denom
eta=eta_0 - c * ( r[0,1]*(tie_px-t[0]) + r[1,1]*(tie_py-t[1]) + r[2,1]*(tie_pz-t[2]) ) /denom

ksi_delta = ksi_kp - ksi;
eta_delta = eta_kp - eta;

obs_eq = Matrix([ksi_delta, eta_delta]).vec()
obs_eq_jacobian = obs_eq.jacobian(all_symbols)

print(obs_eq)
print(obs_eq_jacobian)

with open("metric_camera_colinearity_rodrigues_wc_jacobian.h",'w') as f_cpp:
    f_cpp.write("inline void observation_equation_metric_camera_colinearity_rodrigues_wc(Eigen::Matrix<double, 2, 1> &delta, double ksi_0, double eta_0, double c, double px, double py, double pz, double sx, double sy, double sz, double tie_px, double tie_py, double tie_pz, double ksi_kp, double eta_kp)\n")
    f_cpp.write("{")
    f_cpp.write("delta.coeffRef(0,0) = %s;\n"%(ccode(obs_eq[0,0])))
    f_cpp.write("delta.coeffRef(1,0) = %s;\n"%(ccode(obs_eq[1,0])))
    f_cpp.write("}")
    f_cpp.write("\n")
    f_cpp.write("inline void observation_equation_metric_camera_colinearity_rodrigues_wc_jacobian(Eigen::Matrix<double, 2, 9, Eigen::RowMajor> &j, double ksi_0, double eta_0, double c, double px, double py, double pz, double sx, double sy, double sz, double tie_px, double tie_py, double tie_pz, double ksi_kp, double eta_kp)\n")
    f_cpp.write("{")
    for i in range (2):
        for j in range (9):
            f_cpp.write("j.coeffRef(%d,%d) = %s;\n"%(i,j, ccode(obs_eq_jacobian[i,j])))
    f_cpp.write("}")