Кубический интерполяционный сплайн
×

Кубический интерполяционный сплайн

Для проверки работоспособности программы требуется для функции f(x) = (x - 1)6, задав отрезок [a, b] из крайних точек, выбирая промежуточные точки с шагом ℎ = (b - a) / N, N задано, построить сплайн.

Теорию рекомендую почитать здесь.

Прежде чем запускать основной код, нужно сформировать код для метода прогонки и проинициализировать его.

Вспомогательный код для решения СЛАУ методом прогонки (подробнее в этой статье):

def Metod_Progonki(A,B):
    #Известные константы
    k1 = -A[0,1]
    m1 = B[0]
    k2 = -A[A.shape[0] - 1, A.shape[1] - 2]
    m2 = B[B.shape[0] - 1]
    alfa = k1
    beta = m1
    #Поиск альф и бет
    c = 2
    a = 0
    b = 1
    alf = [alfa]
    bet = [beta]
    for i in range(1, A.shape[0] - 1):
        beta = (B[i] - A[i,a] * beta) / (A[i,a] * alfa + A[i,b])
        alfa = -A[i,c] / (A[i,a] * alfa + A[i,b])
        a += 1
        b += 1
        c += 1
        alf.append(alfa)
        bet.append(beta)
    #расчет игриков
    y = (k2 * beta + m2) / (1 - k2 * alfa)
    otv = [y]
    for i in range(len(alf) - 1, -1, -1):
        y = alf[i] * y + bet[i]
        otv.append(y)
    #переворачиваем значения в списке
    otvet = []
    for i in reversed(otv): otvet.append(i)
    return otvet

Этот код следует добавить в отдельный файл в ту же папку PyCharm, что и основной код:

Основной код:

#библиотека для параметризации функции и построения графиков
from sympy import *

#для решения трехдиагональной СЛАУ
from Project1 import Progonka
import numpy

x = symbols('x')
y = (x - 1) ** 6 #исходная функция
a, b = 0.5, 1.5 #отрезок из крайних точек
N = 10 #число разбиений

def cube_interp(y, a, b, N):
    #получение списков координат опорных точек сплайна
    global xi, yi
    xi, yi = [], []
    h = (b - a) / N #шаг
    while a < b:
        xi.append(a)
        yi.append(y.evalf(subs={'x':a}))
        a += h
    if round(a - h, 5) != b:
        xi.append(b)
        yi.append(y.evalf(subs={'x': b}))
    #ищем константы ci уравнений
    A = numpy.zeros([N - 1, N - 1])
    A[0, 0] = 2 * (xi[2] - xi[0])
    A[0, 1] = xi[2] - xi[1]
    A[N - 2, N - 3] = xi[N - 1] - xi[N - 2]
    A[N - 2, N - 2] = 2 * (xi[N] - xi[N - 2])
    for i in range(2, N - 1):
        A[i - 1, i - 2] = xi[i] - xi[i - 1]
        A[i - 1, i - 1] = 2 * (xi[i + 1] - xi[i - 1])
        A[i - 1, i] = xi[i + 1] - xi[i]

    a = numpy.zeros([N - 1])
    for i in range(1, N):
        a[i - 1] = 6 * ((yi[i + 1] - yi[i]) / (xi[i + 1] - xi[i]) - (yi[i] - yi[i - 1]) / (xi[i] - xi[i - 1]))

    #с помощью метода прогонки находим константы ci
    ci = [0]
    for j in Progonka.Metod_Progonki(A, a):
        ci.append(float(j))
    ci.append(0)

    #находим константы di
    di = [0]
    for i in range(1, N + 1):
        di.append((ci[i] - ci[i - 1]) / (xi[i] - xi[i - 1]))

    #находим константы bi
    bi = [0]
    for i in range(1, N + 1):
        hi = xi[i] - xi[i - 1]
        bi.append(ci[i] * hi / 2 - di[i] * hi ** 2 / 6 + (yi[i] - yi[i - 1]) / hi)

    #находим константы ai
    ai = []
    for i in yi: ai.append(i)

    #вычисление уравнений кусков кубического сплайна с привязкой к своим отрезкам
    yn = {}
    for i in range(1, N + 1):
        yn[xi[i - 1], xi[i]] = ai[i] + bi[i] * (x - xi[i]) + ci[i] * (x - xi[i]) ** 2 / 2 + di[i] * (x - xi[i]) ** 3 / 6
    return yn

#вызов функции и вывод на экран
print(cube_interp(y, a, b, N))

#построение функции и сплайна в одних осях
p = plot(y, (x, a, b), show=False)
for i, j in cube_interp(y, a, b, N):
    p.extend(plot(cube_interp(y, a, b, N)[i, j], (x, i, j), line_color='r', show=False))
p.show()

Результат: