packages feed

concraft-0.6.0: tools/concraft-analyse-model.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards #-}

import           Control.Applicative ((<$>))
import           Control.Arrow (second)
import           Control.Monad (void)
import           System.Console.CmdArgs
import           Data.List (foldl')
import qualified Data.Map as M
import qualified Data.Number.LogFloat as L

import           Data.Colour.Names
import           Data.Colour
import           Data.Accessor
import           Graphics.Rendering.Chart

import qualified Data.CRF.Chain2.Tiers.Model as CRF
import qualified Data.CRF.Chain2.Tiers.Feature as CRF
import qualified Data.CRF.Chain2.Tiers as CRF

import qualified NLP.Concraft as C
import qualified NLP.Concraft.Disamb as D


---------------------------------------
-- Histogram
---------------------------------------


-- | Round double value.
roundTo :: Int -> Double -> Double
roundTo n x = (fromInteger $ round $ x * (10^n)) / (10.0^^n)


-- | Make a histogram with a given precision.
hist :: Ord a => [a] -> M.Map a Int
hist =
    let update m x = M.insertWith' (+) x 1 m
    in  foldl' update M.empty


---------------------------------------
-- Rendering
---------------------------------------


drawModel :: Int -> CRF.Model -> FilePath -> IO ()
drawModel rnParam model filePath = do

    void $ renderableToPNGFile (toRenderable layout) 640 480 filePath

  where

    -- Feature map with values in log domain
    featMap = L.logFromLogFloat <$> CRF.toMap model

    -- Values assigned to observation features
    obVals = [x | (ft, x) <- M.assocs featMap, isOFeat ft]

    -- Values assigned to transition features
    trVals = [x | (ft, x) <- M.assocs featMap, not (isOFeat ft)]

    -- Is it an observation feature?
    isOFeat (CRF.OFeat _ _ _) = True
    isOFeat _                 = False

    -- Make log-domain histogram
    mkHist = map (second intLog) . M.toList . hist . map (roundTo rnParam)

    obChart =
          plot_lines_style .> line_color ^= opaque blue
        $ plot_lines_values ^= [mkHist obVals]
        $ plot_lines_title ^= "Observation features"
        $ defaultPlotLines

    trChart =
          plot_lines_style .> line_color ^= opaque green
        $ plot_lines_values ^= [mkHist trVals]
        $ plot_lines_title ^= "Transition features"
        $ defaultPlotLines

    layout =
          layout1_left_axis ^: laxis_override ^= axisGridHide
        $ layout1_right_axis ^: laxis_override ^= axisGridHide
        $ layout1_bottom_axis ^: laxis_override ^= axisGridHide
        $ layout1_plots ^= [Left (toPlot obChart), Right (toPlot trChart)]
        $ layout1_grid_last ^= False
        $ defaultLayout1


-- | Int logarithm.
intLog :: Int -> Double
intLog = (log :: Double -> Double) . fromIntegral


---------------------------------------
-- Command line options
---------------------------------------


data AnaModel = AnaModel
    { inModel   :: FilePath
    , outFile   :: FilePath
    , rnParam   :: Int }
    deriving (Data, Typeable, Show)


anaModel :: AnaModel
anaModel = AnaModel
    { inModel = def &= argPos 0 &= typ "MODEL-FILE"
    , outFile = def &= argPos 1 &= typ "OUTPUT-FILE"
    , rnParam = 1 &= help "Rounding parameter" }


---------------------------------------
-- Main
---------------------------------------


main :: IO ()
main = exec =<< cmdArgs anaModel


exec :: AnaModel -> IO ()
exec AnaModel{..} = do
    model <- CRF.model . D.crf . C.disamb <$> C.loadModel inModel
    drawModel rnParam model outFile