packages feed

rl-satton-0.1.2.4: examples/Examples/Ch4_Gambler.hs

{-|
 - This module relies on older version of library and thus couldn't be
 - compailed.
 -
 - FIXME: update the Gambler module
 --}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}

module Examples.Ch4_Gambler where

import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import qualified Data.List as List
import Data.Map.Strict (Map, (!))
import qualified Data.Map.Strict as Map
import Data.Set (Set)
import qualified Data.Set as Set
import Data.Ratio
import Text.Printf
import Debug.Trace

import Types as RL
import DP as RL

data Bet = Bet {
    bet_amount :: Int
  }
  deriving(Show, Eq, Ord)

data Game num = Game {
    game_win_score :: Int
  }
  deriving(Show)

data Gambler = Gambler {
    g_pocket :: Int
  }
  deriving(Show, Eq, Ord)


instance (Fractional num, Ord num) => DP_Problem num Game Gambler Bet where

  rl_states Game{..} =
    Set.fromList [Gambler pocket | pocket <- [0..game_win_score]]

  rl_actions Game{..} Gambler{..} =
    if g_pocket >= game_win_score || g_pocket <= 0 then
      Set.empty
    else
      let
        border = g_pocket `min` (game_win_score - g_pocket)
      in
      Set.fromList [Bet x | x <- [1..border]]

  rl_transitions Game{..} Gambler{..} Bet{..} =
      Set.fromList [
          (Gambler (g_pocket - bet_amount), 6%10)
        , (Gambler (g_pocket + bet_amount), 4%10)]

  rl_reward Game{..} _ _ Gambler{..} =
      if g_pocket >= game_win_score then
        1
      else
        0

  rl_terminal_states Game{..} = Set.fromList [ Gambler 0, Gambler game_win_score ]

thegame :: Game Rational
thegame = Game 100


example_4_3 :: forall num . (Fractional num, Ord num, Real num) => Game num -> IO ()
example_4_3 thegame =
  let
    showValPolicy :: (StateVal num Gambler, GenericPolicy Gambler Bet) -> String
    showValPolicy (v@StateVal{..}, GenericPolicy{..}) =
      unlines $
      flip map (Map.toAscList v_map `zip` Map.toAscList _p_map) $ \((_, vs) , (s@Gambler{..}, set)) ->
        let
          actmap = List.sortOn (\(p,a)-> a) $ Set.toList set

          show_actmap =
            let
              d :: Bet -> Double
              d a = fromRational $ toRational $ stateval v s a
            in
            List.intercalate "," $
            flip map actmap $ \(a@Bet{..},p) -> show bet_amount ++ " (" ++ (printf "%2.5f" (d a)) ++ ")"

          (Bet{..}, mx)
            | null actmap = (Bet 0, 0)
            | otherwise = head $ actmap
          show_vs = printf "% 2.5f" (fromRational $ toRational vs :: Double)
        in
        (printf ("%02d: ") g_pocket) ++ (replicate bet_amount '#') ++ show bet_amount ++ " " ++ show_vs ++ "  " ++ show_actmap

    debugState :: (StateVal num Gambler, GenericPolicy Gambler Bet) -> IO ()
    debugState = putStrLn . showValPolicy

    opts :: EvalOpts num s a
    opts = defaultOpts {
        eo_max_iter = 1
      , eo_gamma = 1.0
      , eo_etha = 0.00001
      -- , eo_debug = const $ return ()
    }

    stateval :: (DP_Problem num Game s a) => StateVal num s -> s-> a -> num
    stateval v s a = policy_action_value thegame s a opts v

  in do
  (v,p) <- policy_iteraton thegame (uniformGenericPolicy thegame) (zero_sate_values thegame) opts
  debugState (v,p)