Lista 06 · Otimização¶
Acompanha o capítulo 6. Mínimo e máximo são raízes da derivada: varredura para o chute, Newton para a precisão, e o sinal de \(f''\) para conferir. Economia, arquitetura, aviação.
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. Seja \(f(x) = x^2 - 6x + 10\).
a) Calcule \(f\) na grade \(x = 0, 1, 2, \ldots, 6\). Onde fica o menor valor da grade?
b) Faça um passo de Newton para otimização, \(x_1 = x_0 - f'(x_0)/f''(x_0)\), a partir de \(x_0 = 0\), com as derivadas exatas.
c) O passo acertou o mínimo exatamente. Por quê? (Pense no que é a aproximação de Newton para uma parábola.)
d) Use o sinal de \(f''\) para confirmar que é um mínimo.
Exercício 02¶
Escreva minimo_na_grade(f, a, b, n), que calcula f numa grade de n pontos
igualmente espaçados de a a b e devolve o x da grade em que f é menor.
Use np.linspace e np.argmin.
import numpy as np
def minimo_na_grade(f, a, b, n):
"""O x da grade np.linspace(a, b, n) em que f é menor."""
# TODO: a grade, a posição do menor e o x nessa posição
pass
# --- testes (não altere) ---
def g_ex02(x):
return (x - 2.3)**2
def h_ex02(x):
return x**4 - 3 * x**2 + x
assert abs(minimo_na_grade(g_ex02, 0, 5, 51) - 2.3) < 1e-9
assert abs(minimo_na_grade(h_ex02, -2, 2, 41) - (-1.3)) < 1e-9, "o vale mais fundo, na grade"
print("Exercício 02: todos os testes passaram!")
Exercício 03¶
Escreva otimo_newton(f, x0, n_iter), que faz n_iter passos de Newton para
otimização a partir de x0, com
e \(h = 10^{-4}\).
def otimo_newton(f, x0, n_iter):
"""Ponto de f'(x) = 0 por Newton, com f' e f'' pelas diferenças centrais."""
h = 1e-4
x = x0
# TODO: n_iter passos: d1, d2 e x = x - d1 / d2
return x
# --- testes (não altere) ---
import numpy as np
def lata_ex03(r):
return 2 * np.pi * r**2 + 700 / r
def h_ex03(x):
return x**4 - 3 * x**2 + x
assert abs(otimo_newton(lata_ex03, 3.8, 10) - (350 / (2 * np.pi))**(1 / 3)) < 1e-6
assert abs(otimo_newton(h_ex03, 2.0, 30) - 1.1309011) < 1e-5, "a partir de 2, o vale da direita"
print("Exercício 03: todos os testes passaram!")
Exercício 04¶
Escreva tipo_de_ponto(f, x), que devolve o texto "minimo" se a segunda derivada
central (com \(h = 10^{-4}\)) for positiva em x, e "maximo" caso contrário.
def tipo_de_ponto(f, x):
"""'minimo' se f'' > 0 em x, 'maximo' se f'' < 0."""
h = 1e-4
# TODO: d2 pela central e um if
pass
# --- testes (não altere) ---
def h_ex04(x):
return x**4 - 3 * x**2 + x
assert tipo_de_ponto(h_ex04, -1.3008) == "minimo"
assert tipo_de_ponto(h_ex04, 0.1699) == "maximo"
assert tipo_de_ponto(h_ex04, 1.1309) == "minimo"
print("Exercício 04: todos os testes passaram!")
Exercício 05¶
Economia — o preço certo. Um produto custa R$ 20 para fabricar. Quanto mais
caro, menos se vende: a demanda é \(1000\,e^{-0{,}05p}\) unidades a um preço \(p\). A
função lucro(p) (já escrita) é a margem vezes a demanda.
Escreva preco_otimo(), que acha o preço de maior lucro: uma varredura de R$ 20
a R$ 100 (81 pontos) para o chute e 10 passos de Newton em \(-\text{lucro}\).
Depois de passar: qual o lucro máximo? E o lucro vendendo a R$ 30 ou a R$ 60?
import numpy as np
def lucro(p):
"""Lucro (R$) vendendo a p reais: margem vezes demanda. JÁ ESCRITA."""
demanda = 1000 * np.exp(-0.05 * p)
return (p - 20) * demanda
def preco_otimo():
"""Preço que maximiza o lucro: varredura de 20 a 100 e Newton em -lucro."""
# TODO: defina menos_lucro(p); varredura com np.linspace e np.argmin;
# depois 10 passos de Newton com as diferenças centrais
pass
# --- testes (não altere) ---
assert abs(preco_otimo() - 40) < 1e-6, "o preço ótimo é R$ 40 (custo + 1/0.05)"
print("Exercício 05: todos os testes passaram!")
Exercício 06¶
Arquitetura — a janela que deixa entrar mais luz. Uma janela é um retângulo
com um semicírculo em cima (a "janela normanda"). O caixilho tem perímetro fixo
\(P\). A função area_janela(r, P) (já escrita) dá a área de vidro para um raio \(r\)
do semicírculo.
Escreva raio_janela(P), que acha o raio de maior área por Newton em
\(-\text{área}\) (20 passos, \(h = 10^{-4}\)), a partir de \(r = P/8\).
A resposta exata é \(r = P/(4 + \pi)\). Quanto vale a altura do retângulo nesse caso?
import numpy as np
def area_janela(r, P):
"""Área (m²) de uma janela retângulo + semicírculo de raio r e perímetro P. JÁ ESCRITA."""
altura = (P - 2 * r - np.pi * r) / 2
return 2 * r * altura + np.pi * r**2 / 2
def raio_janela(P):
"""Raio que dá a maior área para o perímetro P."""
# TODO: defina menos_area(r) e faça 20 passos de Newton a partir de r = P / 8
pass
# --- testes (não altere) ---
import numpy as np
assert abs(raio_janela(6) - 6 / (4 + np.pi)) < 1e-6
assert abs(raio_janela(10) - 10 / (4 + np.pi)) < 1e-6
print("Exercício 06: todos os testes passaram!")
Exercício 07¶
Aviação — a velocidade que gasta menos combustível. O arrasto de um avião tem duas partes: o atrito com o ar, que cresce com \(v^2\), e o arrasto "induzido" pela sustentação, que diminui com \(v^2\). O combustível gasto por quilômetro é proporcional a \(D(v) = a\,v^2 + b/v^2\).
Escreva velocidade_economica(a, b), que faz uma varredura de 50 a 400 m/s (de 10
em 10, com um laço e o padrão "extremo", sem numpy) para achar o chute e depois 20
passos de Newton (\(h = 10^{-3}\)).
Confira com a resposta exata, \(v = (b/a)^{1/4}\).
def velocidade_economica(a, b):
"""Velocidade que minimiza o arrasto a*v**2 + b/v**2 (varredura + Newton)."""
def arrasto(v):
return a * v**2 + b / v**2
# TODO: varredura de 50 a 400 de 10 em 10 guardando o melhor v;
# depois 20 passos de Newton a partir dele
pass
# --- testes (não altere) ---
assert abs(velocidade_economica(0.0003, 2e6) - (2e6 / 0.0003)**0.25) < 1e-4
assert abs(velocidade_economica(0.0005, 5e5) - (5e5 / 0.0005)**0.25) < 1e-4
print("Exercício 07: todos os testes passaram!")
Exercício 08¶
Juntando as peças. As funções minimo_na_grade e otimo_newton já estão
escritas. Escreva minimo_global(f, a, b), que usa a primeira (com 201 pontos)
para achar o chute e a segunda (20 passos) para refinar.
Teste em \(x^4 - 3x^2 + x\) no intervalo \([-2, 2]\): a resposta tem de ser o vale mais fundo (\(x \approx -1{,}3008\)), e não o da direita — que é o que Newton sozinho acha a partir de \(x = 2\).
import numpy as np
def minimo_na_grade(f, a, b, n):
"""JÁ ESCRITA."""
xs = np.linspace(a, b, n)
return xs[np.argmin(f(xs))]
def otimo_newton(f, x0, n_iter):
"""JÁ ESCRITA."""
h = 1e-4
x = x0
for it in range(n_iter):
d1 = (f(x + h) - f(x - h)) / (2 * h)
d2 = (f(x + h) - 2 * f(x) + f(x - h)) / h**2
x = x - d1 / d2
return x
def minimo_global(f, a, b):
"""O mínimo de f em [a, b]: varredura de 201 pontos e 20 passos de Newton."""
# TODO: duas linhas, uma chamada de cada função pronta
pass
# --- testes (não altere) ---
def h_ex08(x):
return x**4 - 3 * x**2 + x
def g_ex08(x):
return (x - 0.7)**2 + 1
assert abs(minimo_global(h_ex08, -2, 2) - (-1.3008396)) < 1e-6, "o vale mais fundo"
assert abs(minimo_global(g_ex08, -5, 5) - 0.7) < 1e-6
print("Exercício 08: todos os testes passaram!")