Introducida originalmente por Richard E. Bellman en ( Bellman 1957 ) , la programación dinámica estocástica es una técnica para modelar y resolver problemas de toma de decisiones en condiciones de incertidumbre . Estrechamente relacionada con la programación estocástica y la programación dinámica , la programación dinámica estocástica representa el problema en cuestión en forma de ecuación de Bellman . [ 1 ] El objetivo es calcular una política que defina cómo actuar de manera óptima ante la incertidumbre.
Un ejemplo motivador: Los juegos de azar
Una jugadora tiene $2, se le permite jugar un juego de azar 4 veces y su objetivo es maximizar su probabilidad de terminar con al menos $6. Si la jugadora apuesta $En una jugada del juego, entonces con una probabilidad de 0.4 gana el juego, recupera la apuesta inicial y aumenta su capital en $; con una probabilidad de 0,6, pierde la cantidad apostada $; todas las jugadas son independientes por pares . En cualquier jugada del juego, el jugador no puede apostar más dinero del que tiene disponible al comienzo de esa jugada. [ 2 ]
La programación dinámica estocástica puede emplearse para modelar este problema y determinar una estrategia de apuestas que, por ejemplo, maximice la probabilidad de que el jugador alcance una riqueza de al menos 6 dólares al final del horizonte de apuestas.
Tenga en cuenta que si no hay límite en el número de partidas que se pueden jugar, el problema se convierte en una variante de la conocida paradoja de San Petersburgo .

Antecedentes formales
Consideremos un sistema discreto definido enetapas en las que cada etapase caracteriza por
- un estado inicial, dóndees el conjunto de estados factibles al comienzo de la etapa;
- una variable de decisión, dóndees el conjunto de acciones factibles en la etapa- tenga en cuenta quepuede ser una función del estado inicial;
- una función de costo/recompensa inmediata, que representa el costo/recompensa en la etapasies el estado inicial yla acción seleccionada;
- una función de transición de estadoque lleva al sistema hacia el estado.
Dejarrepresentan el costo/recompensa óptimo obtenido al seguir una política óptima a lo largo de las etapasSin pérdida de generalidad , a continuación consideraremos un escenario de maximización de recompensas. En la programación dinámica determinista , se suele trabajar con ecuaciones funcionales que adoptan la siguiente estructura.
dóndey la condición de contorno del sistema es
El objetivo es determinar el conjunto de acciones óptimas que maximicenDado el estado actualy la acción actual, conocemos con certeza la recompensa asegurada durante la etapa actual y – gracias a la función de transición de estado– el estado futuro hacia el cual transita el sistema.
En la práctica, sin embargo, incluso si conocemos el estado del sistema al comienzo de la etapa actual, así como la decisión tomada, el estado del sistema al comienzo de la siguiente etapa y la recompensa del período actual suelen ser variables aleatorias que solo se pueden observar al final de la etapa actual.
La programación dinámica estocástica aborda problemas en los que la recompensa del período actual y/o el estado del siguiente período son aleatorios, es decir, sistemas estocásticos multietapa. El objetivo del responsable de la toma de decisiones es maximizar la recompensa esperada (descontada) durante un horizonte de planificación determinado.
En su forma más general, los programas dinámicos estocásticos tratan con ecuaciones funcionales que toman la siguiente estructura.
dónde
- es la recompensa máxima esperada que se puede obtener durante las etapas, dado el estadoal comienzo de la etapa;
- pertenece al conjuntode acciones factibles en la etapadado el estado inicial;
- es el factor de descuento ;
- es la probabilidad condicional de que el estado al final de la etapaesdado el estado actualy acción seleccionada.
Los procesos de decisión de Markov representan una clase especial de programas dinámicos estocásticos en los que el proceso estocástico subyacente tiene transiciones de estado que satisfacen la propiedad de Markov .
El juego de azar como programa dinámico estocástico
El juego de azar puede formularse como un programa dinámico estocástico de la siguiente manera: hayjuegos (es decir, etapas ) en el horizonte de planificación
- el estadoen períodorepresenta la riqueza inicial al comienzo del período;
- la acción dada estadoen períodoes la cantidad de la apuesta;
- la probabilidad de transicióndel estadopara declararcuando la acciónse toma en el estadose deriva fácilmente de la probabilidad de ganar (0,4) o perder (0,6) un juego.
DejarSea la probabilidad de que, al final del juego 4, la jugadora tenga al menos $6, dado que tiene $al comienzo del juego.
- el beneficio inmediato incurrido si se actúase toma en el estadoviene dado por el valor esperado.
Para derivar la ecuación funcional , definacomo una apuesta que alcanza, luego al comienzo del juego
- sies imposible alcanzar la meta, es decirpara;
- siEl objetivo se alcanza, es decirpara;
- siel jugador debe apostar lo suficiente para alcanzar el objetivo, es decirpara.
ParaLa ecuación funcional es, dónderangos en; el objetivo es encontrar.
Dada la ecuación funcional, se puede obtener una política de apuestas óptima mediante algoritmos de recursión hacia adelante o hacia atrás, como se describe a continuación.
Métodos de solución
Los programas dinámicos estocásticos pueden resolverse de forma óptima mediante algoritmos de recursión hacia atrás o hacia adelante . La memorización se utiliza habitualmente para mejorar el rendimiento. Sin embargo, al igual que la programación dinámica determinista, su variante estocástica también sufre la maldición de la dimensionalidad . Por este motivo, en aplicaciones prácticas se suelen emplear métodos de solución aproximada .
Recursión hacia atrás
Dado un espacio de estados acotado, la recursión hacia atrás ( Bertsekas 2000 ) comienza tabulandopara cada estado posibleperteneciente a la etapa finalUna vez tabulados estos valores, junto con las acciones óptimas dependientes del estado asociadas, es posible pasar a la etapay tabularpara todos los estados posibles pertenecientes a la etapa. El proceso continúa considerando de forma regresiva todas las etapas restantes hasta la primera. Una vez que se completa este proceso de tabulación,– el valor de una política óptima dado el estado inicial– así como la acción óptima asociadase puede recuperar fácilmente de la tabla. Dado que el cálculo procede de forma inversa, es evidente que la recursión hacia atrás puede llevar al cálculo de un gran número de estados que no son necesarios para el cálculo de.
Ejemplo: Juego de azar
Recursión hacia adelante
Dado el estado inicialdel sistema al comienzo del período 1, la recursión hacia adelante ( Bertsekas 2000 ) calculamediante la expansión progresiva de la ecuación funcional ( paso hacia adelante ). Esto implica llamadas recursivas para todosque son necesarios para calcular un valor dadoEl valor de una política óptima y su estructura se recuperan a través de un ( paso hacia atrás ) en el que se resuelven estas llamadas recursivas suspendidas. Una diferencia clave con la recursión hacia atrás es el hecho de quese calcula únicamente para los estados que son relevantes para el cálculo deLa memorización se emplea para evitar el recálculo de estados que ya han sido considerados.
Ejemplo: Juego de azar
Ilustraremos la recursión hacia adelante en el contexto del ejemplo del juego de azar que se discutió anteriormente. Comenzamos el paso hacia adelante considerando
En este punto aún no hemos calculado, que son necesarios para calcular; procedemos y calculamos estos elementos. Tenga en cuenta quePor lo tanto, se puede aprovechar la memorización y realizar los cálculos necesarios una sola vez.
- Cálculo de
Ahora hemos calculadoa pesar deque se necesitan para calcularSin embargo, esto ha dado lugar a recursiones suspendidas adicionales que involucran. Procedemos a calcular estos valores.
- Cálculo de
Dado que la etapa 4 es la última etapa de nuestro sistema,representan condiciones de contorno que se calculan fácilmente de la siguiente manera.
- Condiciones de contorno
En este punto es posible proceder y recuperar la política óptima y su valor mediante un paso hacia atrás que involucra, en primer lugar, la etapa 3.
- Paso hacia atrás que implica
y, luego, la etapa 2.
- Paso hacia atrás que implica
Finalmente recuperamos el valorde una política óptima
Esta es la política óptima que se ha ilustrado previamente. Nótese que existen múltiples políticas óptimas que conducen al mismo valor óptimo.; por ejemplo, en el primer juego se puede apostar 1 dólar o 2 dólares.
Implementación en Python. A continuación se muestra una implementación completa en Python de este ejemplo.
importar functoolsclase memoize : def __init __ ( self , func ) : self.func = func self.memoized = { } self.method_cache = { }def __call__ ( self , * args ): return self . cache_get ( self . memoized , args , lambda : self . func ( * args ))def __get__ ( self , obj , objtype ): return self . cache_get ( self . method_cache , obj , lambda : self . __class__ ( functools . partial ( self . func , obj )), )def cache_get ( self , cache , key , func ): try : return cache [ key ] except KeyError : cache [ key ] = func () return cache [ key ]def reset ( self ) : self.memoized = { } self.method_cache = { }Clase Estado : """El estado del problema de la ruina del jugador"""def __init__ ( self , t : int , wealth : float ): """constructor de estado Argumentos: t {int} -- período de tiempo wealth {float} -- riqueza inicial """ self . t , self . wealth = t , wealthdef __eq__ ( self , other ): return self . __dict__ == other . __dict__def __str__ ( self ): return str ( self . t ) + " " + str ( self . wealth )def __hash__ ( self ): return hash ( str ( self ))clase GamblersRuin : def __init__ ( self , bettingHorizon : int , targetWealth : float , pmf : list [ list [ tuple [ int , float ]]], ): """El problema de la ruina del jugador. Argumentos: bettingHorizon {int} -- horizonte de apuestas targetWealth {float} -- riqueza objetivo pmf {list[list[tuple[int, float]]]} -- función de masa de probabilidad """# inicializar variables de instancia self . bettingHorizon , self . targetWealth , self . pmf = ( bettingHorizon , targetWealth , pmf , )# lambdas self.ag = lambda s : [ i for i in range ( 0 , min ( self.targetWealth // 2 , s.wealth ) + 1 ) ] # generador de acciones self.st = lambda s , a , r : State ( s.t + 1 , s.wealth - a + a * r ) # transición de estado self.iv = ( lambda s , a , r : 1 if s.wealth - a + a * r > = self.targetWealth else 0 ) # función de valor inmediatoself.cache_actions = {} # caché con pares óptimos de estado/ accióndef f ( self , wealth : float ) -> float : s = State ( 0 , wealth ) return self . _f ( s )def q ( self , t : int , wealth : float ) -> float : s = State ( t , wealth ) return self . cache_actions [ str ( s )]@memoize def _f ( self , s : Estado ) -> float : # Recursión hacia adelante values = [ sum ([ p [ 1 ] * ( self . _f ( self . st ( s , a , p [ 0 ])) if s . t < self . bettingHorizon - 1 else self . iv ( s , a , p [ 0 ])) # función de valor for p in self . pmf [ s . t ]]) # realizaciones de apuestas for a in self . ag ( s )] # acciones v = max ( valores ) try : self.cache_actions [ str ( s )] = self.ag ( s )[ valores.index ( v ) ] # almacenar la mejor acción except ValueError : self.cache_actions [ str ( s ) ] = None print ( " Error al recuperar la mejor acción " ) return v # devolver el costo total esperadoinstancia = { "horizonte de apuestas" : 4 , "riqueza objetivo" : 6 , "pmf" : [[( 0 , 0.6 ), ( 2 , 0.4 )] para i en rango ( 0 , 4 )], } gr , riqueza_inicial = Ruina de los jugadores ( ** instancia ), 2# f_1(x) es la probabilidad del jugador de alcanzar $targetWealth al final de bettingHorizon print ( "f_1(" + str ( initial_wealth ) + "): " + str ( gr . f ( initial_wealth )))# Recuperar la acción óptima para el período 2 cuando la riqueza inicial al comienzo del período 2 es de $1. t , initial_wealth = 1 , 1 print ( "b_" + str ( t + 1 ) + "(" + str ( initial_wealth ) + "): " + str ( gr . q ( t , initial_wealth )) )Implementación en Java. GamblersRuin.java es una implementación independiente en Java 8 del ejemplo anterior.
Programación dinámica aproximada
Powell ( 2009 ) ofrece una introducción a la programación dinámica aproximada .
Fuentes
- Bellman, R. (1957), Programación dinámica , Princeton University Press, ISBN 978-0-486-42809-3
{{citation}}: Incompatibilidad de ISBN/Fecha ( ayuda ) . Edición de bolsillo de Dover (2003) - Bertsekas, DP (2000), Programación dinámica y control óptimo (2.ª ed.), Athena Scientific, ISBN 978-1-886529-09-0En dos volúmenes.
- Powell, WB (2009), "Lo que debe saber sobre la programación dinámica aproximada", Naval Research Logistics , 56 (1): 239–249 , CiteSeerX 10.1.1.150.1854 , doi : 10.1002/nav.20347 , S2CID 7134937
Lecturas adicionales
- Ross, SM; Bimbaum, ZW; Lukacs, E. (1983), Introducción a la programación dinámica estocástica , Elsevier, ISBN 978-0-12-598420-1.
Véase también
- Teoría de control : rama de la ingeniería y las matemáticas.
- Programación dinámica : método de optimización de problemas
- Aprendizaje por refuerzo : campo del aprendizaje automático
- Control estocástico – Control óptimo probabilístico
- Proceso estocástico : conjunto de variables aleatorias
- Programación estocástica : marco para modelar problemas de optimización que implican incertidumbre.
Referencias
- ↑ Füllner, Christian; Rebennack, Steffen (2025-08-07). "Programación dinámica dual estocástica y sus variantes: una revisión" . SIAM Review . 67 (3): 415– 539. doi : 10.1137/23M1575093 . ISSN 0036-1445 .
- ↑ Este problema está adaptado de WL Winston, Operations Research: Applications and Algorithms (7.ª edición), Duxbury Press, 2003, cap. 19, ejemplo 3.
- Programación dinámica
- Control óptimo
- Algoritmos y métodos de optimización
- Optimización estocástica