Código-fonte para CB2325NumericaG1.interpolacao.interpolacao_polinomial_vandermond

import matplotlib.pyplot as plt
import numpy as np
from typing import Callable

def _ordenar_coordenadas(x: list, y: list) -> list:
    """Ordena as coordenadas mantendo 'pareamento'.
    
    Pega as coordenadas x e y de cada ponto, ordena em ordem crescente
    as coordenadas x e mantém pareamento com y. Função privada, auxiliar
    da função principal lin_interp.

    Args:
        x: lista das coordenadas x, em x[i], de cada ponto i.
        y: lista das coordenadas y, em y[i], de cada ponto i.

    Returns:
        x_ord: lista das coordenadas x em ordem crescente.
        y_ord: lista das coordenadas y, pareadas com as coordenadas x.
    """
    
    x_np = np.array(x)
    y_np = np.array(y)

    idx = np.argsort(x_np)

    x_ord = x_np[idx]
    y_ord = y_np[idx]

    return x_ord, y_ord

def _random_sample(intv: list, N: int) -> np.array:
    """Cria uma amostra aleatória.
    
    Args:
        intv: intervalo da amostra.
        N: número de amostras.

    Returns:
        Lista numpy.array das amostras.
    """
    r = np.random.uniform(intv[0], intv[1], N-2)
    r.sort()
    return np.array([intv[0]] + list(r) + [intv[1]])

def _error_pol(f: Callable,
               P: Callable,
               intv: list,
               n: int = 1000) -> np.array:
    """Calcula o erro médio e o erro máximo
    
    Args:
        f: função analisada.
        P: função idealizada.
        intv: intervalo analisado.
        n = quantidade de amostras.

    Reuturns:
        Erro médio.
        Erro máximo.
    """
    x = _random_sample(intv, n)
    error = np.abs(f(x)-P(x))
    return np.sum(error)/n, np.max(error)

def _plotar(x: list,
            y: list,
            f: Callable,
            titulo: str = 'Gráfico',
            f_ideal: Callable = None):
    """Plotagem de pontos e de uma função.

    Plotagem dos pontos indicados pelas coordenadas x e y, seguindo a
    função f. Caso haja uma função ideal, ela também é plotada, e seu
    erro é calculado. O erro é mostrado no título do gráfico principal,
    e um gráfico secundário é plotado, mostrando o erro absoluto. Função
    privada, auxiliar da função principal lin_interp.

    Args:
        x: lista das coordenadas x, em x[i], de cada ponto i.
        y: lista das coordenadas y, em y[i], de cada ponto i.
        f: função que será plotada.
        titulo: titulo do gráfico que será plotado.
        f_ideal: função ideal (caso tenha).

    Returns:
        None
    """
    
    # Conversão para numpy.array
    x_points = np.linspace(x[0], x[-1], 500)
    y_points = np.array([f(xp) for xp in x_points])

    if f_ideal: # Caso exista uma função ideal, o erro médio é calculado e mostrado na plotagem
        _, (ax, ax_err) = plt.subplots(
            2, 1, 
            figsize=(10, 10), 
            sharex=True # Compartilha o eixo x
        )
        
        y_ideal = np.array([f_ideal(xp) for xp in x_points]) # Pontos da função ideal

        # Calcuando erros médio e máximo
        intv = [x[0], x[-1]]
        erroMedio, erroMax = _error_pol(f, f_ideal, intv, n= 1000)
        ax.set_title(titulo+f' - Erro Médio = {erroMedio:2.4f} - Erro Máximo = {erroMax:2.4f}')
        
        # Plotando a função ideal 
        ax.plot(x_points, y_ideal, color = 'k', label = 'Função ideal')
        
        # Calculando e plotando o erro absoluto em gráfico anexo ao original
        erro_absoluto = np.abs(y_ideal - y_points)
        ax_err.plot(x_points, erro_absoluto, 'r-', label='Erro Absoluto |Real - Interp.|')
        ax_err.set_xlabel('x')
        ax_err.set_ylabel('Erro Absoluto')
        ax_err.set_title('Gráfico de Erro')
        ax_err.grid(True, alpha=0.3)
        ax_err.legend()
    else:
        # Criando área de plotagem normal, sem gráfico de erro anexo
        _, ax = plt.subplots()
        ax.set_title(titulo)
    
    ax.scatter(x, y, color = 'red', label = 'Dados')
    ax.plot(x_points, y_points, 'b-',
            linewidth=2, label = 'Interpolação Polinomial (Vandermonde)')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.grid(True, alpha=0.3)
    ax.legend()
    plt.show()

    return

[documentos] def vandermond_interp(x: list, y: list, plot: bool = False, f_ideal: Callable = None) -> Callable: """Interpolação polinomial pelo método de Vandermonde Essa função ordena pontos a partir da ordem crescente das coordenadas x. Em seguida, cria matriz de Vandermonde e retorna a solução algébrica para, assim, conseguir os coeficientes do polinômio interpolado. Caso haja uma função ideal, também é calculado o erro, que é representado no plot. Por fim, caso 'plot = True', há uma plotagem do gráfico correspondente. Por padrão, 'plot = False', ou seja, por padrão não há a plotagem. Args: x: lista das coordenadas x, em x[i], de cada ponto i. y: lista das coordenadas y, em y[i], de cada ponto i. plot: indica se deve haver a plotagem (True) ou não (False). f_ideal: função ideal, caso queira fazer comparação de erros. Returns: f: função de interpolação linear por partes. Raises: ValueError: Caso 'x' e 'y' tenham tamanhos diferentes, caso as listas estejam vazias, ou caso as coordenadas em 'x' não sejam distintas. TypeError: caso 'x' ou 'y' não sejam listas, caso 'f_ideal' não seja callable, ou caso 'plot não seja bool'. """ # Tratamento de erros try: n = len(x) m = len(y) except: raise TypeError("Os argumentos 'x' e 'y' devem ser listas.") if f_ideal is not None and not callable(f_ideal): raise TypeError("O argumento 'f_ideal' deve ser uma função (callable).") if type(plot) != bool: raise TypeError("O argumento 'plot' deve ser bool") if n != m: raise ValueError("As listas de coordenadas x e y devem ter o mesmo tamanho.") if n == 0: raise ValueError("As listas x e y não podem estar vazias.") if len(set(x)) != n: raise ValueError("As coordenadas x devem ser todas distintas.") # Ordenação das coordenadas x em ordem crescente x, y = _ordenar_coordenadas(x, y) n = len(x) matrix_vandermond = np.ones([n, n]) # Criação da matriz de Vandermonde com uns for i in range(n): # Eleva cada elemento da matriz ao seu devido expoente for k in range(1, n): matrix_vandermond[i][k] = matrix_vandermond[i][k-1] * x[i] coef = np.linalg.solve(matrix_vandermond, y) # Definição da função de interpolação def f(x1: float) -> float: y1 = 0 for a in coef[::-1]: # Método de Horner para calcular valores de polinômios y1 = a + y1*x1 return y1 # Plotagem do gráfico correspondente à função f if plot: if f_ideal: # Caso exista uma função ideal, o erro é "plotado" no título _plotar(x, y, f, 'Interpolação Polinomial (Vandermonde)', f_ideal= f_ideal) else: _plotar(x, y, f, 'Interpolação Polinomial (Vandermonde)') return f