Lista 11 · Runge e splines¶
Acompanha o capítulo 11. Quando o polinômio de grau alto oscila, escolha bem os pontos (Chebyshev) ou use um polinômio por trecho (spline).
Como esta lista funciona
Abra o caderno no Colab, escreva a sua solução no lugar do # TODO e rode a
célula de teste logo abaixo. Ela mesma diz o que passou e o que falhou — você
não precisa esperar correção de ninguém.
O código de cada exercício também está aqui embaixo, caso você prefira colar num editor local. Os testes comparam números com tolerância.
Exercícios marcados com ✏️ são à mão, no papel, com 4 casas decimais — como na parte em papel das avaliações.
Exercício 01¶
✏️ À mão. A tabela tem os pontos \((0, 1)\), \((1, 3)\) e \((3, 2)\).
a) Pela spline linear (uma reta por trecho), estime \(y\) em \(x = 0{,}5\) e em \(x = 2\).
b) Pelo polinômio de Lagrange pelos três pontos, estime \(y\) em \(x = 2\).
c) A spline linear tem "bico" em \(x = 1\)? Calcule a inclinação de cada lado.
Exercício 02¶
Escreva nos_chebyshev(n, a, b), que devolve um array com os \(n\) nós de Chebyshev
no intervalo \([a, b]\):
(O cosseno dá os nós em \([-1, 1]\); a conta de fora os leva para \([a, b]\).)
import numpy as np
def nos_chebyshev(n, a, b):
"""Os n nós de Chebyshev levados do intervalo [-1, 1] para [a, b]."""
nos = np.zeros(n)
# TODO: para cada k, o cosseno e a mudança de intervalo
return nos
# --- testes (não altere) ---
nos = nos_chebyshev(3, -1, 1)
assert abs(nos[1]) < 1e-12, "com 3 nós em [-1, 1], o do meio é 0"
assert abs(nos[0] - 0.8660254037844387) < 1e-12
nos = nos_chebyshev(4, 0, 10)
assert abs(nos[0] - 9.619397662556434) < 1e-12 and abs(nos[3] - 0.3806023374435661) < 1e-12
print("Exercício 02: todos os testes passaram!")
Exercício 03¶
O fenômeno de Runge em números. Escreva erro_runge(n), que interpola a função
de Runge (runge, já escrita) em n pontos igualmente espaçados de \(-1\) a \(1\) com a
lagrange (já escrita), e devolve o maior erro absoluto entre o polinômio e a
função, medido em 401 pontos de \(-1\) a \(1\).
Depois de passar, calcule para \(n = 5, 9, 13, 17, 21\). O que acontece?
import numpy as np
def runge(x):
"""JÁ ESCRITA."""
return 1 / (1 + 25 * x**2)
def lagrange(xs, ys, x):
"""JÁ ESCRITA."""
soma = 0.0
for i in range(len(xs)):
L = 1.0
for j in range(len(xs)):
if j != i:
L = L * (x - xs[j]) / (xs[i] - xs[j])
soma = soma + ys[i] * L
return soma
def erro_runge(n):
"""Maior erro do polinômio por n pontos igualmente espaçados em [-1, 1],
medido em 401 pontos."""
# TODO: os nós com np.linspace, os 401 pontos de teste, e np.max do erro absoluto
pass
# --- testes (não altere) ---
assert abs(erro_runge(5) - 0.4383566395255679) < 1e-9
assert abs(erro_runge(13) - 3.65771713785101) < 1e-6
assert erro_runge(17) > erro_runge(13), "mais pontos, erro MAIOR"
print("Exercício 03: todos os testes passaram!")
Exercício 04¶
Sensores — reamostrar um sinal. Dois sensores registram em horários diferentes:
um a cada 0,7 s e outro a cada 1 s. Para comparar os dois, é preciso levar um deles
para os horários do outro. Escreva reamostra(t, y, novos_t), que devolve os valores
de y nos instantes novos_t, por interpolação linear com np.interp.
import numpy as np
def reamostra(t, y, novos_t):
"""Valores de y nos instantes novos_t, por interpolação linear."""
# TODO: uma linha com np.interp (atenção à ordem dos argumentos)
pass
# --- testes (não altere) ---
r = reamostra([0, 0.7, 1.4, 2.1], [10, 12, 11, 15], [0, 1, 2])
assert r is not None, "faltou o return?"
assert abs(r[0] - 10) < 1e-12 and abs(r[1] - (12 - 1 * 0.3 / 0.7)) < 1e-9 and abs(r[2] - (11 + 4 * 0.6 / 0.7)) < 1e-9
print("Exercício 04: todos os testes passaram!")
Exercício 05¶
Clima — a hora mais fria. Com as medições de 3 em 3 horas do capítulo (0, 3, ...,
21 h; 25,2; 24,6; 24,4; 27,8; 30,6; 30,9; 28,3; 26,4 °C), escreva
hora_mais_fria(horas, temp), que monta a spline cúbica, calcula-a numa grade de
0,01 h (de horas[0] a horas[-1]) e devolve a hora de temperatura mínima.
Por que a resposta não é nenhuma das horas medidas?
import numpy as np
from scipy.interpolate import CubicSpline
def hora_mais_fria(horas, temp):
"""Hora do dia em que a spline cúbica das medições é mínima (grade de 0,01 h)."""
# TODO: a spline, a grade (quantos pontos para passo de 0,01?) e np.argmin
pass
# --- testes (não altere) ---
h = hora_mais_fria([0, 3, 6, 9, 12, 15, 18, 21], [25.2, 24.6, 24.4, 27.8, 30.6, 30.9, 28.3, 26.4])
assert abs(h - 4.87) < 1e-9, f"veio {h}"
print("Exercício 05: todos os testes passaram!")
Exercício 06¶
Cinema e robótica — o comprimento do caminho. A câmera do capítulo passa pelos
pontos \((0, 0)\), \((2, 1)\), \((4, 0)\), \((4, -2)\), \((2, -3)\) e \((0, -1)\) nos instantes 0 a
5 s. Escreva comprimento_caminho(t, x, y), que monta as splines \(x(t)\) e \(y(t)\),
calcula-as em 1001 instantes igualmente espaçados e soma os comprimentos dos 1000
segmentos retos entre pontos vizinhos (Pitágoras).
Quanto mais comprido que a linha poligonal (os segmentos retos entre os pontos de passagem) é o caminho suave?
import numpy as np
from scipy.interpolate import CubicSpline
def comprimento_caminho(t, x, y):
"""Comprimento do caminho das splines x(t), y(t), somando 1000 segmentos retos."""
# TODO: duas splines, 1001 instantes, e um acumulador com a distância entre vizinhos
pass
# --- testes (não altere) ---
L = comprimento_caminho([0, 1, 2, 3, 4, 5], [0.0, 2.0, 4.0, 4.0, 2.0, 0.0], [0.0, 1.0, 0.0, -2.0, -3.0, -1.0])
assert abs(L - 12.156311132751794) < 1e-9, f"veio {L}"
assert abs(comprimento_caminho([0, 1, 2], [0.0, 3.0, 6.0], [0.0, 4.0, 8.0]) - 10) < 1e-9, "uma reta de comprimento 10"
print("Exercício 06: todos os testes passaram!")