[Programación] Cosa python. Parametros por defecto ?
Angel Arancibia
angel.arancibia en gmail.com
Vie Nov 6 17:03:47 ARST 2009
Hola, resulta que teniamos que hacer un tp de IA sobre diferentes
metodos de busqueda, y lo implementamos sobre python.
El algoritmo A*(que se puede usar como greedy, o busqeuda uniforme
dependiedno de las g y h que le pasemos) quedo algo asi: (para grafos
dirigidos)
# Argumentos:
# func_expandir: debe retornar una lista con los hijos del arbol ...
sea como sea qeu se arme
# h: es la funcion que calcula la heuristica de cada nodo al final,
debe retornar un entero
# g: es la funcion que retorna el costo desde el padre al nodo.
# expandir: es el nodo que se va a expandir. Tiene estructura
expandir=(nodo,padre,ValorG)
# end: es el nombre del nodo destino.
# frontera: es una lista de nodos que esperan apra ser expandidos si
corresponde. Tiene estructura frontera=[(nodo,padre,ValorG)]
# Expandidos: es un diccionario que guarda para cada nodo expandido
(la key) cual es el camino con menor costo. Tiene estructura
expandidos={nodoExpandido:[camino]}
# nExpandidos: cuenta cunatos nodos en total se expandieron.
# Estructuras
#expandidos={nodoExpandido:[camino]}
#frontera=[(nodo,padre,ValorG)]
#expandir=(nodo,padre,ValorG)
def A(func_expandir,h,g,start,end):
return expand_A(func_expandir,h,g,(start,'',0),end)#,[],{},0)
def expand_A(func_expandir,h,g,expandir,end,
frontera=[],expandidos={},nExpandidos=0):
padre=expandir[0]
#Agregamos el nodo expandido al diccionario de expandidos
try:
expandidos[padre]=expandidos[expandir[1]]+[padre]
except:
#Solo ocurre en el primer diccionario, que debemos inicializarlo
expandidos[padre]=[padre]
#chequeo del final
if padre==end:
#retornamos el mejor camino
return (expandidos[padre],nExpandidos)
nExpandidos+=1
#
#para todos los hijos ... los agregamos en la frontera
hijos_del_expandido=func_expandir(padre)
for hijo in hijos_del_expandido:
ghijo=g(hijo,padre)
gtotal=ghijo+expandir[2]
frontera.append((hijo,padre,gtotal))
# recalculamos la mejor f de toda la frontera.
# Chequeamos que tengamso frontera ... sino es que no hay camino
if not frontera:
# frontera vacia, no hay camino
return ([],nExpandidos)
# tomamos como minimo el primer elemento
nodoMin=frontera[1]
hhijo=h(nodoMin[0])
fmin= nodoMin[2]+hhijo
#
for nf in frontera:
hhijo=h(nf[0])
fhg=nf[2]+hhijo
if fhg<fmin:
nodoMin=nf
fmin=fhg
# Sacamos el nodo que expandimos en la proxima vuelta de la frontera ....
frontera.remove(nodoMin)
### recalculamos
# Para debug
##print "expando " + nodoMin[0] + " con f=" + str(fmin)
return expand_A(func_expandir,h,g,nodoMin,end,frontera,expandidos,nExpandidos)
Entonces despues armando las funciones h y g correspondientes, se
lograban los distintos metodos con distinta heuristica. No esta
optimizado ni ahi, pero funciona, y para el caso particular del tp
anda aceptablemente bien.
La cuestion es que no funciona correctamente cuando se lo invoca mas de 1 vez.
# Calculamos A*
A_estrella=A(func_expandir_grafo,haches,ges,'Madrid','Oviedo')
print "Mejor Camino segun A*: "
print "\t"+ str(A_estrella[0]) + "\t Nodos totales expandidos: " +
str(A_estrella[1])
#
## ^^^^ anda joya
#
# Calculamos uniforme
uni=A(func_expandir_grafo,haches_uniforme,ges_uniforme,'Madrid','Oviedo')
print "Mejor Camino segun costo Uniforme: "
print "\t"+str(uni[0]) + "\t Nodos totales expandidos: " + str(uni[1])
#
## ^^ hace cualquiera
### llamamos solo a esta, la otra la sacamos
# Calculamos uniforme exactamente igual a lo anterior
uni=A(func_expandir_grafo,haches_uniforme,ges_uniforme,'Madrid','Oviedo')
print "Mejor Camino segun costo Uniforme: "
print "\t"+str(uni[0]) + "\t Nodos totales expandidos: " + str(uni[1])
#
### ^^^ anda joya
Por lo que vimos, queda algo de mugre o cosa asi en los parametros por
defecto que toma la funcion cuando comienza. Seteando esos valores a
los vacios correspondientes se soluciona. De todas maneras, quizas
alguien me podria ayudar a ver que es lo que pasaba, o como es que la
secuencia de invocaciones distintas a una misma funcion me de valores
distintos, cuando, supuestamente (estoy bien lejos de ser un experto
en python), no hay comparticion de ningun tipo entre las distintas
llamadas.
Bueno eso es todo,
Muchas gracias,
Angel
Más información sobre la lista de distribución Programacion