domingo, 3 de janeiro de 2010

É o máximo!

Acontece com frequência termos que calcular o máximo (ou o mínimo) de uma função f. Isto é, queremos saber qual o valor de x para o qual f(x) assume o valor máximo (ou o mínimo).

O princípio de solução para esta questão não é difícil: calculamos o valor de da função em todos os pontos, identificamos o valor mais elevado (ou mais baixo, no caso do mínimo) e com isso sabemos o valor de x. Trata-se de uma actividade que aponta claramente para o uso de um ciclo for.

A questão mais delicada reside no facto de os cálculos serem feitos com o valor de f(x), mas o que pretendemos identificar é o argumento x. Por isso vamos precisar de manter memorizado o valor melhor para a função e o correspondente valor do argumento. Quanto ao mais podemos assumir que os valores do domínio podem estar ou não ordenados.

Vejamos a implementação e o teste para o caso da função seno.

from math import sin,radians

def arg_max(dom,func):
"""Calcula o máximo da função no domínio dado."""
x_max = dom[0]
f_max = func(x_max)

for x in dom:
x_val = func(x)
if x_val > f_max:
x_max,f_max = x,x_val
return x_max


if __name__ == '__main__':
valores = [radians(g) for g in range(0,360,45)]
print arg_max(valores,sin)

Como se pode verificar usamos o facto de podermos passar como argumento uma função!

E se quisermos calcular o mínimo? Bem, o mínimo é o simétrico do máximo, certo? Então:

def arg_min(dom,func):
"""Calcula o mínimo da função."""
return arg_max(dom, lambda x: -func(x))


Mas porque é que não podemos fazer simplesmente:

def arg_min(dom,func):
"""Calcula o mínimo da função."""
return arg_max(dom, -func)

A resposta: assim não estaríamos a passar a referência para uma função mas a tentar fazer uma operação (unária neste caso) com um nome que não o permite. As funções lambda são também chamadas funções anónimas. Apenas existem durante o seu uso. Têm uma sintaxe simples:

lambda parâmetros : expressão

Os parâmetros podem existir ou não. Na expressão não podemos ter ciclos, nem return.Exemplos:

>>> func = lambda n : n + 3
>>> func(5)
8
>>> area_tri = lambda b,a: 0.5 * b * a
>>> area_tri(4,3)
6.0
>>> primo = lambda x: x[0]
>>> resto = lambda x: x[1:]
>>> lista = [1,2,3,4,5]
>>> primo(lista)
1
>>> resto(lista)
[2, 3, 4, 5]
>>> junta = lambda e,l: [e] + l
>>> junta(6,lista)
[6, 1, 2, 3, 4, 5]
>>> junta(primo(lista),resto(lista))
[1, 2, 3, 4, 5]
>>>

Sem comentários:

Enviar um comentário