Квадратичный интерполяционный сплайн

Квадратичный интерполяционный сплайн

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

Сплайн строится путем соединения всех точек в массиве между собой кусками параболы:

Обратите внимание, что квадратичный сплайн очень капризный и при выборе неподходящего участка основной функции никакого сглаживания не произойдет!!!

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

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

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

import numpy

def Metod_Gaussa(arr, brr):
    for k in range(arr.shape[0] - 1):
        #поиск строки с максимальным элементом
        max_elem = 0
        str = 0
        for i in range (k, arr.shape[0]):
            if abs(arr[i,k]) > abs(max_elem):
                max_elem = arr[i,k]
                str = i
        #меняем местами строки квадратной матрицы
        change = numpy.repeat(arr[k], 1)
        arr[k], arr[str] = arr[str], change
        #меняем местами элементы вектора-столбца
        change = numpy.repeat(brr[k], 1)
        brr[k], brr[str] = brr[str], change
        #делим полученную строку на max_elem
        arr[k] = arr[k] / max_elem
        brr[k] = brr[k] / max_elem
        #домножаем строку на коэффициенты и вычитаем ее из остальных строк
        for i in range (k + 1, arr.shape[0]):
            factor = arr[i,k]
            arr[i] = arr[i] - arr[k] * factor
            brr[i] = brr[i] - brr[k] * factor

    #находим неизвестные
    arg = [brr[brr.shape[0] - 1] / (arr[arr.shape[0] - 1, arr.shape[0] - 1])]
    for i in range(arr.shape[0] - 2, -1, -1):
        n = brr[i]
        for j in range(len(arg)):
            n = n - arg[j] * arr[i, arr.shape[0] - 1 - j]
        arg.append(n)

    #переворачиваем значения в списке
    otv = []
    for i in reversed(arg): otv.append(i)
    return otv

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

Основной код для левого сплайна:

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

#для решения СЛАУ
from Project1 import Gaussa
import numpy

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

def left_square_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}))
    #ищем константы уравнений
    const = [[] for i in range(N)]
    for i in range(N):
        A = numpy.array([[1, xi[i], xi[i] ** 2], [1, xi[i + 1], xi[i + 1] ** 2], [0, 1, 2 * xi[i]]])
        if i == 0:
            a = numpy.array([yi[i], yi[i + 1], 0])
        else:
            a = numpy.array([yi[i], yi[i + 1], const[i - 1][1] + 2 * const[i - 1][2] * xi[i]])
        for j in Gaussa.Metod_Gaussa(A, a): const[i].append(float(j))
    #вычисление уравнений кусков определённого слева квадратичного сплайна с привязкой к своим отрезкам
    yn = {}
    for i in range(N):
        yn[xi[i], xi[i + 1]] = const[i][0] + const[i][1] * x + const[i][2] * x ** 2
    return yn

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

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

Результат:

Основной код для правого сплайна:

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

#для решения СЛАУ
from Project1 import Gaussa
import numpy

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

def right_square_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}))
    #ищем константы уравнений
    const = [[] for i in range(N)]
    for i in range(N, 0, -1):
        A = numpy.array([[1, xi[i], xi[i] ** 2], [1, xi[i - 1], xi[i - 1] ** 2], [0, 1, 2 * xi[i]]])
        if i == N:
            a = numpy.array([yi[i], yi[i - 1], 0])
        else:
            a = numpy.array([yi[i], yi[i - 1], const[N - 1 - i][1] + 2 * const[N - 1 - i][2] * xi[i]])
        for j in Gaussa.Metod_Gaussa(A, a):
            const[N - i].append(float(j))
    #переворачиваем значения в списке
    const_new = []
    for i in reversed(const): const_new.append(i)
    #вычисление уравнений кусков определённого справа квадратичного сплайна с привязкой к своим отрезкам
    yn = {}
    for i in range(N):
        yn[xi[i], xi[i + 1]] = const_new[i][0] + const_new[i][1] * x + const_new[i][2] * x ** 2
    return yn

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

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

Результат: