У игрока есть 2 доллара, ему разрешено сыграть в азартную игру 4 раза, и ее цель - максимизировать вероятность того, что она закончит с минимум 6 долларами. Если игрок ставит $ на ход игры, то с вероятностью 0,4 он выигрывает игру, возвращает первоначальную ставку и увеличивает свою позицию капитала на $ ; с вероятностью 0,6 проигрывает сумму ставки $ ; все игры попарно независимы . При любом ходе игры игрок не может ставить больше денег, чем он имел в начале этой игры. [1]
Стохастическое динамическое программирование может использоваться для моделирования этой проблемы и определения стратегии ставок, которая, например, максимизирует вероятность игрока достичь состояния по крайней мере в 6 долларов к концу горизонта ставок.
Обратите внимание: если количество игр, в которые можно играть, не ограничено, проблема становится вариантом известного петербургского парадокса .
Оптимальная стратегия ставок, которая максимизирует вероятность игрока достичь состояния не менее 6 долларов к концу горизонта ставок; представляет собой сумму ставки для игры, когда у игрока есть $ в начале этой игры. Если лицо, принимающее решения, будет следовать этой политике, с вероятностью 0,1984 он достигнет состояния не менее 6 долларов.
Рассмотрим дискретную систему, определенную на этапах, в которой каждый этап характеризуется
начальное состояние , в котором находится множество допустимых состояний в начале стадии ;
переменные решения , где есть множество возможных действий на этапе - отмечает , что может быть функцией от исходного состояния ;
непосредственная функция затрат / вознаграждения , представляющая затраты / вознаграждение на этапе , если это начальное состояние , а действие выбранного;
функция перехода состояния , что приводит систему в сторону государства .
Позвольте представить оптимальную стоимость / вознаграждение, полученное при следовании оптимальной политике на этапах . Без потери общности в дальнейшем мы рассмотрим настройку максимизации вознаграждения. В детерминированном динамическом программировании обычно имеют дело с функциональными уравнениями, имеющими следующую структуру
где и граничное условие системы
Цель состоит в том, чтобы определить набор оптимальных действий, которые максимизируют . Учитывая текущее состояние и текущее действие , мы с уверенностью знаем вознаграждение, полученное на текущем этапе, и - благодаря функции перехода состояний - будущее состояние, к которому система переходит.
На практике, однако, даже если мы знаем состояние системы в начале текущего этапа, а также принятое решение, состояние системы в начале следующего этапа и вознаграждение за текущий период часто являются случайными величинами, которые можно наблюдать только в конце текущего этапа.
Стохастическое динамическое программирование имеет дело с проблемами, в которых вознаграждение за текущий период и / или состояние следующего периода являются случайными, то есть с многоступенчатыми стохастическими системами. Цель лица, принимающего решения, - максимизировать ожидаемое (дисконтированное) вознаграждение в течение заданного горизонта планирования.
В самом общем виде стохастические динамические программы имеют дело с функциональными уравнениями, имеющими следующую структуру
где
- максимальное ожидаемое вознаграждение, которое может быть получено на этапах при заданном состоянии в начале этапа ;
принадлежит к множеству возможных действий на этапе заданного начального состояния ;
Азартная игра как стохастическая динамическая программа [ править ]
Азартную игру можно сформулировать как стохастическую динамическую программу следующим образом: в горизонте планирования есть игры (т.е. этапы ).
состояние в период представляет начальное состояние в начале периода ;
действие данного состояния в период представляет собой сумму ставки ;
вероятность перехода из состояния в состояние , когда действие берется в состоянии легко вывести из вероятности выигрыша (0.4) или проигрыша (0.6) игры.
Пусть будет вероятностью того, что к концу игры 4 у игрока будет не менее 6 долларов, при условии, что у нее есть доллар в начале игры .
сиюминутная прибыль понесены , если действие берется в состоянии задается ожидаемым значением .
Чтобы вывести функциональное уравнение , определите как ставку, которая достигается , а затем в начале игры
если это невозможно достичь цели, то есть для ;
если цель достигнута, то есть для ;
если игрок должен сделать ставку, достаточную для достижения цели, т . е. для .
Для функционального уравнения , где находится в ; цель - найти .
Учитывая функциональное уравнение, оптимальная политика ставок может быть получена с помощью алгоритмов прямой рекурсии или обратной рекурсии, как описано ниже.
Стохастические динамические программы могут быть оптимально решены с помощью алгоритмов обратной или прямой рекурсии . Мемоизация обычно используется для повышения производительности. Однако, как и детерминированное динамическое программирование, его стохастический вариант страдает проклятием размерности . По этой причине в практических приложениях обычно используются приближенные методы решения .
Обратная рекурсия [ править ]
Учитывая ограниченное пространство состояний, обратная рекурсия ( Bertsekas 2000 ) начинается с составления таблицы для каждого возможного состояния, принадлежащего последней стадии . После того как эти значения сведены в таблицу вместе с соответствующими оптимальными действиями , зависящими от состояния , можно перейти к этапу и составить таблицу для всех возможных состояний, принадлежащих этапу . Процесс продолжается, рассматривая в обратном порядке все оставшиеся этапы вплоть до первого. После завершения процесса составления таблиц - значение оптимальной политики с учетом начального состояния, а также соответствующее оптимальное действие.можно легко извлечь из таблицы. Поскольку вычисление происходит в обратном порядке, очевидно, что обратная рекурсия может привести к вычислению большого количества состояний, которые не являются необходимыми для вычисления .
Пример: азартная игра [ править ]
Этот раздел нуждается в расширении . Вы можете помочь, добавив к нему . ( Январь 2017 г. )
Прямая рекурсия [ править ]
Учитывая начальное состояние системы в начале периода 1, прямая рекурсия ( Bertsekas 2000 ) вычисляется путем постепенного расширения функционального уравнения ( прямой проход ). Это включает в себя рекурсивные вызовы всего, что необходимо для вычисления данного . Затем значение оптимальной политики и ее структура извлекаются посредством ( обратного прохода ), в котором эти приостановленные рекурсивные вызовы разрешаются. Ключевым отличием от обратной рекурсии является тот факт, что она вычисляется только для состояний, релевантных для вычисления . Мемоизация используется, чтобы избежать повторного вычисления состояний, которые уже были рассмотрены.
Пример: азартная игра [ править ]
Мы проиллюстрируем прямую рекурсию в контексте ранее обсужденного экземпляра азартной игры. Мы начинаем прямой проход с рассмотрения
На данный момент мы еще не вычислили , что необходимо для вычислений ; мы продолжаем и вычисляем эти элементы. Обратите внимание, что поэтому можно использовать мемоизацию и выполнить необходимые вычисления только один раз.
Расчет
Теперь мы вычислили все, что необходимо для вычислений . Однако это привело к дополнительным приостановленным рекурсиям . Мы продолжаем и вычисляем эти значения.
Расчет
Поскольку этап 4 является последним этапом в нашей системе, представьте граничные условия , которые легко вычислить следующим образом.
Граничные условия
На этом этапе можно продолжить и восстановить оптимальную политику и ее значение с помощью обратного прохода, включающего, вначале, этап 3.
Обратный проход с участием
а затем этап 2.
Обратный проход с участием
Наконец-то мы восстанавливаем ценность оптимальной политики
Это оптимальная политика, которая была проиллюстрирована ранее. Обратите внимание, что существует несколько оптимальных политик, ведущих к одному и тому же оптимальному значению ; например, в первой игре можно поставить либо 1 доллар, либо 2 доллара.
Реализация Python. Ниже приводится полная реализация этого примера на языке Python .
от типизации импорта списка , Кортеж импорт memoize , как мем импорт functoolsпамятка класса :def __init__ ( self , func ): себя . func = func self . memoized = {} self . method_cache = {}def __call__ ( self , * args ): вернуть себя . cache_get ( self . memoized , args , lambda : self . func ( * args ))def __get__ ( self , obj , objtype ): вернуть себя . cache_get ( самостоятельно . method_cache , OBJ , лямбда : самостоятельно . __class__ ( functools . частичная ( самостоятельно . 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 = {}class State : '' 'состояние проблемы разорения игрока ' ''def __init__ ( self , t : int , богатство : float ): '' 'конструктор состояния Аргументы: t {int} - период времени богатство {float} - начальное богатство ' '' self . т , сам . богатство = т , богатствоdef __eq__ ( self , other ): вернуть себя . __dict__ == другое . __dict__def __str__ ( self ): return str ( self . t ) + "" + str ( собственное . богатство )def __hash__ ( self ): вернуть хэш ( str ( self ))класс GamblersRuin :def __init__ ( self , bettingHorizon : int , targetWealth : float , pmf : List [ List [ Tuple [ int , float ]]]): '' 'проблема разорения игрока Аргументы: bettingHorizon {int} - горизонт ставок targetWealth {float} - целевое богатство pmf {List [List [Tuple [int, float]]]} - функция массы вероятности '' '# инициализировать переменные экземпляра self . bettingHorizon , self . targetWealth , сам . pmf = bettingHorizon , targetWealth , pmf# lambdas self . аг = лямбда s : [ я для я в диапазоне ( 0 , мин ( самостоятельно . targetWealth // 2 , ев . Богатство ) + 1 )] # действие генератора самостоятельно . st = лямбда s , a , r : состояние ( s . t + 1 , s . богатство- a + a * r ) # переход состояния self . iv = лямбда s , a , r : 1, если s . богатство - а + а * г > = себя . targetWealth else 0 # функция немедленного значенияя . cache_actions = {} # кеш с оптимальными парами состояние / действиеdef f ( self , богатство : float ) -> float : s = State ( 0 , богатство ) return self . _f ( s )def q ( self , t : int , богатство : float ) -> float : s = State ( t , богатство ) return self . cache_actions [ str ( s )]@memoize def _f ( self , s : State ) -> float : # Прямая рекурсия v = max ( [ sum ([ p [ 1 ] * ( self . _f ( self . st ( s , a , p [ 0 ])) if s . t < self . bettingHorizon - 1 else self. IV ( ев , , р [ 0 ])) # будущее значение для р в себя . pmf [ s . t ]]) # реализация случайной величины для a in self . ag ( s )]) # действияopt_a = lambda a : sum ([ p [ 1 ] * ( self . _f ( self . st ( s , a , p [ 0 ])), если s . t < self . bettingHorizon - 1 else self . iv ( s , a , p [ 0 ])) для p в self .pmf [ s . t ]]) == v q = [ k for k in filter ( opt_a , self . ag ( s ))] # получить список лучших действий self . cache_actions [ str ( s )] = q [ 0 ] if bool ( q ) else None # сохранить действие в словареreturn v # возвращаемое значениеinstance = { "bettingHorizon" : 4 , "targetWealth" : 6 , "pmf" : [[( 0 , 0.6 ), ( 2 , 0.4 )] для i в диапазоне ( 0 , 4 )]} gr , initial_wealth = GamblersRuin ( ** экземпляр ), 2# f_1 (x) - вероятность игрока достичь $ targetWealth в конце ставки Horizon print ( "f_1 (" + str ( initial_wealth ) + "):" + str ( gr . f ( initial_wealth )))# Восстановите оптимальное действие для периода 2, когда начальное богатство в начале периода 2 составляет 1 доллар. t , initial_wealth = 1 , 1 print ( "b_" + str ( t + 1 ) + "(" + str ( initial_wealth ) + "):" + str ( gr . q ( t , initial_wealth )))
Реализация на Java. GamblersRuin.java - это автономная реализация приведенного выше примера на Java 8 .