packages feed

monad-bayes-0.1.1.0: models/LDA.hs

-- LDA model from Anglican
-- (https://bitbucket.org/probprog/anglican-white-paper)

module LDA where

import qualified Control.Monad as List (replicateM)
import Control.Monad.Bayes.Class
import qualified Data.Map as Map
import Data.Vector as V hiding (length, mapM, mapM_, zip)
import Numeric.Log

vocabulary :: [String]
vocabulary = ["bear", "wolf", "python", "prolog"]

topics :: [String]
topics = ["topic1", "topic2"]

documents :: [[String]]
documents =
  [ words "bear wolf bear wolf bear wolf python wolf bear wolf",
    words "python prolog python prolog python prolog python prolog python prolog",
    words "bear wolf bear wolf bear wolf bear wolf bear wolf",
    words "python prolog python prolog python prolog python prolog python prolog",
    words "bear wolf bear python bear wolf bear wolf bear wolf"
  ]

wordDistPrior :: MonadSample m => m (Vector Double)
wordDistPrior = dirichlet $ V.replicate (length vocabulary) 1

topicDistPrior :: MonadSample m => m (Vector Double)
topicDistPrior = dirichlet $ V.replicate (length topics) 1

wordIndex :: Map.Map String Int
wordIndex = Map.fromList $ zip vocabulary [0 ..]

lda :: MonadInfer m => [[String]] -> m [Int]
lda docs = do
  word_dist_for_topic <- do
    ts <- mapM (const wordDistPrior) [0 .. length topics]
    return $ Map.fromList $ zip [0 .. length topics] ts
  let obs doc = do
        topic_dist <- fmap categorical topicDistPrior
        let f word = do
              topic <- topic_dist
              factor $ (Exp . log) $ (word_dist_for_topic Map.! topic) V.! (wordIndex Map.! word)
        mapM_ f doc
  mapM_ obs docs
  -- return samples since Discrete is not NFData
  mapM (categorical . snd) $ Map.toList word_dist_for_topic

syntheticData :: MonadSample m => Int -> Int -> m [[String]]
syntheticData d w = List.replicateM d (List.replicateM w syntheticWord)
  where
    syntheticWord = uniformD vocabulary