packages feed

concraft 0.9.4 → 0.11.0

raw patch · 21 files changed

+3168/−69 lines, 21 filesdep +data-memocombinatorsdep +paralleldep +pedestrian-dagdep ~aesondep ~binarydep ~comonadPVP ok

version bump matches the API change (PVP)

Dependencies added: data-memocombinators, parallel, pedestrian-dag

Dependency ranges changed: aeson, binary, comonad, crf-chain1-constrained, crf-chain2-tiers, data-lens, sgd, temporary, text-binary, transformers, vector, zlib

API changes (from Hackage documentation)

- NLP.Concraft: disamb :: Concraft -> Disamb
- NLP.Concraft: guessNum :: Concraft -> Int
- NLP.Concraft: guesser :: Concraft -> Guesser Tag
- NLP.Concraft: instance Binary Concraft
- NLP.Concraft: tagset :: Concraft -> Tagset
- NLP.Concraft.Disamb: atts :: Atom -> Map Attr Text
- NLP.Concraft.Disamb: crf :: Disamb -> CRF Ob Atom
- NLP.Concraft.Disamb: initDmb :: TrainConf -> Disamb
- NLP.Concraft.Disamb: instance Binary Disamb
- NLP.Concraft.Disamb: onDiskT :: TrainConf -> Bool
- NLP.Concraft.Disamb: pos :: Atom -> Maybe POS
- NLP.Concraft.Disamb: schemaConf :: Disamb -> SchemaConf
- NLP.Concraft.Disamb: schemaConfT :: TrainConf -> SchemaConf
- NLP.Concraft.Disamb: sgdArgsT :: TrainConf -> SgdArgs
- NLP.Concraft.Disamb: tiers :: Disamb -> [Tier]
- NLP.Concraft.Disamb: tiersT :: TrainConf -> [Tier]
- NLP.Concraft.Disamb: withAtts :: Tier -> Set Attr
- NLP.Concraft.Disamb: withPos :: Tier -> Bool
- NLP.Concraft.Guess: crf :: Guesser t -> CRF Ob t
- NLP.Concraft.Guess: instance (Ord t, Binary t) => Binary (Guesser t)
- NLP.Concraft.Guess: instance Data R0T
- NLP.Concraft.Guess: instance Enum R0T
- NLP.Concraft.Guess: instance Eq R0T
- NLP.Concraft.Guess: instance Ord R0T
- NLP.Concraft.Guess: instance Show R0T
- NLP.Concraft.Guess: instance Typeable R0T
- NLP.Concraft.Guess: onDiskT :: TrainConf -> Bool
- NLP.Concraft.Guess: r0T :: TrainConf -> R0T
- NLP.Concraft.Guess: schemaConf :: Guesser t -> SchemaConf
- NLP.Concraft.Guess: schemaConfT :: TrainConf -> SchemaConf
- NLP.Concraft.Guess: sgdArgsT :: TrainConf -> SgdArgs
- NLP.Concraft.Morphosyntax: data WMap a
- NLP.Concraft.Morphosyntax: instance (Show w, Show t) => Show (Seg w t)
- NLP.Concraft.Morphosyntax: instance (Show w, Show t) => Show (SentO w t)
- NLP.Concraft.Morphosyntax: instance Binary a => Binary (WMap a)
- NLP.Concraft.Morphosyntax: instance Eq a => Eq (WMap a)
- NLP.Concraft.Morphosyntax: instance FromJSON w => FromJSON (Seg w Text)
- NLP.Concraft.Morphosyntax: instance Ord a => Ord (WMap a)
- NLP.Concraft.Morphosyntax: instance Show a => Show (WMap a)
- NLP.Concraft.Morphosyntax: instance ToJSON w => ToJSON (Seg w Text)
- NLP.Concraft.Morphosyntax: instance Word w => Word (Seg w t)
- NLP.Concraft.Morphosyntax: mapWMap :: Ord b => (a -> b) -> WMap a -> WMap b
- NLP.Concraft.Morphosyntax: mkWMap :: Ord a => [(a, Double)] -> WMap a
- NLP.Concraft.Morphosyntax: orig :: SentO w t -> Text
- NLP.Concraft.Morphosyntax: segs :: SentO w t -> Sent w t
- NLP.Concraft.Morphosyntax: tags :: Seg w t -> WMap t
- NLP.Concraft.Morphosyntax: word :: Seg w t -> w
- NLP.Concraft.Morphosyntax.Accuracy: gold :: Stats -> Int
- NLP.Concraft.Morphosyntax.Accuracy: good :: Stats -> Int
- NLP.Concraft.Schema: args :: Body a -> a
- NLP.Concraft.Schema: begPackedC :: SchemaConf -> Entry ()
- NLP.Concraft.Schema: instance Binary SchemaConf
- NLP.Concraft.Schema: instance Binary a => Binary (Body a)
- NLP.Concraft.Schema: instance Show SchemaConf
- NLP.Concraft.Schema: instance Show a => Show (Body a)
- NLP.Concraft.Schema: knownC :: SchemaConf -> Entry ()
- NLP.Concraft.Schema: lowOrthC :: SchemaConf -> Entry ()
- NLP.Concraft.Schema: lowPrefixesC :: SchemaConf -> Entry [Int]
- NLP.Concraft.Schema: lowSuffixesC :: SchemaConf -> Entry [Int]
- NLP.Concraft.Schema: oovOnly :: Body a -> Bool
- NLP.Concraft.Schema: orthC :: SchemaConf -> Entry ()
- NLP.Concraft.Schema: packedC :: SchemaConf -> Entry ()
- NLP.Concraft.Schema: range :: Body a -> [Int]
- NLP.Concraft.Schema: shapeC :: SchemaConf -> Entry ()
+ NLP.Concraft: [disamb] :: Concraft -> Disamb
+ NLP.Concraft: [guessNum] :: Concraft -> Int
+ NLP.Concraft: [guesser] :: Concraft -> Guesser Tag
+ NLP.Concraft: [tagset] :: Concraft -> Tagset
+ NLP.Concraft: instance Data.Binary.Class.Binary NLP.Concraft.Concraft
+ NLP.Concraft.DAG.Disamb: Atom :: Maybe POS -> Map Attr Text -> Maybe Bool -> Atom
+ NLP.Concraft.DAG.Disamb: Disamb :: [Tier] -> SchemaConf -> CRF Ob Atom -> t -> Tag -> Disamb t
+ NLP.Concraft.DAG.Disamb: Marginals :: ProbType
+ NLP.Concraft.DAG.Disamb: MaxProbs :: ProbType
+ NLP.Concraft.DAG.Disamb: Tier :: Bool -> Bool -> Set Attr -> Tier
+ NLP.Concraft.DAG.Disamb: TrainConf :: [Tier] -> SchemaConf -> SgdArgs -> Bool -> t -> Tag -> TrainConf t
+ NLP.Concraft.DAG.Disamb: [atts] :: Atom -> Map Attr Text
+ NLP.Concraft.DAG.Disamb: [crf] :: Disamb t -> CRF Ob Atom
+ NLP.Concraft.DAG.Disamb: [eos] :: Atom -> Maybe Bool
+ NLP.Concraft.DAG.Disamb: [onDiskT] :: TrainConf t -> Bool
+ NLP.Concraft.DAG.Disamb: [pos] :: Atom -> Maybe POS
+ NLP.Concraft.DAG.Disamb: [schemaConfT] :: TrainConf t -> SchemaConf
+ NLP.Concraft.DAG.Disamb: [schemaConf] :: Disamb t -> SchemaConf
+ NLP.Concraft.DAG.Disamb: [sgdArgsT] :: TrainConf t -> SgdArgs
+ NLP.Concraft.DAG.Disamb: [simplifyLabel] :: TrainConf t -> t -> Tag
+ NLP.Concraft.DAG.Disamb: [simplify] :: Disamb t -> t -> Tag
+ NLP.Concraft.DAG.Disamb: [tiersT] :: TrainConf t -> [Tier]
+ NLP.Concraft.DAG.Disamb: [tiers] :: Disamb t -> [Tier]
+ NLP.Concraft.DAG.Disamb: [withAtts] :: Tier -> Set Attr
+ NLP.Concraft.DAG.Disamb: [withEos] :: Tier -> Bool
+ NLP.Concraft.DAG.Disamb: [withPos] :: Tier -> Bool
+ NLP.Concraft.DAG.Disamb: data Atom
+ NLP.Concraft.DAG.Disamb: data Disamb t
+ NLP.Concraft.DAG.Disamb: data ProbType
+ NLP.Concraft.DAG.Disamb: data Tier
+ NLP.Concraft.DAG.Disamb: data TrainConf t
+ NLP.Concraft.DAG.Disamb: getDisamb :: (t -> Tag) -> Get (Disamb t)
+ NLP.Concraft.DAG.Disamb: probs :: (Word w, Ord t) => ProbType -> Disamb t -> Sent w t -> DAG () (WMap t)
+ NLP.Concraft.DAG.Disamb: probsSent :: (Word w, Ord t) => ProbType -> Disamb t -> Sent w t -> Sent w t
+ NLP.Concraft.DAG.Disamb: prune :: Double -> Disamb t -> Disamb t
+ NLP.Concraft.DAG.Disamb: putDisamb :: Disamb t -> Put
+ NLP.Concraft.DAG.Disamb: schematize :: Schema w [t] a -> Sent w [t] -> Sent Ob t
+ NLP.Concraft.DAG.Disamb: train :: (Word w, Ord t) => TrainConf t -> IO [Sent w t] -> IO [Sent w t] -> IO (Disamb t)
+ NLP.Concraft.DAG.DisambSeg: Atom :: Maybe POS -> Map Attr Text -> Maybe Bool -> Atom
+ NLP.Concraft.DAG.DisambSeg: Disamb :: [Tier] -> SchemaConf -> CRF Ob Atom -> t -> Tag -> Disamb t
+ NLP.Concraft.DAG.DisambSeg: Marginals :: ProbType
+ NLP.Concraft.DAG.DisambSeg: MaxProbs :: ProbType
+ NLP.Concraft.DAG.DisambSeg: Tag :: Tag -> Bool -> Tag
+ NLP.Concraft.DAG.DisambSeg: Tier :: Bool -> Bool -> Set Attr -> Tier
+ NLP.Concraft.DAG.DisambSeg: TrainConf :: [Tier] -> SchemaConf -> SgdArgs -> Bool -> t -> Tag -> TrainConf t
+ NLP.Concraft.DAG.DisambSeg: [atts] :: Atom -> Map Attr Text
+ NLP.Concraft.DAG.DisambSeg: [crf] :: Disamb t -> CRF Ob Atom
+ NLP.Concraft.DAG.DisambSeg: [eos] :: Atom -> Maybe Bool
+ NLP.Concraft.DAG.DisambSeg: [hasEos] :: Tag -> Bool
+ NLP.Concraft.DAG.DisambSeg: [onDiskT] :: TrainConf t -> Bool
+ NLP.Concraft.DAG.DisambSeg: [pos] :: Atom -> Maybe POS
+ NLP.Concraft.DAG.DisambSeg: [posiTag] :: Tag -> Tag
+ NLP.Concraft.DAG.DisambSeg: [schemaConfT] :: TrainConf t -> SchemaConf
+ NLP.Concraft.DAG.DisambSeg: [schemaConf] :: Disamb t -> SchemaConf
+ NLP.Concraft.DAG.DisambSeg: [sgdArgsT] :: TrainConf t -> SgdArgs
+ NLP.Concraft.DAG.DisambSeg: [simplifyLabel] :: TrainConf t -> t -> Tag
+ NLP.Concraft.DAG.DisambSeg: [simplify] :: Disamb t -> t -> Tag
+ NLP.Concraft.DAG.DisambSeg: [tiersT] :: TrainConf t -> [Tier]
+ NLP.Concraft.DAG.DisambSeg: [tiers] :: Disamb t -> [Tier]
+ NLP.Concraft.DAG.DisambSeg: [withAtts] :: Tier -> Set Attr
+ NLP.Concraft.DAG.DisambSeg: [withEos] :: Tier -> Bool
+ NLP.Concraft.DAG.DisambSeg: [withPos] :: Tier -> Bool
+ NLP.Concraft.DAG.DisambSeg: data Atom
+ NLP.Concraft.DAG.DisambSeg: data Disamb t
+ NLP.Concraft.DAG.DisambSeg: data ProbType
+ NLP.Concraft.DAG.DisambSeg: data Tag
+ NLP.Concraft.DAG.DisambSeg: data Tier
+ NLP.Concraft.DAG.DisambSeg: data TrainConf t
+ NLP.Concraft.DAG.DisambSeg: getDisamb :: (t -> Tag) -> Get (Disamb t)
+ NLP.Concraft.DAG.DisambSeg: instance GHC.Classes.Eq NLP.Concraft.DAG.DisambSeg.Tag
+ NLP.Concraft.DAG.DisambSeg: instance GHC.Classes.Ord NLP.Concraft.DAG.DisambSeg.Tag
+ NLP.Concraft.DAG.DisambSeg: instance GHC.Show.Show NLP.Concraft.DAG.DisambSeg.Tag
+ NLP.Concraft.DAG.DisambSeg: probs :: (Word w, Ord t) => ProbType -> Disamb t -> Sent w t -> DAG () (WMap t)
+ NLP.Concraft.DAG.DisambSeg: probsSent :: (Word w, Ord t) => ProbType -> Disamb t -> Sent w t -> Sent w t
+ NLP.Concraft.DAG.DisambSeg: prune :: Double -> Disamb t -> Disamb t
+ NLP.Concraft.DAG.DisambSeg: putDisamb :: Disamb t -> Put
+ NLP.Concraft.DAG.DisambSeg: train :: (Word w, Ord t) => TrainConf t -> IO [Sent w t] -> IO [Sent w t] -> IO (Disamb t)
+ NLP.Concraft.DAG.Guess: AnyChosen :: R0T
+ NLP.Concraft.DAG.Guess: AnyInterps :: R0T
+ NLP.Concraft.DAG.Guess: Guesser :: SchemaConf -> CRF Ob s -> s -> Set t -> t -> s -> Guesser t s
+ NLP.Concraft.DAG.Guess: OovChosen :: R0T
+ NLP.Concraft.DAG.Guess: TrainConf :: SchemaConf -> SgdArgs -> Bool -> R0T -> t -> t -> s -> t -> t -> Bool -> TrainConf t s
+ NLP.Concraft.DAG.Guess: [crf] :: Guesser t s -> CRF Ob s
+ NLP.Concraft.DAG.Guess: [onDiskT] :: TrainConf t s -> Bool
+ NLP.Concraft.DAG.Guess: [onlyVisible] :: TrainConf t s -> Bool
+ NLP.Concraft.DAG.Guess: [r0T] :: TrainConf t s -> R0T
+ NLP.Concraft.DAG.Guess: [schemaConfT] :: TrainConf t s -> SchemaConf
+ NLP.Concraft.DAG.Guess: [schemaConf] :: Guesser t s -> SchemaConf
+ NLP.Concraft.DAG.Guess: [sgdArgsT] :: TrainConf t s -> SgdArgs
+ NLP.Concraft.DAG.Guess: [simplifyLabel] :: TrainConf t s -> t -> s
+ NLP.Concraft.DAG.Guess: [simplify] :: Guesser t s -> t -> s
+ NLP.Concraft.DAG.Guess: [stripLabel] :: TrainConf t s -> t -> t
+ NLP.Concraft.DAG.Guess: [unkTagSet] :: Guesser t s -> Set t
+ NLP.Concraft.DAG.Guess: [zeroProbLab] :: Guesser t s -> s
+ NLP.Concraft.DAG.Guess: [zeroProbLabel] :: TrainConf t s -> t
+ NLP.Concraft.DAG.Guess: data Guesser t s
+ NLP.Concraft.DAG.Guess: data R0T
+ NLP.Concraft.DAG.Guess: data TrainConf t s
+ NLP.Concraft.DAG.Guess: getGuesser :: (Binary t, Binary s, Ord s) => (t -> s) -> Get (Guesser t s)
+ NLP.Concraft.DAG.Guess: instance Data.Data.Data NLP.Concraft.DAG.Guess.R0T
+ NLP.Concraft.DAG.Guess: instance GHC.Classes.Eq NLP.Concraft.DAG.Guess.R0T
+ NLP.Concraft.DAG.Guess: instance GHC.Classes.Ord NLP.Concraft.DAG.Guess.R0T
+ NLP.Concraft.DAG.Guess: instance GHC.Enum.Enum NLP.Concraft.DAG.Guess.R0T
+ NLP.Concraft.DAG.Guess: instance GHC.Show.Show NLP.Concraft.DAG.Guess.R0T
+ NLP.Concraft.DAG.Guess: marginals :: (Word w, Ord t, Ord s) => Guesser t s -> Sent w t -> DAG () (WMap t)
+ NLP.Concraft.DAG.Guess: marginalsSent :: (Word w, Ord t, Ord s) => Guesser t s -> Sent w t -> Sent w t
+ NLP.Concraft.DAG.Guess: putGuesser :: (Binary t, Binary s, Ord s) => Guesser t s -> Put
+ NLP.Concraft.DAG.Guess: schemed :: (Word w, Ord t, Ord s) => (t -> s) -> Schema w s a -> [Sent w t] -> [SentL Ob s]
+ NLP.Concraft.DAG.Guess: train :: (Word w, Ord t, Ord s) => TrainConf t s -> IO [Sent w t] -> IO [Sent w t] -> IO (Guesser t s)
+ NLP.Concraft.DAG.Morphosyntax: Seg :: w -> WMap t -> Seg w t
+ NLP.Concraft.DAG.Morphosyntax: SentO :: Sent w t -> Text -> SentO w t
+ NLP.Concraft.DAG.Morphosyntax: [orig] :: SentO w t -> Text
+ NLP.Concraft.DAG.Morphosyntax: [segs] :: SentO w t -> Sent w t
+ NLP.Concraft.DAG.Morphosyntax: [tags] :: Seg w t -> WMap t
+ NLP.Concraft.DAG.Morphosyntax: [word] :: Seg w t -> w
+ NLP.Concraft.DAG.Morphosyntax: class Word a
+ NLP.Concraft.DAG.Morphosyntax: data Seg w t
+ NLP.Concraft.DAG.Morphosyntax: data SentO w t
+ NLP.Concraft.DAG.Morphosyntax: instance (GHC.Show.Show w, GHC.Show.Show t) => GHC.Show.Show (NLP.Concraft.DAG.Morphosyntax.Seg w t)
+ NLP.Concraft.DAG.Morphosyntax: instance Data.Aeson.Types.FromJSON.FromJSON w => Data.Aeson.Types.FromJSON.FromJSON (NLP.Concraft.DAG.Morphosyntax.Seg w Data.Text.Internal.Text)
+ NLP.Concraft.DAG.Morphosyntax: instance Data.Aeson.Types.ToJSON.ToJSON w => Data.Aeson.Types.ToJSON.ToJSON (NLP.Concraft.DAG.Morphosyntax.Seg w Data.Text.Internal.Text)
+ NLP.Concraft.DAG.Morphosyntax: instance NLP.Concraft.DAG.Morphosyntax.Word w => NLP.Concraft.DAG.Morphosyntax.Word (NLP.Concraft.DAG.Morphosyntax.Seg w t)
+ NLP.Concraft.DAG.Morphosyntax: interps :: Seg w t -> [t]
+ NLP.Concraft.DAG.Morphosyntax: interpsSet :: Seg w t -> Set t
+ NLP.Concraft.DAG.Morphosyntax: mapSeg :: Ord b => (a -> b) -> Seg w a -> Seg w b
+ NLP.Concraft.DAG.Morphosyntax: mapSent :: Ord b => (a -> b) -> Sent w a -> Sent w b
+ NLP.Concraft.DAG.Morphosyntax: mapSentO :: Ord b => (a -> b) -> SentO w a -> SentO w b
+ NLP.Concraft.DAG.Morphosyntax: oov :: Word a => a -> Bool
+ NLP.Concraft.DAG.Morphosyntax: orth :: Word a => a -> Text
+ NLP.Concraft.DAG.Morphosyntax: type Sent w t = DAG () (Seg w t)
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: AccCfg :: Bool -> Bool -> Set x -> Tagset -> Bool -> Bool -> Bool -> Bool -> Bool -> AccCfg x
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: Stats :: !Int -> !Int -> !Int -> !Int -> !Int -> Stats
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [accTagset] :: AccCfg x -> Tagset
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [ce] :: Stats -> !Int
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [discardProb0] :: AccCfg x -> Bool
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [expandTag] :: AccCfg x -> Bool
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [fn] :: Stats -> !Int
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [fp] :: Stats -> !Int
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [ignoreTag] :: AccCfg x -> Bool
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [onlyAmb] :: AccCfg x -> Bool
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [onlyMarkedWith] :: AccCfg x -> Set x
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [onlyOov] :: AccCfg x -> Bool
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [tn] :: Stats -> !Int
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [tp] :: Stats -> !Int
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [verbose] :: AccCfg x -> Bool
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: [weakAcc] :: AccCfg x -> Bool
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: accuracy :: Stats -> Double
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: collect :: (Word w, Ord x, Show x) => AccCfg x -> [Sent w (Tag, x)] -> [Sent w (Tag, x)] -> Stats
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: data AccCfg x
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: data Stats
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: instance GHC.Classes.Eq NLP.Concraft.DAG.Morphosyntax.Accuracy.Stats
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: instance GHC.Classes.Ord NLP.Concraft.DAG.Morphosyntax.Accuracy.Stats
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: instance GHC.Show.Show NLP.Concraft.DAG.Morphosyntax.Accuracy.Stats
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: precision :: Stats -> Double
+ NLP.Concraft.DAG.Morphosyntax.Accuracy: recall :: Stats -> Double
+ NLP.Concraft.DAG.Morphosyntax.Ambiguous: identifyAmbiguousSegments :: DAG a b -> DAG a Bool
+ NLP.Concraft.DAG.Schema: Body :: [Int] -> Bool -> a -> Body a
+ NLP.Concraft.DAG.Schema: SchemaConf :: Entry () -> Entry () -> Entry [Int] -> Entry [Int] -> Entry () -> Entry () -> Entry () -> Entry () -> SchemaConf
+ NLP.Concraft.DAG.Schema: [args] :: Body a -> a
+ NLP.Concraft.DAG.Schema: [begPackedC] :: SchemaConf -> Entry ()
+ NLP.Concraft.DAG.Schema: [knownC] :: SchemaConf -> Entry ()
+ NLP.Concraft.DAG.Schema: [lowOrthC] :: SchemaConf -> Entry ()
+ NLP.Concraft.DAG.Schema: [lowPrefixesC] :: SchemaConf -> Entry [Int]
+ NLP.Concraft.DAG.Schema: [lowSuffixesC] :: SchemaConf -> Entry [Int]
+ NLP.Concraft.DAG.Schema: [oovOnly] :: Body a -> Bool
+ NLP.Concraft.DAG.Schema: [orthC] :: SchemaConf -> Entry ()
+ NLP.Concraft.DAG.Schema: [packedC] :: SchemaConf -> Entry ()
+ NLP.Concraft.DAG.Schema: [range] :: Body a -> [Int]
+ NLP.Concraft.DAG.Schema: [shapeC] :: SchemaConf -> Entry ()
+ NLP.Concraft.DAG.Schema: begPackedB :: Word w => Block w t ()
+ NLP.Concraft.DAG.Schema: data Body a
+ NLP.Concraft.DAG.Schema: data SchemaConf
+ NLP.Concraft.DAG.Schema: entry :: [Int] -> Entry ()
+ NLP.Concraft.DAG.Schema: entryWith :: a -> [Int] -> Entry a
+ NLP.Concraft.DAG.Schema: fromBlock :: Word w => Block w t a -> [Int] -> Bool -> Schema w t a
+ NLP.Concraft.DAG.Schema: fromConf :: Word w => SchemaConf -> Schema w t ()
+ NLP.Concraft.DAG.Schema: instance Data.Binary.Class.Binary NLP.Concraft.DAG.Schema.SchemaConf
+ NLP.Concraft.DAG.Schema: instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (NLP.Concraft.DAG.Schema.Body a)
+ NLP.Concraft.DAG.Schema: instance GHC.Show.Show NLP.Concraft.DAG.Schema.SchemaConf
+ NLP.Concraft.DAG.Schema: instance GHC.Show.Show a => GHC.Show.Show (NLP.Concraft.DAG.Schema.Body a)
+ NLP.Concraft.DAG.Schema: knownB :: Word w => Block w t ()
+ NLP.Concraft.DAG.Schema: lowOrthB :: Word w => Block w t ()
+ NLP.Concraft.DAG.Schema: lowPrefixesB :: Word w => [Int] -> Block w t ()
+ NLP.Concraft.DAG.Schema: lowSuffixesB :: Word w => [Int] -> Block w t ()
+ NLP.Concraft.DAG.Schema: nullConf :: SchemaConf
+ NLP.Concraft.DAG.Schema: orthB :: Word w => Block w t ()
+ NLP.Concraft.DAG.Schema: packedB :: Word w => Block w t ()
+ NLP.Concraft.DAG.Schema: schematize :: Schema w t a -> Sent w t -> DAG () [Ob]
+ NLP.Concraft.DAG.Schema: sequenceS_ :: [Sent w t -> a -> Ox b] -> Sent w t -> a -> Ox ()
+ NLP.Concraft.DAG.Schema: shapeB :: Word w => Block w t ()
+ NLP.Concraft.DAG.Schema: type Block w t a = Sent w t -> [EdgeID] -> Ox a
+ NLP.Concraft.DAG.Schema: type Entry a = Maybe (Body a)
+ NLP.Concraft.DAG.Schema: type Ob = ([Int], Text)
+ NLP.Concraft.DAG.Schema: type Ox a = Ox Text a
+ NLP.Concraft.DAG.Schema: type Schema w t a = Sent w t -> EdgeID -> Ox a
+ NLP.Concraft.DAG.Schema: void :: a -> Schema w t a
+ NLP.Concraft.DAG.Segmentation: AmbiCfg :: Bool -> AmbiCfg
+ NLP.Concraft.DAG.Segmentation: AmbiStats :: !Int -> !Int -> AmbiStats
+ NLP.Concraft.DAG.Segmentation: Freq :: FreqConf -> PathTyp
+ NLP.Concraft.DAG.Segmentation: FreqConf :: Map Text (Int, Int) -> Double -> FreqConf
+ NLP.Concraft.DAG.Segmentation: Max :: PathTyp
+ NLP.Concraft.DAG.Segmentation: Min :: PathTyp
+ NLP.Concraft.DAG.Segmentation: [ambi] :: AmbiStats -> !Int
+ NLP.Concraft.DAG.Segmentation: [onlyChosen] :: AmbiCfg -> Bool
+ NLP.Concraft.DAG.Segmentation: [pickFreqMap] :: FreqConf -> Map Text (Int, Int)
+ NLP.Concraft.DAG.Segmentation: [smoothingParam] :: FreqConf -> Double
+ NLP.Concraft.DAG.Segmentation: [total] :: AmbiStats -> !Int
+ NLP.Concraft.DAG.Segmentation: computeAmbiStats :: (Word w) => AmbiCfg -> [Sent w t] -> AmbiStats
+ NLP.Concraft.DAG.Segmentation: computeFreqs :: (Word w) => [Sent w t] -> Map Text (Int, Int)
+ NLP.Concraft.DAG.Segmentation: data AmbiCfg
+ NLP.Concraft.DAG.Segmentation: data AmbiStats
+ NLP.Concraft.DAG.Segmentation: data FreqConf
+ NLP.Concraft.DAG.Segmentation: data PathTyp
+ NLP.Concraft.DAG.Segmentation: findPath :: (Word b) => PathTyp -> DAG a b -> Set EdgeID
+ NLP.Concraft.DAG.Segmentation: instance GHC.Classes.Eq NLP.Concraft.DAG.Segmentation.AmbiCfg
+ NLP.Concraft.DAG.Segmentation: instance GHC.Classes.Eq NLP.Concraft.DAG.Segmentation.AmbiStats
+ NLP.Concraft.DAG.Segmentation: instance GHC.Classes.Ord NLP.Concraft.DAG.Segmentation.AmbiCfg
+ NLP.Concraft.DAG.Segmentation: instance GHC.Classes.Ord NLP.Concraft.DAG.Segmentation.AmbiStats
+ NLP.Concraft.DAG.Segmentation: instance GHC.Show.Show NLP.Concraft.DAG.Segmentation.AmbiCfg
+ NLP.Concraft.DAG.Segmentation: instance GHC.Show.Show NLP.Concraft.DAG.Segmentation.AmbiStats
+ NLP.Concraft.DAG.Segmentation: pickPath :: (Word b) => PathTyp -> DAG a b -> DAG a b
+ NLP.Concraft.DAG2: Concraft :: Tagset -> Int -> Guesser t Tag -> Disamb t -> Concraft t
+ NLP.Concraft.DAG2: [disamb] :: Concraft t -> Disamb t
+ NLP.Concraft.DAG2: [guessNum] :: Concraft t -> Int
+ NLP.Concraft.DAG2: [guesser] :: Concraft t -> Guesser t Tag
+ NLP.Concraft.DAG2: [tagset] :: Concraft t -> Tagset
+ NLP.Concraft.DAG2: data Concraft t
+ NLP.Concraft.DAG2: disambMarginals :: (Word w, Ord t) => Disamb t -> Sent w t -> Anno t Double
+ NLP.Concraft.DAG2: disambPath :: (Ord t) => [(EdgeID, t)] -> Anno t Double -> Anno t Bool
+ NLP.Concraft.DAG2: disambProbs :: (Word w, Ord t) => ProbType -> Disamb t -> Sent w t -> Anno t Double
+ NLP.Concraft.DAG2: findOptimalPaths :: Anno t Double -> [[(EdgeID, t)]]
+ NLP.Concraft.DAG2: guess :: (Word w, Ord t) => Int -> Guesser t Tag -> Sent w t -> Anno t Double
+ NLP.Concraft.DAG2: guessMarginals :: (Word w, Ord t) => Guesser t Tag -> Sent w t -> Anno t Double
+ NLP.Concraft.DAG2: guessSent :: (Word w, Ord t) => Int -> Guesser t Tag -> Sent w t -> Sent w t
+ NLP.Concraft.DAG2: loadModel :: (Ord t, Binary t) => (Tagset -> t -> Tag) -> FilePath -> IO (Concraft t)
+ NLP.Concraft.DAG2: prune :: Double -> Concraft t -> Concraft t
+ NLP.Concraft.DAG2: replace :: (Ord t) => Anno t Double -> Sent w t -> Sent w t
+ NLP.Concraft.DAG2: saveModel :: (Ord t, Binary t) => FilePath -> Concraft t -> IO ()
+ NLP.Concraft.DAG2: tag :: (Word w, Ord t) => Int -> Concraft t -> Sent w t -> Anno t Double
+ NLP.Concraft.DAG2: train :: (Word w, Ord t) => Tagset -> Int -> TrainConf t Tag -> TrainConf t -> IO [Sent w t] -> IO [Sent w t] -> IO (Concraft t)
+ NLP.Concraft.DAG2: type Anno a b = DAG () (Map a b)
+ NLP.Concraft.DAGSeg: Concraft :: Tagset -> Int -> Guesser t Tag -> Disamb t -> Disamb t -> Concraft t
+ NLP.Concraft.DAGSeg: [disamb] :: Concraft t -> Disamb t
+ NLP.Concraft.DAGSeg: [guessNum] :: Concraft t -> Int
+ NLP.Concraft.DAGSeg: [guesser] :: Concraft t -> Guesser t Tag
+ NLP.Concraft.DAGSeg: [segmenter] :: Concraft t -> Disamb t
+ NLP.Concraft.DAGSeg: [tagset] :: Concraft t -> Tagset
+ NLP.Concraft.DAGSeg: data Concraft t
+ NLP.Concraft.DAGSeg: disambMarginals :: (Word w, Ord t) => Disamb t -> Sent w t -> Anno t Double
+ NLP.Concraft.DAGSeg: disambPath :: (Ord t) => [(EdgeID, Set t)] -> Anno t Double -> Anno t Bool
+ NLP.Concraft.DAGSeg: disambProbs :: (Word w, Ord t) => ProbType -> Disamb t -> Sent w t -> Anno t Double
+ NLP.Concraft.DAGSeg: findOptimalPaths :: Ord t => Anno t Double -> [[(EdgeID, Set t)]]
+ NLP.Concraft.DAGSeg: guess :: (Word w, Ord t) => Int -> Guesser t Tag -> Sent w t -> Anno t Double
+ NLP.Concraft.DAGSeg: guessMarginals :: (Word w, Ord t) => Guesser t Tag -> Sent w t -> Anno t Double
+ NLP.Concraft.DAGSeg: guessSent :: (Word w, Ord t) => Int -> Guesser t Tag -> Sent w t -> Sent w t
+ NLP.Concraft.DAGSeg: loadModel :: (Ord t, Binary t) => (Tagset -> t -> Tag) -> (Tagset -> t -> Tag) -> FilePath -> IO (Concraft t)
+ NLP.Concraft.DAGSeg: prune :: Double -> Concraft t -> Concraft t
+ NLP.Concraft.DAGSeg: saveModel :: (Ord t, Binary t) => FilePath -> Concraft t -> IO ()
+ NLP.Concraft.DAGSeg: tag :: (Word w, Ord t) => Int -> Concraft t -> Sent w t -> Anno t Double
+ NLP.Concraft.DAGSeg: type Anno a b = DAG () (Map a b)
+ NLP.Concraft.Disamb: [atts] :: Atom -> Map Attr Text
+ NLP.Concraft.Disamb: [crf] :: Disamb -> CRF Ob Atom
+ NLP.Concraft.Disamb: [eos] :: Atom -> Maybe Bool
+ NLP.Concraft.Disamb: [initDmb] :: TrainConf -> Disamb
+ NLP.Concraft.Disamb: [onDiskT] :: TrainConf -> Bool
+ NLP.Concraft.Disamb: [pos] :: Atom -> Maybe POS
+ NLP.Concraft.Disamb: [schemaConfT] :: TrainConf -> SchemaConf
+ NLP.Concraft.Disamb: [schemaConf] :: Disamb -> SchemaConf
+ NLP.Concraft.Disamb: [sgdArgsT] :: TrainConf -> SgdArgs
+ NLP.Concraft.Disamb: [tiersT] :: TrainConf -> [Tier]
+ NLP.Concraft.Disamb: [tiers] :: Disamb -> [Tier]
+ NLP.Concraft.Disamb: [withAtts] :: Tier -> Set Attr
+ NLP.Concraft.Disamb: [withEos] :: Tier -> Bool
+ NLP.Concraft.Disamb: [withPos] :: Tier -> Bool
+ NLP.Concraft.Disamb: instance Data.Binary.Class.Binary NLP.Concraft.Disamb.Disamb
+ NLP.Concraft.Guess: [crf] :: Guesser t -> CRF Ob t
+ NLP.Concraft.Guess: [onDiskT] :: TrainConf -> Bool
+ NLP.Concraft.Guess: [r0T] :: TrainConf -> R0T
+ NLP.Concraft.Guess: [schemaConfT] :: TrainConf -> SchemaConf
+ NLP.Concraft.Guess: [schemaConf] :: Guesser t -> SchemaConf
+ NLP.Concraft.Guess: [sgdArgsT] :: TrainConf -> SgdArgs
+ NLP.Concraft.Guess: instance (GHC.Classes.Ord t, Data.Binary.Class.Binary t) => Data.Binary.Class.Binary (NLP.Concraft.Guess.Guesser t)
+ NLP.Concraft.Guess: instance Data.Data.Data NLP.Concraft.Guess.R0T
+ NLP.Concraft.Guess: instance GHC.Classes.Eq NLP.Concraft.Guess.R0T
+ NLP.Concraft.Guess: instance GHC.Classes.Ord NLP.Concraft.Guess.R0T
+ NLP.Concraft.Guess: instance GHC.Enum.Enum NLP.Concraft.Guess.R0T
+ NLP.Concraft.Guess: instance GHC.Show.Show NLP.Concraft.Guess.R0T
+ NLP.Concraft.Morphosyntax: [orig] :: SentO w t -> Text
+ NLP.Concraft.Morphosyntax: [segs] :: SentO w t -> Sent w t
+ NLP.Concraft.Morphosyntax: [tags] :: Seg w t -> WMap t
+ NLP.Concraft.Morphosyntax: [word] :: Seg w t -> w
+ NLP.Concraft.Morphosyntax: instance (GHC.Show.Show w, GHC.Show.Show t) => GHC.Show.Show (NLP.Concraft.Morphosyntax.Seg w t)
+ NLP.Concraft.Morphosyntax: instance (GHC.Show.Show w, GHC.Show.Show t) => GHC.Show.Show (NLP.Concraft.Morphosyntax.SentO w t)
+ NLP.Concraft.Morphosyntax: instance Data.Aeson.Types.FromJSON.FromJSON w => Data.Aeson.Types.FromJSON.FromJSON (NLP.Concraft.Morphosyntax.Seg w Data.Text.Internal.Text)
+ NLP.Concraft.Morphosyntax: instance Data.Aeson.Types.ToJSON.ToJSON w => Data.Aeson.Types.ToJSON.ToJSON (NLP.Concraft.Morphosyntax.Seg w Data.Text.Internal.Text)
+ NLP.Concraft.Morphosyntax: instance NLP.Concraft.Morphosyntax.Word w => NLP.Concraft.Morphosyntax.Word (NLP.Concraft.Morphosyntax.Seg w t)
+ NLP.Concraft.Morphosyntax.Accuracy: [gold] :: Stats -> Int
+ NLP.Concraft.Morphosyntax.Accuracy: [good] :: Stats -> Int
+ NLP.Concraft.Morphosyntax.WMap: data WMap a
+ NLP.Concraft.Morphosyntax.WMap: fromMap :: Map a Double -> WMap a
+ NLP.Concraft.Morphosyntax.WMap: instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (NLP.Concraft.Morphosyntax.WMap.WMap a)
+ NLP.Concraft.Morphosyntax.WMap: instance GHC.Classes.Eq a => GHC.Classes.Eq (NLP.Concraft.Morphosyntax.WMap.WMap a)
+ NLP.Concraft.Morphosyntax.WMap: instance GHC.Classes.Ord a => GHC.Classes.Ord (NLP.Concraft.Morphosyntax.WMap.WMap a)
+ NLP.Concraft.Morphosyntax.WMap: instance GHC.Show.Show a => GHC.Show.Show (NLP.Concraft.Morphosyntax.WMap.WMap a)
+ NLP.Concraft.Morphosyntax.WMap: mapWMap :: Ord b => (a -> b) -> WMap a -> WMap b
+ NLP.Concraft.Morphosyntax.WMap: mkWMap :: Ord a => [(a, Double)] -> WMap a
+ NLP.Concraft.Morphosyntax.WMap: trim :: (Ord a) => Int -> WMap a -> WMap a
+ NLP.Concraft.Schema: [args] :: Body a -> a
+ NLP.Concraft.Schema: [begPackedC] :: SchemaConf -> Entry ()
+ NLP.Concraft.Schema: [knownC] :: SchemaConf -> Entry ()
+ NLP.Concraft.Schema: [lowOrthC] :: SchemaConf -> Entry ()
+ NLP.Concraft.Schema: [lowPrefixesC] :: SchemaConf -> Entry [Int]
+ NLP.Concraft.Schema: [lowSuffixesC] :: SchemaConf -> Entry [Int]
+ NLP.Concraft.Schema: [oovOnly] :: Body a -> Bool
+ NLP.Concraft.Schema: [orthC] :: SchemaConf -> Entry ()
+ NLP.Concraft.Schema: [packedC] :: SchemaConf -> Entry ()
+ NLP.Concraft.Schema: [range] :: Body a -> [Int]
+ NLP.Concraft.Schema: [shapeC] :: SchemaConf -> Entry ()
+ NLP.Concraft.Schema: instance Data.Binary.Class.Binary NLP.Concraft.Schema.SchemaConf
+ NLP.Concraft.Schema: instance Data.Binary.Class.Binary a => Data.Binary.Class.Binary (NLP.Concraft.Schema.Body a)
+ NLP.Concraft.Schema: instance GHC.Show.Show NLP.Concraft.Schema.SchemaConf
+ NLP.Concraft.Schema: instance GHC.Show.Show a => GHC.Show.Show (NLP.Concraft.Schema.Body a)
- NLP.Concraft.Disamb: Atom :: Maybe POS -> Map Attr Text -> Atom
+ NLP.Concraft.Disamb: Atom :: Maybe POS -> Map Attr Text -> Maybe Bool -> Atom
- NLP.Concraft.Disamb: Tier :: Bool -> Set Attr -> Tier
+ NLP.Concraft.Disamb: Tier :: Bool -> Bool -> Set Attr -> Tier

Files

concraft.cabal view
@@ -1,5 +1,5 @@ name:               concraft-version:            0.9.4+version:            0.11.0 synopsis:           Morphological disambiguation based on constrained CRFs description:     A morphological disambiguation library based on@@ -7,7 +7,7 @@ license:            BSD3 license-file:       LICENSE cabal-version:      >= 1.6-copyright:          Copyright (c) 2011 Jakub Waszczuk, 2012 IPI PAN+copyright:          Copyright (c) 2011-2018 Jakub Waszczuk, 2012 IPI PAN author:             Jakub Waszczuk maintainer:         waszczuk.kuba@gmail.com stability:          experimental@@ -26,26 +26,29 @@         base                    >= 4        && < 5       , array                   >= 0.4      && < 0.6       , containers              >= 0.4      && < 0.6-      , binary                  >= 0.5      && < 0.8+      , binary                  >= 0.5      && < 0.9       , bytestring              >= 0.9      && < 0.11       , text                    >= 0.11     && < 1.3-      , text-binary             >= 0.1      && < 0.2-      , vector                  >= 0.10     && < 0.11+      , text-binary             >= 0.1      && < 0.3+      , vector                  >= 0.10     && < 0.13       , vector-binary           >= 0.1      && < 0.2       , monad-ox                >= 0.3      && < 0.4-      , sgd                     >= 0.3.3    && < 0.4+      , sgd                     >= 0.4.0    && < 0.5       , tagset-positional       >= 0.3      && < 0.4-      , crf-chain1-constrained  >= 0.3      && < 0.4-      , crf-chain2-tiers        >= 0.2.1    && < 0.3+      , crf-chain1-constrained  >= 0.4      && < 0.5+      , crf-chain2-tiers        >= 0.3      && < 0.4       , monad-codec             >= 0.2      && < 0.3-      , data-lens               >= 2.10     && < 2.11-      , transformers            >= 0.2      && < 0.5-      , comonad                 >= 4.0      && < 4.3-      , temporary               >= 1.1      && < 1.2-      , aeson                   >= 0.6      && < 0.9-      , zlib                    >= 0.5      && < 0.6+      , data-lens               >= 2.10     && < 2.12+      , transformers            >= 0.2      && < 0.6+      , comonad                 >= 4.0      && < 5.1+      , aeson                   >= 0.6      && < 1.3+      , zlib                    >= 0.5      && < 0.7       , lazy-io                 >= 0.1      && < 0.2       , cmdargs                 >= 0.10     && < 0.11+      , pedestrian-dag          >= 0.2      && < 0.3+      , temporary               >= 1.1      && < 1.3+      , parallel                >= 3.2      && < 3.3+      , data-memocombinators    >= 0.5.1    && < 0.6      exposed-modules:         NLP.Concraft@@ -54,7 +57,20 @@       , NLP.Concraft.Guess       , NLP.Concraft.Disamb       , NLP.Concraft.Morphosyntax+      , NLP.Concraft.Morphosyntax.WMap       , NLP.Concraft.Morphosyntax.Accuracy++      , NLP.Concraft.DAG.Morphosyntax+      , NLP.Concraft.DAG.Morphosyntax.Accuracy+      , NLP.Concraft.DAG.Morphosyntax.Ambiguous+      , NLP.Concraft.DAG.Segmentation+      , NLP.Concraft.DAG.Schema+      , NLP.Concraft.DAG.Guess+      , NLP.Concraft.DAG.Disamb+      , NLP.Concraft.DAG.DisambSeg+      -- , NLP.Concraft.DAG+      , NLP.Concraft.DAG2+      , NLP.Concraft.DAGSeg      other-modules:         NLP.Concraft.Disamb.Positional
src/NLP/Concraft.hs view
@@ -3,7 +3,7 @@  module NLP.Concraft (--- * Model +-- * Model   Concraft (..) , saveModel , loadModel@@ -21,6 +21,7 @@ ) where  +import           Prelude hiding (Word) import           System.IO (hClose) import           Control.Applicative ((<$>), (<*>)) import           Control.Monad (when)@@ -233,5 +234,23 @@     hClose tmpHandle     let txtSent = mapSent $ P.showTag tagset         tagSent = mapSent $ P.parseTag tagset-    writePar tmpPath $ map txtSent xs-    handler (map tagSent <$> readPar tmpPath)+    -- writePar tmpPath $ map txtSent xs+    -- handler (map tagSent <$> readPar tmpPath)+    handler (return xs)++-- withTemp+--     :: (FromJSON w, ToJSON w)+--     => P.Tagset+--     -> FilePath                     -- ^ Directory to create the file in+--     -> String                       -- ^ Template for `Temp.withTempFile`+--     -> [Sent w P.Tag]               -- ^ Input dataset+--     -> (IO [Sent w P.Tag] -> IO a)  -- ^ Handler+--     -> IO a+-- withTemp _      _   _    [] handler = handler (return [])+-- withTemp tagset dir tmpl xs handler =+--   Temp.withTempFile dir tmpl $ \tmpPath tmpHandle -> do+--     hClose tmpHandle+--     let txtSent = mapSent $ P.showTag tagset+--         tagSent = mapSent $ P.parseTag tagset+--     writePar tmpPath $ map txtSent xs+--     handler (map tagSent <$> readPar tmpPath)
src/NLP/Concraft/Analysis.hs view
@@ -15,6 +15,7 @@ ) where  +import           Prelude hiding (Word) import qualified Control.Monad.LazyIO as LazyIO import qualified Data.Text.Lazy as L 
+ src/NLP/Concraft/DAG/Disamb.hs view
@@ -0,0 +1,333 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TupleSections #-}+++module NLP.Concraft.DAG.Disamb+(+-- * Types+  Disamb (..)+, putDisamb+, getDisamb++-- * Tiers+, P.Tier (..)+, P.Atom (..)++-- -- * Marginals+-- , marginalsSent+-- , marginals++-- * Probs in general+, CRF.ProbType (..)+, probsSent+, probs++-- * Training+, TrainConf (..)+, train++-- * Pruning+, prune++-- * Internal+, schematize+) where+++import Prelude hiding (words)+import Control.Applicative ((<$>), (<*>), pure)+import Data.Binary (Binary, put, get, Put, Get)+import Data.Text.Binary ()+import System.Console.CmdArgs+import qualified Data.Set as S+import qualified Data.Map as M+import qualified Data.Vector as V+import qualified Data.List as List++import qualified Data.DAG as DAG+import           Data.DAG (DAG)++import qualified Control.Monad.Ox as Ox+import qualified Numeric.SGD.Momentum as SGD+import qualified Data.CRF.Chain2.Tiers.DAG as CRF+import qualified Data.Tagset.Positional as T++-- import           NLP.Concraft.Schema hiding (schematize)+-- import qualified NLP.Concraft.Morphosyntax as X+import qualified NLP.Concraft.Disamb.Positional as P+import           NLP.Concraft.DAG.Schema hiding (schematize)+import qualified NLP.Concraft.DAG.Morphosyntax as X+++-- | A disambiguation model.+data Disamb t = Disamb+    { tiers         :: [P.Tier]+    , schemaConf    :: SchemaConf+    , crf           :: CRF.CRF Ob P.Atom+    -- , simpliMap     :: M.Map t T.Tag+    , simplify      :: t -> T.Tag+      -- ^ A map which simplifies the tags of generic type `t` to simplified+      -- positional tags. The motivation behind this is that tags can have a+      -- richer structure.+      --+      -- NOTE: it can happen in real situations that a tag is encountered which+      -- is not known by the model. It would be nice to be able to treat it as+      -- the closest tag that can be handled. Then, one have to define the+      -- notion of the similarilty between tags, though... But probably it+      -- should be done at a different level (where more information about the+      -- structure of `t` is known)+    }+++-- instance (Binary t) => Binary (Disamb t) where+--     put Disamb{..} = put tiers >> put schemaConf >> put crf >> put simpliMap+--     get = Disamb <$> get <*> get <*> get <*> get+++-- | Store the entire disambiguation model apart from the simplification+-- function.+putDisamb :: Disamb t -> Put+putDisamb Disamb{..} =+  put tiers >> put schemaConf >> put crf+++-- | Get the disambiguation model, provided the simplification function.+-- getDisamb :: (M.Map t T.Tag) -> Get (Disamb t)+getDisamb :: (t -> T.Tag) -> Get (Disamb t)+getDisamb smp =+  Disamb <$> get <*> get <*> get <*> pure smp+++--------------------------+-- Simplify+--------------------------+++-- -- | Simplify the given label.+-- simplify :: (Ord t) => Disamb t -> t -> T.Tag+-- simplify Disamb{..} x =+--   case M.lookup x simpliMap of+--     Nothing -> defaultTag+--     Just y -> y+--   where+--     defaultTag = snd $ M.findMin simpliMap+++--------------------------+-- Schematize+--------------------------+++-- | Schematize the input sentence according to 'schema' rules.+schematize :: Schema w [t] a -> X.Sent w [t] -> CRF.Sent Ob t+schematize schema sent =+  DAG.mapE f sent+  where+    f i = const $ CRF.mkWord (obs i) (lbs i)+    obs = S.fromList . Ox.execOx . schema sent+    lbs i = X.interpsSet w+      where w = DAG.edgeLabel i sent+++-- --------------------------+-- -- Marginals+-- --------------------------+--+--+-- -- | Determine the marginal probabilities of to individual labels in the sentence.+-- marginals :: (X.Word w, Ord t) => Disamb t -> X.Sent w t -> DAG () (X.WMap t)+-- marginals dmb = fmap X.tags . marginalsSent dmb+--+--+-- -- | Determine the marginal probabilities of to individual labels in the sentence.+-- -- marginalsSent :: (X.Word w, Ord t) => Disamb t -> X.Sent w t -> DAG () (X.WMap [P.Atom])+-- marginalsSent :: (X.Word w, Ord t) => Disamb t -> X.Sent w t -> X.Sent w t+-- marginalsSent dmb sent+--   = (\new -> inject dmb new sent)+--   . fmap getTags+--   . marginalsCRF dmb+--   $ sent+--   where+--     getTags = X.mkWMap . M.toList . choice -- CRF.unProb . snd+--     -- below we mix the chosen and the potential interpretations together+--     choice w = M.unionWith (+)+--       (CRF.unProb . snd $ w)+--       (M.fromList . map (,0) . interps $ w)+--     interps = S.toList . CRF.lbs . fst+--+--+-- -- | Ascertain the marginal probabilities of the individual labels in the sentence.+-- marginalsCRF :: (X.Word w, Ord t) => Disamb t -> X.Sent w t -> CRF.SentL Ob P.Atom+-- marginalsCRF dmb+--   = CRF.marginals (crf dmb)+--   . schematize schema+--   . X.mapSent (split . simplify dmb)+--   where+--     schema = fromConf (schemaConf dmb)+--     split  = P.split (tiers dmb)+++--------------------------+-- Injection+--------------------------+++-- | Replace the probabilities of the sentence labels with the new probabilities+-- stemming from the CRF sentence.+inject+  :: (Ord t, X.Word w)+  => Disamb t+  -> DAG () (X.WMap [P.Atom])+  -> X.Sent w t+  -> X.Sent w t+inject dmb newSent srcSent =+  let doit (target, src) =+        let oldTags = X.tags src+            newTags = injectWMap dmb target oldTags+        in  src {X.tags = newTags}+  in  fmap doit (DAG.zipE newSent srcSent)+++-- | Replace label probabilities with the new probabilities.+injectWMap+  :: (Ord t)+  => Disamb t+  -> X.WMap [P.Atom]+  -> X.WMap t+  -> X.WMap t+injectWMap dmb newSpl src = X.mkWMap+  [ ( tag+    , maybe 0 id $+      M.lookup (P.split (tiers dmb) (simplify dmb tag) Nothing) (X.unWMap newSpl) )+  | (tag, _) <- M.toList (X.unWMap src) ]+++-- -- | Unsplit a complex tag (assuming that it is one of the interpretations of+-- -- the word).+-- unSplit :: Eq t => (r -> t) -> X.Seg w r -> t -> r+-- unSplit split word x = case jy of+--     Just y  -> y+--     Nothing -> error "unSplit: no such interpretation"+--   where+--     jy = List.find ((==x) . split) (X.interps word)+++--------------------------+-- Probs in general+--------------------------+++-- | Determine the marginal probabilities of to individual labels in the sentence.+probs :: (X.Word w, Ord t) => CRF.ProbType -> Disamb t -> X.Sent w t -> DAG () (X.WMap t)+probs probTyp dmb = fmap X.tags . probsSent probTyp dmb+++-- | Determine the marginal probabilities of to individual labels in the sentence.+-- marginalsSent :: (X.Word w, Ord t) => Disamb t -> X.Sent w t -> DAG () (X.WMap [P.Atom])+probsSent :: (X.Word w, Ord t) => CRF.ProbType -> Disamb t -> X.Sent w t -> X.Sent w t+probsSent probTyp dmb sent+  = (\new -> inject dmb new sent)+  . fmap getTags+  . probsCRF probTyp dmb+  $ sent+  where+    getTags = X.mkWMap . M.toList . choice -- CRF.unProb . snd+    -- below we mix the chosen and the potential interpretations together+    choice w = M.unionWith (+)+      (CRF.unProb . snd $ w)+      (M.fromList . map (,0) . interps $ w)+    interps = S.toList . CRF.lbs . fst+++++-- | Ascertain the marginal probabilities of the individual labels in the sentence.+probsCRF :: (X.Word w, Ord t) => CRF.ProbType -> Disamb t -> X.Sent w t -> CRF.SentL Ob P.Atom+probsCRF probTyp dmb+  = CRF.probs probTyp (crf dmb)+  . schematize schema+  . X.mapSent (split . simplify dmb)+  where+    schema = fromConf (schemaConf dmb)+    split  = \t -> P.split (tiers dmb) t Nothing+++--------------------------+-- Pruning+--------------------------+++-- | Prune disamb model: discard model features with absolute values+-- (in log-domain) lower than the given threshold.+prune :: Double -> Disamb t -> Disamb t+prune x dmb =+    let crf' = CRF.prune x (crf dmb)+    in  dmb { crf = crf' }+++--------------------------+-- Training+--------------------------+++-- | Training configuration.+data TrainConf t = TrainConf+  { tiersT      :: [P.Tier]+  , schemaConfT :: SchemaConf+  , sgdArgsT    :: SGD.SgdArgs+  , onDiskT     :: Bool+  -- | Label simplification function+  , simplifyLabel :: t -> T.Tag+  }+++-- | Train disambiguation module.+train+    :: (X.Word w, Ord t)+    => TrainConf t      -- ^ Training configuration+    -> IO [X.Sent w t]  -- ^ Training data+    -> IO [X.Sent w t]  -- ^ Evaluation data+    -> IO (Disamb t)+train TrainConf{..} trainData evalData = do+--   tagSet <- S.unions . map tagSetIn <$> trainData+--   putStr "\nTagset size: " >> print (S.size tagSet)+--   let tagMap = M.fromList+--         [ (t, simplifyLabel t)+--         | t <- S.toList tagSet ]+  crf <- CRF.train (length tiersT) CRF.selectHidden sgdArgsT onDiskT+    (schemed simplifyLabel schema split <$> trainData)+    (schemed simplifyLabel schema split <$> evalData)+  putStr "\nNumber of features: " >> print (CRF.size crf)+  return $ Disamb tiersT schemaConfT crf simplifyLabel -- tagMap+  where+    schema = fromConf schemaConfT+    split  = \t -> P.split tiersT t Nothing+++-- | Schematized dataset.+schemed+  -- :: (X.Word w, Ord t)+  :: (Ord a)+  => (t -> T.Tag)+  -> Schema w [a] b+  -> (T.Tag -> [a])+  -> [X.Sent w t]+  -> [CRF.SentL Ob a]+schemed simpl schema split =+    map onSent+  where+    onSent sent =+        let xs = fmap (X.mapSeg split) (X.mapSent simpl sent)+            mkProb = CRF.mkProb . M.toList . X.unWMap . X.tags+        -- in  fmap (uncurry CRF.mkWordL) $+        in  DAG.zipE (schematize schema xs) (fmap mkProb xs)+++-- -- | Retrieve the tagset in the given sentence.+-- tagSetIn :: (Ord t) => X.Sent w t -> S.Set t+-- tagSetIn dag = S.fromList+--   [ tag+--   | edgeID <- DAG.dagEdges dag+--   , let edge = DAG.edgeLabel edgeID dag+--   , tag <- M.keys . X.unWMap . X.tags $ edge ]
+ src/NLP/Concraft/DAG/DisambSeg.hs view
@@ -0,0 +1,270 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TupleSections #-}+++-- | A version of the disambigation model adapted to perform sentence+-- segmentation as well.+++module NLP.Concraft.DAG.DisambSeg+(+-- * Types+  Tag (..)+, Disamb (..)+, putDisamb+, getDisamb++-- * Tiers+, P.Tier (..)+, P.Atom (..)++-- -- * Marginals+-- , marginalsSent+-- , marginals++-- * Probs in general+, CRF.ProbType (..)+, probsSent+, probs++-- * Training+, TrainConf (..)+, train++-- * Pruning+, prune+) where+++import Prelude hiding (words)+import Control.Applicative ((<$>), (<*>), pure)+import Data.Binary (Binary, put, get, Put, Get)+import Data.Text.Binary ()+import System.Console.CmdArgs+import qualified Data.Set as S+import qualified Data.Map as M+import qualified Data.Vector as V+import qualified Data.List as List++import qualified Data.DAG as DAG+import           Data.DAG (DAG)++import qualified Control.Monad.Ox as Ox+import qualified Numeric.SGD.Momentum as SGD+import qualified Data.CRF.Chain2.Tiers.DAG as CRF+import qualified Data.Tagset.Positional as T++-- import           NLP.Concraft.Schema hiding (schematize)+-- import qualified NLP.Concraft.Morphosyntax as X+import qualified NLP.Concraft.Disamb.Positional as P+import           NLP.Concraft.DAG.Schema hiding (schematize)+import qualified NLP.Concraft.DAG.Morphosyntax as X++import NLP.Concraft.DAG.Disamb (schematize)+++-- | The internal tag type.+data Tag = Tag+  { posiTag :: T.Tag+    -- ^ Positional tag+  , hasEos :: Bool+    -- ^ End-of-sentence marker+  } deriving (Show, Eq, Ord)+++-- | A disambiguation model.+data Disamb t = Disamb+    { tiers         :: [P.Tier]+    , schemaConf    :: SchemaConf+    , crf           :: CRF.CRF Ob P.Atom+    , simplify      :: t -> Tag+      -- ^ A function which simplifies the tags of the generic type `t` to (i)+      -- the corresponding positional tags and (ii) information if the segment+      -- represents sentence end.+      --+      -- NOTE: it can happen in real situations that a tag is encountered which+      -- is not known by the model. It would be nice to be able to treat it as+      -- the closest tag that can be handled. Then, one have to define the+      -- notion of the similarilty between tags, though... But probably it+      -- should be done at a different level (where more information about the+      -- structure of `t` is known)+    }+++-- | Store the entire disambiguation model apart from the simplification+-- function.+putDisamb :: Disamb t -> Put+putDisamb Disamb{..} =+  put tiers >> put schemaConf >> put crf+++-- | Get the disambiguation model, provided the simplification function.+-- getDisamb :: (M.Map t T.Tag) -> Get (Disamb t)+getDisamb :: (t -> Tag) -> Get (Disamb t)+getDisamb smp =+  Disamb <$> get <*> get <*> get <*> pure smp+++--------------------------+-- Injection+--------------------------+++-- | Replace the probabilities of the sentence labels with the new probabilities+-- stemming from the CRF sentence.+inject+  :: (Ord t, X.Word w)+  => Disamb t+  -> DAG () (X.WMap [P.Atom])+  -> X.Sent w t+  -> X.Sent w t+inject dmb newSent srcSent =+  let doit (target, src) =+        let oldTags = X.tags src+            newTags = injectWMap dmb target oldTags+        in  src {X.tags = newTags}+  in  fmap doit (DAG.zipE newSent srcSent)+++-- | Replace label probabilities with the new probabilities.+injectWMap+  :: (Ord t)+  => Disamb t+  -> X.WMap [P.Atom]+  -> X.WMap t+  -> X.WMap t+injectWMap dmb newSpl src = X.mkWMap+  [ ( tag+    , maybe 0 id $+      M.lookup (split (tiers dmb) (simplify dmb tag)) (X.unWMap newSpl) )+  | (tag, _) <- M.toList (X.unWMap src) ]+++--------------------------+-- Probs in general+--------------------------+++-- | Determine the marginal probabilities of to individual labels in the sentence.+probs :: (X.Word w, Ord t) => CRF.ProbType -> Disamb t -> X.Sent w t -> DAG () (X.WMap t)+probs probTyp dmb = fmap X.tags . probsSent probTyp dmb+++-- | Determine the marginal probabilities of to individual labels in the sentence.+-- marginalsSent :: (X.Word w, Ord t) => Disamb t -> X.Sent w t -> DAG () (X.WMap [P.Atom])+probsSent :: (X.Word w, Ord t) => CRF.ProbType -> Disamb t -> X.Sent w t -> X.Sent w t+probsSent probTyp dmb sent+  = (\new -> inject dmb new sent)+  . fmap getTags+  . probsCRF probTyp dmb+  $ sent+  where+    getTags = X.mkWMap . M.toList . choice -- CRF.unProb . snd+    -- below we mix the chosen and the potential interpretations together+    choice w = M.unionWith (+)+      (CRF.unProb . snd $ w)+      (M.fromList . map (,0) . interps $ w)+    interps = S.toList . CRF.lbs . fst+++++-- | Ascertain the marginal probabilities of the individual labels in the sentence.+probsCRF :: (X.Word w, Ord t) => CRF.ProbType -> Disamb t -> X.Sent w t -> CRF.SentL Ob P.Atom+probsCRF probTyp dmb+  = CRF.probs probTyp (crf dmb)+  . schematize schema+  . X.mapSent (split (tiers dmb) . simplify dmb)+  where+    schema = fromConf (schemaConf dmb)+++--------------------------+-- Pruning+--------------------------+++-- | Prune disamb model: discard model features with absolute values+-- (in log-domain) lower than the given threshold.+prune :: Double -> Disamb t -> Disamb t+prune x dmb =+    let crf' = CRF.prune x (crf dmb)+    in  dmb { crf = crf' }+++--------------------------+-- Training+--------------------------+++-- | Training configuration.+data TrainConf t = TrainConf+  { tiersT      :: [P.Tier]+  , schemaConfT :: SchemaConf+  , sgdArgsT    :: SGD.SgdArgs+  , onDiskT     :: Bool+  -- | Label simplification function+  , simplifyLabel :: t -> Tag+  }+++-- | Train disambiguation module.+train+    :: (X.Word w, Ord t)+    => TrainConf t      -- ^ Training configuration+    -> IO [X.Sent w t]  -- ^ Training data+    -> IO [X.Sent w t]  -- ^ Evaluation data+    -> IO (Disamb t)+train TrainConf{..} trainData evalData = do+--   tagSet <- S.unions . map tagSetIn <$> trainData+--   putStr "\nTagset size: " >> print (S.size tagSet)+--   let tagMap = M.fromList+--         [ (t, simplifyLabel t)+--         | t <- S.toList tagSet ]+  crf <- CRF.train (length tiersT) CRF.selectHidden sgdArgsT onDiskT+    (schemed simplifyLabel schema (split tiersT) <$> trainData)+    (schemed simplifyLabel schema (split tiersT) <$> evalData)+  putStr "\nNumber of features: " >> print (CRF.size crf)+  return $ Disamb tiersT schemaConfT crf simplifyLabel -- tagMap+  where+    schema = fromConf schemaConfT+++-- | Schematized dataset.+schemed+  -- :: (X.Word w, Ord t)+  :: (Ord a)+  => (t -> Tag)+  -> Schema w [a] b+  -> (Tag -> [a])+  -> [X.Sent w t]+  -> [CRF.SentL Ob a]+schemed simpl schema split =+    map onSent+  where+    onSent sent =+        let xs = fmap (X.mapSeg split) (X.mapSent simpl sent)+            mkProb = CRF.mkProb . M.toList . X.unWMap . X.tags+        -- in  fmap (uncurry CRF.mkWordL) $+        in  DAG.zipE (schematize schema xs) (fmap mkProb xs)+++-- -- | Retrieve the tagset in the given sentence.+-- tagSetIn :: (Ord t) => X.Sent w t -> S.Set t+-- tagSetIn dag = S.fromList+--   [ tag+--   | edgeID <- DAG.dagEdges dag+--   , let edge = DAG.edgeLabel edgeID dag+--   , tag <- M.keys . X.unWMap . X.tags $ edge ]++++--------------------------+-- Utils+--------------------------+++-- | Split the tag with respect to the given tiers.+split :: [P.Tier] -> Tag -> [P.Atom]+split tiers tag = P.split tiers (posiTag tag) (Just $ hasEos tag)
+ src/NLP/Concraft/DAG/Guess.hs view
@@ -0,0 +1,352 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TupleSections #-}+++module NLP.Concraft.DAG.Guess+(+-- * Types+  Guesser (..)+, putGuesser+, getGuesser++-- * Marginals+, marginals+, marginalsSent++-- -- * Guessing+-- , guess+-- , include+-- , guessSent++-- * Training+, TrainConf (..)+, R0T (..)+, train++-- * Utils+, schemed+) where+++import Prelude hiding (words)+import Control.Applicative ((<$>), (<*>), pure)+import Data.Binary (Binary, put, get, Put, Get)+import Data.Text.Binary ()+import System.Console.CmdArgs+import qualified Data.Set as S+import qualified Data.Map.Strict as M+-- import qualified Data.Vector as V++import qualified Data.DAG as DAG+import           Data.DAG (DAG)++import qualified Control.Monad.Ox as Ox+-- import qualified Data.CRF.Chain1.Constrained as CRF+import qualified Data.CRF.Chain1.Constrained.DAG as CRF+-- import qualified Data.CRF.Chain1.Constrained.Dataset.External as CRF.Ext+import qualified Numeric.SGD.Momentum as SGD++-- import           NLP.Concraft.Schema hiding (schematize)+-- import qualified NLP.Concraft.Morphosyntax as X+import           NLP.Concraft.DAG.Schema hiding (schematize)+import qualified NLP.Concraft.DAG.Morphosyntax as X+++-- | A guessing model.+data Guesser t s = Guesser+    { schemaConf    :: SchemaConf+    , crf           :: CRF.CRF Ob s+    , zeroProbLab   :: s+    , unkTagSet     :: S.Set t+      -- ^ The tagset considered for the unknown words (TODO: a solution+      -- parallel and not 100% consistent with what is implemented in the CRF+      -- library)+    , simplify      :: t -> s+      -- ^ A tag simplification function+    }+++-- instance (Ord t, Binary t, Ord s, Binary s) => Binary (Guesser t s) where+--     put Guesser{..} = do+--       put schemaConf+--       put crf+--       put zeroProbLab+--       put simpliMap+--     get = Guesser <$> get <*> get <*> get <*> get+++-- | Store the entire guessing model apart from the simplification function.+putGuesser :: (Binary t, Binary s, Ord s) => Guesser t s -> Put+putGuesser Guesser{..} = do+  put schemaConf+  put crf+  put zeroProbLab+  put unkTagSet+++-- | Get the disambiguation model, provided the simplification function.+-- getGuesser :: (M.Map t T.Tag) -> Get (Guesser t)+getGuesser :: (Binary t, Binary s, Ord s) => (t -> s) -> Get (Guesser t s)+getGuesser smp =+  Guesser <$> get <*> get <*> get <*> get <*> pure smp+++-- --------------------------+-- -- Simplify+-- --------------------------+--+--+-- -- | Simplify the given label.+-- simplify :: (Ord t) => Guesser t s -> t -> s+-- simplify Guesser{..} x =+--   case M.lookup x simpliMap of+--     Nothing -> zeroProbLab+--     Just y -> y+++--------------------------+-- Schematize+--------------------------+++-- | Schematize the input sentence according to the 'schema' rules.+-- TODO: looks like there is no reason at all for `Schema w t a` to+-- be parametrized with `t`?+schematize :: (X.Word w) => Schema w t a -> X.Sent w t -> CRF.Sent Ob t+schematize schema sent =+  DAG.mapE f sent+  where+    f i = const $ CRF.Word (obs i) (lbs i)+    obs = S.fromList . Ox.execOx . schema sent+    lbs i+      | X.oov w  = S.empty+      | otherwise = X.interpsSet w+      where w = DAG.edgeLabel i sent+++--------------------------+-- Marginals+--------------------------+++-- | Determine the marginal probabilities of the individual labels in the sentence.+marginals :: (X.Word w, Ord t, Ord s) => Guesser t s -> X.Sent w t -> DAG () (X.WMap t)+marginals gsr = fmap X.tags . marginalsSent gsr+++-- | Replace the probabilities of the sentence labels with the marginal probabilities+-- stemming from the model.+marginalsSent :: (X.Word w, Ord t, Ord s) => Guesser t s -> X.Sent w t -> X.Sent w t+marginalsSent gsr sent+  = (\new -> inject gsr new sent)+  . fmap tags+  . marginalsCRF gsr+  $ sent+  where+    tags = X.mkWMap . M.toList . considerZero . choice+    -- we mix the chosen and the potential interpretations together+    choice w = M.unionWith (+)+      (CRF.unProb . CRF.choice $ w)+      (M.fromList . map (,0) . interps $ w)+    interps = S.toList . CRF.lbs . CRF.word+    -- if empty, we choose the zero probability label.+    considerZero m+      | M.null m = M.singleton (zeroProbLab gsr) 0+      | otherwise = m+++-- | Ascertain the marginal probabilities of to individual labels in the sentence.+marginalsCRF :: (X.Word w, Ord t, Ord s) => Guesser t s -> X.Sent w t -> CRF.SentL Ob s+marginalsCRF gsr dag0 =+  let schema = fromConf (schemaConf gsr)+      dag = X.mapSent (simplify gsr) dag0+  in  CRF.marginals (crf gsr) (schematize schema dag)+++-- -- | Replace the probabilities of the sentence labels with the new probabilities+-- -- stemming from the CRF sentence.+-- inject :: DAG () (X.WMap t) -> X.Sent w t -> X.Sent w t+-- inject newSent srcSent =+--   let doit (new, src) = src {X.tags = new}+--   in  fmap doit (DAG.zipE newSent srcSent)+++-- | Replace the probabilities of the sentence labels with the new probabilities+-- stemming from the CRF sentence.+--+-- TODO: The behavior for OOV words seems unoptimal, since all possible labels+-- are taken into account, and not only the default CRF ones.  Still, it's not+-- necessarily a problem, maybe not even from the speed point of view.+--+inject+  :: (Ord t, Ord s, X.Word w)+  => Guesser t s+  -> DAG () (X.WMap s)+  -> X.Sent w t+  -> X.Sent w t+inject gsr newSent srcSent =+  let doit (target, src) =+        let oldTags = if X.oov (X.word src)+                      then X.mkWMap . map (,0) . S.toList . unkTagSet $ gsr+                      else X.tags src+            newTags = injectWMap gsr target oldTags+        in  src {X.tags = newTags}+  in  fmap doit (DAG.zipE newSent srcSent)+++-- -- | Replace label probabilities with the new probabilities.+-- inject+--   :: (Ord t, Ord s)+--   => Guesser t s+--   -> DAG () (X.WMap s)+--   -> DAG () (X.WMap t)+--   -> DAG () (X.WMap t)+-- inject gsr newDat srcDag =+--   let doit (newSpl, src) = injectWMap gsr newSpl src+--   in  fmap doit (DAG.zipE newDat srcDag)+++-- | Replace label probabilities with the new probabilities.+injectWMap+  :: (Ord t, Ord s)+  => Guesser t s+  -> X.WMap s+  -> X.WMap t+  -> X.WMap t+injectWMap gsr newSpl src = X.mkWMap+  [ ( tag+    , maybe 0 id $+      M.lookup (simplify gsr tag) (X.unWMap newSpl) )+  | (tag, _) <- M.toList (X.unWMap src) ]+++-- --------------------------+-- -- ???+-- --------------------------+--+--+--+-- -- -- | Determine the 'k' most probable labels for each word in the sentence.+-- -- guess :: (X.Word w, Ord t)+-- --       => Int -> Guesser t -> X.Sent w t -> [[t]]+-- -- guess k gsr sent =+-- --     let schema = fromConf (schemaConf gsr)+-- --     in  CRF.tagK k (crf gsr) (schematize schema sent)+--+--+-- -- -- | Insert guessing results into the sentence.  Only interpretations+-- -- -- of OOV words will be extended.+-- -- include :: (X.Word w, Ord t) => [[t]] -> X.Sent w t -> X.Sent w t+-- -- include xss sent =+-- --     [ word { X.tags = tags }+-- --     | (word, tags) <- zip sent sentTags ]+-- --   where+-- --     sentTags =+-- --         [ if X.oov word+-- --             then addInterps (X.tags word) xs+-- --             else X.tags word+-- --         | (xs, word) <- zip xss sent ]+-- --     addInterps wm xs = X.mkWMap+-- --         $  M.toList (X.unWMap wm)+-- --         ++ zip xs [0, 0 ..]+-- --+-- --+-- -- -- | Combine `guess` with `include`.+-- -- guessSent :: (X.Word w, Ord t)+-- --           => Int -> Guesser t+-- --           -> X.Sent w t -> X.Sent w t+-- -- guessSent guessNum guesser sent =+-- --     include (guess guessNum guesser sent) sent+-- --+++--------------------------+-- Training+--------------------------+++-- | Method of constructing the default set of labels (R0).+data R0T+    = AnyInterps        -- ^ See `CRF.anyInterps`+    | AnyChosen         -- ^ See `CRF.anyChosen`+    | OovChosen         -- ^ See `CRF.oovChosen`+    deriving (Show, Eq, Ord, Enum, Typeable, Data)+++-- | Training configuration.+data TrainConf t s = TrainConf+    { schemaConfT   :: SchemaConf+    -- | SGD parameters.+    , sgdArgsT      :: SGD.SgdArgs+    -- | Store SGD dataset on disk+    , onDiskT       :: Bool+    -- | R0 construction method+    , r0T           :: R0T+    -- | Zero probability label+    , zeroProbLabel :: t+    -- | Label simplification function+    , simplifyLabel :: t -> s+    -- | Strip the label from irrelevant information.  Used to determine othe set of+    -- possible tags for unknown words.+    , stripLabel :: t -> t+    -- | Guess only visible features+    , onlyVisible :: Bool+    }+++-- | Train guesser.+train+    :: (X.Word w, Ord t, Ord s)+    => TrainConf t s        -- ^ Training configuration+    -> IO [X.Sent w t]      -- ^ Training data+    -> IO [X.Sent w t]      -- ^ Evaluation data+    -> IO (Guesser t s)+train TrainConf{..} trainData evalData = do+  let schema = fromConf schemaConfT+      mkR0   = case r0T of+        AnyInterps  -> CRF.anyInterps+        AnyChosen   -> CRF.anyChosen+        OovChosen   -> CRF.oovChosen+      featExtract =+        if onlyVisible+        then const CRF.presentFeats+        else \r0 -> CRF.hiddenFeats r0 . map (fmap fst)+  tagSet <- S.unions . map (tagSetIn stripLabel) <$> trainData+--   let tagMap = M.fromList+--         [ (t, simplifyLabel t)+--         | t <- S.toList tagSet ]+  crf <- CRF.train sgdArgsT onDiskT+    -- mkR0 (const CRF.presentFeats)+    -- mkR0 (\r0 -> CRF.hiddenFeats r0 . map (fmap fst))+    mkR0 featExtract+    (schemed simplifyLabel schema <$> trainData)+    (schemed simplifyLabel schema <$> evalData)+  return $ Guesser schemaConfT crf (simplifyLabel zeroProbLabel) tagSet simplifyLabel+++-- | Schematized dataset.+schemed+  :: (X.Word w, Ord t, Ord s)+  => (t -> s)+  -> Schema w s a+  -> [X.Sent w t]+  -> [CRF.SentL Ob s]+schemed simpl schema =+    map onSent+  where+    onSent dag0 =+        let dag = X.mapSent simpl dag0+            mkProb = CRF.mkProb . M.toList . X.unWMap . X.tags+        in  fmap (uncurry CRF.mkWordL) $+            DAG.zipE (schematize schema dag) (fmap mkProb dag)+++-- | Retrieve the tagset in the given sentence, provided the stripping function+-- (see `stripLabel`).+tagSetIn :: (Ord t) => (t -> t) -> X.Sent w t -> S.Set t+tagSetIn strip dag = S.fromList+  [ strip tag+  | edgeID <- DAG.dagEdges dag+  , let edge = DAG.edgeLabel edgeID dag+  , tag <- M.keys . X.unWMap . X.tags $ edge ]
+ src/NLP/Concraft/DAG/Morphosyntax.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE FlexibleInstances #-}+++-- | Types and functions related to the morphosyntax data layer.+++module NLP.Concraft.DAG.Morphosyntax+(+-- * Segment+  Seg (..)+, mapSeg+, interpsSet+, interps++-- * Word class+, Word (..)++-- * Sentence+, Sent+, mapSent+, SentO (..)+, mapSentO++-- * Weighted collection+, module NLP.Concraft.Morphosyntax.WMap+) where+++import           Prelude hiding (Word)+import           Control.Applicative ((<$>), (<*>))+import           Control.Arrow (first)+import           Data.Aeson+import           Data.Binary (Binary)+import qualified Data.Set as S+import qualified Data.Map as M+import qualified Data.Text as T+import qualified Data.Text.Lazy as L++import qualified Data.DAG as DAG+import           Data.DAG (DAG)+-- import qualified Data.CRF.Chain1.Constrained.DAG.Dataset.Internal as DAG+-- import           Data.CRF.Chain1.Constrained.DAG.Dataset.Internal (DAG)++import           NLP.Concraft.Morphosyntax.WMap+++--------------------------+-- Segment+--------------------------+++-- | A segment parametrized over a word type and a tag type.+data Seg w t = Seg {+    -- | A word represented by the segment. Typically it will be an instance of+    -- the `Word` class.+      word  :: w+    -- | A set of interpretations. To each interpretation a weight of+    -- appropriateness within the context is assigned.+    , tags  :: WMap t }+    deriving (Show)+++instance ToJSON w => ToJSON (Seg w T.Text) where+    toJSON Seg{..} = object+        [ "word" .= word+        , "tags" .= unWMap tags ]++instance FromJSON w => FromJSON (Seg w T.Text) where+    parseJSON (Object v) = Seg+        <$> v .: "word"+        <*> (mkWMap <$> v .: "tags")+    parseJSON _ = error "parseJSON (segment): absurd"+++-- | Map function over segment tags.+mapSeg :: Ord b => (a -> b) -> Seg w a -> Seg w b+mapSeg f w = w { tags = mapWMap f (tags w) }+++-- | Interpretations of the segment.+interpsSet :: Seg w t -> S.Set t+interpsSet = M.keysSet . unWMap . tags+++-- | Interpretations of the segment.+interps :: Seg w t -> [t]+interps = S.toList . interpsSet+++--------------------------+-- Word class+--------------------------+++class Word a where+    -- | Orthographic form.+    orth    :: a -> T.Text+    -- | Out-of-vocabulary (OOV) word.+    oov     :: a -> Bool+++instance Word w => Word (Seg w t) where+    orth = orth . word+    {-# INLINE orth #-}+    oov = oov . word+    {-# INLINE oov #-}+++----------------------+-- Sentence+----------------------+++-- | A sentence.+-- type Sent w t = [Seg w t]+type Sent w t = DAG () (Seg w t)+++-- | Map function over sentence tags.+mapSent :: Ord b => (a -> b) -> Sent w a -> Sent w b+mapSent = fmap . mapSeg+++-- | A sentence with original, textual representation.+data SentO w t = SentO+    { segs  :: Sent w t+    , orig  :: L.Text }+    -- deriving (Show)+++-- | Map function over sentence tags.+mapSentO :: Ord b => (a -> b) -> SentO w a -> SentO w b+mapSentO f x =+    let segs' = mapSent f (segs x)+    in  x { segs = segs' }
+ src/NLP/Concraft/DAG/Morphosyntax/Accuracy.hs view
@@ -0,0 +1,304 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections #-}+++-- | Accuracy statistics.+++module NLP.Concraft.DAG.Morphosyntax.Accuracy+(+-- * Stats+  Stats(..)+, AccCfg (..)+, collect+, precision+, recall+, accuracy+) where+++import           Prelude hiding (Word)+import           GHC.Conc (numCapabilities)++import           Control.Arrow (first)+import qualified Control.Parallel.Strategies as Par++import           Data.List (transpose)+import qualified Data.Foldable as F+import qualified Data.Set as S+import qualified Data.Map.Strict as M+import qualified Data.Tagset.Positional as P++import qualified Data.DAG as DAG+import           NLP.Concraft.DAG.Morphosyntax+import           NLP.Concraft.DAG.Morphosyntax.Ambiguous+  (identifyAmbiguousSegments)+-- import           NLP.Concraft.DAG.Morphosyntax.Align++-- import qualified Data.Text as T+import Debug.Trace (trace)+++-- | Configuration of accuracy computation.+data AccCfg x = AccCfg+  { onlyOov   :: Bool+    -- ^ Limit calculations to OOV words+  , onlyAmb   :: Bool+    -- ^ Limit calculations to segmentation-ambiguous words+  , onlyMarkedWith :: S.Set x+    -- ^ Limit calculations to segments marked with one of the given labels;+    -- if empty, the option has no effect+  , accTagset :: P.Tagset+    -- ^ The underlying tagset+  , expandTag :: Bool+    -- ^ Should the tags be expanded?+  , ignoreTag :: Bool+    -- ^ Compute segmentation-level accurracy. The actually chosen tags are+    -- ignored, only information about the chosen DAG edges is relevant.+  , weakAcc :: Bool+    -- ^ If weak, there has to be an overlap in the tags assigned to a given+    -- segment in both datasets. Otherwise, the two sets of tags have to be+    -- identical.+  , discardProb0 :: Bool+    -- ^ Whether sentences with near 0 probability should be discarded from+    -- evaluation.+  , verbose :: Bool+    -- ^ Print information about compared elements+  }+++-- | True positives, false positives, etc.+data Stats = Stats+  { tp :: !Int+    -- ^ True positive+  , fp :: !Int+    -- ^ False positive+  , tn :: !Int+    -- ^ True negative+  , fn :: !Int+    -- ^ False negative+  , ce :: !Int+    -- ^ Consistency error (number of edges for which both `fp` and `fn` hold)+  } deriving (Show, Eq, Ord)+++-- | Initial statistics.+zeroStats :: Stats+zeroStats = Stats 0 0 0 0 0+++addStats :: Stats -> Stats -> Stats+addStats x y = Stats+  { tp = tp x + tp y+  , fp = fp x + fp y+  , tn = tn x + tn y+  , fn = fn x + fn y+  , ce = ce x + ce y+  }+++goodAndBad+  :: (Word w, Ord x, Show x)+  => AccCfg x+  -> Sent w (P.Tag, x) -- ^ Gold (reference) DAG+  -> Sent w (P.Tag, x) -- ^ Tagged (to compare) DAG+  -> Stats+goodAndBad cfg dag1 dag2+  | discardProb0 cfg && (dagProb dag1 < eps || dagProb dag2 < eps) = zeroStats+  | otherwise =+    -- By using `DAG.zipE'`, we allow the DAGs to be slighly different in terms+    -- of their edge sets.+      F.foldl' addStats zeroStats+      . DAG.mapE gather+      $ dag+  where+    eps = 1e-9++    dag = DAG.zipE' dag1 dag2+    ambiDag = identifyAmbiguousSegments dag++    traceThem gold tagg =+      if verbose cfg+      then trace+           ( let info = (,) <$> orth <*> choice cfg in+               "comparing '" +++               show (info <$> gold) +++               "' with '" +++               show (info <$> tagg) +++               "'"+           )+      else id++    gather edgeID (gold, tagg)+      | (onlyOov cfg `implies` isOov) &&+        (onlyAmb cfg `implies` isAmb) &&+        ((not . S.null) (onlyMarkedWith cfg) `implies` isMarked) =+          traceThem gold tagg $+          gather0+          (maybe S.empty (choice cfg) gold)+          (maybe S.empty (choice cfg) tagg)+      | otherwise = zeroStats+      where+        isOov = oov $ case (gold, tagg) of+          (Just seg, _) -> seg+          (_, Just seg) -> seg+          _ -> error "Accuracy.goodAndBad: impossible happened"+        hasMarker =+          any (`S.member` onlyMarkedWith cfg) . map (snd . fst) . M.toList+        isMarked = hasMarker $ case (gold, tagg) of+          (Just seg1, Just seg2) ->+            unWMap (tags seg1) `M.union` unWMap (tags seg2)+          (Just seg, _) -> unWMap $ tags seg+          (_, Just seg) -> unWMap $ tags seg+          _ -> error "Accuracy.goodAndBad: impossible2 happened"+        isAmb = DAG.edgeLabel edgeID ambiDag++    gather0 gold tagg+      | S.null gold && S.null tagg =+          zeroStats {tn = 1}+      | S.null gold =+          zeroStats {fp = 1}+      | S.null tagg =+          zeroStats {fn = 1}+      | otherwise =+          if consistent gold tagg+          then zeroStats {tp = 1}+          else zeroStats {fp = 1, fn = 1, ce = 1}++    consistent xs ys+      | weakAcc cfg = (not . S.null) (S.intersection xs ys)+      | otherwise = xs == ys+++goodAndBad'+  :: (Word w, Ord x, Show x)+  => AccCfg x+  -> [Sent w (P.Tag, x)]+  -> [Sent w (P.Tag, x)]+  -> Stats+goodAndBad' cfg goldData taggData =+  F.foldl' addStats zeroStats+  [ goodAndBad cfg dag1 dag2+  | (dag1, dag2) <- zip goldData taggData ]+++-- | Compute the accuracy of the model with respect to the labeled dataset.+-- To each `P.Tag` an additional information `x` can be assigned, which will be+-- taken into account when computing statistics.+collect+  :: (Word w, Ord x, Show x)+  => AccCfg x+  -> [Sent w (P.Tag, x)] -- ^ Gold dataset+  -> [Sent w (P.Tag, x)] -- ^ Tagged dataset (to be compare with the gold)+  -> Stats+collect cfg goldData taggData =+    let k = numCapabilities+        parts = partition k (zip goldData taggData)+        xs = Par.parMap Par.rseq (uncurry (goodAndBad' cfg) . unzip) parts+    in  F.foldl' addStats zeroStats xs+    -- in  fromIntegral good / fromIntegral (good + bad)+++precision :: Stats -> Double+precision Stats{..}+  = fromIntegral tp+  / fromIntegral (tp + fp)+++recall :: Stats -> Double+recall Stats{..}+  = fromIntegral tp+  / fromIntegral (tp + fn)+++accuracy :: Stats -> Double+accuracy Stats{..}+  = fromIntegral (tp + tn)+  / fromIntegral (tp + fp + tn + fn - ce)+  -- Not that, above, we substract `ce` so as to count inconsistency errors+  -- as single ones (their are accounted for twice in `fp + fn`).+++------------------------------------------------------+-- Verification+------------------------------------------------------+++-- | Compute the probability of the DAG, based on the probabilities assigned to+-- different edges and their labels.+dagProb :: Sent w t -> Double+dagProb dag = sum+  [ fromEdge edgeID+  | edgeID <- DAG.dagEdges dag+  , DAG.isInitialEdge edgeID dag ]+  where+    fromEdge edgeID+      = edgeProb edgeID+      * fromNode (DAG.endsWith edgeID dag)+    edgeProb edgeID =+      let Seg{..} = DAG.edgeLabel edgeID dag+      in  sum . map snd . M.toList $ unWMap tags+    fromNode nodeID =+      case DAG.outgoingEdges nodeID dag of+        [] -> 1+        xs -> sum (map fromEdge xs)+++-- -- | Filter out the sentences with ~0 probability.+-- verifyDataset :: [Sent w t] -> [Sent w t]+-- verifyDataset =+--   filter verify+--   where+--     verify dag = dagProb dag >= eps+--     eps = 1e-9+++--------------------------+-- Utils+--------------------------+++-- | Select the chosen tags.+--+--   * Tag expansion is performed here (if demanded)+--   * Tags are replaced by a dummy in case of `AmbiSeg` comparison+choice :: (Ord x) => AccCfg x -> Seg w (P.Tag, x) -> S.Set (P.Tag, x)+choice AccCfg{..}+  = S.fromList . expandMaybe . best+  where+    expandMaybe+      | ignoreTag = map (first $ const dummyTag)+      | expandTag = concatMap (\(tag, x) -> map (,x) $ P.expand accTagset tag)+      | otherwise = id+    dummyTag = P.Tag "AmbiSeg" M.empty+++-- | The best tags.+best :: Seg w t -> [t]+best seg+  | null zs   = []+  | otherwise =+      let maxProb = maximum (map snd zs)+      in  if maxProb < eps+          then []+          else map fst+               . filter ((>= maxProb - eps) . snd)+               $ zs+  where+    zs = M.toList . unWMap . tags $ seg+    eps = 1.0e-9+++partition :: Int -> [a] -> [[a]]+partition n =+    transpose . group n+  where+    group _ [] = []+    group k xs = take k xs : (group k $ drop k xs)+++-- | Implication.+implies :: Bool -> Bool -> Bool+implies p q = if p then q else True
+ src/NLP/Concraft/DAG/Morphosyntax/Ambiguous.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+++-- | Segmentation-level ambiguities. TODO: consider moving the module contents+-- to `NLP.Concraft.DAG`.+++module NLP.Concraft.DAG.Morphosyntax.Ambiguous+  ( identifyAmbiguousSegments+  ) where+++import qualified Data.MemoCombinators as Memo+import qualified Data.DAG as DAG+++------------------------------------------------------+-- Marking segmantation ambiguities+------------------------------------------------------+++-- | Identify ambigouos segments (roughly, segments which can be by-passed) in+-- the given DAG. Such ambiguous edges are marked in the resulting DAG with+-- `True` values.+identifyAmbiguousSegments :: DAG.DAG a b -> DAG.DAG a Bool+identifyAmbiguousSegments dag =+  flip DAG.mapE dag $ \edgeID _ ->+    incoming edgeID * outgoing edgeID < totalPathNum+  where+    incoming = inComingNum dag+    outgoing = outGoingNum dag+    totalPathNum = sum+      [ outgoing edgeID+      | edgeID <- DAG.dagEdges dag+      , DAG.isInitialEdge edgeID dag ]+++-- | Compute the number of paths from a starting edge to the given edge.+inComingNum :: DAG.DAG a b -> DAG.EdgeID -> Int+inComingNum dag =+  incoming+  where+    incoming =+      Memo.wrap DAG.EdgeID DAG.unEdgeID Memo.integral incoming'+    incoming' edgeID+      | DAG.isInitialEdge edgeID dag = 1+      | otherwise = sum $ do+          prevID <- DAG.prevEdges edgeID dag+          return $ incoming prevID+++-- | Compute the number of paths from the given edge to a target edge.+outGoingNum :: DAG.DAG a b -> DAG.EdgeID -> Int+outGoingNum dag =+  outgoing+  where+    outgoing =+      Memo.wrap DAG.EdgeID DAG.unEdgeID Memo.integral outgoing'+    outgoing' edgeID+      | DAG.isFinalEdge edgeID dag = 1+      | otherwise = sum $ do+          nextID <- DAG.nextEdges edgeID dag+          return $ outgoing nextID
+ src/NLP/Concraft/DAG/Schema.hs view
@@ -0,0 +1,393 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}++-- | Observation schema blocks for Concraft.++module NLP.Concraft.DAG.Schema+(+-- * Types+  Ob+, Ox+, Schema+, void+, sequenceS_++-- * Usage+, schematize++-- * Configuration+, Body (..)+, Entry+, entry+, entryWith+, SchemaConf (..)+, nullConf+, fromConf++-- * Schema blocks+, Block+, fromBlock+, orthB+, lowOrthB+, lowPrefixesB+, lowSuffixesB+, knownB+, shapeB+, packedB+, begPackedB+) where+++import Control.Applicative ((<$>), (<*>), pure)+import Control.Monad (forM_, guard)+import Data.Binary (Binary, put, get)+-- import qualified Data.Vector as V+import           Data.Maybe (maybeToList)+import qualified Data.Text as T+import qualified Control.Monad.Ox as Ox+import qualified Control.Monad.Ox.Text as Ox++import qualified Data.DAG as DAG+import           Data.DAG (DAG, EdgeID)++import qualified NLP.Concraft.DAG.Morphosyntax as X+++------------------------------+-- Basic Types+------------------------------+++-- | An observation consist of an index (of list type) and an actual+-- observation value.+type Ob = ([Int], T.Text)+++-- | The Ox monad specialized to word token type and text observations.+type Ox a = Ox.Ox T.Text a+++------------------------------+-- Schema+------------------------------+++-- | A schema is a block of the Ox computation performed within the+-- context of the sentence and the absolute sentence position.+type Schema w t a = X.Sent w t -> EdgeID -> Ox a+-- type Schema w t a = V.Vector (X.Seg w t) -> Int -> Ox a+++-- | A dummy schema block.+-- TODO: is it a monad, an applicative?+void :: a -> Schema w t a+void x _ _ = return x+++-- | Sequence the list of schemas (or blocks) and discard individual values.+sequenceS_+    :: [X.Sent w t -> a -> Ox b]+    ->  X.Sent w t -> a -> Ox ()+sequenceS_ xs sent =+    let ys = map ($sent) xs+    in  \k -> sequence_ (map ($k) ys)+++------------------------------+-- Primitive Observations+------------------------------+++-- | Record structure of the basic observation types.+data BaseOb = BaseOb+    { orth          :: EdgeID -> Maybe T.Text+    , lowOrth       :: EdgeID -> Maybe T.Text }+++-- | Construct the 'BaseOb' structure given the sentence.+mkBaseOb :: X.Word w => X.Sent w t -> BaseOb+mkBaseOb sent = BaseOb+    { orth      = _orth+    , lowOrth   = _lowOrth }+  where+    at          = onEdgeWith sent+    _orth       = (X.orth `at`)+    _lowOrth i  = T.toLower <$> _orth i+++------------------------------+-- Block+------------------------------+++-- | A block is a chunk of the Ox computation performed within the+-- context of the sentence and the list of absolute sentence positions.+type Block w t a = X.Sent w t -> [EdgeID] -> Ox a+++-- | Transform a block to a schema depending on+-- * A list of relative sentence positions,+-- * A boolean value; if true, the block computation+--   will be performed only on positions where an OOV+--   word resides.+fromBlock :: X.Word w => Block w t a -> [Int] -> Bool -> Schema w t a+fromBlock blk xs oovOnly sent = \i ->+  blkSent $ do+    x <- xs+    j <- maybeToList $ shift x i sent+    guard $ oov j+    return j+  -- \k -> blkSent [x + k | x <- xs, oov (x + k)]+  where+    blkSent = blk sent+    oov k   = if not oovOnly+      then True+      else maybe False id $ X.oov `at` k+    at      = onEdgeWith sent+++-- | Orthographic form at the current position.+orthB :: X.Word w => Block w t ()+orthB sent = \ks ->+    let orthOb = onEdgeWith sent X.orth+    in  mapM_ (Ox.save . orthOb) ks+++-- | Orthographic form at the current position.+lowOrthB :: X.Word w => Block w t ()+lowOrthB sent = \ks ->+    let BaseOb{..} = mkBaseOb sent+    in  mapM_ (Ox.save . lowOrth) ks+++-- | List of lowercased prefixes of given lengths.+lowPrefixesB :: X.Word w => [Int] -> Block w t ()+lowPrefixesB ns sent = \ks ->+    forM_ ks $ \i ->+        mapM_ (Ox.save . lowPrefix i) ns+  where+    BaseOb{..}      = mkBaseOb sent+    lowPrefix i j   = Ox.prefix j =<< lowOrth i+++-- | List of lowercased suffixes of given lengths.+lowSuffixesB :: X.Word w => [Int] -> Block w t ()+lowSuffixesB ns sent = \ks ->+    forM_ ks $ \i ->+        mapM_ (Ox.save . lowSuffix i) ns+  where+    BaseOb{..}      = mkBaseOb sent+    lowSuffix i j   = Ox.suffix j =<< lowOrth i+++-- | Shape of the word.+knownB :: X.Word w => Block w t ()+knownB sent = \ks -> do+    mapM_ (Ox.save . knownAt) ks+  where+    at          = onEdgeWith sent+    knownAt i   = boolF <$> (not . X.oov) `at` i+    boolF True  = "T"+    boolF False = "F"+++-- | Shape of the word.+shapeB :: X.Word w => Block w t ()+shapeB sent = \ks -> do+    mapM_ (Ox.save . shape) ks+  where+    BaseOb{..}      = mkBaseOb sent+    shape i         = Ox.shape <$> orth i+++-- | Packed shape of the word.+packedB :: X.Word w => Block w t ()+packedB sent = \ks -> do+    mapM_ (Ox.save . shapeP) ks+  where+    BaseOb{..}      = mkBaseOb sent+    shape i         = Ox.shape <$> orth i+    shapeP i        = Ox.pack <$> shape i+++-- | Packed shape of the word.+begPackedB :: X.Word w => Block w t ()+begPackedB sent = \ks -> do+    mapM_ (Ox.save . begPacked) ks+  where+    BaseOb{..}      = mkBaseOb sent+    shape i         = Ox.shape <$> orth i+    shapeP i        = Ox.pack <$> shape i+    begPacked i     = isBeg i <> pure "-" <> shapeP i+    isBeg i         = (Just . boolF) (i == 0)+    boolF True      = "T"+    boolF False     = "F"+    x <> y          = T.append <$> x <*> y+++------------------------------+-- Configuration+------------------------------+++-- | Body of configuration entry.+data Body a = Body {+    -- | Range argument for the schema block. +      range     :: [Int]+    -- | When true, the entry is used only for oov words.+    , oovOnly   :: Bool+    -- | Additional arguments for the schema block.+    , args      :: a }+    deriving (Show)++instance Binary a => Binary (Body a) where+    put Body{..} = put range >> put oovOnly >> put args+    get = Body <$> get <*> get <*> get++-- | Maybe entry.+type Entry a = Maybe (Body a)++-- | Entry with additional arguemnts.+entryWith :: a -> [Int] -> Entry a+entryWith v xs = Just (Body xs False v)+++-- | Plain entry with no additional arugments.+entry :: [Int] -> Entry ()+entry = entryWith ()+++-- | Configuration of the schema.  All configuration elements specify the+-- range over which a particular observation type should be taken on account.+-- For example, the @[-1, 0, 2]@ range means that observations of particular+-- type will be extracted with respect to previous (@k - 1@), current (@k@)+-- and after the next (@k + 2@) positions when identifying the observation+-- set for position @k@ in the input sentence.+data SchemaConf = SchemaConf {+    -- | The 'orthB' schema block.+      orthC             :: Entry ()+    -- | The 'lowOrthB' schema block.+    , lowOrthC          :: Entry ()+    -- | The 'lowPrefixesB' schema block.  The first list of ints+    -- represents lengths of prefixes.+    , lowPrefixesC      :: Entry [Int]+    -- | The 'lowSuffixesB' schema block.  The first list of ints+    -- represents lengths of suffixes.+    , lowSuffixesC      :: Entry [Int]+    -- | The 'knownB' schema block.+    , knownC            :: Entry ()+    -- | The 'shapeB' schema block.+    , shapeC            :: Entry ()+    -- | The 'packedB' schema block.+    , packedC            :: Entry ()+    -- | The 'begPackedB' schema block.+    , begPackedC         :: Entry ()+    } deriving (Show)++instance Binary SchemaConf where+    put SchemaConf{..} = do+        put orthC+        put lowOrthC+        put lowPrefixesC+        put lowSuffixesC+        put knownC+        put shapeC+        put packedC+        put begPackedC+    get = SchemaConf+        <$> get <*> get <*> get <*> get+        <*> get <*> get <*> get <*> get+++-- | Null configuration of the observation schema.+nullConf :: SchemaConf+nullConf = SchemaConf+    Nothing Nothing Nothing Nothing+    Nothing Nothing Nothing Nothing+++mkArg0 :: X.Word w => Block w t () -> Entry () -> Schema w t ()+mkArg0 blk (Just x) = fromBlock blk (range x) (oovOnly x)+mkArg0 _   Nothing  = void ()+++mkArg1 :: X.Word w => (a -> Block w t ()) -> Entry a -> Schema w t ()+mkArg1 blk (Just x) = fromBlock (blk (args x)) (range x) (oovOnly x)+mkArg1 _   Nothing  = void ()+++-- | Build the schema based on the configuration.+fromConf :: X.Word w => SchemaConf -> Schema w t ()+fromConf SchemaConf{..} = sequenceS_+    [ mkArg0 orthB orthC+    , mkArg0 lowOrthB lowOrthC+    , mkArg1 lowPrefixesB lowPrefixesC+    , mkArg1 lowSuffixesB lowSuffixesC+    , mkArg0 knownB knownC+    , mkArg0 shapeB shapeC+    , mkArg0 packedB packedC+    , mkArg0 begPackedB begPackedC ]+++-- -- | Use the schema to extract observations from the sentence.+-- schematize :: Schema w t a -> X.Sent w t -> [[Ob]]+-- schematize schema xs =+--     map (Ox.execOx . schema v) [0 .. n - 1]+--   where+--     v = V.fromList xs+--     n = V.length v+++-- | Use the schema to extract observations from the sentence.+schematize :: Schema w t a -> X.Sent w t -> DAG () [Ob]+schematize schema sent =+  let f = const . Ox.execOx . schema sent+  in  DAG.mapE f sent+++------------------------------+-- DAG+------------------------------+++-- | Value of the given function with respect to the given sentence and its+-- edge. Return Nothing if the edge is out of bounds.+onEdgeWith :: DAG x a -> (a -> b) -> EdgeID -> Maybe b+onEdgeWith dag f k = f <$> DAG.maybeEdgeLabel k dag+++-- | Value of the given function with respect to the given sentence and its+-- edge. Return `[]` if the edge is out of bounds.+onEdgeWith' :: DAG x a -> (a -> [b]) -> EdgeID -> [b]+onEdgeWith' dag f k =+  g $ f <$> DAG.maybeEdgeLabel k dag+  where+    g Nothing = []+    g (Just xs) = xs+++-- | Move the specified number of edges forward or backward. This implementation+-- always choses the shortest path, provided that DAG edges are topologicaly+-- sorted.+shift+  :: Int+  -- ^ Offset: how many edges to move forward (if positive)+  -- or backward (if negative)+  -> EdgeID+  -- ^ Move from where+  -> DAG a b+  -- ^ The underlying sentence+  -> Maybe EdgeID+  -- ^ The resulting edge ID+shift k i dag+  | k > 0 = do+      j <- mayHead $ DAG.nextEdges i dag+      shift (k - 1) j dag+  | k < 0 = do+      j <- mayTail $ DAG.prevEdges i dag+      shift (k + 1) j dag+  | otherwise = return i+  where+    mayHead (x:xs) = Just x+    mayHead [] = Nothing+    mayTail = mayHead . reverse
+ src/NLP/Concraft/DAG/Segmentation.hs view
@@ -0,0 +1,334 @@+{-# LANGUAGE RecordWildCards #-}+++-- | Baseline word-segmentation functions.+++module NLP.Concraft.DAG.Segmentation+( PathTyp (..)+, pickPath+, findPath++-- * Frequencies+, computeFreqs+, FreqConf (..)++-- * Ambiguity-related stats+, computeAmbiStats+, AmbiCfg (..)+, AmbiStats (..)+) where+++import           Control.Monad (guard)+-- import qualified Control.Monad.State.Strict as State+import qualified Data.Foldable as F++import qualified Data.MemoCombinators as Memo+import qualified Data.Set as S+import qualified Data.Map.Strict as M+import qualified Data.List as L+import qualified Data.Text as T+import           Data.Ord (comparing)++import           Data.DAG (DAG)+import qualified Data.DAG as DAG++-- import qualified Data.Tagset.Positional as P++import qualified NLP.Concraft.DAG.Morphosyntax as X+import qualified NLP.Concraft.DAG.Morphosyntax.Ambiguous as Ambi+++------------------------------------+-- Shortest-path segmentation+------------------------------------++-- | Configuration related to frequency-based path picking.+data FreqConf = FreqConf+  { pickFreqMap :: M.Map T.Text (Int, Int)+    -- ^ A map which assigns (chosen, not chosen) counts to the invidiaul+    -- orthographic forms (see `computeFreqs`).+  , smoothingParam :: Double+    -- ^ A naive smoothing related parameter, which should be adddd to each+    -- count in `pickFreqMap`.+--   , orth :: DAG.EdgeID -> T.Text+--     -- ^ Orthographic form of a given edge+  }+++-- | Which path type to search: shortest (`Min`) or longest (`Max`)+data PathTyp+  = Min+  | Max+  | Freq FreqConf+++-- | Select the shortest-path (or longest, depending on `PathTyp`) in the given+-- DAG and remove all the edges which are not on this path.+pickPath+  :: (X.Word b)+  => PathTyp+  -> DAG a b+  -> DAG a b+pickPath pathTyp dag =+  let+    dag' = DAG.filterDAG (findPath pathTyp dag) dag+  in+    if DAG.isOK dag'+    then dag'+    else error "Segmentation.pickPath: the resulting DAG not correct"+++-- | Retrieve the edges which belong to the shortest/longest (depending on the+-- argument function: `minimum` or `maximum`) path in the given DAG.+findPath+  :: (X.Word b)+  => PathTyp+  -> DAG a b+  -> S.Set DAG.EdgeID+findPath pathTyp dag+  = S.fromList . pickNode . map fst+  -- Below, we take the node with the smallest (reverse) or highest (no reverse)+  -- distance to a target node, depending on the path type (`Min` or `Max`).+  . reverseOrNot+  . L.sortBy (comparing snd)+  $ sourceNodes+  where+    sourceNodes = do+      nodeID <- DAG.dagNodes dag+      guard . null $ DAG.ingoingEdges nodeID dag+      return (nodeID, dist nodeID)+    reverseOrNot = case pathTyp of+      Max -> reverse+      _ -> id+    forward nodeID+      | null (DAG.outgoingEdges nodeID dag) = []+      | otherwise = pick $ do+          nextEdgeID <- DAG.outgoingEdges nodeID dag+          let nextNodeID = DAG.endsWith nextEdgeID dag+          -- guard $ dist nodeID == dist nextNodeID + 1+          guard $ dist nodeID == dist nextNodeID + arcLen nextEdgeID+          -- return nextNodeID+          return nextEdgeID+    pickNode ids = case ids of+      nodeID : _ -> forward nodeID+      [] -> error "Segmentation.pickPath: no node to pick!?"+    pick ids = case ids of+      edgeID : _ -> edgeID : forward (DAG.endsWith edgeID dag)+      [] -> error "Segmentation.pickPath: nothing to pick!?"+    dist = computeDist pathTyp dag+    -- distance between two nodes connected by an arc+    arcLen =+      case pathTyp of+        Freq conf -> computeArcLen conf dag+        _ -> const 1+++------------------------------------+-- Distance from target nodes+------------------------------------+++-- | Compute the minimal/maximal distance (depending on the argument function)+-- from each node to a target node.+computeDist+  :: (X.Word b)+  => PathTyp+  -> DAG a b+  -> DAG.NodeID+  -> Double+computeDist pathTyp dag =+  dist+  where+    minMax = case pathTyp of+      Max -> maximum+      _ -> minimum+    dist =+      Memo.wrap DAG.NodeID DAG.unNodeID Memo.integral dist'+    dist' nodeID+      | null (DAG.outgoingEdges nodeID dag) = 0+      | otherwise = minMax $ do+          nextEdgeID <- DAG.outgoingEdges nodeID dag+          let nextNodeID = DAG.endsWith nextEdgeID dag+          -- return $ dist nextNodeID + 1+          return $ dist nextNodeID + arcLen nextEdgeID+    arcLen =+      case pathTyp of+        Freq conf -> computeArcLen conf dag+        _ -> const 1+++------------------------------------+-- Frequency-based segmentation+------------------------------------+++-- | Compute chosen/not-chosen counts of the individual orthographic forms in+-- the DAGs. Only the ambiguous segments are taken into account.+computeFreqs :: (X.Word w) => [X.Sent w t] -> M.Map T.Text (Int, Int)+computeFreqs dags = M.fromListWith addBoth $ do+  dag <- dags+  let ambiDAG = Ambi.identifyAmbiguousSegments dag+  edgeID <- DAG.dagEdges dag+  guard $ DAG.edgeLabel edgeID ambiDAG == True+  let seg = DAG.edgeLabel edgeID dag+      orth = edgeOrth seg+      edgeWeight = sum . M.elems . X.unWMap . X.tags $ seg+      eps = 1e-9+  return $+    if edgeWeight > eps+    then (orth, (1, 0))+    else (orth, (0, 1))+  where+    addBoth (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)+++computeArcLen+  :: (X.Word b)+  => FreqConf+  -> DAG a b+  -> DAG.EdgeID+  -> Double+computeArcLen FreqConf{..} dag edgeID =+  (\x -> -x) . log $+    case M.lookup (edgeOrth $ DAG.edgeLabel edgeID dag) pickFreqMap of+      Just (chosen, notChosen) ->+        (fromIntegral chosen + smoothingParam) /+        (fromIntegral (chosen + notChosen) + smoothingParam*2)+      Nothing -> 0.5 -- smoothingParam / (smoothingParam*2)+++-- | Retrieve the orthographic representation of a given segment for the purpose+-- of frequency-based segmentation.+edgeOrth :: X.Word w => w -> T.Text+edgeOrth = T.toLower . T.strip . X.orth+++------------------------------------+-- Frequency-based segmentation+--+-- How this can work?+--+-- For each segment (i.e, a particular orthographic form) we would like to find+-- a simple measure of how likely it is to use it in a segmentation.+--+-- # Solution 1+--+-- A simple way would be to determine the probability as follows:+--+--   p(orth) = chosen(orth) / possible(orth)+--+-- where `chosen(orth)` is the number of *chosen* (disamb) edges in the training+-- dataset whose orthographic form is `orth`, and `possible(orth)` is the total+-- number of edges in train with the `orth` orthographic form.+--+-- Now, the problem is that we would need to use smoothing to account for forms+-- not in the training dataset:+--+--   p(orth) = chosen(orth) + 1 / possible(orth) + 2+--+-- The reason to add 2 in the denominator is that it can be rewritten as:+--+--   p(orth) = chosen(orth) + 1 / chosen(orth) + 1 + not-chosen(orth) + 1+--+-- So the default probability is 1/2.  Not too bad?+--+-- # Solution 2+--+-- An alternative would be to decide, for a given segment, whether it should be+-- taken or not. For example, if a given segment (i.e., orthographic form) is+-- chosen in more than a half of situations where it can actually be chosen,+-- then it should belong to the path.  Otherwise, it should not.+--+-- Then we have to choose how to represent the fact that the edge should be+-- taken (i.e. should belong to a path). One way to do that is to say that, if+-- the form is chosen, its weight is 0; otherwise, its weight is 1. This does+-- not account for the length of edges, so another solution would be to say that+-- if the edge/form is chosen, then its weight is 0; otherwise, it is equal to+-- its length. Then again, the length of an edge can be computed in several+-- manners, e.g., as the string length of the orthographic form, or as the+-- number of segments which can be used inside. But the latter is not always+-- possible to compute.+--+-- # Choice+--+-- For now, solution 1 seems more principled. So we need to compute a map from+-- orthographic forms to pairs of (chosen, not chosen) counts on the basis of+-- the training dataset. Afterwards, we use "naive" smoothing+-- (http://ivan-titov.org/teaching/nlmi-15/lecture-4.pdf) and transform the+-- resulting probability with `(-) . log`. This gives as a positive value+-- assigned to each segment, and we need to find the path with the lowest+-- weigth.+------------------------------------+++------------------------------------+-- Ambiguity stats+------------------------------------+++-- | Numbers of tokens.+data AmbiCfg = AmbiCfg+  { onlyChosen :: Bool+    -- ^ Only take the chosen tokens into account+  } deriving (Show, Eq, Ord)+++-- | Numbers of tokens.+data AmbiStats = AmbiStats+  { ambi :: !Int+    -- ^ Ambiguous tokens+  , total :: !Int+    -- ^ All tokens+  } deriving (Show, Eq, Ord)+++-- | Initial statistics.+zeroAmbiStats :: AmbiStats+zeroAmbiStats = AmbiStats 0 0+++addAmbiStats :: AmbiStats -> AmbiStats -> AmbiStats+addAmbiStats x y = AmbiStats+  { ambi = ambi x + ambi y+  , total = total x + total y+  }+++-- | Compute:+-- * the number of tokens participating in ambiguities+-- * the total number of tokens+computeAmbiStats+  :: (X.Word w)+  => AmbiCfg+  -> [X.Sent w t]+  -> AmbiStats+computeAmbiStats cfg sents =+  F.foldl' addAmbiStats zeroAmbiStats+  [ ambiStats cfg sent+  | sent <- sents ]+++ambiStats+  :: (X.Word w)+  => AmbiCfg+  -> X.Sent w t+  -> AmbiStats+ambiStats AmbiCfg{..} dag+  = F.foldl' addAmbiStats zeroAmbiStats+  . DAG.mapE gather+  $ DAG.zipE dag ambiDag+  where+    ambiDag = Ambi.identifyAmbiguousSegments dag+    gather edgeID (seg, isAmbi)+      | isAmbi && prob >= eps =+          AmbiStats {ambi = 1, total = 1}+      | prob >= eps =+          AmbiStats {ambi = 0, total = 1}+      | otherwise =+          AmbiStats {ambi = 0, total = 0}+      where+        isChosen = (prob >= eps) || (not onlyChosen)+        prob = sum . M.elems . X.unWMap $ X.tags seg+        eps = 0.5
+ src/NLP/Concraft/DAG2.hs view
@@ -0,0 +1,369 @@+{-# LANGUAGE RecordWildCards #-}+++-- | Top-level module adated to DAGs, guessing and disambiguation.+++module NLP.Concraft.DAG2+(+-- * Model+  Concraft (..)+, saveModel+, loadModel+++-- * Annotation+, Anno+, replace++-- * Best paths+, findOptimalPaths+, disambPath++-- * Marginals+-- , D.ProbType (..)+, guessMarginals+, disambMarginals+, disambProbs++-- * Tagging+, guess+, guessSent+, tag+-- , tag'++-- * Training+, train++-- * Pruning+, prune+) where+++import           System.IO (hClose)+import           Control.Applicative ((<$>), (<*>)) -- , (<|>))+import           Control.Arrow (first)+import           Control.Monad (when, guard)+-- import           Data.Maybe (listToMaybe)+import qualified Data.Foldable as F+import qualified Data.Set as S+import qualified Data.Map.Strict as M+import           Data.Binary (Binary, put, get, Put, Get)+import qualified Data.Binary as Binary+import           Data.Binary.Put (runPut)+import           Data.Binary.Get (runGet)+import           Data.Aeson+import qualified System.IO.Temp as Temp+import qualified Data.ByteString.Lazy as BL+import qualified Codec.Compression.GZip as GZip++import           Data.DAG (DAG, EdgeID)+import qualified Data.DAG as DAG++import qualified Data.Tagset.Positional as P++-- import           NLP.Concraft.Analysis+import           NLP.Concraft.Format.Temp+import qualified NLP.Concraft.DAG.Morphosyntax as X+import           NLP.Concraft.DAG.Morphosyntax (Sent, WMap)+import qualified NLP.Concraft.DAG.Guess as G+import qualified NLP.Concraft.DAG.Disamb as D+++---------------------+-- Model+---------------------+++modelVersion :: String+modelVersion = "dag2:0.11"+++-- | Concraft data.+data Concraft t = Concraft+  { tagset        :: P.Tagset+  , guessNum      :: Int+  , guesser       :: G.Guesser t P.Tag+  , disamb        :: D.Disamb t }+++-- instance (Ord t, Binary t) => Binary (Concraft t) where+--     put Concraft{..} = do+--         put modelVersion+--         put tagset+--         put guessNum+--         put guesser+--         put disamb+--     get = do+--         comp <- get+--         when (comp /= modelVersion) $ error $+--             "Incompatible model version: " ++ comp +++--             ", expected: " ++ modelVersion+--         Concraft <$> get <*> get <*> get  <*> get+++putModel :: (Ord t, Binary t) => Concraft t -> Put+putModel Concraft{..} = do+  put modelVersion+  put tagset+  put guessNum+  G.putGuesser guesser+  D.putDisamb disamb+++-- | Get the model, given the tag simplification function for the disambigutation model.+getModel+  :: (Ord t, Binary t)+  => (P.Tagset -> t -> P.Tag)+     -- ^ Simplification function+  -> Get (Concraft t)+getModel smp = do+  comp <- get+  when (comp /= modelVersion) $ error $+    "Incompatible model version: " ++ comp +++    ", expected: " ++ modelVersion+  tagset <- get+  Concraft tagset <$> get <*> G.getGuesser (smp tagset) <*> D.getDisamb (smp tagset)+++-- | Save model in a file.  Data is compressed using the gzip format.+saveModel :: (Ord t, Binary t) => FilePath -> Concraft t -> IO ()+-- saveModel path = BL.writeFile path . GZip.compress . Binary.encode+saveModel path = BL.writeFile path . GZip.compress . runPut . putModel+++-- | Load model from a file.+loadModel :: (Ord t, Binary t) => (P.Tagset -> t -> P.Tag) -> FilePath -> IO (Concraft t)+loadModel smp path = do+    -- x <- Binary.decode . GZip.decompress <$> BL.readFile path+    x <- runGet (getModel smp) . GZip.decompress <$> BL.readFile path+    x `seq` return x+++----------------------+-- Annotation+----------------------+++-- | DAG annotation, assignes @b@ values to @a@ labels for each edge in the+-- graph.+type Anno a b = DAG () (M.Map a b)+++-- | Replace sentence probability values with the given annotation.+replace :: (Ord t) => Anno t Double -> Sent w t -> Sent w t+replace anno sent =+  fmap join $ DAG.zipE anno sent+  where+    join (m, seg) = seg {X.tags = X.fromMap m}+--     apply f+--       = X.fromMap+--       . M.mapWithKey (\key _val -> f M.! key)+--       . X.unWMap+++-- | Extract marginal annotations from the given sentence.+extract :: Sent w t -> Anno t Double+extract = fmap $ X.unWMap . X.tags+++----------------------+-- Best path+----------------------+++-- | Find all optimal paths in the given annotation. Optimal paths are those+-- which go through tags with the assigned probability 1.+findOptimalPaths :: Anno t Double -> [[(EdgeID, t)]]+findOptimalPaths dag = do+  edgeID <- DAG.dagEdges dag+  guard $ DAG.isInitialEdge edgeID dag+  doit edgeID+  where+    doit i = inside i ++ final i+    inside i = do+      (tag, weight) <- M.toList (DAG.edgeLabel i dag)+      guard $ weight >= 1.0 - eps+      j <- DAG.nextEdges i dag+      xs <- doit j+      return $ (i, tag) : xs+    final i = do+      guard $ DAG.isFinalEdge i dag+      (tag, weight) <- M.toList (DAG.edgeLabel i dag)+      guard $ weight >= 1.0 - eps+      return [(i, tag)]+    eps = 1.0e-9+++-- | Make the given path with disamb markers in the given annotation+-- and produce a new disamb annotation.+disambPath :: (Ord t) => [(EdgeID, t)] -> Anno t Double -> Anno t Bool+disambPath path =+  DAG.mapE doit+  where+    pathMap = M.fromList path+    doit edgeID m = M.fromList $ do+      let onPath = M.lookup edgeID pathMap+      x <- M.keys m+      return (x, Just x == onPath)+++----------------------+-- Marginals and Probs+----------------------+++-- | Determine marginal probabilities corresponding to individual+-- tags w.r.t. the guessing model.+guessMarginals :: (X.Word w, Ord t) => G.Guesser t P.Tag -> Sent w t -> Anno t Double+guessMarginals gsr = fmap X.unWMap . G.marginals gsr+++-- | Determine marginal probabilities corresponding to individual+-- tags w.r.t. the guessing model.+disambMarginals :: (X.Word w, Ord t) => D.Disamb t -> Sent w t -> Anno t Double+-- disambMarginals dmb = fmap X.unWMap . D.marginals dmb+disambMarginals = disambProbs D.Marginals+++-- | Determine probabilities corresponding to individual+-- tags w.r.t. the guessing model.+disambProbs :: (X.Word w, Ord t) => D.ProbType -> D.Disamb t -> Sent w t -> Anno t Double+disambProbs typ dmb = fmap X.unWMap . D.probs typ dmb+++-------------------------------------------------+-- Trimming+-------------------------------------------------+++-- | Trim down the set of potential labels to `k` most probable ones+-- for each OOV word in the sentence.+trimOOV :: (X.Word w, Ord t) => Int -> Sent w t -> Sent w t+trimOOV k =+  fmap trim+  where+    trim edge = if X.oov edge+      then trimEdge edge+      else edge+    trimEdge edge = edge {X.tags = X.trim k (X.tags edge)}+++---------------------+-- Tagging+---------------------+++-- | Determine marginal probabilities corresponding to individual tags w.r.t.+-- the guessing model and, afterwards, trim the sentence to keep only the `k`+-- most probably labels for each OOV edge. Note that, for OOV words, the entire+-- set of default tags is considered.+guessSent :: (X.Word w, Ord t) => Int -> G.Guesser t P.Tag -> Sent w t -> Sent w t+guessSent k gsr sent = trimOOV k $ replace (guessMarginals gsr sent) sent+++-- | Perform guessing, trimming, and finally determine marginal probabilities+-- corresponding to individual tags w.r.t. the guessing model.+guess :: (X.Word w, Ord t) => Int -> G.Guesser t P.Tag -> Sent w t -> Anno t Double+guess k gsr = extract . guessSent k gsr+++-- | Perform guessing, trimming, and finally determine marginal probabilities+-- corresponding to individual tags w.r.t. the disambiguation model.+tag :: (X.Word w, Ord t) => Int -> Concraft t -> Sent w t -> Anno t Double+tag k crf = disambMarginals (disamb crf) . guessSent k (guesser crf)+++-- -- | Perform guessing, trimming, and finally determine probabilities+-- -- corresponding to individual tags w.r.t. the disambiguation model.+-- tag' :: X.Word w => Int -> D.ProbType -> Concraft -> Sent w P.Tag -> Anno P.Tag Double+-- tag' k typ Concraft{..} = disambProbs typ disamb . guessSent k guesser+++---------------------+-- Training+---------------------+++-- | Train the `Concraft` model.+-- No reanalysis of the input data will be performed.+--+-- The `FromJSON` and `ToJSON` instances are used to store processed+-- input data in temporary files on a disk.+train+    :: (X.Word w, Ord t)+    => P.Tagset             -- ^ A morphosyntactic tagset to which `P.Tag`s+                            --   of the training and evaluation input data+                            --   must correspond.+    -> Int                  -- ^ How many tags is the guessing model supposed+                            --   to produce for a given OOV word?  It will be+                            --   used (see `G.guessSent`) on both training and+                            --   evaluation input data prior to the training+                            --   of the disambiguation model.+    -> G.TrainConf t P.Tag  -- ^ Training configuration for the guessing model.+    -> D.TrainConf t        -- ^ Training configuration for the+                            --   disambiguation model.+    -> IO [Sent w t]    -- ^ Training dataset.  This IO action will be+                            --   executed a couple of times, so consider using+                            --   lazy IO if your dataset is big.+    -> IO [Sent w t]    -- ^ Evaluation dataset IO action.  Consider using+                            --   lazy IO if your dataset is big.+    -> IO (Concraft t)+train tagset guessNum guessConf disambConf trainR'IO evalR'IO = do+  Temp.withTempDirectory "." ".guessed" $ \tmpDir -> do+  let temp = withTemp tagset tmpDir++  putStrLn "\n===== Train guessing model ====="+  guesser <- G.train guessConf trainR'IO evalR'IO+  let guess = guessSent guessNum guesser+  trainG  <- map guess <$> trainR'IO+  evalG   <- map guess <$> evalR'IO++  temp "train" trainG $ \trainG'IO -> do+  temp "eval"  evalG  $ \evalG'IO  -> do++  putStrLn "\n===== Train disambiguation model ====="+  disamb <- D.train disambConf trainG'IO evalG'IO+  return $ Concraft tagset guessNum guesser disamb+++---------------------+-- Temporary storage+---------------------+++-- | Store dataset on a disk and run a handler on a list which is read+-- lazily from the disk.  A temporary file will be automatically+-- deleted after the handler is done.+--+-- NOTE: (11/11/2017): it's just a dummy function right now, which does+-- not use disk storage at all.+--+withTemp+  -- :: (FromJSON w, ToJSON w)+  :: P.Tagset+  -> FilePath                     -- ^ Directory to create the file in+  -> String                       -- ^ Template for `Temp.withTempFile`+  -> [Sent w t]                   -- ^ Input dataset+  -> (IO [Sent w t] -> IO a)      -- ^ Handler+  -> IO a+withTemp _      _   _    [] handler = handler (return [])+withTemp tagset dir tmpl xs handler =+  Temp.withTempFile dir tmpl $ \tmpPath tmpHandle -> do+    hClose tmpHandle+    let txtSent = X.mapSent $ P.showTag tagset+        tagSent = X.mapSent $ P.parseTag tagset+    handler (return xs)+++---------------------+-- Pruning+---------------------+++-- | Prune disambiguation model: discard model features with+-- absolute values (in log-domain) lower than the given threshold.+prune :: Double -> Concraft t -> Concraft t+prune x concraft =+    let disamb' = D.prune x (disamb concraft)+    in  concraft { disamb = disamb' }
+ src/NLP/Concraft/DAGSeg.hs view
@@ -0,0 +1,436 @@+{-# LANGUAGE RecordWildCards #-}+++-- | Top-level module adated to DAGs, guessing and disambiguation.+++module NLP.Concraft.DAGSeg+(+-- * Model+  Concraft (..)+, saveModel+, loadModel+++-- * Annotation+, Anno++-- * Best paths+, findOptimalPaths+, disambPath++-- * Marginals+-- , D.ProbType (..)+, guessMarginals+, disambMarginals+, disambProbs++-- * Tagging+, guessSent+, guess+, tag+-- , tag'++-- -- * Training+-- , train++-- * Pruning+, prune+) where+++-- import           Prelude hiding (Word)+import           System.IO (hClose)+import           Control.Applicative ((<$>), (<*>)) -- , (<|>))+import           Control.Arrow (first, second)+import           Control.Monad (when, guard)+-- import           Data.Maybe (listToMaybe)+import qualified Data.Foldable as F+import qualified Data.Set as S+import qualified Data.Map.Strict as M+import           Data.Binary (Binary, put, get, Put, Get)+import qualified Data.Binary as Binary+import           Data.Binary.Put (runPut)+import           Data.Binary.Get (runGet)+import           Data.Aeson+import qualified System.IO.Temp as Temp+import qualified Data.ByteString.Lazy as BL+import qualified Codec.Compression.GZip as GZip+import           Data.Ord (comparing)+import           Data.List (sortBy)++import           Data.DAG (DAG, EdgeID)+import qualified Data.DAG as DAG++import qualified Data.Tagset.Positional as P++-- import           NLP.Concraft.Analysis+import           NLP.Concraft.Format.Temp+import qualified NLP.Concraft.DAG.Morphosyntax as X+import           NLP.Concraft.DAG.Morphosyntax (Sent, WMap)+import qualified NLP.Concraft.DAG.Guess as G+import qualified NLP.Concraft.DAG.DisambSeg as D+++---------------------+-- Model+---------------------+++modelVersion :: String+modelVersion = "dagseg:0.11"+++-- | Concraft data.+data Concraft t = Concraft+  { tagset        :: P.Tagset+  , guessNum      :: Int+  , guesser       :: G.Guesser t P.Tag+  , segmenter     :: D.Disamb t+  , disamb        :: D.Disamb t+  }+++putModel :: (Ord t, Binary t) => Concraft t -> Put+putModel Concraft{..} = do+  put modelVersion+  put tagset+  put guessNum+  G.putGuesser guesser+  D.putDisamb segmenter+  D.putDisamb disamb+++-- | Get the model, given the tag simplification function for the disambigutation model.+getModel+  :: (Ord t, Binary t)+  => (P.Tagset -> t -> P.Tag)+     -- ^ Guesser simplification function+  -> (P.Tagset -> t -> D.Tag)+     -- ^ Segmentation/disamb simplification function (TODO: two different+     -- simplification functions?)+  -> Get (Concraft t)+getModel gsrSmp dmbSmp = do+  comp <- get+  when (comp /= modelVersion) $ error $+    "Incompatible model version: " ++ comp +++    ", expected: " ++ modelVersion+  tagset <- get+  Concraft tagset <$> get+    <*> G.getGuesser (gsrSmp tagset)+    <*> D.getDisamb (dmbSmp tagset)+    <*> D.getDisamb (dmbSmp tagset)+++-- | Save model in a file.  Data is compressed using the gzip format.+saveModel :: (Ord t, Binary t) => FilePath -> Concraft t -> IO ()+-- saveModel path = BL.writeFile path . GZip.compress . Binary.encode+saveModel path = BL.writeFile path . GZip.compress . runPut . putModel+++-- | Load model from a file.+loadModel+  :: (Ord t, Binary t)+  => (P.Tagset -> t -> P.Tag)+     -- ^ Guesser simplification function+  -> (P.Tagset -> t -> D.Tag)+     -- ^ Disamb simplification function+  -> FilePath+  -> IO (Concraft t)+loadModel gsrSmp dmbSmp path = do+    -- x <- Binary.decode . GZip.decompress <$> BL.readFile path+    x <- runGet (getModel gsrSmp dmbSmp) . GZip.decompress <$> BL.readFile path+    x `seq` return x+++----------------------+-- Annotation+----------------------+++-- | DAG annotation, assignes @b@ values to @a@ labels for each edge in the+-- graph.+type Anno a b = DAG () (M.Map a b)+++-- | Replace sentence probability values with the given annotation.+replace :: (Ord t) => Anno t Double -> Sent w t -> Sent w t+replace anno sent =+  fmap join $ DAG.zipE anno sent+  where+    join (m, seg) = seg {X.tags = X.fromMap m}+++-- | Insert the guessing results into the sentence. Only interpretations of OOV+-- words will be extended.  The probabilities of the new tags are set to 0.+insertGuessed :: (X.Word w, Ord t) => Anno t Double -> Sent w t -> Sent w t+insertGuessed anno sent =+  fmap join $ DAG.zipE anno sent+  where+    join (gueMap, seg)+      | X.oov (X.word seg) =+          let oldMap  = X.unWMap (X.tags seg)+              gueMap0 = M.fromList+                      . map (second $ const 0)+                      $ M.toList gueMap+              newMap  = M.unionWith (+) oldMap gueMap0+          in  seg {X.tags = X.fromMap newMap}+      | otherwise = seg+++-- | Extract marginal annotations from the given sentence.+extract :: Sent w t -> Anno t Double+extract = fmap $ X.unWMap . X.tags+++----------------------+-- Best path+----------------------+++-- -- | Find all optimal paths in the given annotation. Optimal paths are those+-- -- which go through tags with the assigned probability 1.+-- findOptimalPaths :: Anno t Double -> [[(EdgeID, t)]]+-- findOptimalPaths dag = do+--   edgeID <- DAG.dagEdges dag+--   guard $ DAG.isInitialEdge edgeID dag+--   doit edgeID+--   where+--     doit i = inside i ++ final i+--     inside i = do+--       (tag, weight) <- M.toList (DAG.edgeLabel i dag)+--       guard $ weight >= 1.0 - eps+--       j <- DAG.nextEdges i dag+--       xs <- doit j+--       return $ (i, tag) : xs+--     final i = do+--       guard $ DAG.isFinalEdge i dag+--       (tag, weight) <- M.toList (DAG.edgeLabel i dag)+--       guard $ weight >= 1.0 - eps+--       return [(i, tag)]+--     eps = 1.0e-9+++-- | Find all optimal paths in the given annotation. Optimal paths are those+-- which go through tags with the assigned probability 1. For a given chosen+-- edge, all the tags with probability 1 are selected.+findOptimalPaths :: Ord t => Anno t Double -> [[(EdgeID, S.Set t)]]+findOptimalPaths dag = do+  edgeID <- DAG.dagEdges dag+  guard $ DAG.isInitialEdge edgeID dag+  doit edgeID+  where+    doit i = inside i ++ final i+    inside i = do+      let tags =+            [ tag+            | (tag, weight) <- M.toList (DAG.edgeLabel i dag)+            , weight >= 1.0 - eps ]+      guard . not $ null tags+      j <- DAG.nextEdges i dag+      xs <- doit j+      return $ (i, S.fromList tags) : xs+    final i = do+      guard $ DAG.isFinalEdge i dag+      let tags =+            [ tag+            | (tag, weight) <- M.toList (DAG.edgeLabel i dag)+            , weight >= 1.0 - eps ]+      guard . not $ null tags+      return [(i, S.fromList tags)]+    eps = 1.0e-9+++-- -- | Make the given path with disamb markers in the given annotation+-- -- and produce a new disamb annotation.+-- disambPath :: (Ord t) => [(EdgeID, t)] -> Anno t Double -> Anno t Bool+-- disambPath path =+--   DAG.mapE doit+--   where+--     pathMap = M.fromList path+--     doit edgeID m = M.fromList $ do+--       let onPath = M.lookup edgeID pathMap+--       x <- M.keys m+--       return (x, Just x == onPath)+++-- | Make the given path with disamb markers in the given annotation+-- and produce a new disamb annotation.+disambPath :: (Ord t) => [(EdgeID, S.Set t)] -> Anno t Double -> Anno t Bool+disambPath path =+  DAG.mapE doit+  where+    pathMap = M.fromList path+    doit edgeID m = M.fromList $ do+      let onPath = maybe S.empty id $ M.lookup edgeID pathMap+      x <- M.keys m+      return (x, S.member x onPath)+++----------------------+-- Marginals and Probs+----------------------+++-- | Determine marginal probabilities corresponding to individual+-- tags w.r.t. the guessing model.+guessMarginals :: (X.Word w, Ord t) => G.Guesser t P.Tag -> Sent w t -> Anno t Double+guessMarginals gsr = fmap X.unWMap . G.marginals gsr+++-- | Determine marginal probabilities corresponding to individual+-- tags w.r.t. the guessing model.+disambMarginals :: (X.Word w, Ord t) => D.Disamb t -> Sent w t -> Anno t Double+-- disambMarginals dmb = fmap X.unWMap . D.marginals dmb+disambMarginals = disambProbs D.Marginals+++-- | Determine probabilities corresponding to individual+-- tags w.r.t. the guessing model.+disambProbs :: (X.Word w, Ord t) => D.ProbType -> D.Disamb t -> Sent w t -> Anno t Double+disambProbs typ dmb = fmap X.unWMap . D.probs typ dmb+++-------------------------------------------------+-- Trimming+-------------------------------------------------+++-- | Trim down the set of potential labels to `k` most probable ones+-- for each OOV word in the sentence.+trimOOV :: (X.Word w, Ord t) => Int -> Sent w t -> Sent w t+trimOOV k =+  fmap trim+  where+    trim edge = if X.oov edge+      then edge {X.tags = trimWMap k (X.tags edge)}+      else edge+    trimWMap n = X.fromMap . trimMap n . X.unWMap+++-- | Trim down the set of potential labels to the `k` most probable ones.+trimMap :: (Ord t) => Int -> M.Map t Double -> M.Map t Double+trimMap k+  = M.fromList+  . take k+  . reverse+  . sortBy (comparing snd)+  . M.toList+++---------------------+-- Tagging+---------------------+++-- | Extend the OOV words with new, guessed interpretations.+--+-- Determine marginal probabilities corresponding to individual tags w.r.t.+-- the guessing model and, afterwards, trim the sentence to keep only the `k`+-- most probably labels for each OOV edge. Note that, for OOV words, the entire+-- set of default tags is considered.+--+guessSent :: (X.Word w, Ord t) => Int -> G.Guesser t P.Tag -> Sent w t -> Sent w t+guessSent k gsr sent = insertGuessed (fmap (trimMap k) (guessMarginals gsr sent)) sent+-- guessSent k gsr sent = trimOOV k $ replace (guessMarginals gsr sent) sent+++-- | Perform guessing, trimming, and finally determine marginal probabilities+-- corresponding to individual tags w.r.t. the guessing model.+guess :: (X.Word w, Ord t) => Int -> G.Guesser t P.Tag -> Sent w t -> Anno t Double+guess k gsr sent = extract . trimOOV k $ replace (guessMarginals gsr sent) sent+++-- | Perform guessing, trimming, and finally determine marginal probabilities+-- corresponding to individual tags w.r.t. the disambiguation model.+tag :: (X.Word w, Ord t) => Int -> Concraft t -> Sent w t -> Anno t Double+tag k crf = disambMarginals (disamb crf) . guessSent k (guesser crf)+++---------------------+-- Training+---------------------+++-- -- | Train the `Concraft` model.+-- -- No reanalysis of the input data will be performed.+-- --+-- -- The `FromJSON` and `ToJSON` instances are used to store processed+-- -- input data in temporary files on a disk.+-- train+--     :: (X.Word w, Ord t)+--     => P.Tagset             -- ^ A morphosyntactic tagset to which `P.Tag`s+--                             --   of the training and evaluation input data+--                             --   must correspond.+--     -> Int                  -- ^ How many tags is the guessing model supposed+--                             --   to produce for a given OOV word?  It will be+--                             --   used (see `G.guessSent`) on both training and+--                             --   evaluation input data prior to the training+--                             --   of the disambiguation model.+--     -> G.TrainConf t P.Tag  -- ^ Training configuration for the guessing model.+--     -> D.TrainConf t        -- ^ Training configuration for the+--                             --   disambiguation model.+--     -> IO [Sent w t]    -- ^ Training dataset.  This IO action will be+--                             --   executed a couple of times, so consider using+--                             --   lazy IO if your dataset is big.+--     -> IO [Sent w t]    -- ^ Evaluation dataset IO action.  Consider using+--                             --   lazy IO if your dataset is big.+--     -> IO (Concraft t)+-- train tagset guessNum guessConf disambConf trainR'IO evalR'IO = do+--   Temp.withTempDirectory "." ".guessed" $ \tmpDir -> do+--   let temp = withTemp tagset tmpDir+--+--   putStrLn "\n===== Train guessing model ====="+--   guesser <- G.train guessConf trainR'IO evalR'IO+--   let guess = guessSent guessNum guesser+--   trainG  <- map guess <$> trainR'IO+--   evalG   <- map guess <$> evalR'IO+--+--   temp "train" trainG $ \trainG'IO -> do+--   temp "eval"  evalG  $ \evalG'IO  -> do+--+--   putStrLn "\n===== Train disambiguation model ====="+--   disamb <- D.train disambConf trainG'IO evalG'IO+--   return $ Concraft tagset guessNum guesser disamb+--+--+-- ---------------------+-- -- Temporary storage+-- ---------------------+--+--+-- -- | Store dataset on a disk and run a handler on a list which is read+-- -- lazily from the disk.  A temporary file will be automatically+-- -- deleted after the handler is done.+-- --+-- -- NOTE: (11/11/2017): it's just a dummy function right now, which does+-- -- not use disk storage at all.+-- --+-- withTemp+--   -- :: (FromJSON w, ToJSON w)+--   :: P.Tagset+--   -> FilePath                     -- ^ Directory to create the file in+--   -> String                       -- ^ Template for `Temp.withTempFile`+--   -> [Sent w t]                   -- ^ Input dataset+--   -> (IO [Sent w t] -> IO a)      -- ^ Handler+--   -> IO a+-- withTemp _      _   _    [] handler = handler (return [])+-- withTemp tagset dir tmpl xs handler =+--   Temp.withTempFile dir tmpl $ \tmpPath tmpHandle -> do+--     hClose tmpHandle+--     let txtSent = X.mapSent $ P.showTag tagset+--         tagSent = X.mapSent $ P.parseTag tagset+--     handler (return xs)+++---------------------+-- Pruning+---------------------+++-- | Prune the disambiguation model: discard model features with absolute values+-- (in log-domain) lower than the given threshold.+prune :: Double -> Concraft t -> Concraft t+prune x concraft =+    let disamb' = D.prune x (disamb concraft)+    in  concraft { disamb = disamb' }
src/NLP/Concraft/Disamb.hs view
@@ -89,7 +89,7 @@     $ sent   where     schema  = fromConf schemaConf-    split   = P.split tiers+    split   = \t -> P.split tiers t Nothing     embed   = unSplit split  @@ -105,7 +105,7 @@         | y <- X.interps word ]  --- | Combine `disamb` with `include`. +-- | Combine `disamb` with `include`. disambSent :: X.Word w => Disamb -> X.Sent w T.Tag -> X.Sent w T.Tag disambSent = include . disamb @@ -121,7 +121,7 @@     $ sent   where     schema  = fromConf schemaConf-    split   = P.split tiers+    split   = \t -> P.split tiers t Nothing     embed w = X.mkWMap . zip (X.interps w)  @@ -161,7 +161,7 @@     return $ Disamb tiersT schemaConfT crf   where     schema = fromConf schemaConfT-    split  = P.split tiersT+    split  = \t -> P.split tiersT t Nothing  -- Improve disamb model. train ReTrainConf{..} trainData evalData = do@@ -173,7 +173,7 @@   where     Disamb{..} = initDmb     schema = fromConf schemaConf-    split  = P.split tiers+    split  = \t -> P.split tiers t Nothing   -- | Schematized data from the plain file.
src/NLP/Concraft/Disamb/Positional.hs view
@@ -23,31 +23,46 @@ data Tier = Tier {     -- | Does it include the part of speech?       withPos   :: Bool+    -- | End-of-sentence marker.+    , withEos   :: Bool     -- | Tier grammatical attributes.-    , withAtts  :: S.Set TP.Attr }+    , withAtts  :: S.Set TP.Attr+    }  instance Binary Tier where-    put Tier{..} = put withPos >> put withAtts-    get = Tier <$> get <*> get+    put Tier{..} = put withPos >> put withEos >> put withAtts+    get = Tier <$> get <*> get <*> get  -- | An atomic part of morphosyntactic tag with optional POS. data Atom = Atom     { pos   :: Maybe TP.POS-    , atts  :: M.Map TP.Attr T.Text }-    deriving (Show, Eq, Ord)+    , atts  :: M.Map TP.Attr T.Text+    , eos   :: Maybe Bool+      -- ^ NOTE: could be simplified to Bool, but this way it's more readable+    } deriving (Show, Eq, Ord)  instance Binary Atom where-    put Atom{..} = put pos >> put atts-    get = Atom <$> get <*> get+    put Atom{..} = put pos >> put atts >> put eos+    get = Atom <$> get <*> get <*> get  -- | Select tier attributes.-select :: Tier -> TP.Tag -> Atom-select Tier{..} tag = Atom-    { pos   = if withPos then Just (TP.pos tag) else Nothing-    , atts  = M.filterWithKey (\k _ -> k `S.member` withAtts) (TP.atts tag) }+select+  :: Tier       -- ^ The tier+  -> TP.Tag     -- ^ The positional tag+  -> Maybe Bool -- ^ (Maybe) end-of-sentence marker+  -> Atom+select Tier{..} tag eos = Atom+    { pos  = if withPos then Just (TP.pos tag) else Nothing+    , atts = M.filterWithKey (\k _ -> k `S.member` withAtts) (TP.atts tag)+    , eos  = if withEos then eos else Nothing+    }  -- | Split the positional tag.-split :: [Tier] -> TP.Tag -> [Atom]-split tiers tag =-    [ select tier tag+split+  :: [Tier]     -- ^ The tiers+  -> TP.Tag     -- ^ The positional tag+  -> Maybe Bool -- ^ (Maybe) end-of-sentence marker+  -> [Atom]+split tiers tag eos =+    [ select tier tag eos     | tier <- tiers ]
src/NLP/Concraft/Format/Temp.hs view
@@ -17,13 +17,22 @@ encodePar = BC.unlines . map encode  decodePar :: FromJSON w => BC.ByteString -> [Sent w T.Text]-decodePar = +decodePar =     let getRight (Right x) = x         getRight (Left e)  = error $ "error in decodePar: " ++ e     in  map (getRight . eitherDecode') . BC.lines  writePar :: ToJSON w => FilePath -> [Sent w T.Text] -> IO () writePar path = BC.writeFile path . encodePar+-- writePar path xs = do+--   putStrLn $ "Writing JSON to: " ++ path+--   BC.putStrLn (encodePar xs)+--   BC.writeFile path (encodePar xs)  readPar :: FromJSON w => FilePath -> IO [Sent w T.Text] readPar = fmap decodePar . BC.readFile+-- readPar path = do+--   putStrLn $ "Reading JSON from: " ++ path+--   cs <- BC.readFile path+--   BC.putStrLn cs+--   return (decodePar cs)
src/NLP/Concraft/Guess.hs view
@@ -6,7 +6,7 @@ ( -- * Types   Guesser (..)- + -- * Guessing , guess , include@@ -30,10 +30,13 @@  import qualified Control.Monad.Ox as Ox import qualified Data.CRF.Chain1.Constrained as CRF+-- import qualified Data.CRF.Chain1.Constrained.DAG as CRF import qualified Numeric.SGD as SGD  import NLP.Concraft.Schema hiding (schematize) import qualified NLP.Concraft.Morphosyntax as X+-- import           NLP.Concraft.DAG.Schema hiding (schematize)+-- import qualified NLP.Concraft.DAG.Morphosyntax as X   -- | A guessing model.@@ -56,7 +59,7 @@     v = V.fromList sent     n = V.length v     obs = S.fromList . Ox.execOx . schema v-    lbs i +    lbs i         | X.oov w  = S.empty         | otherwise = X.interpsSet w         where w = v V.! i@@ -89,7 +92,7 @@         ++ zip xs [0, 0 ..]  --- | Combine `guess` with `include`. +-- | Combine `guess` with `include`. guessSent :: (X.Word w, Ord t)           => Int -> Guesser t           -> X.Sent w t -> X.Sent w t@@ -99,7 +102,7 @@  -- | Method of constructing the default set of labels (R0). data R0T-    = AnyInterps        -- ^ See `CRF.anyInterps` +    = AnyInterps        -- ^ See `CRF.anyInterps`     | AnyChosen         -- ^ See `CRF.anyChosen`     | OovChosen         -- ^ See `CRF.oovChosen`     deriving (Show, Eq, Ord, Enum, Typeable, Data)
src/NLP/Concraft/Morphosyntax.hs view
@@ -8,7 +8,7 @@   module NLP.Concraft.Morphosyntax-( +( -- * Segment   Seg (..) , mapSeg@@ -25,12 +25,11 @@ , mapSentO  -- * Weighted collection-, WMap (unWMap)-, mapWMap-, mkWMap+, module NLP.Concraft.Morphosyntax.WMap ) where  +import           Prelude hiding (Word) import           Control.Applicative ((<$>), (<*>)) import           Control.Arrow (first) import           Data.Aeson@@ -40,7 +39,9 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as L +import           NLP.Concraft.Morphosyntax.WMap + -------------------------- -- Segment --------------------------@@ -51,9 +52,8 @@     -- | A word represented by the segment.  Typically it will be     -- an instance of the `Word` class.       word  :: w-    -- | A set of interpretations.  To each interpretation-    -- a weight of appropriateness within the context-    -- is assigned.+    -- | A set of interpretations. To each interpretation a weight of+    -- appropriateness within the context is assigned.     , tags  :: WMap t }     deriving (Show) @@ -66,7 +66,7 @@ instance FromJSON w => FromJSON (Seg w T.Text) where     parseJSON (Object v) = Seg         <$> v .: "word"-        <*> (WMap <$> v .: "tags")+        <*> (mkWMap <$> v .: "tags")     parseJSON _ = error "parseJSON (segment): absurd"  @@ -92,7 +92,7 @@  class Word a where     -- | Orthographic form.-    orth    :: a -> T.Text +    orth    :: a -> T.Text     -- | Out-of-vocabulary (OOV) word.     oov     :: a -> Bool @@ -127,22 +127,3 @@ mapSentO f x =     let segs' = mapSent f (segs x)     in  x { segs = segs' }--------------------------- Weighted collection--------------------------- | A set with a non-negative weight assigned to each of--- its elements.-newtype WMap a = WMap { unWMap :: M.Map a Double }-    deriving (Show, Eq, Ord, Binary)----- | Make a weighted collection.  Negative elements will be ignored.-mkWMap :: Ord a => [(a, Double)] -> WMap a-mkWMap = WMap . M.fromListWith (+) . filter ((>=0).snd)----- | Map function over weighted collection elements. -mapWMap :: Ord b => (a -> b) -> WMap a -> WMap b-mapWMap f = mkWMap . map (first f) . M.toList . unWMap
src/NLP/Concraft/Morphosyntax/Accuracy.hs view
@@ -15,6 +15,7 @@ ) where   +import           Prelude hiding (Word) import           Data.List (foldl') import qualified Data.Set as S import qualified Data.Map as M
src/NLP/Concraft/Morphosyntax/Align.hs view
@@ -10,6 +10,7 @@ ) where  +import           Prelude hiding (Word) import           Control.Applicative ((<|>)) import           Data.Maybe (fromJust) import           Data.List (find)
+ src/NLP/Concraft/Morphosyntax/WMap.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+++module NLP.Concraft.Morphosyntax.WMap+( WMap (unWMap)+, fromMap+, mapWMap+, mkWMap+, trim+) where+++import           Control.Arrow (first)+import           Data.Binary (Binary)+import           Data.Ord (comparing)+import           Data.List (sortBy)+import qualified Data.Map as M+++----------------------+-- Weighted collection+----------------------+++-- | A set with a non-negative weight assigned to each of+-- its elements.+newtype WMap a = WMap { unWMap :: M.Map a Double }+    deriving (Show, Eq, Ord, Binary)+++-- | Create WMap from a map.+fromMap :: M.Map a Double -> WMap a+fromMap = WMap+++-- | Make a weighted collection.  Negative elements will be ignored.+mkWMap :: Ord a => [(a, Double)] -> WMap a+mkWMap = WMap . M.fromListWith (+) . filter ((>=0).snd)+++-- | Map function over weighted collection elements.+mapWMap :: Ord b => (a -> b) -> WMap a -> WMap b+mapWMap f = mkWMap . map (first f) . M.toList . unWMap+++--------------------------+-- Trimming+--------------------------+++-- | Trim down the set of potential labels to `k` most probable ones.+trim :: (Ord a) => Int -> WMap a -> WMap a+trim k+  = mkWMap+  . take k+  . reverse+  . sortBy (comparing snd)+  . M.toList+  . unWMap