import cmath as cm                  # Математическая библеотека
import numpy as np                  # Вспомогательная мат. библеотека
import scipy.interpolate as it      # Интерполяция сплайнами
import matplotlib.pyplot as mp      # Библеотека для отрисовки графиков

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

#                               В ДВУХ ЭТИХ ФУНКЦИЯХ НУЖНО ПОМЕНЯТЬ КОЭФИЦЕНТЫ !!!

# Первая функция
def F1(X , C1 = 5, C2 = 6, M1 = 7, M2 = 8):
    return (C1 + C2 + M1 + M2) * (cm.log(cm.pi - X + 1) ** (cm.log(X + 1)))

# Вторая функция
def F2(X , B1 = 1, B2 = 1, B3 = 1, B4 = 1):
    return (B1 + B2 + B3 + B4) * abs(X - 0.5)

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

# Получение массива координат из функции
# Принимает: функцию, интервал от A до B, шаг
def Func_oXY(F, A = 0, B = 1, STEP = 0.001): X = np.arange(A,B,STEP); return {"X" : X, "Y" : [ F(x) for x in X] }

# Интерполяционный многочлен Лагранжа
# Принимает: функцию, интервал от A до B
# Метод строит график функции и отображает точк(у,и) приближения
def Interpolation_Lagrange_Lolynomial(F, A = 0, B = 1, N = 7, STEP=0.01, Num = 1, TITLE=""):

    # Функция Лагранжа
    # X это мноество точек, Xn точка для приближения
    def Lagranz(X, F, n):
        Z = 0
        for J in range(0,n+1):
            P = 1
            for I in range(0,n+1):
                if (I != J):
                    P *= (X - I/n)/(J/n - I/n)
            Z += F(J/n) * P
        return Z

    # Позиция на графике
    mp.subplot(3,2,Num); mp.title(TITLE,fontsize=10)

    # Получаем все возможные точки функции с шагом
    _F = Func_oXY(F,A,B,STEP) 

    # Строим саму функцию
    mp.plot(_F["X"], _F["Y"], 'Green', label="Функция" ) 

    # Строим приближение
    mp.plot(_F["X"], Lagranz(_F["X"], F, N), Color='Red',alpha=0.8, label="Приближение") 

    # Легенда
    mp.legend()

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

# Интерполяция с помощью синк-аппроксимации
def Sink_Approximation(F, A = 0, B = 1, NODES = 50, STEP=0.01, Num = 1,TITLE=""):

    # Синк апроксимация
    def Sink(x, n = NODES): return sum([((np.sin(np.pi*(n*x-k))) / (np.pi*(n*x-k)))*F(k/n) for k in range(1, n)])

    # Позиция на графике
    mp.subplot(3,2,Num); mp.title(TITLE,fontsize=10)

    # Получаем все возможные точки функции с шагом
    _F = Func_oXY(F,A,B) 

    # Строим саму функцию
    mp.plot(_F["X"], _F["Y"], 'Green', label="Функция" ) 
   
    # Строим приближение
    mp.plot(_F["X"] , [Sink(x) for x in np.linspace(A,B,len(_F["X"]))], Color='Red',alpha=0.8, label="Приближение") 
    
    # Легенда
    mp.legend()

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

# Интерполяция сплайнами
def Spline_Interpolation(F, A = 0, B = 1, NODES = 10, STEP=0.01, Num = 1,TITLE=""):

    # Позиция на графике
    mp.subplot(3,2,Num); mp.title(TITLE,fontsize=10)

    # Получаем все возможные точки функции с шагом
    _F = Func_oXY(F,A,B)

    # Строим саму функцию
    mp.plot(_F["X"], _F["Y"], 'Green', label="Функция") 

    # Строим набор точек приближения
    
    _X = np.linspace(A,B,NODES)
    _Y = [it.splev(x, it.splrep(_X, [F(x) for x in _X])) for x in _F["X"]]
    #_Y = [Spline(x, _X, [ F(x) for x in _X]) for x in _F["X"]]                # Самописную функцию выпилил, работает не оч...

    # Строим приближение
    mp.plot(_F["X"], _Y, Color='Red',alpha=0.8, label="Приближение") 

    # Легенда
    mp.legend()

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

# Стартер
def Start():

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

    # Интерполяционный многочлен Лагранжа
    Interpolation_Lagrange_Lolynomial(F1,0,1,Num=1, TITLE="Приближение функции: $f(x) = (c1 + c2 + m1 + m2) ln (Pi - x + 1) ^ ( ln(x + 1) )$")
    Interpolation_Lagrange_Lolynomial(F2,0,1,Num=2, TITLE="Приближение функции: $f(x) = (b1 + b2 + b3 + b4) |x - 0.5|$")

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

    # Приближение методом синк-апроксимации
    Sink_Approximation(F1,0,1,Num=3, TITLE="Приближение синк-апроксимацией")
    Sink_Approximation(F2,0,1,Num=4, TITLE="Приближение синк-апроксимацией")

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

    # Приближение с помощью интерпоялционных сплайнов
    Spline_Interpolation(F1,0,1,Num=5, TITLE="Приближение с помощью сплайнов")
    Spline_Interpolation(F2,0,1,Num=6, TITLE="Приближение с помощью сплайнов")

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

    # Отрисовка
    mp.show()

# Главный метод
if __name__ == "__main__": Start()
    
    

# ЭТИ ОПЕРАЦИИ РАВНОСИЛЬНЫ !!!


# M = [i for i in range(10)]


# M = []
# for i in range(10):
#   M.append(i)

